#!/usr/bin/perl -w
# (c) Stijn van Dongen.

#  Usage: <program> <label file>, prints to STDOUT.
#  You have to supply the right numbers for a number of variables.
#  It has to be done in the code; guidelines and comments are provided.
#  Take notice: units are measured in millimeters,
#  European A4 paper size is 210 x 297 mm.
#  Documentation starts further below.

# TEXT LAY-OUT PARAMETERS TEXT LAY-OUT PARAMETERS TEXT LAY-OUT PARAMETERS

                                      # All lengths are in millimeters (mm).
$addx          =  22;                 # within-label x ofset,   (mm) see below
$adjusty       =  0;                  # for slight adjustments, (mm) see below
$fontheight    =  5;                  # fontheight              (mm) see below
$blskip        =  6;                  # baselineskip            (mm) see below
$fontname      =  "AvantGarde-Book";  # font name,                   see below

$B_test        =  0;                  # change to `0' for production output.

# LABEL LAY-OUT PARAMETERS LABEL LAY-OUT PARAMETERS LABEL LAY-OUT PARAMETERS

                                      # All lengths are in millimeters (mm).
$paperwidth    =  210;                # full paper width.
$paperheight   =  297;                # full paper height.

$ofsetx        =  5;                  # x-dist top-left paper to top-left label
$ofsety        =  15;                 # y-dist top-left paper to top-left label
                                      # (see also below)

$labelwidth    =  100;                # your width of label.
$labelheight   =  38;                 # your height of label.

$nrwide        =  2;                  # nr of labels wide.
$nrhigh        =  7;                  # nr of labels high.


#     Further structure of this preamble:
#  Section GENERAL COMMENTS.
#        Various remarks about using this program.
#  Section TEXT LAY-OUT PARAMETERS.
#        5 parameters (given above) defining the layout of the text on the
#        labels are described. These are used for finetuning.
#  Section LABEL LAY-OUT PARAMETERS.
#        8 further parameters (given above) that define the layout of the
#        labels on the page are described. These have to be set once for the
#        type of paper used.


# GENERAL COMMENTS GENERAL COMMENTS GENERAL COMMENTS GENERAL COMMENTS


#  + The program processes (double) newline separated records (paragraphs)
#  in a file. records are skipped if the first line starts with either `?' or
#  `#'. This is meant for outcommenting records. This is easy to change of
#  course, but there are no hooks.


#  + Somewhere it says `$B_test = 1;' (currently at the top of this file).
#  This is for testing your formatting on screen, by drawing the label
#  boundaries. Change `1' to `0' to toggle this. Note that there are no hooks
#  to show contiguous space inbetween labels. If there is such space you have
#  to lie about your label dimensions (see below) and probably also use the
#  `adjusty' paramater. The center of the boundaries will then be aligned with
#  the horizontals and verticals defined by the left and top sides of the
#  labels.


#  + If labels are noncontiguously aligned, then you have to lie
#  about the width and height of a label, such that the width
#  includes one stretch of horizontally adjacent `void' and the
#  height includes one stretch of vertically adjacent `void'.
#  You then must probably use the `adjusty' parameter to correct
#  for misplaced vertical centering.


#  + It should currently be possible to print digraphs
#  such as йьш± et cetera. This PS hack was copied from `mpage' output
#  without a deep understanding of the details, but the code looks very clean
#  (the charvec thing).


#  + I don't know whether other fonts might break the digraph (йьш±) feature
#  mentioned above. Standard fonts should work ok I guess.


#  + It is currently not possible to use PostScript octal character codes
#  in the input, because backslashes are escaped in the straightforwardliest
#  way possible. But you can use digraphs, did I mention that?


#  + The parameter `adjusty' (variable $adjusty in perl) is used
#  for the purpose of adjustment of the vertical layout. Labels are
#  automatically centered vertically; the printed matter can be shifted using
#  the adjusty variable, but this amount will be the same for all labels and
#  will not depend on the number of lines in the label. This parameter is
#  useful if there is void space inbetween labels (see above), if you don't
#  like centered material, or if you think centering is not good enough (since
#  centering is based on baselines, there will seem to be slightly more white
#  space on top than below).



