git ssb

0+

cel / freecheck



Tree: 5600d514ae78f157e1232e090a04330cf6fe5aef

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
31use Getopt::Long;
32use 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
116GetOptions ("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
132or Show_Usage();
133
134if ($opt_help) {
135 Show_Usage();
136}
137
138if ($opt_config) {
139 $ConfigFile = $opt_config;
140} elsif ( ! -e $ConfigFile ) {
141 copy $systemConfigFile, $ConfigFile;
142}
143
144# Some defaults...
145if (!$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
155Get_Sections();
156
157# If we're missing the [Global] section, or if a requested section
158# cannot be found, die.
159if (!$global_found) {
160 die ("No [Global] section found in config file\n");
161}
162
163if ($accounts !~ /${opt_account}/i) {
164 die ("Account $opt_account not found in config file\n");
165}
166
167if ($checkblanks !~ /$opt_checktype/i) {
168 die ("Check type $opt_checktype not found in config file\n");
169}
170
171if ($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
176if ($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...
200Parse_Config($config_file);
201
202# Overwrite anything we got from the config file with what was on the
203# Command Line (if anything...)
204
205if ($opt_checknum) {
206 $Definitions{"CheckNumber"} = $opt_checknum;
207}
208
209if ($opt_pages) {
210 $Definitions{"NumPages"} = $opt_pages;
211}
212
213if ($opt_nomicr) {
214 $Definitions{"PrintMICRLine"} = "false";
215}
216
217if ($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)
223if ($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
236while ( $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
248if ( $Definitions{"Routing"} !~ /^R[0-9]+R$/ ) {
249 $error = $error . "Error - Routing number must be numeric, with an \"R\" on each end\n";
250}
251
252if ( $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
256if ( $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
260if ( $Definitions{"CheckNumber"} !~ /^[0-9]+$/ ) {
261 $error = $error . "Error - Check number must be numeric \n";
262}
263
264if ( $Definitions{"NumPages"} !~ /^[0-9]+$/ ) {
265 $error = $error . "Error - Number of pages must be numeric\n";
266}
267
268if ( $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
272if ($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
293if ( $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
299if ( 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
307unless ( ( $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
329if (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
357if ( $error && !$opt_test ) {
358 print STDERR $error;
359 die("Errors Encountered\n");
360}
361
362# Print PostScript
363
364# Initial stuff:
365print <<"__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
375Print_Defs();
376
377
378if (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}
395ifelse
396
397%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
398%
399% Calculate LogoMatrix
400%
401% LogoXScale
402LogoWidth LogoPadding 2 mul sub
403% BBWidth
404 LogoBBox 2 get % x2
405 LogoBBox 0 get % x1
406 sub % x2 x1 sub
407div % LogoWidth BBWidth div
408% LogoYScale
409LogoHeight LogoPadding 2 mul sub
410% BBHeight
411 LogoBBox 3 get % y2
412 LogoBBox 1 get % y1
413 sub % y2 y1 sub
414div % LogoHeight BBHeight div
415
416% if
4172 copy lt % LogoXScale LogoYScale lt
418{
419 pop % discard LogoYScale
420}
421% else
422{
423 exch pop % discard LogoXScale
424}
425ifelse
426% ^ (LogoXScale < LogoYScale ? LogoXScale : LogoYScale)
427dup 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
507userdict /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
555currentdict 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
562forms_ops begin
563userdict 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
591def % LogoForm
592LogoForm /EPSArray get
593readdata
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
610print while (<DATA>);
611
612if (defined $Definitions{'LogoFile'}) {
613 print <<"__END_OF_POSTSCRIPT__";
614end % userdict
615end % forms_ops
616__END_OF_POSTSCRIPT__
617}
618
619print "%%EOF\n";
620
621
622# Update the config file with the new check number, if it's not just a test
623if (!$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
639sub 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
655sub 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?
668sub 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
711sub 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
726sub 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
747sub 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
771sub 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
1754FixMICR
1755
1756NumPages { % 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