Files: 5600d514ae78f157e1232e090a04330cf6fe5aef / freecheck
44875 bytesRaw
1 | #!/usr/bin/perl |
2 | |
3 | #--------------- |
4 | # |
5 | # FreeCheck - a free check printing application released |
6 | # under the GNU General Public Licene. |
7 | # |
8 | # Copyright (C) 2000 Eric Sandeen <sandeen-freecheck@sandeen.net> |
9 | # Copyright (C) 2002 James Klicman <james@klicman.org> |
10 | # |
11 | # This program is free software; you can redistribute it and/or modify |
12 | # it under the terms of the GNU General Public License as published by |
13 | # the Free Software Foundation; either version 2 of the License, or |
14 | # (at your option) any later version. |
15 | # |
16 | # This program is distributed in the hope that it will be useful, |
17 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
19 | # GNU General Public License for more details. |
20 | # |
21 | # You should have received a copy of the GNU General Public License |
22 | # along with this program; if not, write to the Free Software |
23 | # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
24 | # |
25 | #--------------- |
26 | |
27 | $version = "0.30.1"; |
28 | $systemConfigFile = "/etc/freecheck/freecheck.cfg"; |
29 | $ConfigFile = $ENV{"HOME"} . "/.freecheck.cfg"; |
30 | |
31 | use Getopt::Long; |
32 | use File::Copy qw(copy); |
33 | |
34 | |
35 | # This tells us how to format the strings from the cfg file |
36 | # so we can print it as a PostScript definition |
37 | # The key read will replace "value" for each of these |
38 | # Strings are enclosed in parentheses (String) (Foobar) |
39 | # Fonts are preceded by a "/" /FontName /Arial |
40 | # Digits are fine as they are Digit 123 |
41 | # Booleans are fine too Bool true |
42 | # But to be safe, do digits and bools as subroutines: |
43 | # Subroutines are in {} {subr} {3 mul} |
44 | |
45 | %Formats = qw( |
46 | # Globals |
47 | MICRFontName /value |
48 | MICRFontSize {value} |
49 | TransitSymbol (value) |
50 | OnUsSymbol (value) |
51 | AmountSymbol (value) |
52 | DashSymbol (value) |
53 | MICRVerTweak {value} |
54 | MICRHorTweak {value} |
55 | # Account |
56 | CheckNumber {value} |
57 | PrintCheckBody {value} |
58 | PrintMICRLine {value} |
59 | NumPages {value} |
60 | Name1 (value) |
61 | Name2 (value) |
62 | Address1 (value) |
63 | Address2 (value) |
64 | CityStateZip (value) |
65 | PhoneNumber (value) |
66 | BankName (value) |
67 | BankAddr1 (value) |
68 | BankAddr2 (value) |
69 | BankCityStateZip (value) |
70 | AuxOnUs (value) |
71 | Routing (value) |
72 | OnUs (value) |
73 | Fraction (value) |
74 | PrintVOID {value} |
75 | # Styles |
76 | CheckLayout /value |
77 | StandardFontName /value |
78 | StandardFontSize {value} |
79 | BoldFontName /value |
80 | BoldFontSize {value} |
81 | CheckNumDigits {value} |
82 | CheckNumFontName /value |
83 | CheckNumFontSize {value} |
84 | FractionFontName /value |
85 | FractionFontSize {value} |
86 | Underline {value} |
87 | LineWidth {value} |
88 | MemoLineHeight {value} |
89 | SignatureLineHeight {value} |
90 | BankInfoHeight {value} |
91 | AmountLineHeight {value} |
92 | PayeeLineHeight {value} |
93 | DateLineHeight {value} |
94 | LogoFile (value) |
95 | LogoWidth {value} |
96 | LogoHeight {value} |
97 | LogoPadding {value} |
98 | LogoHorOffset {value} |
99 | LogoVerOffset {value} |
100 | LogoBorder {value} |
101 | LogoBBox [value] |
102 | # Check Blank Types |
103 | CheckHeight {value} |
104 | CheckWidth {value} |
105 | CheckHorOffset {value} |
106 | CheckVerOffset {value} |
107 | ChecksPerPage {value} |
108 | ChecksMod {value} |
109 | LeftMargin {value} |
110 | RightMargin {value} |
111 | TopMargin {value} |
112 | ); |
113 | |
114 | # Parse command line options and deal with them: |
115 | |
116 | GetOptions ("config:s", # Config file |
117 | "account:s", # Account definition name |
118 | "checknum:i", # Check number optional (overrides acct file) |
119 | "pages:i", # Number of pages to print |
120 | "checkstyle:s", # Check style (defaults to "normal_style.ps" |
121 | "checktype:s", # Check blank definition |
122 | "nomicr", # Prevents MICR line from printing (body only) |
123 | "nobody", # Prevents body from printing (MICR line only) |
124 | "showaccounts", # Show available accounts |
125 | "showstyles", # Show available check styles |
126 | "showblanks", # Show available check blanks |
127 | "test", # Don't increment check n, and print VOID |
128 | "preserve", # Don't increment check n |
129 | "cgi:s", # Accept big string from CGI script (or similar) |
130 | "help") |
131 | |
132 | or Show_Usage(); |
133 | |
134 | if ($opt_help) { |
135 | Show_Usage(); |
136 | } |
137 | |
138 | if ($opt_config) { |
139 | $ConfigFile = $opt_config; |
140 | } elsif ( ! -e $ConfigFile ) { |
141 | copy $systemConfigFile, $ConfigFile; |
142 | } |
143 | |
144 | # Some defaults... |
145 | if (!$opt_cgi) { |
146 | $opt_account = "sample" unless defined $opt_account; |
147 | $opt_checktype = "MVG3001" unless defined $opt_checktype; |
148 | $opt_checkstyle = "normal" unless defined $opt_checkstyle; |
149 | } |
150 | |
151 | # Pull the config file into a string... |
152 | $config_file = read_file($ConfigFile); |
153 | |
154 | # See what sections are available |
155 | Get_Sections(); |
156 | |
157 | # If we're missing the [Global] section, or if a requested section |
158 | # cannot be found, die. |
159 | if (!$global_found) { |
160 | die ("No [Global] section found in config file\n"); |
161 | } |
162 | |
163 | if ($accounts !~ /${opt_account}/i) { |
164 | die ("Account $opt_account not found in config file\n"); |
165 | } |
166 | |
167 | if ($checkblanks !~ /$opt_checktype/i) { |
168 | die ("Check type $opt_checktype not found in config file\n"); |
169 | } |
170 | |
171 | if ($checkstyles !~ /$opt_checkstyle/i) { |
172 | die ("Style $opt_checkstyle not found in config file\n"); |
173 | } |
174 | |
175 | # Show list of available sections, if requested |
176 | if ($opt_showaccounts || $opt_showstyles || $opt_showblanks) { |
177 | print "\nFreeCheck v$version\n"; |
178 | if ($opt_showaccounts) { |
179 | print "Accounts:\n"; |
180 | foreach (split(/\s+/,$accounts)) { |
181 | print "\t$_\n"; |
182 | } |
183 | } |
184 | if ($opt_showstyles) { |
185 | print "Check Styles:\n"; |
186 | foreach (split(/\s+/,$checkstyles)) { |
187 | print "\t$_\n"; |
188 | } |
189 | } |
190 | if ($opt_showblanks) { |
191 | print "Check Types:\n"; |
192 | foreach (split(/\s+/,$checkblanks)) { |
193 | print "\t$_\n"; |
194 | } |
195 | } |
196 | die("\n"); |
197 | } |
198 | |
199 | # Go through the config and fill up a hash with PostScript defines... |
200 | Parse_Config($config_file); |
201 | |
202 | # Overwrite anything we got from the config file with what was on the |
203 | # Command Line (if anything...) |
204 | |
205 | if ($opt_checknum) { |
206 | $Definitions{"CheckNumber"} = $opt_checknum; |
207 | } |
208 | |
209 | if ($opt_pages) { |
210 | $Definitions{"NumPages"} = $opt_pages; |
211 | } |
212 | |
213 | if ($opt_nomicr) { |
214 | $Definitions{"PrintMICRLine"} = "false"; |
215 | } |
216 | |
217 | if ($opt_nobody) { |
218 | $Definitions{"PrintCheckBody"} = "false"; |
219 | } |
220 | |
221 | # This probably isn't in the config file (although it might be...) |
222 | # so cover both possibilites (true/false) |
223 | if ($opt_test) { |
224 | $Definitions{"PrintVOID"} = "true"; |
225 | } else { |
226 | $Definitions{"PrintVOID"} = "false"; |
227 | } |
228 | |
229 | # the --cgi option lets us pass in name value pairs in a string. |
230 | # This will overwrite anything we got from the config file, or |
231 | # from the other command line options (--cgi has the last word) |
232 | # Parse as follows: |
233 | # name is the first word, everything following it is the value |
234 | # each line contains one name/value pair. |
235 | |
236 | while ( $opt_cgi =~ /(^\w+)\s+?(.*$)/mcg ) { |
237 | $Definitions{$1} = $2; |
238 | } |
239 | |
240 | ################## |
241 | # Error Checking # |
242 | ################## |
243 | |
244 | $error = ""; |
245 | |
246 | # Make sure that MICR line is only numbers and symbols |
247 | |
248 | if ( $Definitions{"Routing"} !~ /^R[0-9]+R$/ ) { |
249 | $error = $error . "Error - Routing number must be numeric, with an \"R\" on each end\n"; |
250 | } |
251 | |
252 | if ( $Definitions{"AuxOnUs"} !~ /^[0-9\-CPS]*$/ ) { |
253 | $error = $error . "Error - Auxiliary On-Us field may only be numeric, with \"-\", and MICR symbols (C,P,S)\n"; |
254 | } |
255 | |
256 | if ( $Definitions{"OnUs"} !~ /^[0-9\-CPS]+$/ ) { |
257 | $error = $error . "Error - On-Us field may only be numeric, with \"-\", and MICR symbols (C,P,S)\n"; |
258 | } |
259 | |
260 | if ( $Definitions{"CheckNumber"} !~ /^[0-9]+$/ ) { |
261 | $error = $error . "Error - Check number must be numeric \n"; |
262 | } |
263 | |
264 | if ( $Definitions{"NumPages"} !~ /^[0-9]+$/ ) { |
265 | $error = $error . "Error - Number of pages must be numeric\n"; |
266 | } |
267 | |
268 | if ( $Definitions{"Fraction"} !~ /^[0-9]{2}\s*\-\s*[0-9]{1,4}\s*\/\s*[0-9]{3,4}$/ ) { |
269 | $error = $error . "Error - Routing fraction must be numeric, with a \"-\" in the numerator\n"; |
270 | } |
271 | |
272 | if ($Definitions{'CheckLayout'} !~ /^(Original|QStandard|QWallet)$/) { |
273 | $error .= "Error - CheckLayout must be Original, QStandard or QWallet\n"; |
274 | } |
275 | |
276 | # Get routing symbol and institution number from routing number |
277 | $RoutingSymbol = substr($Definitions{"Routing"},1,4); |
278 | $Institution = substr($Definitions{"Routing"},5,4); |
279 | |
280 | # Strip any leading zeros... |
281 | # Only should be one on routing... |
282 | $RoutingSymbol =~ s/^0//; |
283 | # One or more on institution |
284 | #$Institution =~ s/^0+//; |
285 | |
286 | # Fraction format: |
287 | # |
288 | # 2 digits, a "-", institution number (no leading zeros) |
289 | # ------------------------------------------------------ |
290 | # routing number (no leading zeros) |
291 | |
292 | |
293 | if ( $Definitions{"Fraction"} !~ /^[0-9]{2}\-${Institution}\/${RoutingSymbol}$/ ) { |
294 | $error = $error . "Error - Routing fraction does not match routing number\n"; |
295 | } |
296 | |
297 | |
298 | # Test the MICR line for correctness |
299 | if ( length ($Definitions{"Routing"}) != 11 ) { |
300 | $error = $error . "Error - Routing number must be exactly 9 digits long, with |
301 | an \"R\" on each end\n"; |
302 | } |
303 | |
304 | # Test the MICR checksum |
305 | # Don't forget the real routing number is sandwiched between "Rs" |
306 | |
307 | unless ( ( $Definitions{"Routing"} !~ /^R[0-9]+R$/) || ( length ($Definitions{"Routing"}) != 11 ) ){ |
308 | |
309 | $CheckSum = 0; |
310 | |
311 | @CheckSumMults = (3, 7, 1, 3, 7, 1, 3, 7); |
312 | for ($Digit = 1; $Digit < 9; $Digit++) { |
313 | $CheckSum = $CheckSum + |
314 | $CheckSumMults[$Digit-1] * substr($Definitions{"Routing"}, $Digit, 1); |
315 | } |
316 | |
317 | $CheckSum = 10 - ($CheckSum % 10); |
318 | |
319 | # Kludge alert... |
320 | if ($CheckSum == 10) { |
321 | $CheckSum = 0; |
322 | } |
323 | |
324 | if ( $CheckSum ne substr($Definitions{"Routing"}, 9, 1) ) { |
325 | $error = $error . "Error - Routing Number Checksum Incorrect\n"; |
326 | } |
327 | } |
328 | |
329 | if (defined $Definitions{'LogoFile'}) { |
330 | if (open(EPS,"<$Definitions{'LogoFile'}")) { |
331 | my $foundbbox = 0; |
332 | while (<EPS>) { |
333 | break if /^%%EndComments/; |
334 | next unless s/^%%((?:HiRes)?BoundingBox):\s*//; |
335 | my $hires = ($1 eq 'HiResBoundingBox'); |
336 | $foundbbox = 1; |
337 | if (/^(-?\d+(?:\.\d+)?(?:\s+-?\d+(?:\.\d+)?){3})\s*(?:%.*)?$/) { |
338 | $Definitions{'LogoBBox'} = $1; |
339 | } else { |
340 | $error .= "Error - Can't parse EPS Logo BoundingBox comment\n"; |
341 | } |
342 | # keep looking until HiResBoundingBox or EndComments |
343 | break if $hires; |
344 | } |
345 | close(EPS); |
346 | |
347 | unless ($foundbbox) { |
348 | $error .= "Error - Required EPS Logo BoundingBox not found\n"; |
349 | } |
350 | } else { |
351 | $error .= "Error - Can't open LogoFile $Definitions{'LogoFile'}: $!\n"; |
352 | } |
353 | } |
354 | |
355 | |
356 | # die() if we got errors |
357 | if ( $error && !$opt_test ) { |
358 | print STDERR $error; |
359 | die("Errors Encountered\n"); |
360 | } |
361 | |
362 | # Print PostScript |
363 | |
364 | # Initial stuff: |
365 | print <<"__END_OF_POSTSCRIPT__"; |
366 | %!PS-Adobe-3.0 |
367 | %%Title: FreeCheck |
368 | %%LanguageLevel: 2 |
369 | %%EndComments |
370 | %%BeginProlog |
371 | /inch {72 mul} def |
372 | __END_OF_POSTSCRIPT__ |
373 | |
374 | # Go through $Definitions and print them out PostScript-Like |
375 | Print_Defs(); |
376 | |
377 | |
378 | if (defined $Definitions{'LogoFile'}) { |
379 | my $filesize = (stat($Definitions{'LogoFile'}))[7]; |
380 | print <<"__END_OF_POSTSCRIPT__"; |
381 | %%BeginProcSet: logo |
382 | %%Creator: James Klicman <james\@klicman.org> |
383 | %%CreationDate: October 2002 |
384 | %%Version: 0.3 |
385 | |
386 | % if |
387 | /LogoPadding where |
388 | { |
389 | pop % discard dict |
390 | } |
391 | % else |
392 | { |
393 | /LogoPadding 0 def |
394 | } |
395 | ifelse |
396 | |
397 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
398 | % |
399 | % Calculate LogoMatrix |
400 | % |
401 | % LogoXScale |
402 | LogoWidth LogoPadding 2 mul sub |
403 | % BBWidth |
404 | LogoBBox 2 get % x2 |
405 | LogoBBox 0 get % x1 |
406 | sub % x2 x1 sub |
407 | div % LogoWidth BBWidth div |
408 | % LogoYScale |
409 | LogoHeight LogoPadding 2 mul sub |
410 | % BBHeight |
411 | LogoBBox 3 get % y2 |
412 | LogoBBox 1 get % y1 |
413 | sub % y2 y1 sub |
414 | div % LogoHeight BBHeight div |
415 | |
416 | % if |
417 | 2 copy lt % LogoXScale LogoYScale lt |
418 | { |
419 | pop % discard LogoYScale |
420 | } |
421 | % else |
422 | { |
423 | exch pop % discard LogoXScale |
424 | } |
425 | ifelse |
426 | % ^ (LogoXScale < LogoYScale ? LogoXScale : LogoYScale) |
427 | dup matrix scale /LogoMatrix exch def |
428 | |
429 | /DrawLogo { |
430 | /LogoForm where { |
431 | pop % discard dict |
432 | gsave |
433 | |
434 | LogoHorOffset LogoVerOffset translate |
435 | |
436 | __END_OF_POSTSCRIPT__ |
437 | |
438 | if ($Definitions{'LogoBorder'} > 0) { |
439 | print <<"__END_OF_POSTSCRIPT__"; |
440 | /LogoBorder where { |
441 | pop % discard dict |
442 | newpath |
443 | LeftMargin LogoBorder 2 div add |
444 | CheckHeight TopMargin sub LogoBorder 2 div sub moveto |
445 | |
446 | LogoWidth LogoBorder sub 0 rlineto |
447 | 0 LogoHeight LogoBorder sub neg rlineto |
448 | LogoWidth LogoBorder sub neg 0 rlineto |
449 | closepath |
450 | LogoBorder setlinewidth stroke |
451 | } if |
452 | __END_OF_POSTSCRIPT__ |
453 | |
454 | } |
455 | |
456 | print <<"__END_OF_POSTSCRIPT__"; |
457 | |
458 | % Logo is placed at the top-left corner of the check |
459 | LeftMargin CheckHeight TopMargin sub translate |
460 | |
461 | LogoForm /BBox get aload pop % ^ llx lly urx ury |
462 | |
463 | % translate top-left corner of LogoBBox to current point |
464 | % ^ llx lly urx ury |
465 | 3 index neg % llx neg ^ llx lly urx ury -llx |
466 | 1 index neg % ury neg ^ llx lly urx ury -llx -ury |
467 | LogoForm /Matrix get |
468 | transform % -llx -ury LogoMatrix transform |
469 | translate % transformedX transformedY translate |
470 | |
471 | % calculate real width and height of LogoBBox |
472 | % ^ llx lly urx ury |
473 | exch % ^ llx lly ury urx |
474 | 4 -1 roll % ^ lly ury urx llx |
475 | sub % urx llx sub ^ lly ury urx-llx |
476 | 3 -2 roll % ^ urx-llx lly ury |
477 | exch % ^ urx-llx ury lly |
478 | sub % ury lly sub |
479 | % ^ urx-llx ury-lly |
480 | LogoForm /Matrix get |
481 | transform % urx-llx ury-lly LogoMatrix transform |
482 | % ^ RealLogoWidth RealLogoHeight |
483 | |
484 | % Calculate difference of RealLogoWidth, RealLogoHeight |
485 | % and LogoWidth, LogoHeight for centering logo. |
486 | exch LogoWidth exch sub 2 div |
487 | exch LogoHeight exch sub 2 div neg |
488 | translate % LogoHAlign LogoVAlign translate |
489 | |
490 | LogoForm execform |
491 | |
492 | grestore |
493 | } if |
494 | } def |
495 | %%EndProcSet |
496 | |
497 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
498 | |
499 | % |
500 | % The following EPS Form handling code is based on code contained in |
501 | % Adobe Technical Note #5144 Using EPS Files in PostScript Language Forms. |
502 | % |
503 | |
504 | %%BeginResource: procset forms_ops 1.0 0 |
505 | %%Title: (Forms Operators) |
506 | %%Version: 1.0 |
507 | userdict /forms_ops 10 dict dup begin put |
508 | |
509 | /StartEPSF { % prepare for EPSF inclusion |
510 | userdict begin |
511 | /PreEPS_state save def |
512 | /dict_stack countdictstack def |
513 | /ops_count count 1 sub def |
514 | /showpage {} def |
515 | } bind def |
516 | |
517 | /EPSFCleanUp { % clean up after EPSF inclusion |
518 | count ops_count sub {pop} repeat |
519 | countdictstack dict_stack sub {end} repeat |
520 | PreEPS_state restore |
521 | end % userdict |
522 | } bind def |
523 | |
524 | /STRING_SIZE 16000 def % Best value to not fragment printer's VM |
525 | % recommended ARRAY_SIZE = filesize/16000 + 2 |
526 | % +2 resulted in errors |
527 | % +3 worked |
528 | /ARRAY_SIZE $filesize 16000 idiv 3 add def |
529 | |
530 | % for initial counter and final empty string. |
531 | /buffer STRING_SIZE string def |
532 | /inputFile currentfile 0 (% EOD_Marker_$$) /SubFileDecode filter def |
533 | |
534 | /readdata { % array readdata -- |
535 | 1 { % put counter on stack |
536 | % stack: array counter |
537 | 2 copy % stack: array counter array counter |
538 | inputFile buffer readstring % read contents of currentfile into buffer |
539 | % stack: array counter array counter string boolean |
540 | 4 1 roll % put boolean indicating EOF lower on stack |
541 | STRING_SIZE string copy % copy buffer string into new string |
542 | % stack: array counter boolean array counter newstring |
543 | put % put string into array |
544 | not {exit} if % if EOF has been reached, exit loop. |
545 | 1 add % increment counter |
546 | } loop |
547 | % increment counter and place empty string in next position |
548 | 1 add 2 copy () put pop |
549 | currentglobal true setglobal exch |
550 | 0 1 array put % create an array for counter in global VM, |
551 | % so as not to be affected by save/restore calls in EPS file. |
552 | % place as first element of string array. |
553 | setglobal % restore previously set value |
554 | } bind def |
555 | currentdict readonly pop end |
556 | %%EndResource |
557 | %%EndProlog |
558 | %%BeginSetup |
559 | % set MaxFormItem to be equivalent to MaxFormCache |
560 | << /MaxFormItem currentsystemparams /MaxFormCache get >> setuserparams |
561 | % make forms procset available |
562 | forms_ops begin |
563 | userdict begin |
564 | % download form resource |
565 | %%BeginResource: form LogoForm |
566 | /LogoForm |
567 | 10 dict begin |
568 | /FormType 1 def |
569 | /EPSArray ARRAY_SIZE array def |
570 | /AcquisitionProc { |
571 | EPSArray dup 0 get dup 0 get % array counter_array counter |
572 | dup 3 1 roll % array counter counter_array counter |
573 | 1 add 0 exch put % increment counter |
574 | get % use old counter as index into array, placing |
575 | % next string on operand stack. |
576 | } bind def |
577 | /PaintProc { |
578 | begin |
579 | StartEPSF |
580 | % May want to translate here, prior to executing EPS |
581 | EPSArray 0 get 0 1 put |
582 | //AcquisitionProc 0 () /SubFileDecode filter |
583 | cvx exec |
584 | EPSFCleanUp |
585 | end |
586 | } bind def |
587 | /Matrix //LogoMatrix def |
588 | /BBox //LogoBBox def |
589 | currentdict |
590 | end |
591 | def % LogoForm |
592 | LogoForm /EPSArray get |
593 | readdata |
594 | %%BeginDocument: ($Definitions{'LogoFile'}) |
595 | __END_OF_POSTSCRIPT__ |
596 | |
597 | open(EPS, "<$Definitions{'LogoFile'}") || die "can't open logo file: $!\n"; |
598 | print while (<EPS>); |
599 | close(EPS); |
600 | |
601 | print <<"__END_OF_POSTSCRIPT__"; |
602 | %%EndDocument |
603 | % EOD_Marker_$$ |
604 | %%EndResource |
605 | %%EndSetup |
606 | __END_OF_POSTSCRIPT__ |
607 | } |
608 | |
609 | # Then print the main body |
610 | print while (<DATA>); |
611 | |
612 | if (defined $Definitions{'LogoFile'}) { |
613 | print <<"__END_OF_POSTSCRIPT__"; |
614 | end % userdict |
615 | end % forms_ops |
616 | __END_OF_POSTSCRIPT__ |
617 | } |
618 | |
619 | print "%%EOF\n"; |
620 | |
621 | |
622 | # Update the config file with the new check number, if it's not just a test |
623 | if (!$opt_test && !$opt_cgi && !$opt_preserve) { |
624 | $next_check_number = $Definitions{"CheckNumber"} |
625 | + ($Definitions{"NumPages"} * $Definitions{"ChecksPerPage"}); |
626 | |
627 | $config_file = Replace_Val($config_file, "Account", $opt_account, |
628 | "CheckNumber", $next_check_number); |
629 | write_file ($ConfigFile, $config_file); |
630 | } |
631 | |
632 | ############### |
633 | # Subroutines # |
634 | ############### |
635 | |
636 | # read_file and write_file shamelessly stolen from the File::Slurp module |
637 | # Short enough, and I didn't want to require a non-standard module |
638 | |
639 | sub read_file |
640 | { |
641 | my ($file) = @_; |
642 | |
643 | local(*F); |
644 | my $r; |
645 | my (@r); |
646 | |
647 | open(F, "<$file") || die "open $file: $!"; |
648 | @r = <F>; |
649 | close(F); |
650 | |
651 | return @r if wantarray; |
652 | return join("",@r); |
653 | } |
654 | |
655 | sub write_file |
656 | { |
657 | my ($f, @data) = @_; |
658 | |
659 | local(*F); |
660 | |
661 | open(F, ">$f") || die "open >$f: $!"; |
662 | (print F @data) || die "write $f: $!"; |
663 | close(F) || die "close $f: $!"; |
664 | return 1; |
665 | } |
666 | |
667 | # Wow, this is ugly! Anybody have a better suggestion? |
668 | sub Parse_Config { |
669 | local ($config_file) = ($_[0]); |
670 | # Find each section we're looking for... |
671 | while ($config_file =~ /^\[\s*( |
672 | Global | |
673 | Account\s+${opt_account} | |
674 | Style\s+${opt_checkstyle} | |
675 | CheckBlank\s+${opt_checktype} |
676 | )\s*\]/xmgci) { |
677 | # and get the lines under it one by one |
678 | while ($config_file =~ /(^.+$)/mgc) { |
679 | $line = $+; |
680 | # If this line is a comment, skip it |
681 | if ($line =~ /^#/) { |
682 | next; |
683 | } |
684 | # If the line we just found is a new section..."[...]" |
685 | if ($line =~ /^\[.+\]/) { |
686 | # and it is another section we're looking for |
687 | # Grab the next line, and keep going |
688 | if ($line =~ /\[\s*( |
689 | Global | |
690 | Account\s+${opt_account} | |
691 | Style\s+${opt_checkstyle} | |
692 | CheckBlank\s+${opt_checktype} |
693 | )\s*]/xi) { |
694 | # Grab the next line, and keep going |
695 | next; |
696 | } else { |
697 | # Not a section we need, so break out |
698 | # of the loop |
699 | last; |
700 | } |
701 | } |
702 | |
703 | ($key, $val) = split (/\s*=\s*/,$line); |
704 | # Need to strip trailing whitespace... |
705 | $val =~ s/\s*$//; |
706 | $Definitions{$key} = $val; |
707 | } # line-by-line while |
708 | } # section match conditional |
709 | } |
710 | |
711 | sub Replace_Val { |
712 | local ($string, $section, $name, $key, $value) = |
713 | ($_[0], $_[1], $_[2], $_[3], $_[4]); |
714 | # We want to get "[section name] ... key = value" and replace it |
715 | # with the new value. |
716 | |
717 | # s - "." matches ANYTHING including newline |
718 | # m - ^ and $ match after and before any newline |
719 | # in this case, ".+?" means the minimum number of <anything> i.e. end |
720 | # when we find the first instance of $key after [section name] |
721 | $string =~ |
722 | s/(^\[\s*$section\s+$name\s*\].+?^${key}\s*=\s*).*?$/$+$value/smi; |
723 | $string; |
724 | } |
725 | # Given a section type, list all the section names of that type |
726 | sub Get_Sections { |
727 | local $section; |
728 | while ($config_file =~ /^\[\s*( |
729 | Global | |
730 | Account.+ | |
731 | Style.+ | |
732 | CheckBlank.+ |
733 | )\s*\]/xmgci) { |
734 | $section = $+; |
735 | if ( $section =~/CheckBlank\s+(.+)/i ) { |
736 | $checkblanks = "$+ $checkblanks"; |
737 | } elsif ( $section =~/Style\s+(.+)/i ) { |
738 | $checkstyles = "$+ $checkstyles"; |
739 | } elsif ( $section =~/Account\s+(.+)/i ) { |
740 | $accounts = "$+ $accounts"; |
741 | } elsif ( $section =~/Global/i ) { |
742 | $global_found = "true"; |
743 | } |
744 | } |
745 | } |
746 | |
747 | sub Show_Usage { |
748 | print "\nFreeCheck v.$version - a Free Check printing Utility\n\n"; |
749 | print "Usage: freecheck <options>:\n"; |
750 | print "\n"; |
751 | print "options:\n"; |
752 | print " --config <filename> config file (default \"~/.freecheck.cfg\")\n"; |
753 | print " --account <name> account to use (default \"$opt_account\")\n"; |
754 | print " --checknum <integer> starting check number (overrides cfg)\n"; |
755 | print " --pages <integer> number of pages to print (overrides cfg)\n"; |
756 | print " --checkstyle <filename> check style to use (default \"$opt_checkstyle\")\n"; |
757 | print " --checktype <filename> blank check type to use (default \"$opt_checktype\")\n"; |
758 | print " --nomicr do not print MICR line\n"; |
759 | print " --nobody do not print check body\n"; |
760 | print " --showaccounts show all configured accounts\n"; |
761 | print " --showstyles show all configured check styles\n"; |
762 | print " --showblanks show all configured check blanks\n"; |
763 | print " --help print this message\n"; |
764 | print " --preserve print but don't increment check number\n"; |
765 | print " --test print but don't increment check number\n"; |
766 | print " and print VOID on the check\n"; |
767 | print " --cgi accept string from CGI script (see docs)\n"; |
768 | die "\n"; |
769 | } |
770 | |
771 | sub Print_Defs { |
772 | # Go through each def in the hash table, and print according to the |
773 | # formatting hash |
774 | while ( ($key, $val) = each (%Definitions) ) { |
775 | print "/$key\t"; |
776 | $_ = $Formats{$key}; |
777 | s/value/$val/; |
778 | print; |
779 | print " def\n"; |
780 | } |
781 | } |
782 | # End of Perl |
783 | __END__ |
784 | |
785 | % This is the main body of the postscript file, that acts on all of the |
786 | % definitions we got from the config file. |
787 | |
788 | % Available Check Layouts |
789 | /CheckLayoutDict << |
790 | /Original { DrawOriginalCheckBody } |
791 | /QStandard { DrawQStandardCheckBody } |
792 | /QWallet { DrawQWalletCheckBody } |
793 | >> def |
794 | |
795 | % Other Constants: |
796 | |
797 | % Size of the rectangular box for the amount (digits) |
798 | /AmountBoxWidth {1 inch} def |
799 | /AmountBoxHeight {0.25 inch} def |
800 | |
801 | % Max number of digits in check number, and allocate string |
802 | /CheckNumDigits 4 def |
803 | /CheckNumberString CheckNumber log floor 1 add cvi string def |
804 | |
805 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
806 | % Helpful Printing Routines % |
807 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
808 | |
809 | % Shows a line, then does a "carriage return / line feed" |
810 | % But only if the string exists (more than 0 chars) |
811 | % (How do we get the current font size (height)?) |
812 | |
813 | /ShowAndCR { |
814 | % if |
815 | dup length 0 gt % First copy |
816 | { |
817 | dup show % Second copy |
818 | stringwidth pop neg 0 rmoveto % Original copy & move back |
819 | neg 0 exch rmoveto % line down |
820 | } |
821 | % else |
822 | { |
823 | pop % discard (string) |
824 | pop % discard height |
825 | } |
826 | ifelse |
827 | } def |
828 | |
829 | %%BeginProcSet: substitute |
830 | %%Creator: James Klicman <james@klicman.org> |
831 | %%CreationDate: October 2002 |
832 | %%Version: 0.3 |
833 | % |
834 | % (string) (O) (N) substitute - |
835 | % |
836 | % example: (A?C) (?) (B) substitute -> (ABC) |
837 | % |
838 | /substitute { |
839 | 0 get exch 0 get exch % convert (O) and (N) to char codes |
840 | 0 % counter |
841 | 3 index % (string) {} forall |
842 | { |
843 | % ^ (string) O N counter C |
844 | 3 index % (O)[0] |
845 | eq % (string)[i] == (O)[0] |
846 | { |
847 | % ^ (string) O N counter |
848 | 3 index % (string) |
849 | % ^ (string) O N counter (string) |
850 | 1 index % counter |
851 | % ^ (string) O N counter (string) counter |
852 | 3 index % N |
853 | % ^ (string) O N counter (string) counter N |
854 | put % (string) counter N put |
855 | } if |
856 | 1 add % increment counter |
857 | } forall |
858 | pop % counter |
859 | pop % N |
860 | pop % O |
861 | pop % (string) |
862 | } def |
863 | %%EndProcSet |
864 | |
865 | % Fix up the MICR line components (replace placeholders with MICR |
866 | % characters) |
867 | % Argh... surely there's a better way - anyone? use "forall?" |
868 | |
869 | /FixMICR { |
870 | |
871 | /CheckNumStart -1 def |
872 | /CheckNumEnd -1 def |
873 | /CheckNumInOnUs false def |
874 | /CheckNumInAuxOnUs false def |
875 | |
876 | % Get starting and ending positions for check number in |
877 | % (Aux)OnUs field |
878 | % (This will break if check number is entered in both fields) |
879 | |
880 | OnUs length 1 sub -1 0 { |
881 | dup % dups the index |
882 | OnUs exch get (C) 0 get eq { |
883 | /CheckNumInOnUs true def |
884 | % If end number not yet defined, define it |
885 | CheckNumEnd 0 lt { |
886 | /CheckNumEnd exch def |
887 | } { |
888 | /CheckNumStart exch def |
889 | } ifelse |
890 | |
891 | } { |
892 | pop |
893 | } ifelse |
894 | } for |
895 | |
896 | AuxOnUs length 1 sub -1 0 { |
897 | dup % dups the index |
898 | AuxOnUs exch get (C) 0 get eq { |
899 | /CheckNumInAuxOnUs true def |
900 | % If end number not yet defined, define it |
901 | CheckNumEnd 0 lt { |
902 | /CheckNumEnd exch def |
903 | } { |
904 | /CheckNumStart exch def |
905 | } ifelse |
906 | |
907 | } { |
908 | pop |
909 | } ifelse |
910 | } for |
911 | |
912 | |
913 | % Replace "R" in routing number with actual transit number symbol |
914 | % That's it - should be no spaces, dashes, or anything but digits |
915 | Routing (R) TransitSymbol substitute |
916 | |
917 | % Replace "S" with space character in AuxOnUs |
918 | AuxOnUs (S) ( ) substitute |
919 | |
920 | % Replace "-" with dash character in AuxOnUs |
921 | AuxOnUs (-) DashSymbol substitute |
922 | |
923 | % Replace "P" with OnUs character in AuxOnUs |
924 | AuxOnUs (P) OnUsSymbol substitute |
925 | |
926 | % Replace "S" with space character in OnUs |
927 | OnUs (S) ( ) substitute |
928 | |
929 | % Replace "-" with dash character in OnUs |
930 | OnUs (-) DashSymbol substitute |
931 | |
932 | % Replace "P" with OnUs character in OnUs |
933 | OnUs (P) OnUsSymbol substitute |
934 | |
935 | } def |
936 | |
937 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
938 | % Original Feature Printing Routines % |
939 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
940 | |
941 | /DrawMemoLine { |
942 | LeftMargin MemoLineHeight CheckHeight mul moveto |
943 | 2.5 inch 0 inch rlineto |
944 | -2.5 inch 0 inch rmoveto |
945 | 0 2 rmoveto |
946 | (for) show |
947 | } def |
948 | |
949 | /DrawSignatureLine { % Expects height of signature line |
950 | % and right edge of check for |
951 | % beginning position |
952 | |
953 | CheckWidth SignatureLineHeight CheckHeight mul moveto |
954 | RightMargin neg 0 rmoveto |
955 | -2.5 inch 0 rmoveto |
956 | 2.5 inch 0 inch rlineto |
957 | |
958 | } def |
959 | |
960 | /DrawAmountLine { |
961 | CheckWidth AmountLineHeight CheckHeight mul moveto |
962 | RightMargin neg 0 rmoveto |
963 | (DOLLARS) stringwidth pop neg 0 rmoveto |
964 | (DOLLARS) show |
965 | (DOLLARS) stringwidth pop neg 0 rmoveto |
966 | -2 0 rmoveto |
967 | LeftMargin AmountLineHeight CheckHeight mul lineto |
968 | } def |
969 | |
970 | /DrawAccountHolderInfo { |
971 | LeftMargin CheckHeight moveto |
972 | 0 TopMargin neg rmoveto |
973 | 0 StandardFontSize neg rmoveto |
974 | |
975 | % make room for Logo if specified |
976 | /LogoForm where { |
977 | pop % discard dict |
978 | LogoWidth |
979 | /LogoBorder where { |
980 | pop % discard dict |
981 | LogoBorder 2 div add |
982 | } if |
983 | /LogoPadding where { |
984 | pop % discard dict |
985 | LogoPadding 2 div add |
986 | } if |
987 | 0 rmoveto |
988 | } if |
989 | |
990 | StandardFontSize Name1 ShowAndCR |
991 | StandardFontSize Name2 ShowAndCR |
992 | |
993 | StandardFontName findfont |
994 | StandardFontSize 1 sub scalefont |
995 | setfont |
996 | |
997 | StandardFontSize 1 sub Address1 ShowAndCR |
998 | StandardFontSize 1 sub Address2 ShowAndCR |
999 | StandardFontSize 1 sub CityStateZip ShowAndCR |
1000 | StandardFontSize 1 sub PhoneNumber ShowAndCR |
1001 | |
1002 | StandardFontName findfont |
1003 | StandardFontSize 1 add scalefont |
1004 | setfont |
1005 | } def |
1006 | |
1007 | /DrawDateLine { |
1008 | 0.6 CheckWidth mul DateLineHeight CheckHeight mul moveto |
1009 | (Date) show |
1010 | 1 inch 0 rlineto |
1011 | } def |
1012 | |
1013 | /DrawBankInfo { |
1014 | LeftMargin BankInfoHeight CheckHeight mul moveto |
1015 | |
1016 | StandardFontSize BankName ShowAndCR |
1017 | |
1018 | StandardFontName findfont |
1019 | StandardFontSize 1 sub scalefont |
1020 | setfont |
1021 | |
1022 | StandardFontSize 1 sub BankAddr1 ShowAndCR |
1023 | StandardFontSize 1 sub BankAddr2 ShowAndCR |
1024 | StandardFontSize 1 sub BankCityStateZip ShowAndCR |
1025 | |
1026 | StandardFontName findfont |
1027 | StandardFontSize 1 add scalefont |
1028 | setfont |
1029 | } def |
1030 | |
1031 | /DrawPayeeLine { |
1032 | |
1033 | LeftMargin PayeeLineHeight CheckHeight mul moveto |
1034 | (ORDER OF) show |
1035 | (ORDER OF) stringwidth pop neg StandardFontSize rmoveto |
1036 | (PAY TO THE) show |
1037 | 0 StandardFontSize neg rmoveto |
1038 | 4 0 rmoveto |
1039 | currentpoint mark |
1040 | |
1041 | CheckWidth PayeeLineHeight CheckHeight mul moveto |
1042 | RightMargin neg 0 rmoveto |
1043 | AmountBoxWidth neg 0 rmoveto |
1044 | |
1045 | 0 AmountBoxHeight rlineto |
1046 | AmountBoxWidth 0 rlineto |
1047 | 0 AmountBoxHeight neg rlineto |
1048 | AmountBoxWidth neg 0 rlineto |
1049 | |
1050 | -4 0 rmoveto |
1051 | |
1052 | /Helvetica-Bold findfont |
1053 | 14 scalefont |
1054 | setfont |
1055 | |
1056 | ($) stringwidth pop neg 0 rmoveto |
1057 | ($) show |
1058 | ($) stringwidth pop neg 0 rmoveto |
1059 | |
1060 | -4 0 rmoveto |
1061 | cleartomark |
1062 | lineto |
1063 | |
1064 | StandardFontName findfont |
1065 | StandardFontSize scalefont |
1066 | setfont |
1067 | |
1068 | } def |
1069 | |
1070 | /DrawCheckNumber { |
1071 | CheckWidth CheckHeight moveto |
1072 | RightMargin neg TopMargin neg rmoveto |
1073 | CheckNumFontName findfont |
1074 | CheckNumFontSize scalefont |
1075 | setfont |
1076 | |
1077 | CheckNumberString stringwidth pop neg 0 rmoveto |
1078 | 0 -14 rmoveto |
1079 | CheckNumberString show |
1080 | |
1081 | StandardFontName findfont |
1082 | StandardFontSize scalefont |
1083 | setfont |
1084 | } def |
1085 | |
1086 | /DrawFraction { |
1087 | 0.6 CheckWidth mul CheckHeight moveto |
1088 | 0 TopMargin neg rmoveto |
1089 | 0 StandardFontSize neg rmoveto |
1090 | Fraction show |
1091 | } def |
1092 | |
1093 | /DrawStub { |
1094 | CheckHorOffset 2 inch ge { |
1095 | save |
1096 | newpath |
1097 | CheckHorOffset neg 0 translate |
1098 | StandardFontName findfont |
1099 | StandardFontSize 1 sub scalefont |
1100 | setfont |
1101 | /StubSpacing {CheckHeight 6 div} def |
1102 | CheckHorOffset 2 div StubSpacing 5 mul moveto |
1103 | CheckNumberString show |
1104 | 0.3 inch StubSpacing 4 mul moveto |
1105 | (Date ) show |
1106 | CheckHorOffset 0.3 inch sub StubSpacing 4 mul lineto |
1107 | 0.3 inch StubSpacing 3 mul moveto |
1108 | (Payee ) show |
1109 | CheckHorOffset 0.3 inch sub StubSpacing 3 mul lineto |
1110 | 0.3 inch StubSpacing 2 mul moveto |
1111 | (Amount ) show |
1112 | CheckHorOffset 0.3 inch sub StubSpacing 2 mul lineto |
1113 | 0.3 inch StubSpacing 1 mul moveto |
1114 | (Memo ) show |
1115 | CheckHorOffset 0.3 inch sub StubSpacing 1 mul lineto |
1116 | stroke |
1117 | restore |
1118 | } if |
1119 | } def |
1120 | |
1121 | /DrawOriginalCheckBody { |
1122 | DrawBankInfo |
1123 | DrawAccountHolderInfo |
1124 | DrawMemoLine |
1125 | DrawSignatureLine |
1126 | DrawAmountLine |
1127 | DrawPayeeLine |
1128 | DrawCheckNumber |
1129 | DrawFraction |
1130 | DrawDateLine |
1131 | /DrawLogo where { pop DrawLogo } if |
1132 | DrawStub |
1133 | } def |
1134 | |
1135 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1136 | % QStandard & QWallet Feature Printing Routines % |
1137 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1138 | |
1139 | %%BeginProcSet: nextline |
1140 | %%Creator: James Klicman <james@klicman.org> |
1141 | %%CreationDate: October 2002 |
1142 | %%Version: 0.3 |
1143 | |
1144 | % |
1145 | % state used by initline and nextline |
1146 | % |
1147 | /LINESTATE << |
1148 | /x 0 |
1149 | /y 0 |
1150 | /rx 0 |
1151 | /ry 0 |
1152 | >> def |
1153 | |
1154 | % |
1155 | % LineHeight initline - |
1156 | % |
1157 | /initline { |
1158 | LINESTATE begin |
1159 | currentpoint |
1160 | /y exch def |
1161 | /x exch def |
1162 | /ty exch def |
1163 | /tx exch def |
1164 | end |
1165 | } def |
1166 | |
1167 | % |
1168 | % - nextline - |
1169 | % |
1170 | /nextline { |
1171 | LINESTATE begin |
1172 | x tx add |
1173 | dup /x exch def % x += tx |
1174 | y ty add |
1175 | dup /y exch def % y += ty |
1176 | moveto % x y moveto |
1177 | end |
1178 | } def |
1179 | %%EndProcSet |
1180 | |
1181 | |
1182 | %%BeginProcSet: alignment |
1183 | %%Creator: James Klicman <james@klicman.org> |
1184 | %%CreationDate: October 2002 |
1185 | %%Version: 0.3 |
1186 | % |
1187 | % (string) centeralign (string) |
1188 | % |
1189 | /centeralign { |
1190 | dup % dup (string) |
1191 | stringwidth % calculate string xWidth, yHeight |
1192 | pop % discard yHeight |
1193 | 2 div neg % -(xWidth / 2) |
1194 | 0 rmoveto % rmoveto center |
1195 | } def |
1196 | |
1197 | % |
1198 | % (string) rightalign (string) |
1199 | % |
1200 | /rightalign { |
1201 | dup stringwidth % calculate string xWidth, yHeight |
1202 | pop % discard yHeight |
1203 | neg 0 rmoveto % -xWidth 0 rmoveto |
1204 | } def |
1205 | |
1206 | % |
1207 | % (string) stringbbox x1 y1 x2 y2 |
1208 | % |
1209 | % This procedure is based on the method described in Chapter 5 page 333 |
1210 | % of the PostScript Language Reference third edition. |
1211 | % |
1212 | /stringbbox { |
1213 | gsave |
1214 | newpath 0 0 moveto false charpath flattenpath pathbbox % x1 y1 x2 y2 |
1215 | grestore |
1216 | } def |
1217 | |
1218 | % |
1219 | % (string) topalign (string) |
1220 | % |
1221 | /topalign { |
1222 | dup stringbbox % ^+ x1 y1 x2 y2 |
1223 | neg 0 exch rmoveto % 0 -y2 rmoveto |
1224 | pop % x2 |
1225 | pop % y1 |
1226 | pop % x1 |
1227 | } def |
1228 | |
1229 | % |
1230 | % (string) bottomalign (string) |
1231 | % |
1232 | /bottomalign { |
1233 | dup stringbbox % ^+ x1 y1 x2 y2 |
1234 | pop % y2 |
1235 | pop % x2 |
1236 | neg 0 exch rmoveto % 0 -y1 rmoveto |
1237 | pop % x1 |
1238 | } def |
1239 | %%EndProcSet |
1240 | |
1241 | |
1242 | %%BeginProcSet: qchecks |
1243 | %%Creator: James Klicman <james@klicman.org> |
1244 | %%CreationDate: October 2002 |
1245 | %%Version: 0.3 |
1246 | |
1247 | /QStandardConfig << |
1248 | /RightMarginX CheckWidth RightMargin sub |
1249 | /UnderlineOffset -3 |
1250 | /MemoLineWidth 3.25 inch |
1251 | /SignatureLineWidth 3.25 inch |
1252 | /PayToTheOrderOf { |
1253 | currentpoint % oldpoint |
1254 | 0 StandardFontSize rmoveto % move up one line |
1255 | (PAY TO THE) show |
1256 | moveto % oldpoint moveto |
1257 | (ORDER OF ) show |
1258 | } |
1259 | % QStandard Coords, Check Size 8.5" x 3.5" |
1260 | /Date [ 503.08 183.44] |
1261 | /Amount [ 499.96 147.44 ] |
1262 | /Verbal [ 36.04 123.44 ] |
1263 | /Payee [ 84.04 147.44 ] |
1264 | /Memo [ 63.16 39.44 ] |
1265 | /Address [ 72.04 99.44 ] |
1266 | /Stub false |
1267 | >> def |
1268 | |
1269 | /QWalletConfig << |
1270 | /RightMarginX CheckWidth RightMargin sub |
1271 | /UnderlineOffset -2 |
1272 | /MemoLineWidth 2.5 inch |
1273 | /SignatureLineWidth 2.5 inch |
1274 | /PayToTheOrderOf { |
1275 | 0 StandardFontSize 2 mul rmoveto % move up two lines |
1276 | 0 StandardFontSize neg initline |
1277 | (PAY) show nextline |
1278 | (TO THE) show nextline |
1279 | (ORDER OF ) show |
1280 | } |
1281 | % QWallet Coords, Check Size 6" x 2.8333" |
1282 | /Date [ 346.12 147.44 ] |
1283 | /Amount [ 331.96 135.44 ] |
1284 | /Verbal [ 24.04 123.44 ] |
1285 | /Payee [ 46.12 135.44 ] |
1286 | /Address [ 25.0 99.44 ] |
1287 | /Memo [ 45.16 39.44 ] |
1288 | /Stub true |
1289 | /StubDate [ 31.96 147.44 ] |
1290 | /StubPayee [ 31.96 123.44 ] |
1291 | /StubAmount [ 52.12 87.44 ] |
1292 | /StubMemo [ 31.96 63.44 ] |
1293 | /StubCategory [ 31.96 39.44 ] |
1294 | /StubAccount [ 31.96 15.44 ] |
1295 | >> def |
1296 | |
1297 | |
1298 | % |
1299 | % /name (label) DrawQLabeline-rightmargin - |
1300 | % |
1301 | % draw label and underline to right margin |
1302 | % |
1303 | /DrawQLabeline-rightmargin { |
1304 | % show label |
1305 | % ^ /name (label) |
1306 | exch QCONFIG exch get aload pop % ^ (label) X Y |
1307 | 2 copy % ^ (label) X Y X Y |
1308 | moveto % X Y moveto |
1309 | 3 -1 roll % (label) X Y -> X Y (label) |
1310 | rightalign show % (label) rightalign show |
1311 | |
1312 | % ^ X Y |
1313 | |
1314 | Underline { % if |
1315 | % underline |
1316 | % line goes from end of label to right margin |
1317 | % ^ X Y |
1318 | exch ( ) stringwidth pop sub exch % backup X one space |
1319 | QCONFIG /UnderlineOffset get add % adjust underline position |
1320 | newpath |
1321 | dup % UnderlineY dup |
1322 | 3 1 roll % X, Y, Y -> Y, X, Y |
1323 | moveto % X Y moveto |
1324 | % UnderlineY is on the stack |
1325 | |
1326 | QCONFIG /RightMarginX get |
1327 | exch lineto % RightMarginX UnderlineY lineto |
1328 | stroke |
1329 | } |
1330 | % else |
1331 | { pop pop } |
1332 | ifelse |
1333 | } def |
1334 | |
1335 | /DrawQDate { |
1336 | /Date (Date ) DrawQLabeline-rightmargin |
1337 | } def |
1338 | |
1339 | /DrawQAmount { |
1340 | /Amount ($ ) DrawQLabeline-rightmargin |
1341 | } def |
1342 | |
1343 | /DrawQPayee { |
1344 | % label: PAY TO THE ORDER OF |
1345 | LeftMargin |
1346 | QCONFIG /Payee get 1 get % PayeeY |
1347 | moveto % LeftMargin PayeeY moveto |
1348 | QCONFIG /PayToTheOrderOf get exec |
1349 | |
1350 | Underline { % if |
1351 | % underline: Payee |
1352 | % line goes from end of "ORDER OF" to beginning of "$ amount" |
1353 | currentpoint |
1354 | QCONFIG /UnderlineOffset get add % CurrentY + UnderlineOffset |
1355 | newpath |
1356 | dup % UnderlineY dup |
1357 | 3 1 roll % X, Y, Y -> Y, X, Y |
1358 | moveto % X Y moveto |
1359 | % ^ UnderlineY |
1360 | |
1361 | QCONFIG /Amount get 0 get % AmountX |
1362 | ( $ ) stringwidth pop % AdjustX |
1363 | sub % PayeeLineEndX = AmountX - AdjustX |
1364 | |
1365 | exch lineto % PayeeLineEndX UnderlineY lineto |
1366 | stroke |
1367 | } if |
1368 | } def |
1369 | |
1370 | /DrawQVerbal { |
1371 | % label: Dollars |
1372 | QCONFIG /RightMarginX get |
1373 | ( DOLLARS) stringwidth |
1374 | pop % discard yHeight |
1375 | sub % RightMarginX - StringWidthX |
1376 | |
1377 | % ^ LabelX |
1378 | |
1379 | QCONFIG /Verbal get 1 get % VerbalY |
1380 | 2 copy % LabelX VerbalY 2 copy |
1381 | moveto % LabelX VerbalY moveto |
1382 | ( DOLLARS) show |
1383 | |
1384 | % ^ LabelX VerbalY |
1385 | |
1386 | Underline { % if |
1387 | newpath |
1388 | QCONFIG /UnderlineOffset get add % VerbalY + UnderlineOffset |
1389 | dup % dup UnderlineY |
1390 | 3 1 roll % X Y Y -> Y X Y |
1391 | moveto % LabelX UnderlineY moveto |
1392 | |
1393 | LeftMargin exch lineto % LeftMargin UnderlineY lineto |
1394 | |
1395 | stroke |
1396 | } |
1397 | % else |
1398 | { pop pop } |
1399 | ifelse |
1400 | } def |
1401 | |
1402 | /DrawQMemo { |
1403 | % label: Memo |
1404 | LeftMargin |
1405 | QCONFIG /Memo get 1 get % MemoY |
1406 | moveto % LeftMargin MemoY moveto |
1407 | (Memo ) show |
1408 | |
1409 | Underline { % if |
1410 | % underline: Memo |
1411 | 0 QCONFIG /UnderlineOffset get rmoveto % 0 UnderlineOffset rmoveto |
1412 | currentpoint |
1413 | newpath |
1414 | moveto % currentpoint moveto |
1415 | QCONFIG /MemoLineWidth get 0 rlineto |
1416 | stroke |
1417 | } if |
1418 | } def |
1419 | |
1420 | /DrawQSignature { |
1421 | QCONFIG /RightMarginX get |
1422 | |
1423 | % if |
1424 | userdict /SignatureLineHeight known |
1425 | { |
1426 | SignatureLineHeight |
1427 | } |
1428 | % else |
1429 | { |
1430 | QCONFIG /Memo get 1 get % MemoY |
1431 | QCONFIG /UnderlineOffset get % UnderlineOffset |
1432 | add % MemoY UnderlineOffset add |
1433 | } ifelse |
1434 | |
1435 | % ^ RightMarginX SignatureY |
1436 | newpath |
1437 | moveto % RightMarginX UnderlineY moveto |
1438 | QCONFIG /SignatureLineWidth get neg 0 rlineto |
1439 | stroke |
1440 | } def |
1441 | |
1442 | % |
1443 | % [(string) ...] boldlines DrawQInfo - |
1444 | % |
1445 | % Draw array of strings as separate lines of text centered and topaligned |
1446 | % to the currentpoint. Null strings are skipped. If the string is non-null |
1447 | % and it's index is less than boldlines, the bold font is used. |
1448 | % |
1449 | /DrawQInfo { |
1450 | 0 % counter |
1451 | false % istopaligned |
1452 | % ^ [(string)] boldlines counter istopaligned |
1453 | 4 -1 roll % ^ boldlines counter istopaligned [(string)] |
1454 | { |
1455 | % ^ boldlines counter istopaligned (string) |
1456 | dup length 0 gt { % if |
1457 | |
1458 | % bold font if one of boldlines |
1459 | 2 index % counter |
1460 | 4 index % boldlines |
1461 | lt { |
1462 | currentfont % save font to stack |
1463 | BoldFontName findfont |
1464 | StandardFontSize scalefont |
1465 | setfont |
1466 | 5 1 roll % ^ font boldlines counter istopaligned (string) |
1467 | } if |
1468 | |
1469 | exch % ^ (string) istopaligned |
1470 | % if istopaligned |
1471 | { |
1472 | nextline |
1473 | true % istopaligned |
1474 | } |
1475 | % else |
1476 | { |
1477 | topalign |
1478 | 0 StandardFontSize neg initline |
1479 | true % istopaligned |
1480 | } |
1481 | ifelse |
1482 | |
1483 | exch % ^ istopaligned (string) |
1484 | centeralign show % (string) centeralign show |
1485 | |
1486 | % ^ boldlines counter istopaligned |
1487 | |
1488 | % restore font if one of boldlines |
1489 | 1 index % counter |
1490 | 3 index % boldlines |
1491 | lt { |
1492 | % ^ font boldlines counter istopaligned |
1493 | 4 -1 roll % ^ boldlines counter istopaligned font |
1494 | setfont % restore font from stack |
1495 | } if |
1496 | } |
1497 | % else |
1498 | { pop } % discard (string) |
1499 | ifelse |
1500 | |
1501 | exch 1 add exch % increment counter |
1502 | } forall |
1503 | pop % discard istopaligned |
1504 | pop % discard counter |
1505 | pop % discard boldlines |
1506 | } def |
1507 | |
1508 | /DrawQBankInfo { |
1509 | QCONFIG /Date get 0 get 4 div 3 mul % DraweeX |
1510 | CheckHeight TopMargin sub % DraweeY |
1511 | moveto % DraweeX DraweeY moveto |
1512 | [ BankName BankAddr1 BankAddr2 BankCityStateZip ] 1 DrawQInfo |
1513 | } def |
1514 | |
1515 | /DrawQAccountHolderInfo { |
1516 | QCONFIG /Date get 0 get 3 div % DraweeX |
1517 | CheckHeight TopMargin sub % DrawerY |
1518 | moveto % DrawerX DrawerY moveto |
1519 | [ Name1 Name2 Address1 Address2 CityStateZip PhoneNumber ] 2 DrawQInfo |
1520 | } def |
1521 | |
1522 | /DrawQCheckNumberAndFraction { |
1523 | currentfont % save font to stack |
1524 | CheckNumFontName findfont |
1525 | CheckNumFontSize scalefont |
1526 | setfont |
1527 | |
1528 | CheckWidth RightMargin sub % NumberX |
1529 | CheckHeight TopMargin sub % NumberY |
1530 | moveto % NumberX NumberY moveto |
1531 | CheckNumberString topalign |
1532 | 0 StandardFontSize 1.25 mul neg initline |
1533 | rightalign show |
1534 | nextline |
1535 | |
1536 | FractionFontName findfont |
1537 | FractionFontSize scalefont |
1538 | setfont |
1539 | |
1540 | Fraction topalign rightalign show |
1541 | |
1542 | setfont % restore font from stack |
1543 | } def |
1544 | |
1545 | % |
1546 | % LeftX RightX Y (label) DrawQStubLabeline - |
1547 | % |
1548 | /DrawQStubLabeline { |
1549 | 4 -1 roll % ^ RightX Y (label) LeftX |
1550 | 2 index % Y index |
1551 | moveto % LeftX Y moveto |
1552 | % ^ RightX Y (label) |
1553 | show % (label) show |
1554 | % ^ RightX Y |
1555 | QCONFIG /UnderlineOffset get % ^ RightX Y UnderlineOffset |
1556 | dup 0 exch rmoveto % Offset start of line |
1557 | add % Y UnderlineOffset add |
1558 | lineto % RightX Y lineto |
1559 | } def |
1560 | |
1561 | /DrawQStub { |
1562 | CheckHorOffset 2 inch ge |
1563 | QCONFIG /Stub get |
1564 | and { % if |
1565 | gsave |
1566 | |
1567 | CheckHorOffset neg 0 translate |
1568 | |
1569 | newpath |
1570 | |
1571 | StandardFontName findfont |
1572 | StandardFontSize 1 sub scalefont |
1573 | setfont |
1574 | |
1575 | 0.1875 inch % ^ LeftX |
1576 | dup CheckHorOffset exch sub % ^ LeftX RightX |
1577 | |
1578 | 2 copy % LeftX RightX |
1579 | QCONFIG /StubDate get 1 get % DateY |
1580 | (DATE ) |
1581 | DrawQStubLabeline |
1582 | |
1583 | 2 copy % LeftX RightX |
1584 | QCONFIG /StubPayee get 1 get % PayeeY |
1585 | (PAYEE ) |
1586 | DrawQStubLabeline |
1587 | |
1588 | 2 copy % LeftX RightX |
1589 | QCONFIG /StubAmount get 1 get % AmountY |
1590 | (AMOUNT ) |
1591 | DrawQStubLabeline |
1592 | |
1593 | 2 copy % LeftX RightX |
1594 | QCONFIG /StubMemo get 1 get % MemoY |
1595 | (MEMO ) |
1596 | DrawQStubLabeline |
1597 | |
1598 | 2 copy % LeftX RightX |
1599 | QCONFIG /StubCategory get 1 get % CategoryY |
1600 | (CATG. ) |
1601 | DrawQStubLabeline |
1602 | |
1603 | 2 copy % LeftX RightX |
1604 | QCONFIG /StubAccount get 1 get % AccountY |
1605 | (ACCT. ) |
1606 | DrawQStubLabeline |
1607 | |
1608 | Underline { stroke } if |
1609 | |
1610 | CheckNumFontName findfont |
1611 | CheckNumFontSize scalefont |
1612 | setfont |
1613 | |
1614 | % ^ LeftX RightX |
1615 | CheckHeight TopMargin sub moveto % RightX TextTop moveto |
1616 | CheckNumberString topalign rightalign show |
1617 | |
1618 | pop % LeftX |
1619 | |
1620 | grestore |
1621 | } if |
1622 | } def |
1623 | |
1624 | /DrawQCheckBody { |
1625 | DrawQDate |
1626 | DrawQAmount |
1627 | DrawQPayee |
1628 | DrawQVerbal |
1629 | DrawQMemo |
1630 | DrawQSignature |
1631 | DrawQBankInfo |
1632 | DrawQAccountHolderInfo |
1633 | DrawQCheckNumberAndFraction |
1634 | DrawQStub |
1635 | /DrawLogo where { pop DrawLogo } if |
1636 | } def |
1637 | |
1638 | /DrawQStandardCheckBody { |
1639 | /QCONFIG QStandardConfig def |
1640 | DrawQCheckBody |
1641 | } def |
1642 | |
1643 | /DrawQWalletCheckBody { |
1644 | /QCONFIG QWalletConfig def |
1645 | DrawQCheckBody |
1646 | } def |
1647 | %%EndProcSet |
1648 | |
1649 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1650 | % Standard Feature Printing Routines % |
1651 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1652 | |
1653 | /DrawMICR { |
1654 | % 0.25 high, 5.6875 from right edge should be in the middle |
1655 | % of the tolerance band |
1656 | CheckWidth 0.25 inch moveto |
1657 | -5.6875 inch 0 inch rmoveto |
1658 | MICRHorTweak MICRVerTweak rmoveto |
1659 | % Now we're at the nominal start of the routing number |
1660 | |
1661 | MICRFontName findfont |
1662 | MICRFontSize scalefont |
1663 | setfont |
1664 | |
1665 | % Number of digits in the CheckNumberString |
1666 | /CheckNumDigit CheckNumberString length 1 sub def |
1667 | |
1668 | CheckNumInAuxOnUs { |
1669 | CheckNumEnd -1 CheckNumStart { |
1670 | CheckNumDigit 0 ge { |
1671 | AuxOnUs exch CheckNumberString CheckNumDigit get put |
1672 | /CheckNumDigit CheckNumDigit 1 sub def |
1673 | } { |
1674 | AuxOnUs exch (0) 0 get put |
1675 | } ifelse |
1676 | } for |
1677 | } if |
1678 | |
1679 | |
1680 | AuxOnUs stringwidth pop neg 0 rmoveto |
1681 | AuxOnUs show |
1682 | |
1683 | Routing show |
1684 | |
1685 | CheckNumInOnUs { |
1686 | CheckNumEnd -1 CheckNumStart { |
1687 | CheckNumDigit 0 ge { |
1688 | OnUs exch CheckNumberString CheckNumDigit get put |
1689 | /CheckNumDigit CheckNumDigit 1 sub def |
1690 | } { |
1691 | OnUs exch (0) 0 get put |
1692 | } ifelse |
1693 | } for |
1694 | } if |
1695 | |
1696 | OnUs show |
1697 | |
1698 | StandardFontName findfont |
1699 | StandardFontSize scalefont |
1700 | setfont |
1701 | } def |
1702 | |
1703 | |
1704 | /DrawVOID { |
1705 | save |
1706 | StandardFontName findfont |
1707 | 50 scalefont |
1708 | setfont |
1709 | newpath |
1710 | CheckWidth 2 div 1 inch moveto |
1711 | 30 rotate |
1712 | (V O I D) stringwidth pop 0 moveto |
1713 | (V O I D) true charpath |
1714 | stroke |
1715 | restore |
1716 | } def |
1717 | |
1718 | /DrawCheck { |
1719 | |
1720 | % Convert CheckNumber integer to a string |
1721 | CheckNumber CheckNumberString cvs |
1722 | pop % discard reference to CheckNumberString |
1723 | |
1724 | PrintCheckBody { |
1725 | CheckLayoutDict CheckLayout get exec |
1726 | } if |
1727 | |
1728 | PrintMICRLine { |
1729 | DrawMICR |
1730 | } if |
1731 | |
1732 | PrintVOID { |
1733 | % Draw border around check, and print "VOID" for testing |
1734 | 0 0 moveto |
1735 | CheckWidth 0 lineto |
1736 | CheckWidth CheckHeight lineto |
1737 | 0 CheckHeight lineto |
1738 | |
1739 | 0 0 lineto |
1740 | |
1741 | DrawVOID |
1742 | } if |
1743 | |
1744 | } def |
1745 | |
1746 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1747 | % Main Printing Procedure % |
1748 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1749 | |
1750 | /CurrentPage 1 def |
1751 | |
1752 | % Replace symbol placeholders with actual glyphs |
1753 | % Also get starting and ending position for check number |
1754 | FixMICR |
1755 | |
1756 | NumPages { % repeat |
1757 | /CheckNumber CheckNumber ChecksPerPage add def |
1758 | CheckHorOffset CheckVerOffset translate |
1759 | |
1760 | StandardFontName findfont |
1761 | StandardFontSize scalefont |
1762 | setfont |
1763 | |
1764 | LineWidth setlinewidth |
1765 | |
1766 | % Loop through printing checks, starting with the bottom one |
1767 | |
1768 | ChecksPerPage { % repeat |
1769 | /CheckNumber CheckNumber 1 sub def |
1770 | |
1771 | % if |
1772 | ChecksMod 0 lt |
1773 | CheckNumber ChecksPerPage mod ChecksMod eq |
1774 | or { |
1775 | newpath |
1776 | DrawCheck |
1777 | stroke |
1778 | } if |
1779 | 0 CheckHeight translate |
1780 | } repeat |
1781 | |
1782 | showpage |
1783 | |
1784 | /CheckNumber CheckNumber ChecksPerPage add def |
1785 | /CurrentPage CurrentPage 1 add def |
1786 | } repeat |
1787 |
Built with git-ssb-web