git ssb

0+

cel / freecheck



Tree: 13d9698d9bd7a27d73234d96206ed5fe86166381

Files: 13d9698d9bd7a27d73234d96206ed5fe86166381 / freecheck

45161 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 3 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, see <http://www.gnu.org/licenses/>.
23#
24#---------------
25
26$version = "0.30.1";
27$systemConfigFile = "/etc/freecheck/freecheck.cfg";
28$ConfigFile = $ENV{"HOME"} . "/.freecheck.cfg";
29
30use Getopt::Long;
31use File::Copy qw(copy);
32
33
34# This tells us how to format the strings from the cfg file
35# so we can print it as a PostScript definition
36# The key read will replace "value" for each of these
37# Strings are enclosed in parentheses (String) (Foobar)
38# Fonts are preceded by a "/" /FontName /Arial
39# Digits are fine as they are Digit 123
40# Booleans are fine too Bool true
41# But to be safe, do digits and bools as subroutines:
42# Subroutines are in {} {subr} {3 mul}
43
44%Formats = qw(
45 # Globals
46 MICRFontName /value
47 MICRFontSize {value}
48 MICRExtraLineWidth {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 gsave
1046 0.66 setgray
1047 0 AmountBoxHeight rlineto
1048 AmountBoxWidth 0 rlineto
1049 0 AmountBoxHeight neg rlineto
1050 AmountBoxWidth neg 0 rlineto
1051 stroke
1052 grestore
1053
1054 -4 0 rmoveto
1055
1056 /Helvetica-Bold findfont
1057 14 scalefont
1058 setfont
1059
1060 ($) stringwidth pop neg 0 rmoveto
1061 ($) show
1062 ($) stringwidth pop neg 0 rmoveto
1063
1064 -4 14 rmoveto
1065 0 -14 rlineto
1066 cleartomark
1067 lineto
1068
1069 StandardFontName findfont
1070 StandardFontSize scalefont
1071 setfont
1072
1073} def
1074
1075/DrawCheckNumber {
1076 CheckWidth CheckHeight moveto
1077 RightMargin neg TopMargin neg rmoveto
1078 CheckNumFontName findfont
1079 CheckNumFontSize scalefont
1080 setfont
1081
1082 CheckNumberString stringwidth pop neg 0 rmoveto
1083 0 -14 rmoveto
1084 CheckNumberString show
1085
1086 StandardFontName findfont
1087 StandardFontSize scalefont
1088 setfont
1089} def
1090
1091/DrawFraction {
1092 0.6 CheckWidth mul CheckHeight moveto
1093 0 TopMargin neg rmoveto
1094 0 StandardFontSize neg rmoveto
1095 Fraction show
1096} def
1097
1098/DrawStub {
1099 CheckHorOffset 2 inch ge {
1100 save
1101 newpath
1102 CheckHorOffset neg 0 translate
1103 StandardFontName findfont
1104 StandardFontSize 1 sub scalefont
1105 setfont
1106 /StubSpacing {CheckHeight 6 div} def
1107 CheckHorOffset 2 div StubSpacing 5 mul moveto
1108 CheckNumberString show
1109 0.3 inch StubSpacing 4 mul moveto
1110 (Date ) show
1111 CheckHorOffset 0.3 inch sub StubSpacing 4 mul lineto
1112 0.3 inch StubSpacing 3 mul moveto
1113 (Payee ) show
1114 CheckHorOffset 0.3 inch sub StubSpacing 3 mul lineto
1115 0.3 inch StubSpacing 2 mul moveto
1116 (Amount ) show
1117 CheckHorOffset 0.3 inch sub StubSpacing 2 mul lineto
1118 0.3 inch StubSpacing 1 mul moveto
1119 (Memo ) show
1120 CheckHorOffset 0.3 inch sub StubSpacing 1 mul lineto
1121 stroke
1122 restore
1123 } if
1124} def
1125
1126/DrawOriginalCheckBody {
1127 DrawBankInfo
1128 DrawAccountHolderInfo
1129 DrawMemoLine
1130 DrawSignatureLine
1131 DrawAmountLine
1132 DrawPayeeLine
1133 DrawCheckNumber
1134 DrawFraction
1135 DrawDateLine
1136 /DrawLogo where { pop DrawLogo } if
1137 DrawStub
1138} def
1139
1140%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1141% QStandard & QWallet Feature Printing Routines %
1142%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1143
1144%%BeginProcSet: nextline
1145%%Creator: James Klicman <james@klicman.org>
1146%%CreationDate: October 2002
1147%%Version: 0.3
1148
1149%
1150% state used by initline and nextline
1151%
1152/LINESTATE <<
1153 /x 0
1154 /y 0
1155 /rx 0
1156 /ry 0
1157>> def
1158
1159%
1160% LineHeight initline -
1161%
1162/initline {
1163 LINESTATE begin
1164 currentpoint
1165 /y exch def
1166 /x exch def
1167 /ty exch def
1168 /tx exch def
1169 end
1170} def
1171
1172%
1173% - nextline -
1174%
1175/nextline {
1176 LINESTATE begin
1177 x tx add
1178 dup /x exch def % x += tx
1179 y ty add
1180 dup /y exch def % y += ty
1181 moveto % x y moveto
1182 end
1183} def
1184%%EndProcSet
1185
1186
1187%%BeginProcSet: alignment
1188%%Creator: James Klicman <james@klicman.org>
1189%%CreationDate: October 2002
1190%%Version: 0.3
1191%
1192% (string) centeralign (string)
1193%
1194/centeralign {
1195 dup % dup (string)
1196 stringwidth % calculate string xWidth, yHeight
1197 pop % discard yHeight
1198 2 div neg % -(xWidth / 2)
1199 0 rmoveto % rmoveto center
1200} def
1201
1202%
1203% (string) rightalign (string)
1204%
1205/rightalign {
1206 dup stringwidth % calculate string xWidth, yHeight
1207 pop % discard yHeight
1208 neg 0 rmoveto % -xWidth 0 rmoveto
1209} def
1210
1211%
1212% (string) stringbbox x1 y1 x2 y2
1213%
1214% This procedure is based on the method described in Chapter 5 page 333
1215% of the PostScript Language Reference third edition.
1216%
1217/stringbbox {
1218 gsave
1219 newpath 0 0 moveto false charpath flattenpath pathbbox % x1 y1 x2 y2
1220 grestore
1221} def
1222
1223%
1224% (string) topalign (string)
1225%
1226/topalign {
1227 dup stringbbox % ^+ x1 y1 x2 y2
1228 neg 0 exch rmoveto % 0 -y2 rmoveto
1229 pop % x2
1230 pop % y1
1231 pop % x1
1232} def
1233
1234%
1235% (string) bottomalign (string)
1236%
1237/bottomalign {
1238 dup stringbbox % ^+ x1 y1 x2 y2
1239 pop % y2
1240 pop % x2
1241 neg 0 exch rmoveto % 0 -y1 rmoveto
1242 pop % x1
1243} def
1244%%EndProcSet
1245
1246
1247%%BeginProcSet: qchecks
1248%%Creator: James Klicman <james@klicman.org>
1249%%CreationDate: October 2002
1250%%Version: 0.3
1251
1252/QStandardConfig <<
1253 /RightMarginX CheckWidth RightMargin sub
1254 /UnderlineOffset -3
1255 /MemoLineWidth 3.25 inch
1256 /SignatureLineWidth 3.25 inch
1257 /PayToTheOrderOf {
1258 currentpoint % oldpoint
1259 0 StandardFontSize rmoveto % move up one line
1260 (PAY TO THE) show
1261 moveto % oldpoint moveto
1262 (ORDER OF ) show
1263 }
1264 % QStandard Coords, Check Size 8.5" x 3.5"
1265 /Date [ 503.08 183.44]
1266 /Amount [ 499.96 147.44 ]
1267 /Verbal [ 36.04 123.44 ]
1268 /Payee [ 84.04 147.44 ]
1269 /Memo [ 63.16 39.44 ]
1270 /Address [ 72.04 99.44 ]
1271 /Stub false
1272>> def
1273
1274/QWalletConfig <<
1275 /RightMarginX CheckWidth RightMargin sub
1276 /UnderlineOffset -2
1277 /MemoLineWidth 2.5 inch
1278 /SignatureLineWidth 2.5 inch
1279 /PayToTheOrderOf {
1280 0 StandardFontSize 2 mul rmoveto % move up two lines
1281 0 StandardFontSize neg initline
1282 (PAY) show nextline
1283 (TO THE) show nextline
1284 (ORDER OF ) show
1285 }
1286 % QWallet Coords, Check Size 6" x 2.8333"
1287 /Date [ 346.12 147.44 ]
1288 /Amount [ 331.96 135.44 ]
1289 /Verbal [ 24.04 123.44 ]
1290 /Payee [ 46.12 135.44 ]
1291 /Address [ 25.0 99.44 ]
1292 /Memo [ 45.16 39.44 ]
1293 /Stub true
1294 /StubDate [ 31.96 147.44 ]
1295 /StubPayee [ 31.96 123.44 ]
1296 /StubAmount [ 52.12 87.44 ]
1297 /StubMemo [ 31.96 63.44 ]
1298 /StubCategory [ 31.96 39.44 ]
1299 /StubAccount [ 31.96 15.44 ]
1300>> def
1301
1302
1303%
1304% /name (label) DrawQLabeline-rightmargin -
1305%
1306% draw label and underline to right margin
1307%
1308/DrawQLabeline-rightmargin {
1309 % show label
1310 % ^ /name (label)
1311 exch QCONFIG exch get aload pop % ^ (label) X Y
1312 2 copy % ^ (label) X Y X Y
1313 moveto % X Y moveto
1314 3 -1 roll % (label) X Y -> X Y (label)
1315 rightalign show % (label) rightalign show
1316
1317 % ^ X Y
1318
1319 Underline { % if
1320 % underline
1321 % line goes from end of label to right margin
1322 % ^ X Y
1323 exch ( ) stringwidth pop sub exch % backup X one space
1324 QCONFIG /UnderlineOffset get add % adjust underline position
1325 newpath
1326 dup % UnderlineY dup
1327 3 1 roll % X, Y, Y -> Y, X, Y
1328 moveto % X Y moveto
1329 % UnderlineY is on the stack
1330
1331 QCONFIG /RightMarginX get
1332 exch lineto % RightMarginX UnderlineY lineto
1333 stroke
1334 }
1335 % else
1336 { pop pop }
1337 ifelse
1338} def
1339
1340/DrawQDate {
1341 /Date (Date ) DrawQLabeline-rightmargin
1342} def
1343
1344/DrawQAmount {
1345 /Amount ($ ) DrawQLabeline-rightmargin
1346} def
1347
1348/DrawQPayee {
1349 % label: PAY TO THE ORDER OF
1350 LeftMargin
1351 QCONFIG /Payee get 1 get % PayeeY
1352 moveto % LeftMargin PayeeY moveto
1353 QCONFIG /PayToTheOrderOf get exec
1354
1355 Underline { % if
1356 % underline: Payee
1357 % line goes from end of "ORDER OF" to beginning of "$ amount"
1358 currentpoint
1359 QCONFIG /UnderlineOffset get add % CurrentY + UnderlineOffset
1360 newpath
1361 dup % UnderlineY dup
1362 3 1 roll % X, Y, Y -> Y, X, Y
1363 moveto % X Y moveto
1364 % ^ UnderlineY
1365
1366 QCONFIG /Amount get 0 get % AmountX
1367 ( $ ) stringwidth pop % AdjustX
1368 sub % PayeeLineEndX = AmountX - AdjustX
1369
1370 exch lineto % PayeeLineEndX UnderlineY lineto
1371 stroke
1372 } if
1373} def
1374
1375/DrawQVerbal {
1376 % label: Dollars
1377 QCONFIG /RightMarginX get
1378 ( DOLLARS) stringwidth
1379 pop % discard yHeight
1380 sub % RightMarginX - StringWidthX
1381
1382 % ^ LabelX
1383
1384 QCONFIG /Verbal get 1 get % VerbalY
1385 2 copy % LabelX VerbalY 2 copy
1386 moveto % LabelX VerbalY moveto
1387 ( DOLLARS) show
1388
1389 % ^ LabelX VerbalY
1390
1391 Underline { % if
1392 newpath
1393 QCONFIG /UnderlineOffset get add % VerbalY + UnderlineOffset
1394 dup % dup UnderlineY
1395 3 1 roll % X Y Y -> Y X Y
1396 moveto % LabelX UnderlineY moveto
1397
1398 LeftMargin exch lineto % LeftMargin UnderlineY lineto
1399
1400 stroke
1401 }
1402 % else
1403 { pop pop }
1404 ifelse
1405} def
1406
1407/DrawQMemo {
1408 % label: Memo
1409 LeftMargin
1410 QCONFIG /Memo get 1 get % MemoY
1411 moveto % LeftMargin MemoY moveto
1412 (Memo ) show
1413
1414 Underline { % if
1415 % underline: Memo
1416 0 QCONFIG /UnderlineOffset get rmoveto % 0 UnderlineOffset rmoveto
1417 currentpoint
1418 newpath
1419 moveto % currentpoint moveto
1420 QCONFIG /MemoLineWidth get 0 rlineto
1421 stroke
1422 } if
1423} def
1424
1425/DrawQSignature {
1426 QCONFIG /RightMarginX get
1427
1428 % if
1429 userdict /SignatureLineHeight known
1430 {
1431 SignatureLineHeight
1432 }
1433 % else
1434 {
1435 QCONFIG /Memo get 1 get % MemoY
1436 QCONFIG /UnderlineOffset get % UnderlineOffset
1437 add % MemoY UnderlineOffset add
1438 } ifelse
1439
1440 % ^ RightMarginX SignatureY
1441 newpath
1442 moveto % RightMarginX UnderlineY moveto
1443 QCONFIG /SignatureLineWidth get neg 0 rlineto
1444 stroke
1445} def
1446
1447%
1448% [(string) ...] boldlines DrawQInfo -
1449%
1450% Draw array of strings as separate lines of text centered and topaligned
1451% to the currentpoint. Null strings are skipped. If the string is non-null
1452% and it's index is less than boldlines, the bold font is used.
1453%
1454/DrawQInfo {
1455 0 % counter
1456 false % istopaligned
1457 % ^ [(string)] boldlines counter istopaligned
1458 4 -1 roll % ^ boldlines counter istopaligned [(string)]
1459 {
1460 % ^ boldlines counter istopaligned (string)
1461 dup length 0 gt { % if
1462
1463 % bold font if one of boldlines
1464 2 index % counter
1465 4 index % boldlines
1466 lt {
1467 currentfont % save font to stack
1468 BoldFontName findfont
1469 StandardFontSize scalefont
1470 setfont
1471 5 1 roll % ^ font boldlines counter istopaligned (string)
1472 } if
1473
1474 exch % ^ (string) istopaligned
1475 % if istopaligned
1476 {
1477 nextline
1478 true % istopaligned
1479 }
1480 % else
1481 {
1482 topalign
1483 0 StandardFontSize neg initline
1484 true % istopaligned
1485 }
1486 ifelse
1487
1488 exch % ^ istopaligned (string)
1489 centeralign show % (string) centeralign show
1490
1491 % ^ boldlines counter istopaligned
1492
1493 % restore font if one of boldlines
1494 1 index % counter
1495 3 index % boldlines
1496 lt {
1497 % ^ font boldlines counter istopaligned
1498 4 -1 roll % ^ boldlines counter istopaligned font
1499 setfont % restore font from stack
1500 } if
1501 }
1502 % else
1503 { pop } % discard (string)
1504 ifelse
1505
1506 exch 1 add exch % increment counter
1507 } forall
1508 pop % discard istopaligned
1509 pop % discard counter
1510 pop % discard boldlines
1511} def
1512
1513/DrawQBankInfo {
1514 QCONFIG /Date get 0 get 4 div 3 mul % DraweeX
1515 CheckHeight TopMargin sub % DraweeY
1516 moveto % DraweeX DraweeY moveto
1517 [ BankName BankAddr1 BankAddr2 BankCityStateZip ] 1 DrawQInfo
1518} def
1519
1520/DrawQAccountHolderInfo {
1521 QCONFIG /Date get 0 get 3 div % DraweeX
1522 CheckHeight TopMargin sub % DrawerY
1523 moveto % DrawerX DrawerY moveto
1524 [ Name1 Name2 Address1 Address2 CityStateZip PhoneNumber ] 2 DrawQInfo
1525} def
1526
1527/DrawQCheckNumberAndFraction {
1528 currentfont % save font to stack
1529 CheckNumFontName findfont
1530 CheckNumFontSize scalefont
1531 setfont
1532
1533 CheckWidth RightMargin sub % NumberX
1534 CheckHeight TopMargin sub % NumberY
1535 moveto % NumberX NumberY moveto
1536 CheckNumberString topalign
1537 0 StandardFontSize 1.25 mul neg initline
1538 rightalign show
1539 nextline
1540
1541 FractionFontName findfont
1542 FractionFontSize scalefont
1543 setfont
1544
1545 Fraction topalign rightalign show
1546
1547 setfont % restore font from stack
1548} def
1549
1550%
1551% LeftX RightX Y (label) DrawQStubLabeline -
1552%
1553/DrawQStubLabeline {
1554 4 -1 roll % ^ RightX Y (label) LeftX
1555 2 index % Y index
1556 moveto % LeftX Y moveto
1557 % ^ RightX Y (label)
1558 show % (label) show
1559 % ^ RightX Y
1560 QCONFIG /UnderlineOffset get % ^ RightX Y UnderlineOffset
1561 dup 0 exch rmoveto % Offset start of line
1562 add % Y UnderlineOffset add
1563 lineto % RightX Y lineto
1564} def
1565
1566/DrawQStub {
1567 CheckHorOffset 2 inch ge
1568 QCONFIG /Stub get
1569 and { % if
1570 gsave
1571
1572 CheckHorOffset neg 0 translate
1573
1574 newpath
1575
1576 StandardFontName findfont
1577 StandardFontSize 1 sub scalefont
1578 setfont
1579
1580 0.1875 inch % ^ LeftX
1581 dup CheckHorOffset exch sub % ^ LeftX RightX
1582
1583 2 copy % LeftX RightX
1584 QCONFIG /StubDate get 1 get % DateY
1585 (DATE )
1586 DrawQStubLabeline
1587
1588 2 copy % LeftX RightX
1589 QCONFIG /StubPayee get 1 get % PayeeY
1590 (PAYEE )
1591 DrawQStubLabeline
1592
1593 2 copy % LeftX RightX
1594 QCONFIG /StubAmount get 1 get % AmountY
1595 (AMOUNT )
1596 DrawQStubLabeline
1597
1598 2 copy % LeftX RightX
1599 QCONFIG /StubMemo get 1 get % MemoY
1600 (MEMO )
1601 DrawQStubLabeline
1602
1603 2 copy % LeftX RightX
1604 QCONFIG /StubCategory get 1 get % CategoryY
1605 (CATG. )
1606 DrawQStubLabeline
1607
1608 2 copy % LeftX RightX
1609 QCONFIG /StubAccount get 1 get % AccountY
1610 (ACCT. )
1611 DrawQStubLabeline
1612
1613 Underline { stroke } if
1614
1615 CheckNumFontName findfont
1616 CheckNumFontSize scalefont
1617 setfont
1618
1619 % ^ LeftX RightX
1620 CheckHeight TopMargin sub moveto % RightX TextTop moveto
1621 CheckNumberString topalign rightalign show
1622
1623 pop % LeftX
1624
1625 grestore
1626 } if
1627} def
1628
1629/DrawQCheckBody {
1630 DrawQDate
1631 DrawQAmount
1632 DrawQPayee
1633 DrawQVerbal
1634 DrawQMemo
1635 DrawQSignature
1636 DrawQBankInfo
1637 DrawQAccountHolderInfo
1638 DrawQCheckNumberAndFraction
1639 DrawQStub
1640 /DrawLogo where { pop DrawLogo } if
1641} def
1642
1643/DrawQStandardCheckBody {
1644 /QCONFIG QStandardConfig def
1645 DrawQCheckBody
1646} def
1647
1648/DrawQWalletCheckBody {
1649 /QCONFIG QWalletConfig def
1650 DrawQCheckBody
1651} def
1652%%EndProcSet
1653
1654%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1655% Standard Feature Printing Routines %
1656%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1657
1658/boldshow {
1659 MICRExtraLineWidth 0 gt {
1660 currentpoint stroke newpath moveto
1661 true charpath
1662 currentlinewidth
1663 MICRExtraLineWidth setlinewidth
1664 gsave
1665 stroke
1666 grestore
1667 gsave
1668 fill
1669 grestore
1670 setlinewidth
1671 } {
1672 show
1673 } ifelse
1674} def
1675
1676/DrawMICR {
1677 % 0.25 high, 5.6875 from right edge should be in the middle
1678 % of the tolerance band
1679 CheckWidth 0.25 inch moveto
1680 -5.6875 inch 0 inch rmoveto
1681 MICRHorTweak MICRVerTweak rmoveto
1682 % Now we're at the nominal start of the routing number
1683
1684 MICRFontName findfont
1685 MICRFontSize scalefont
1686 setfont
1687
1688 % Number of digits in the CheckNumberString
1689 /CheckNumDigit CheckNumberString length 1 sub def
1690
1691 CheckNumInAuxOnUs {
1692 CheckNumEnd -1 CheckNumStart {
1693 CheckNumDigit 0 ge {
1694 AuxOnUs exch CheckNumberString CheckNumDigit get put
1695 /CheckNumDigit CheckNumDigit 1 sub def
1696 } {
1697 AuxOnUs exch (0) 0 get put
1698 } ifelse
1699 } for
1700 } if
1701
1702
1703 AuxOnUs stringwidth pop neg 0 rmoveto
1704 AuxOnUs boldshow
1705
1706 Routing boldshow
1707
1708 CheckNumInOnUs {
1709 CheckNumEnd -1 CheckNumStart {
1710 CheckNumDigit 0 ge {
1711 OnUs exch CheckNumberString CheckNumDigit get put
1712 /CheckNumDigit CheckNumDigit 1 sub def
1713 } {
1714 OnUs exch (0) 0 get put
1715 } ifelse
1716 } for
1717 } if
1718
1719 OnUs boldshow
1720
1721 StandardFontName findfont
1722 StandardFontSize scalefont
1723 setfont
1724} def
1725
1726
1727/DrawVOID {
1728 save
1729 StandardFontName findfont
1730 50 scalefont
1731 setfont
1732 newpath
1733 CheckWidth 2 div 1 inch moveto
1734 30 rotate
1735 (V O I D) stringwidth pop 0 moveto
1736 (V O I D) true charpath
1737 stroke
1738 restore
1739} def
1740
1741/DrawCheck {
1742
1743 % Convert CheckNumber integer to a string
1744 CheckNumber CheckNumberString cvs
1745 pop % discard reference to CheckNumberString
1746
1747 PrintCheckBody {
1748 CheckLayoutDict CheckLayout get exec
1749 } if
1750
1751 PrintMICRLine {
1752 DrawMICR
1753 } if
1754
1755 PrintVOID {
1756 % Draw border around check, and print "VOID" for testing
1757 0 0 moveto
1758 CheckWidth 0 lineto
1759 CheckWidth CheckHeight lineto
1760 0 CheckHeight lineto
1761
1762 0 0 lineto
1763
1764 DrawVOID
1765 } if
1766
1767} def
1768
1769%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1770% Main Printing Procedure %
1771%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1772
1773/CurrentPage 1 def
1774
1775% Replace symbol placeholders with actual glyphs
1776% Also get starting and ending position for check number
1777FixMICR
1778
1779NumPages { % repeat
1780 /CheckNumber CheckNumber ChecksPerPage add def
1781 CheckHorOffset CheckVerOffset translate
1782
1783 StandardFontName findfont
1784 StandardFontSize scalefont
1785 setfont
1786
1787 LineWidth setlinewidth
1788
1789 % Loop through printing checks, starting with the bottom one
1790
1791 ChecksPerPage { % repeat
1792 /CheckNumber CheckNumber 1 sub def
1793
1794 % if
1795 ChecksMod 0 lt
1796 CheckNumber ChecksPerPage mod ChecksMod eq
1797 or {
1798 newpath
1799 DrawCheck
1800 stroke
1801 } if
1802 0 CheckHeight translate
1803 } repeat
1804
1805 showpage
1806
1807 /CheckNumber CheckNumber ChecksPerPage add def
1808 /CurrentPage CurrentPage 1 add def
1809} repeat
1810

Built with git-ssb-web