# TEXT LAY-OUT PARAMETERS TEXT LAY-OUT PARAMETERS TEXT LAY-OUT PARAMETERS


#                                ________________________
#                               |      ^                 |
#                               |      |                 |
#                               |      v                 |
#                               |<---->First line        |
#                               | addx Second line       |
#                               |      Third line        |
#                               |      ^                 |
#                               |      |                 |
#                               |______v_________________|
#
#                 All lengths are in millimeters.
#
#  addx ......... The x ofset of first line of text within a label.
#  adjusty ...... Adjustment of the y ofset (lines are automatically
#                 vertically centered). Default 0 should look ok.
#
#  fontheight ... Font height (in millimeters!).
#  blskip ....... Baselineskip (in millimeters!).
#  fontname ..... Fontname - has to be such that PS can find it.
#
#           All font names available on *my* system.
#
#  Bookman-Demi                     Courier
#  Bookman-DemiItalic               Courier-Oblique
#  Bookman-Light                    Courier-Bold
#  Bookman-LightItalic              Courier-BoldOblique
#                                
#  AvantGarde-Book                  Helvetica
#  AvantGarde-BookOblique           Helvetica-Oblique
#  AvantGarde-Demi                  Helvetica-Bold
#  AvantGarde-DemiOblique           Helvetica-BoldOblique
#
#  Helvetica-Narrow                 Palatino-Roman
#  Helvetica-Narrow-Oblique         Palatino-Italic
#  Helvetica-Narrow-Bold            Palatino-Bold
#  Helvetica-Narrow-BoldOblique     Palatino-BoldItalic
#
#  NewCenturySchlbk-Roman           Times-Roman
#  NewCenturySchlbk-Italic          Times-Italic
#  NewCenturySchlbk-Bold            Times-Bold
#  NewCenturySchlbk-BoldItalic      Times-BoldItalic



# LABEL LAY-OUT PARAMETERS LABEL LAY-OUT PARAMETERS LABEL LAY-OUT PARAMETERS


#  Assume the labels are arranged this way on the page:
#
#                        |-|   <- ofsetx
#                        : :
#                   _     ______________________
#                   | ЁЁ | ,___ ____  ...  ___  |
#                   Ї ЁЁ | |___|___|_ ... |___| |
#               ofsety   | |___|___|_ ... |___| |
#                        | |___|___|_ ... |___| |
#                        | |___|___|_ ... |___| |
#                        | .................... |
#                        | .................... |
#                        | .................... |
#                        | |___|___|_ ... |___| |
#                        | |___|___|_ ... |___| |
#                        | |___|___|_ ... |___| |
#                        | |___|___|_ ... |___| |
#                        | |___|___|_ ... |___| |
#                        |______________________|
#
#                 All lengths are in millimeters.
#
#  paperwidth ... Full width.
#  paperheight .. Full height.
#
#  ofsetx ....... x-dist top left paper - top left top left label
#  ofsety ....... y-dist top left paper - top left top left label
#                 The top left top left label is marked `,' in the scheme
#                 above.  (5,15) works for `Avery' 2x7 laserjet labels.
#
#  labelwidth ... Supply (in millimeters) your label width.
#  labelheight .. Supply (in millimeters) your label height.
#                 It is assumed that there is no void space between labels; if
#                 there *is* void space inbetween labels you will have to lie
#                 about your label dimension (increase them).
#
#  nrwide ....... Supply the number of labels wide.
#  nrhigh ....... Supply the number of labels high.


#--------------------------------------------------------#


{
   $/             =  "";
   @addresses     =  <>;
}

$pscode = q~%!PS-Adobe-2.0
%%Orientation: Portrait
%%EndComments

%%BeginProlog

