\ProvidesPackage{makebarcode}[2008/07/27 Make various bar codes]
\PackageInfo{makebarcode}{$Id: makebarcode.sty 224 2008-07-26 23:07:27Z zw $\@gobble}

\RequirePackage{kvoptions}
\SetupKeyvalOptions{family=zwbc,prefix=zwbc@}

\DeclareStringOption[.19mm]{X}[.19mm]
\DeclareStringOption[\ZWbc@Hdefault]{H}[\ZWbc@Hdefault]
\DeclareStringOption[0mm]{bcorr}[0mm]
\DeclareStringOption[3]{ratio}[3]
\DeclareStringOption[2]{K} % for 2/5 Matrix, should be in <1.5; 4>
\DeclareStringOption[1]{MtoXratio}[1]
\DeclareStringOption{code}
\DeclareBoolOption{help}

% For ITF codes
% \ZWbc@ITFdefine X R H
\def\ZWbc@ITFdefine #1 #2 #3 {\@tempdima #1mm \multiply\@tempdima 5 \divide\@tempdima 2
  \expandafter\def\expandafter\ZWbc@r\expandafter{\the\@tempdima}%
  \def\ZWbc@R{#2mm}\def\ZWbc@ITF{X=#1mm,H=#3mm,ratio=2.5,MtoXratio=1,code=2/5-Interleaved}}

\DeclareVoidOption{S1.2}{\ZWbc@ITFdefine 1.219 13.1 38.2 }
\DeclareVoidOption{S1.1}{\ZWbc@ITFdefine 1.118 12.0 35.0 }
\DeclareVoidOption{S1}{\ZWbc@ITFdefine   1.016 10.9 31.8 }
\DeclareVoidOption{S.9}{\ZWbc@ITFdefine  0.914  9.8 28.7 }
\DeclareVoidOption{S.8}{\ZWbc@ITFdefine  0.813  8.7 25.4 }
\DeclareVoidOption{S.7}{\ZWbc@ITFdefine  0.711  7.1 22.3 }
\DeclareVoidOption{S.6}{\ZWbc@ITFdefine  0.635  6.4 19.8 }

\DeclareBoolOption{lines}
\DeclareComplementaryOption{frame}{lines}

\ZWbc@ITFdefine 1.016 10.9 31.8 

\ProcessKeyvalOptions*

% List all bar code names at the end of the package
\ifzwbc@help
  \AtEndOfPackage{\PackageInfo{makebarcode}{\ZWbc@codeList\@gobble}}
\fi

% Disable help at the end of the package
\AtEndOfPackage{\DisableKeyvalOption[action=warning,package=makebarcode]{zwbc}{help}}

% Interleave two strings, use as \ZWbc@interleave#1/#2*, result goes to \ZWbc@CHAR
\def\ZWbc@interleave{\def\ZWbc@CHAR{}\ZWbc@dointerleave}
\def\ZWbc@dointerleave#1#2/#3*{%
    \expandafter\def\expandafter\ZWbc@CHAR\expandafter{\ZWbc@CHAR #1}%
    \ifcat_#3_%
      \def\next{}%
    \else
      \def\next{\ZWbc@dointerleave#3/#2*}%
    \fi \next}

% Temp counter
\newcount\ZWbc@ctr

% Make the table: \ZWbc@mktable name code code code @
% The code has the form key|value, if the key is empty, the table is
% automatically numbered

\def\ZWbc@mktable #1 {\ZWbc@ctr\z@
    \def\ZWbc@name{#1}\futurelet\next\ZWbc@tblcode}

\def\ZWbc@tblcode{\if\next\zw@sp \def\next{\ZWbc@xsp:}\else
    \if\next @\let\next\@gobble\else \let\next\ZWbc@mkcode \fi \fi \next}

\def\ZWbc@mkcode #1|#2 {%
    \ifcat_#1_%
      \edef\ZWbc@key{\number\ZWbc@ctr}\advance\ZWbc@ctr\@ne
    \else
      \def\ZWbc@key{#1}%
    \fi
    \expandafter\gdef\csname ZWbc@tbl_\ZWbc@name_\ZWbc@key\endcsname{#2}%
    \ZWbc@nextcode}

\futurelet\zw@sp{ }
\def\ZWbc@xsp: {\ZWbc@nextcode}
\def\ZWbc@nextcode{\futurelet\next\ZWbc@tblcode}

{\catcode`\_12 \lccode`_=32 \lowercase{\gdef\ZWbc@inactspace{_}}}

% Make alias: \ZWbc@alias tblname existing_key new_key

\def\ZWbc@alias #1 #2 #3 {\expandafter\expandafter\expandafter
    \let\expandafter\csname ZWbc@tbl_#1_#3\expandafter\endcsname
                    \csname ZWbc@tbl_#1_#2\endcsname}

% This macro contains the current bar code name for error messages

\def\ZWbc@currentbarcodename{Unknown}

% This macro performs table lookup. It returns the coresponding character(s). If the
% character(s) cannot be found in the table, the starred version returns the input
% character(s) while the standard version emits an error message and returns \ZWbc@.
% The result will be stored in \ZWbc@CHAR.

\def\ZWbc@lookup{\@ifstar\ZWbc@slookup\ZWbc@nlookup}
\def\ZWbc@slookup{\ZWbc@dolookup*}
\def\ZWbc@nlookup{\ZWbc@dolookup!}

\def\ZWbc@dolookup#1#2#3{% switchchar # table_name # character(s)
    \def\ZWbc@key{ZWbc@tbl_#2_#3}%
    \expandafter\ifx\csname\ZWbc@key\endcsname\relax
      \if*#1 #3\else
        \PackageError{makebarcode}{%
           Character(s) `#3' not allowed in \ZWbc@currentbarcodename.}%
          {You want to print `#3' in the bar code \ZWbc@currentbarcodename\MessageBreak
           but it is not defined in the code table. If you proceed,\MessageBreak
           it will be ignored and the resulting bar code will be wrong.}%
        \let\ZWbc@CHAR\ZWbc@
      \else
        \def\ZWbc@CHAR{#3}%
      \fi
    \else
      \edef\ZWbc@CHAR{\csname\ZWbc@key\endcsname}%
    \fi}

% Make \ZWbc@ unexpandable
\let\ZWbc@\relax

% Dimensions

\newdimen\ZWbc@dimX
\newdimen\ZWbc@dimH
\newdimen\ZWbc@dimB
\newdimen\ZWbc@dim@

% Make a bar or blank of a specified width

\def\ZWbc@bar#1{\ZWbc@dim@#1\advance\ZWbc@dim@ -\ZWbc@dimB
    \vrule height \ZWbc@dimH depth \z@ width \ZWbc@dim@}

\def\ZWbc@blank#1{\ZWbc@dim@#1\advance\ZWbc@dim@ \ZWbc@dimB
    \kern \ZWbc@dim@}

% Make an element, bar or blank

\def\ZWbc@element{\ifx\ZWbc@prevelem\ZWbc@blank
    \let\ZWbc@prevelem\ZWbc@bar \else
    \let\ZWbc@prevelem\ZWbc@blank \fi \ZWbc@prevelem}

% Set required width to \@tempdima, two algorithms used

\def\ZWbc@widenarrow#1{%
    \if 0#1%
      \@tempdima=\ZWbc@dimX
    \else
      \@tempdima=\zwbc@ratio\ZWbc@dimX
      \if K#1%
        \@tempdima=\zwbc@K\@tempdima
      \fi
    \fi}

\def\ZWbc@propwidth#1{\@tempdima=#1\ZWbc@dimX}

% Make a character, width algorithm given as the first token
% bar specification is delimited by @

\def\ZWbc@character#1{\let\ZWbc@alg#1\let\ZWbc@prevelem\ZWbc@blank
    \ZWbc@printchar}

\def\ZWbc@printchar#1#2@{\ZWbc@alg#1\ZWbc@element{\@tempdima}%
    \ifcat_#2_\let\next\ZWbc@endchar\else
    \def\next{\ZWbc@printchar#2@}\fi \next}

\def\ZWbc@endchar{\ifx\ZWbc@prevelem\ZWbc@bar \ZWbc@blank{\zwbc@MtoXratio\ZWbc@dimX}\fi}

% Make a barcode

\DeclareRobustCommand\barcode{\begingroup \catcode`\-12 \catcode`\"12 \ZWbc@barcode}
\newcommand*\ZWbc@barcode[1][]{\ifcat$#1$ \else \setkeys{zwbc}{#1}\fi
  \let\ZWbc@mkbarcode\endgroup
  \ifcat$\zwbc@code$
    \PackageError{makebarcode}{%
       No barcode type specified.}%
      {You have not specified the type of the barcode. If you proceed,\MessageBreak
       the argument will be displayed as a normal text.}%
  \else
    \edef\ZWbc@currentbarcodename{\zwbc@code}%
    \edef\ZWbc@@@{ZWbc@code_\ZWbc@currentbarcodename}%
    \expandafter\ifx\csname\ZWbc@@@\endcsname\relax
      \PackageError{makebarcode}{%
         Unknown barcode type \ZWbc@currentbarcodename}%
        {You have requested barcode type \ZWbc@currentbarcodename which is not\MessageBreak
         implemented in this package. If you proceed, the argument\MessageBreak
         will be displayed as a normal text.}%
    \else
      \expandafter\let\expandafter\ZWbc@mkbarcode\csname\ZWbc@@@\endcsname\ZWbc@setdims
    \fi
  \fi \ZWbc@mkbarcode}

\def\ZWbc@def#1{\ZWbc@addTo{\MessageBreak #1}\expandafter\def\csname ZWbc@code_#1\endcsname}

\def\ZWbc@addTo#1{\expandafter\def\expandafter\ZWbc@codeList\expandafter{\ZWbc@codeList #1}}
\def\ZWbc@codeList{List of supported bar codes:}

% Set dimensions

\def\ZWbc@setdims{%
    \ZWbc@dimX=\zwbc@X
    \ZWbc@dimH=\zwbc@H
    \ZWbc@dimB=\zwbc@bcorr}

\def\ZWbc@Hdefault{40\ZWbc@dimX}

% Sanitization

\def\BarcodeSanitize{\@sanitize \catcode`\\0 }

% End barcode printing

\def\ZWbc@endbarcode{%
  \expandafter\ZWbc@character\expandafter\ZWbc@widenarrow\ZWbc@stop @\unkern
  \endgroup}

% Table for 2/5 codes

\ZWbc@mktable 2/5
     0|00110
     1|10001
     2|01001
     3|11000
     4|00101
     5|10100
     6|01100
     7|00011
     8|10010
     9|01010
     @

% 2/5 Start/Stop characters

\ZWbc@mktable 2/5startstop
     Start|110
     Stop|101
     IATAstart|00
     IATAstop|10
     InterleavedStart|000
     InterleavedStop|100
     MatrixStart|K0000
     @

\ZWbc@alias 2/5startstop MatrixStart MatrixStop
\ZWbc@alias 2/5startstop InterleavedStart DatalogicStart
\ZWbc@alias 2/5startstop InterleavedStop DatalogicStop

% 2/5 Industrial

\ZWbc@def{2/5-Industrial}{%
  \ZWbc@lookup{2/5startstop}{Start}%
  \expandafter\ZWbc@interleave\ZWbc@CHAR/00*%
  \edef\ZWbc@start{\ZWbc@CHAR}%
  \ZWbc@lookup{2/5startstop}{Stop}%
  \expandafter\ZWbc@interleave\ZWbc@CHAR/00*%
  \edef\ZWbc@stop{\ZWbc@CHAR}\ZWbc@init@twofive}

% 2/5 IATA

\ZWbc@def{2/5-IATA}{%
  \ZWbc@lookup{2/5startstop}{IATAstart}%
  \expandafter\ZWbc@interleave\ZWbc@CHAR/0*%
  \edef\ZWbc@start{\ZWbc@CHAR}%
  \ZWbc@lookup{2/5startstop}{IATAstop}%
  \expandafter\ZWbc@interleave\ZWbc@CHAR/0*%
  \edef\ZWbc@stop{\ZWbc@CHAR}\ZWbc@init@twofive}

% 2/5 Matrix

\ZWbc@def{2/5-Matrix}{%
  \ZWbc@lookup{2/5startstop}{MatrixStart}%
  \edef\ZWbc@start{\ZWbc@CHAR}%
  \ZWbc@lookup{2/5startstop}{MatrixStop}%
  \edef\ZWbc@stop{\ZWbc@CHAR}\ZWbc@compacttrue\ZWbc@init@twofive}

% 2/5 Datalogic

\ZWbc@def{2/5-Datalogic}{%
  \ZWbc@lookup{2/5startstop}{DatalogicStart}%
  \edef\ZWbc@start{\ZWbc@CHAR}%
  \ZWbc@lookup{2/5startstop}{DatalogicStop}%
  \edef\ZWbc@stop{\ZWbc@CHAR}\ZWbc@compacttrue\ZWbc@init@twofive}

% 2/5 Inverted

\ZWbc@def{2/5-Inverted}{%
  \ZWbc@lookup{2/5startstop}{Start}%
  \edef\ZWbc@CHAR{000/\ZWbc@CHAR*}%
  \expandafter\ZWbc@interleave\ZWbc@CHAR
  \edef\ZWbc@start{\ZWbc@CHAR}%
  \ZWbc@lookup{2/5startstop}{Stop}%
  \edef\ZWbc@CHAR{0000/\ZWbc@CHAR*}%
  \expandafter\ZWbc@interleave\ZWbc@CHAR
  \edef\ZWbc@stop{\ZWbc@CHAR}\ZWbc@invertedtrue\ZWbc@init@twofive}

% 2/5-Interleaved

\ZWbc@def{2/5-Interleaved}{%
  \ZWbc@lookup{2/5startstop}{InterleavedStart}%
  \edef\ZWbc@start{\ZWbc@CHAR}%
  \ZWbc@lookup{2/5startstop}{InterleavedStop}%
  \edef\ZWbc@stop{\ZWbc@CHAR}\begingroup \BarcodeSanitize \ZWbc@count@twofive}

% Optionally prepend leading zero
\def\ZWbc@count@twofive#1{\endgroup
  \edef\ZWbc@string{#1}\expandafter\ZWbc@nextchar\ZWbc@string*}

\def\ZWbc@nextchar#1#2*{\ZWbc@flip
  \ifcat_#2_%
    \let\next\ZWbc@int@leading
  \else
    \def\next{\ZWbc@nextchar#2*}%
  \fi \next}

\def\ZWbc@int@leading{\ifZWbc@compact \edef\ZWbc@string{0\ZWbc@string}\fi
  \expandafter\ZWbc@character\expandafter\ZWbc@widenarrow\ZWbc@start @%
  \expandafter\ZWbc@int@twofive\ZWbc@string*}

\def\ZWbc@int@twofive#1#2#3*{%
  \ZWbc@lookup{2/5}{#1}%
  \ifx\ZWbc@CHAR\ZWbc@ \else
    \edef\ZWbc@temp{\ZWbc@CHAR}%
    \ZWbc@lookup{2/5}{#2}%
    \ifx\ZWbc@CHAR\ZWbc@ \else
      \edef\ZWbc@temp{\ZWbc@temp/\ZWbc@CHAR*}%
      \expandafter\ZWbc@interleave\ZWbc@temp
      \expandafter\ZWbc@character\expandafter\ZWbc@widenarrow\ZWbc@CHAR @%
    \fi
  \fi
  \ifcat_#3_\let\next\ZWbc@endbarcode\else
  \def\next{\ZWbc@int@twofive#3*}\fi \next}

\def\ZWbc@flip{\ifZWbc@compact \ZWbc@compactfalse \else \ZWbc@compacttrue \fi}

% Common 2/5 commands

\newif\ifZWbc@compact
\newif\ifZWbc@inverted

\def\ZWbc@init@twofive{\begingroup \BarcodeSanitize \ZWbc@twofive}

\def\ZWbc@twofive#1{\endgroup \edef\ZWbc@string{#1}%
  \expandafter\ZWbc@character\expandafter\ZWbc@widenarrow\ZWbc@start @%
  \expandafter\ZWbc@dotwofive\ZWbc@string*}

\def\ZWbc@dotwofive#1#2*{%
  \ZWbc@lookup{2/5}{#1}%
  \ifx\ZWbc@CHAR\ZWbc@ \else
    \ifZWbc@compact \else
      \ifZWbc@inverted
        \edef\ZWbc@CHAR{00000/\ZWbc@CHAR*}%
        \expandafter\ZWbc@interleave\ZWbc@CHAR
      \else
        \expandafter\ZWbc@interleave\ZWbc@CHAR/0000*%
      \fi
    \fi
    \expandafter\ZWbc@character\expandafter\ZWbc@widenarrow\ZWbc@CHAR @%
  \fi
  \ifcat_#2_\let\next\ZWbc@endbarcode\else
  \def\next{\ZWbc@dotwofive#2*}\fi \next}

% Table for 39 codes (** is a start/stop character, not 2 stars)

\ZWbc@mktable 39
     |000110100
     |100100001
     |001100001
     |101100000
     |000110001
     |100110000
     |001110000
     |000100101
     |100100100
     |001100100
     |100001001
     |001001001
     |101001000
     |000011001
     |100011000
     |001011000
     |000001101
     |100001100
     |001001100
     |000011100
     |100000011
     |001000011
     |101000010
     |000010011
     |100010010
     |001010010
     |000000111
     |100000110
     |001000110
     |000010110
     |110000001
     |011000001
     |111000000
     |010010001
     |110010000
     |011010000
     |010000101
     |110000100
     |011000100
     |010101000
     |010100010
     |010001010
     |000101010
     |010010100
     @

{\catcode`\$ 12 \catcode`\%12
\ZWbc@mktable 39num
     0|0
     1|1
     2|2
     3|3
     4|4
     5|5
     6|6
     7|7
     8|8
     9|9
     A|10
     B|11
     C|12
     D|13
     E|14
     F|15
     G|16
     H|17
     I|18
     J|19
     K|20
     L|21
     M|22
     N|23
     O|24
     P|25
     Q|26
     R|27
     S|28
     T|29
     U|30
     V|31
     W|32
     X|33
     Y|34
     Z|35
     -|36
     .|37
     { }|38
     $|39
     /|40
     +|41
     %|42
     **|43
     @
}

% Code39

\ZWbc@def{Code39}{%
  \ZWbc@lookup{39num}{**}%
  \ZWbc@lookup{39}{\ZWbc@CHAR}%
  \edef\ZWbc@start{\ZWbc@CHAR}%
  \let\ZWbc@stop\ZWbc@start
  \ZWbc@init@threenine}

\def\ZWbc@init@threenine{\begingroup \BarcodeSanitize \ZWbc@threenine}

\def\ZWbc@threenine#1{\endgroup \edef\ZWbc@string{#1}%
  \expandafter\ZWbc@character\expandafter\ZWbc@widenarrow\ZWbc@start @%
  \expandafter\ZWbc@dothreenine\ZWbc@string*}

\def\ZWbc@dothreenine#1#2*{%
  \ZWbc@lookup{39num}{#1}%
  \ifx\ZWbc@CHAR\ZWbc@ \else
    \ZWbc@lookup{39}{\ZWbc@CHAR}%
    \expandafter\ZWbc@character\expandafter\ZWbc@widenarrow\ZWbc@CHAR @%
  \fi
  \ifcat_#2_\let\next\ZWbc@endbarcode\else
  \def\next{\ZWbc@dothreenine#2*}\fi \next}

% HPlabel, requires rotating, must be loaded separatelly
% see http://www.hp.com/go/storagemedia

\def\HPlabel{\begingroup \BarcodeSanitize \ZWbc@HPlabel}
\ZWbc@addTo{\MessageBreak\string\HPlabel\space (using Code39)}

\def\ZWbc@HPlabel#1{\endgroup \edef\ZWbc@hpstring{#1}%
  \vbox to 16.5mm{\hsize 78mm \parindent\z@ \parskip\z@ \lineskiplimit\z@ \lineskip.9mm
    \usefont{OT1}{phv}{m}{n}\leftskip 5.5mm \rightskip\leftskip
    \noindent \barcode[code=Code39,X=.42mm,ratio=3,H=6.3mm,bcorr=0mm]{#1}\par
    \setbox\ZWbc@hpbox=\hbox
       {\begin{turn}{180}\barcode[code=Code39,X=.23mm,ratio=3,H=6.5mm,bcorr=0mm]{#1}\end{turn}}
    \noindent \raise\dp\ZWbc@hpbox\box\ZWbc@hpbox \hfill
    \begin{sideways}\vbox{\hsize 6.5mm \fontsize{10}{11}\selectfont
      \leftskip\z@ \rightskip\z@ \centering
      \expandafter\ZWbc@mkHPlabel\ZWbc@hpstring\ZWbc@}\end{sideways}\par
  \vss
  \centering \fontsize{6}{6}\selectfont
  This edge of the label toward hub of tape\par}}

\def\ZWbc@mkHPlabel#1#2#3#4#5#6#7#8#9\ZWbc@{%
  \ifcat_#8_\ZWbc@HPtoofew\fi
  \ifcat_#9_\else\ZWbc@HPtoomany\fi
  #1\par#2\par#3\par#4\par#5\par#6\par#7#8\par}

\newbox\ZWbc@hpbox

\def\ZWbc@HPtoomany{\ZWbc@HPerror{many}}
\def\ZWbc@HPtoofew{\ZWbc@HPerror{few}}
\def\ZWbc@HPerror#1{\PackageError{makebarcode}%
  {Too #1 characters supplied in HP label code \ZWbc@hpstring}%
  {The label code must contain exactly 8 characters.\MessageBreak
   Your label will be unusable.}}

% ITF-6/14/16

\def\ITFbarcode{\begingroup \BarcodeSanitize \ZWbc@ITFbarcode}
\ZWbc@addTo{\MessageBreak\string\ITFbarcode\space (ITF-6/14/16)}

\newbox\ZWbc@ITFbox
\newdimen\ZWbc@ITFwidth
\newtoks\ZWbc@ITFtoks

\newcommand*\ZWbc@ITFbarcode[2][]{\ifcat$#1$\else \setkeys{zwbc}{#1}\fi
  \vbox{\hbox{\vbox{%
    \ifzwbc@lines
      \hrule height \ZWbc@r
    \else
      \hrule height 4.8mm
    \fi
    \setbox\ZWbc@ITFbox=\hbox{%
      \ifzwbc@lines
        \hskip\ZWbc@r
      \else
        \vrule width 4.8mm \hskip\ZWbc@R
      \fi
      \relax
      \expandafter\barcode\expandafter[\ZWbc@ITF]{#2}%
      \ifzwbc@lines
        \hskip\ZWbc@r
      \else
        \hskip\ZWbc@R \vrule width 4.8mm
      \fi}%
    \global\ZWbc@ITFwidth\wd\ZWbc@ITFbox \box\ZWbc@ITFbox
    \ifzwbc@lines
      \hrule height \ZWbc@r
    \else
      \hrule height 4.8mm
    \fi}}%
    \vskip\ZWbc@r
    \ZWbc@startITFdigits #2\ZWbc@
    \font\ocrb ocrb10 at 14.4pt
    \hbox to \ZWbc@ITFwidth{\hskip\@tempdima \ocrb \the\ZWbc@ITFtoks\hskip\@tempdima}%
  }%
  \endgroup}


\def\ZWbc@startITFdigits#1{\ZWbc@ctr\@ne
  \@tempdima\ZWbc@r \multiply\@tempdima 2
  \ifzwbc@lines
    \advance\@tempdima\ZWbc@r
  \else
    \advance\@tempdima\ZWbc@R
    \advance\@tempdima 4.8mm
  \fi
  \ZWbc@ITFtoks{#1}\ZWbc@ITFdigits}

\def\ZWbc@ITFdigits#1#2\ZWbc@{%
  \ZWbc@ITFtoks\expandafter{\the\ZWbc@ITFtoks\hfill #1}%
  \advance\ZWbc@ctr\@ne
  \ifcat$#2$%
    \let\next\ZWbc@endITFdigits
  \else
    \def\next{\ZWbc@ITFdigits#2\ZWbc@}%
  \fi \next}

\def\ZWbc@endITFdigits{%
  \ifnum\ZWbc@ctr=6 \else
    \ifnum\ZWbc@ctr=14 \else
      \ifnum\ZWbc@ctr=16 \else
        \PackageError{makebarcode}%
          {Wrong number of digits for ITF-6/14/16}%
          {Only ITF-6, ITF-14, ITF-16 are allowed.\MessageBreak
           You must supply corresponding number of digits.\MessageBreak
           This bar code will be unusable.}%
      \fi
    \fi
  \fi}

% Test macro (to be removed)
\def\ZWBCtest #1 {\csname ZWbc@#1\endcsname}