/reencsmalldict 12 dict def
/ReEncodeSmall
{ reencsmalldict begin
   /newcodesandnames exch def
   /newfontname exch def
   /basefontname exch def
   /basefontdict basefontname findfont def
   /newfont basefontdict maxlength dict def
   basefontdict
      { exch dup /FID ne
         { dup /Encoding eq
            { exch dup length array copy newfont 3 1 roll put }
            { exch newfont 3 1 roll put }
            ifelse
         }
         { pop pop }
         ifelse
      } forall
   newfont /FontName newfontname put
   newcodesandnames aload pop newcodesandnames length 2 idiv
   { newfont /Encoding get 3 1 roll put } repeat
   newfontname newfont definefont pop end
} def
/charvec [
026 /Scaron
027 /Ydieresis
028 /Zcaron
029 /scaron
030 /trademark
031 /zcaron
032 /space
033 /exclam
034 /quotedbl
035 /numbersign
036 /dollar
037 /percent
038 /ampersand
039 /quoteright
040 /parenleft
041 /parenright
042 /asterisk
043 /plus
044 /comma
045 /minus
046 /period
047 /slash
048 /zero
049 /one
050 /two
051 /three
052 /four
053 /five
054 /six
055 /seven
056 /eight
057 /nine
058 /colon
059 /semicolon
060 /less
061 /equal
062 /greater
063 /question
064 /at
065 /A
066 /B
067 /C
068 /D
069 /E
070 /F
071 /G
072 /H
073 /I
074 /J
075 /K
076 /L
077 /M
078 /N
079 /O
080 /P
081 /Q
082 /R
083 /S
084 /T
085 /U
086 /V
087 /W
088 /X
089 /Y
090 /Z
091 /bracketleft
092 /backslash
093 /bracketright
094 /asciicircum
095 /underscore
096 /quoteleft
097 /a
098 /b
099 /c
100 /d
101 /e
102 /f
103 /g
104 /h
105 /i
106 /j
107 /k
108 /l
109 /m
110 /n
111 /o
112 /p
113 /q
114 /r
115 /s
116 /t
117 /u
118 /v
119 /w
120 /x
121 /y
122 /z
123 /braceleft
124 /bar
125 /braceright
126 /asciitilde
127 /.notdef
128 /fraction
129 /florin
130 /quotesingle
131 /quotedblleft
132 /guilsinglleft
133 /guilsinglright
134 /fi
135 /fl
136 /endash
137 /dagger
138 /daggerdbl
139 /bullet
140 /quotesinglbase
141 /quotedblbase
142 /quotedblright
143 /ellipsis
144 /dotlessi
145 /grave
146 /acute
147 /circumflex
148 /tilde
149 /oe
150 /breve
151 /dotaccent
152 /perthousand
153 /emdash
154 /ring
155 /Lslash
156 /OE
157 /hungarumlaut
158 /ogonek
159 /caron
160 /lslash
161 /exclamdown
162 /cent
163 /sterling
164 /currency
165 /yen
166 /brokenbar
167 /section
168 /dieresis
169 /copyright
170 /ordfeminine
171 /guillemotleft
172 /logicalnot
173 /hyphen
174 /registered
175 /macron
176 /degree
177 /plusminus
178 /twosuperior
179 /threesuperior
180 /acute
181 /mu
182 /paragraph
183 /periodcentered
184 /cedilla
185 /onesuperior
186 /ordmasculine
187 /guillemotright
188 /onequarter
189 /onehalf
190 /threequarters
191 /questiondown
192 /Agrave
193 /Aacute
194 /Acircumflex
195 /Atilde
196 /Adieresis
197 /Aring
198 /AE
199 /Ccedilla
200 /Egrave
201 /Eacute
202 /Ecircumflex
203 /Edieresis
204 /Igrave
205 /Iacute
206 /Icircumflex
207 /Idieresis
208 /Eth
209 /Ntilde
210 /Ograve
211 /Oacute
212 /Ocircumflex
213 /Otilde
214 /Odieresis
215 /multiply
216 /Oslash
217 /Ugrave
218 /Uacute
219 /Ucircumflex
220 /Udieresis
221 /Yacute
222 /Thorn
223 /germandbls
224 /agrave
225 /aacute
226 /acircumflex
227 /atilde
228 /adieresis
229 /aring
230 /ae
231 /ccedilla
232 /egrave
233 /eacute
234 /ecircumflex
235 /edieresis
236 /igrave
237 /iacute
238 /icircumflex
239 /idieresis
240 /eth
241 /ntilde
242 /ograve
243 /oacute
244 /ocircumflex
245 /otilde
246 /odieresis
247 /divide
248 /oslash
249 /ugrave
250 /uacute
251 /ucircumflex
252 /udieresis
253 /yacute
254 /thorn
255 /ydieresis
] def
/fontheight  #fontheight def
/#fontname /OurCharSet charvec ReEncodeSmall
/textfont /OurCharSet findfont fontheight scalefont def
/fnamefont /Times-Bold findfont 14 scalefont def
/headerfont /Times-Bold findfont 12 scalefont def
textfont setfont
(a) stringwidth pop /mp_a_x exch def

/mts { moveto show } def

/paperheight #paperheight  def
/paperwidth  #paperwidth   def

/ofsetx      #ofsetx       def
/ofsety      #ofsety       def

/labelheight #labelheight  def
/labelwidth  #labelwidth   def

/addx        #addx         def
/adjusty     #adjusty      def

/nrwide      #nrwide       def
/nrhigh      #nrhigh       def

/blskip      #blskip def

/B_test      #B_test def

/proc_grid {
   B_test 1 eq {
   gsave

   1.0 setlinewidth
   0 1 nrhigh
   {  paperheight ofsety sub exch labelheight mul sub 0 exch moveto
      paperwidth 0 rlineto stroke
   } for

   0 1 nrwide
   {  ofsetx exch labelwidth mul add 0 moveto
      0 paperheight rlineto stroke
   } for
   grestore
   } if
} def

%%EndProlog
%%Page: 1 1
2.845 2.845 scale

~;


$pscode =~ s/#addx/$addx/g;
$pscode =~ s/#adjusty/$adjusty/g;

$pscode =~ s/#fontheight/$fontheight/g;
$pscode =~ s/#blskip/$blskip/g;

$pscode =~ s/#fontname/$fontname/g;


$pscode =~ s/#paperheight/$paperheight/g;
$pscode =~ s/#paperwidth/$paperwidth/g;

$pscode =~ s/#ofsety/$ofsety/g;
$pscode =~ s/#ofsetx/$ofsetx/g;

$pscode =~ s/#labelheight/$labelheight/g;
$pscode =~ s/#labelwidth/$labelwidth/g;

$pscode =~ s/#nrwide/$nrwide/g;
$pscode =~ s/#nrhigh/$nrhigh/g;

$pscode =~ s/#B_test/$B_test/g;
print $pscode;

$addy    =  0.5 * ($labelheight - $blskip);
$page    =  1;

while (@addresses) {
   my ($i, $j);

   ADDRESS:
   for ($i=0;$i<$nrwide;$i++) {
      for ($j=0;$j<$nrhigh;$j++) {
         
         my $posx = $ofsetx + ($i * $labelwidth);
         my $posy = $paperheight - $ofsety - ($j * $labelheight);
         my $address;
         my @lines;

         while (1) {
            $address = shift @addresses;
            unless ($address) {
               $B_EOF = 1;
               last ADDRESS;
            }
            chomp $address;
            @lines = split "\n", $address;

            if ($lines[0] !~ /^[\#\?]/) {
               last;
            }
         }

         my $nrlines = scalar @lines;
         my $addyy = $addy + $adjusty - (($nrlines -3) * $blskip * 0.5);

         my $l    =  0;

         for my $line (@lines) {
            $line =~ s/([\(\)\\])/\\$1/g;
            my $posxx = $posx + $addx;
            my $posyy = $posy - $addyy - ($blskip * $l);
            print "($line) $posxx $posyy mts\n";
            $l++;
         }
         print "\n";
      }
   }

print "proc_grid\n";

$page++;
print "showpage\n\n";
if ($B_EOF) {
   print "%%EOF\n";
}
else {
   print "%%Page: $page $page\n";
   print "2.845 2.845 scale\n";
}

}

