|
|
1.1 root 1: /*
2: *
3: * postdaisy - PostScript translator for Diablo 1640 files.
4: *
5: * A program that translates Diablo 1640 files into PostScript. Absolutely nothing
6: * is guaranteed. Quite a few things haven't been implemented, and what's been
7: * done isn't well tested. Most of the documentation used to write this program
8: * was taken from the 'Diablo Emulator' section of a recent Imagen manual.
9: *
10: * Some of document comments that are generated may not be right. Most of the test
11: * files I used produced a trailing blank page. I've put a check in formfeed() that
12: * won't print the last page if it doesn't contain any text, but PAGES comments may
13: * not be right. The DOCUMENTFONTS comment will also be wrong if auto underline or
14: * bold printing have been turned on by escape commands.
15: *
16: * The brute force approach used to implement horizontal and vertical tabs leaves
17: * much to be desired, and may not work for very small initial hmi and vmi values.
18: * At the very least I should have used malloc() to get space for the two tabstop
19: * arrays after hmi and vmi are known!
20: *
21: * Reverse printing mode hasn't been tested at all, but what's here should be
22: * close even though it's not efficient.
23: *
24: * The PostScript prologue is copied from *prologue before any of the input files
25: * are translated. The program expects that the following PostScript procedures
26: * are defined in that file:
27: *
28: * setup
29: *
30: * mark ... setup -
31: *
32: * Handles special initialization stuff that depends on how this program
33: * was called. Expects to find a mark followed by key/value pairs on the
34: * stack. The def operator is applied to each pair up to the mark, then
35: * the default state is set up.
36: *
37: * pagesetup
38: *
39: * page pagesetup -
40: *
41: * Does whatever is needed to set things up for the next page. Expects to
42: * find the current page number on the stack.
43: *
44: * t
45: *
46: * mark str1 x1 str2 x2 ... strn xn y hmi t mark
47: *
48: * Handles all the text on the stack. Characters in the strings are
49: * printed using hmi as the character advance, and all strings are at
50: * vertical position y. Each string is begins at the horizontal position
51: * that preceeds it.
52: *
53: * f
54: *
55: * font f -
56: *
57: * Use font f, where f is the full PostScript font name. Only used when
58: * we switch to auto underline (Courier-Italic) or bold (Courier-Bold)
59: * printing.
60: *
61: * done
62: *
63: * done
64: *
65: * Makes sure the last page is printed. Only needed when we're printing
66: * more than one page on each sheet of paper.
67: *
68: * Many default values, like the magnification and orientation, are defined in
69: * the prologue, which is where they belong. If they're changed (by options), an
70: * appropriate definition is made after the prologue is added to the output file.
71: * The -P option passes arbitrary PostScript through to the output file. Among
72: * other things it can be used to set (or change) values that can't be accessed by
73: * other options.
74: *
75: */
76:
77: #include <stdio.h>
78: #include <signal.h>
79: #include <ctype.h>
80: #include <fcntl.h>
81:
82: #include "comments.h" /* PostScript file structuring comments */
83: #include "gen.h" /* general purpose definitions */
84: #include "path.h" /* for the prologue */
85: #include "ext.h" /* external variable declarations */
86: #include "postdaisy.h" /* a few special definitions */
87:
88: char *optnames = "a:c:f:h:l:m:n:o:p:r:s:v:x:y:A:C:E:J:L:P:DI";
89:
90: char *prologue = POSTDAISY; /* default PostScript prologue */
91: char *formfile = FORMFILE; /* stuff for multiple pages per sheet */
92:
93: int formsperpage = 1; /* page images on each piece of paper */
94: int copies = 1; /* and this many copies of each sheet */
95:
96: char htabstops[COLUMNS]; /* horizontal */
97: char vtabstops[ROWS]; /* and vertical tabs */
98:
99: int res = RES; /* input file resolution - sort of */
100:
101: int hmi = HMI; /* horizontal motion index - 1/120 inch */
102: int vmi = VMI; /* vertical motion index - 1/48 inch */
103: int ohmi = HMI; /* original hmi */
104: int ovmi = VMI; /* and vmi - for tabs and char size */
105:
106: int hpos = 0; /* current horizontal */
107: int vpos = 0; /* and vertical position */
108:
109: int lastx = -1; /* printer's last horizontal */
110: int lasty = -1; /* and vertical position */
111: int lasthmi = -1; /* hmi for current text strings */
112:
113: int lastc = -1; /* last printed character */
114: int prevx = -1; /* at this position */
115:
116: int leftmargin = LEFTMARGIN; /* page margins */
117: int rightmargin = RIGHTMARGIN;
118: int topmargin = TOPMARGIN;
119: int bottommargin = BOTTOMMARGIN;
120:
121: int stringcount = 0; /* number of strings on the stack */
122: int stringstart = 1; /* column where current one starts */
123: int advance = 1; /* -1 if in backward print mode */
124:
125: int lfiscr = OFF; /* line feed implies carriage return */
126: int crislf = OFF; /* carriage return implies line feed */
127:
128: int linespp = 0; /* lines per page if it's positive */
129: int markedpage = FALSE; /* helps prevent trailing blank page */
130: int page = 0; /* page we're working on */
131: int printed = 0; /* printed this many pages */
132:
133: Fontmap fontmap[] = FONTMAP; /* for translating font names */
134: char *fontname = "Courier"; /* use this PostScript font */
135: int shadowprint = OFF; /* automatic bold printing if ON */
136:
137: FILE *fp_in; /* read from this file */
138: FILE *fp_out = stdout; /* and write stuff here */
139: FILE *fp_acct = NULL; /* for accounting data */
140:
141: /*****************************************************************************/
142:
143: main(agc, agv)
144:
145: int agc;
146: char *agv[];
147:
148: {
149:
150: /*
151: *
152: * A simple program that translates Diablo 1640 files into PostScript. Nothing
153: * is guaranteed - the program not well tested and doesn't implement everything.
154: *
155: */
156:
157: argc = agc; /* other routines may want them */
158: argv = agv;
159:
160: prog_name = argv[0]; /* really just for error messages */
161:
162: init_signals(); /* sets up interrupt handling */
163: header(); /* PostScript header comments */
164: options(); /* handle the command line options */
165: setup(); /* for PostScript */
166: arguments(); /* followed by each input file */
167: done(); /* print the last page etc. */
168: account(); /* job accounting data */
169:
170: exit(x_stat); /* not much could be wrong */
171:
172: } /* End of main */
173:
174: /*****************************************************************************/
175:
176: init_signals()
177:
178: {
179:
180: /*
181: *
182: * Makes sure we handle interrupts.
183: *
184: */
185:
186: if ( signal(SIGINT, interrupt) == SIG_IGN ) {
187: signal(SIGINT, SIG_IGN);
188: signal(SIGQUIT, SIG_IGN);
189: signal(SIGHUP, SIG_IGN);
190: } else {
191: signal(SIGHUP, interrupt);
192: signal(SIGQUIT, interrupt);
193: } /* End else */
194:
195: signal(SIGTERM, interrupt);
196:
197: } /* End of init_signals */
198:
199: /*****************************************************************************/
200:
201: header()
202:
203: {
204:
205: int ch; /* return value from getopt() */
206: int old_optind = optind; /* for restoring optind - should be 1 */
207:
208: /*
209: *
210: * Scans the option list looking for things, like the prologue file, that we need
211: * right away but could be changed from the default. Doing things this way is an
212: * attempt to conform to Adobe's latest file structuring conventions. In particular
213: * they now say there should be nothing executed in the prologue, and they have
214: * added two new comments that delimit global initialization calls. Once we know
215: * where things really are we write out the job header, follow it by the prologue,
216: * and then add the ENDPROLOG and BEGINSETUP comments.
217: *
218: */
219:
220: while ( (ch = getopt(argc, argv, optnames)) != EOF )
221: if ( ch == 'L' )
222: prologue = optarg;
223: else if ( ch == '?' )
224: error(FATAL, "");
225:
226: optind = old_optind; /* get ready for option scanning */
227:
228: fprintf(stdout, "%s", CONFORMING);
229: fprintf(stdout, "%s %s\n", VERSION, PROGRAMVERSION);
230: fprintf(stdout, "%s %s\n", DOCUMENTFONTS, ATEND);
231: fprintf(stdout, "%s %s\n", PAGES, ATEND);
232: fprintf(stdout, "%s", ENDCOMMENTS);
233:
234: if ( cat(prologue) == FALSE )
235: error(FATAL, "can't read %s", prologue);
236:
237: if ( DOROUND )
238: cat(ROUNDPAGE);
239:
240: fprintf(stdout, "%s", ENDPROLOG);
241: fprintf(stdout, "%s", BEGINSETUP);
242: fprintf(stdout, "mark\n");
243:
244: } /* End of header */
245:
246: /*****************************************************************************/
247:
248: options()
249:
250: {
251:
252: int ch; /* return value from getopt() */
253: int n; /* for CR and LF modes */
254:
255: /*
256: *
257: * Reads and processes the command line options. Added the -P option so arbitrary
258: * PostScript code can be passed through. Expect it could be useful for changing
259: * definitions in the prologue for which options have not been defined.
260: *
261: * Although any PostScript font can be used, things will only work for constant
262: * width fonts.
263: *
264: */
265:
266: while ( (ch = getopt(argc, argv, optnames)) != EOF ) {
267: switch ( ch ) {
268: case 'a': /* aspect ratio */
269: fprintf(stdout, "/aspectratio %s def\n", optarg);
270: break;
271:
272: case 'c': /* copies */
273: copies = atoi(optarg);
274: fprintf(stdout, "/#copies %s store\n", optarg);
275: break;
276:
277: case 'f': /* use this PostScript font */
278: fontname = get_font(optarg);
279: fprintf(stdout, "/font /%s def\n", fontname);
280: break;
281:
282: case 'h': /* default character spacing */
283: ohmi = hmi = atoi(optarg) * HSCALE;
284: fprintf(stdout, "/hmi %s def\n", optarg);
285: break;
286:
287: case 'l': /* lines per page */
288: linespp = atoi(optarg);
289: break;
290:
291: case 'm': /* magnification */
292: fprintf(stdout, "/magnification %s def\n", optarg);
293: break;
294:
295: case 'n': /* forms per page */
296: formsperpage = atoi(optarg);
297: fprintf(stdout, "%s %s\n", FORMSPERPAGE, optarg);
298: fprintf(stdout, "/formsperpage %s def\n", optarg);
299: break;
300:
301: case 'o': /* output page list */
302: out_list(optarg);
303: break;
304:
305: case 'p': /* landscape or portrait mode */
306: if ( *optarg == 'l' )
307: fprintf(stdout, "/landscape true def\n");
308: else fprintf(stdout, "/landscape false def\n");
309: break;
310:
311: case 'r': /* set CR and LF modes */
312: n = atoi(optarg);
313: if ( n & 01 )
314: lfiscr = ON;
315: else lfiscr = OFF;
316: if ( n & 02 )
317: crislf = ON;
318: else crislf = OFF;
319: break;
320:
321: case 's': /* point size */
322: fprintf(stdout, "/pointsize %s def\n", optarg);
323: break;
324:
325: case 'v': /* default line spacing */
326: ovmi = vmi = atoi(optarg) * VSCALE;
327: break;
328:
329: case 'x': /* shift things horizontally */
330: fprintf(stdout, "/xoffset %s def\n", optarg);
331: break;
332:
333: case 'y': /* and vertically on the page */
334: fprintf(stdout, "/yoffset %s def\n", optarg);
335: break;
336:
337: case 'A': /* force job accounting */
338: case 'J':
339: if ( (fp_acct = fopen(optarg, "a")) == NULL )
340: error(FATAL, "can't open accounting file %s", optarg);
341: break;
342:
343: case 'C': /* copy file straight to output */
344: if ( cat(optarg) == FALSE )
345: error(FATAL, "can't read %s", optarg);
346: break;
347:
348: case 'E': /* text font encoding */
349: fontencoding = optarg;
350: break;
351:
352: case 'L': /* PostScript prologue file */
353: prologue = optarg;
354: break;
355:
356: case 'P': /* PostScript pass through */
357: fprintf(stdout, "%s\n", optarg);
358: break;
359:
360: case 'R': /* special global or page level request */
361: saverequest(optarg);
362: break;
363:
364: case 'D': /* debug flag */
365: debug = ON;
366: break;
367:
368: case 'I': /* ignore FATAL errors */
369: ignore = ON;
370: break;
371:
372: case '?': /* don't understand the option */
373: error(FATAL, "");
374: break;
375:
376: default: /* don't know what to do for ch */
377: error(FATAL, "missing case for option %c\n", ch);
378: break;
379: } /* End switch */
380: } /* End while */
381:
382: argc -= optind; /* get ready for non-option args */
383: argv += optind;
384:
385: } /* End of options */
386:
387: /*****************************************************************************/
388:
389: char *get_font(name)
390:
391: char *name; /* name the user asked for */
392:
393: {
394:
395: int i; /* for looking through fontmap[] */
396:
397: /*
398: *
399: * Called from options() to map a user's font name into a legal PostScript name.
400: * If the lookup fails *name is returned to the caller. That should let you choose
401: * any PostScript font, although things will only work well for constant width
402: * fonts.
403: *
404: */
405:
406: for ( i = 0; fontmap[i].name != NULL; i++ )
407: if ( strcmp(name, fontmap[i].name) == 0 )
408: return(fontmap[i].val);
409:
410: return(name);
411:
412: } /* End of get_font */
413:
414: /*****************************************************************************/
415:
416: setup()
417:
418: {
419:
420: /*
421: *
422: * Handles things that must be done after the options are read but before the
423: * input files are processed.
424: *
425: */
426:
427: writerequest(0, stdout); /* global requests eg. manual feed */
428: setencoding(fontencoding);
429: fprintf(stdout, "setup\n");
430:
431: if ( formsperpage > 1 ) {
432: if ( cat(formfile) == FALSE )
433: error(FATAL, "can't read %s", formfile);
434: fprintf(stdout, "%d setupforms\n", formsperpage);
435: } /* End if */
436:
437: fprintf(stdout, "%s", ENDSETUP);
438:
439: } /* End of setup */
440:
441: /*****************************************************************************/
442:
443: arguments()
444:
445: {
446:
447: /*
448: *
449: * Makes sure all the non-option command line arguments are processed. If we get
450: * here and there aren't any arguments left, or if '-' is one of the input files
451: * we'll process stdin.
452: *
453: */
454:
455: fp_in = stdin;
456:
457: if ( argc < 1 )
458: text();
459: else { /* at least one argument is left */
460: while ( argc > 0 ) {
461: if ( strcmp(*argv, "-") == 0 )
462: fp_in = stdin;
463: else if ( (fp_in = fopen(*argv, "r")) == NULL )
464: error(FATAL, "can't open %s", *argv);
465: text();
466: if ( fp_in != stdin )
467: fclose(fp_in);
468: argc--;
469: argv++;
470: } /* End while */
471: } /* End else */
472:
473: } /* End of arguments */
474:
475: /*****************************************************************************/
476:
477: done()
478:
479: {
480:
481: /*
482: *
483: * Finished with all the input files, so mark the end of the pages, make sure the
484: * last page is printed, and restore the initial environment.
485: *
486: */
487:
488: fprintf(stdout, "%s", TRAILER);
489: fprintf(stdout, "done\n");
490: fprintf(stdout, "%s %s\n", DOCUMENTFONTS, fontname);
491: fprintf(stdout, "%s %d\n", PAGES, printed);
492:
493: } /* End of done */
494:
495: /*****************************************************************************/
496:
497: account()
498:
499: {
500:
501: /*
502: *
503: * Writes an accounting record to *fp_acct provided it's not NULL. Accounting
504: * is requested using the -A or -J options.
505: *
506: */
507:
508: if ( fp_acct != NULL )
509: fprintf(fp_acct, " print %d\n copies %d\n", printed, copies);
510:
511: } /* End of account */
512:
513: /*****************************************************************************/
514:
515: text()
516:
517: {
518:
519: int ch; /* next input character */
520:
521: /*
522: *
523: * Translates the next input file into PostScript. The redirect(-1) call forces
524: * the initial output to go to /dev/null - so the stuff formfeed() does at the
525: * end of each page doesn't go to stdout.
526: *
527: */
528:
529: redirect(-1); /* get ready for the first page */
530: formfeed(); /* force PAGE comment etc. */
531: inittabs();
532:
533: while ( (ch = getc(fp_in)) != EOF )
534: switch ( ch ) {
535: case '\010': /* backspace */
536: backspace();
537: break;
538:
539: case '\011': /* horizontal tab */
540: htab();
541: break;
542:
543: case '\012': /* new line */
544: linefeed();
545: break;
546:
547: case '\013': /* vertical tab */
548: vtab();
549: break;
550:
551: case '\014': /* form feed */
552: formfeed();
553: break;
554:
555: case '\015': /* carriage return */
556: carriage();
557: break;
558:
559: case '\016': /* extended character set - SO */
560: break;
561:
562: case '\017': /* extended character set - SI */
563: break;
564:
565: case '\031': /* next char from supplementary set */
566: break;
567:
568: case '\033': /* 2 or 3 byte escape sequence */
569: escape();
570: break;
571:
572: default:
573: oput(ch);
574: break;
575: } /* End switch */
576:
577: formfeed(); /* next file starts on a new page? */
578:
579: } /* End of text */
580:
581: /*****************************************************************************/
582:
583: inittabs()
584:
585: {
586:
587: int i; /* loop index */
588:
589: /*
590: *
591: * Initializes the horizontal and vertical tab arrays. The way tabs are handled is
592: * quite inefficient and may not work for all initial hmi or vmi values.
593: *
594: */
595:
596: for ( i = 0; i < COLUMNS; i++ )
597: htabstops[i] = ((i % 8) == 0) ? ON : OFF;
598:
599: for ( i = 0; i < ROWS; i++ )
600: vtabstops[i] = ((i * ovmi) > BOTTOMMARGIN) ? ON : OFF;
601:
602: } /* End of inittabs */
603:
604: /*****************************************************************************/
605:
606: cleartabs()
607:
608: {
609:
610: int i; /* loop index */
611:
612: /*
613: *
614: * Clears all horizontal and vertical tab stops.
615: *
616: */
617:
618: for ( i = 0; i < ROWS; i++ )
619: htabstops[i] = OFF;
620:
621: for ( i = 0; i < COLUMNS; i++ )
622: vtabstops[i] = OFF;
623:
624: } /* End of cleartabs */
625:
626: /*****************************************************************************/
627:
628: formfeed()
629:
630: {
631:
632: /*
633: *
634: * Called whenever we've finished with the last page and want to get ready for the
635: * next one. Also used at the beginning and end of each input file, so we have to
636: * be careful about what's done. I've added a simple test before the showpage that
637: * should eliminate the extra blank page that was put out at the end of many jobs,
638: * but the PAGES comments may be wrong.
639: *
640: */
641:
642: if ( fp_out == stdout ) /* count the last page */
643: printed++;
644:
645: endline(); /* print the last line */
646:
647: fprintf(fp_out, "cleartomark\n");
648: if ( feof(fp_in) == 0 || markedpage == TRUE )
649: fprintf(fp_out, "showpage\n");
650: fprintf(fp_out, "saveobj restore\n");
651: fprintf(fp_out, "%s %d %d\n", ENDPAGE, page, printed);
652:
653: if ( ungetc(getc(fp_in), fp_in) == EOF )
654: redirect(-1);
655: else redirect(++page);
656:
657: fprintf(fp_out, "%s %d %d\n", PAGE, page, printed+1);
658: fprintf(fp_out, "/saveobj save def\n");
659: fprintf(fp_out, "mark\n");
660: writerequest(printed+1, fp_out);
661: fprintf(fp_out, "%d pagesetup\n", printed+1);
662:
663: vgoto(topmargin);
664: hgoto(leftmargin);
665:
666: markedpage = FALSE;
667:
668: } /* End of formfeed */
669:
670: /*****************************************************************************/
671:
672: linefeed()
673:
674: {
675:
676: int line = 0; /* current line - based on ovmi */
677:
678: /*
679: *
680: * Adjust our current vertical position. If we've passed the bottom of the page
681: * or exceeded the number of lines per page, print it and go to the upper left
682: * corner of the next page. This routine is also called from carriage() if crislf
683: * is ON.
684: *
685: */
686:
687: vmot(vmi);
688:
689: if ( lfiscr == ON )
690: hgoto(leftmargin);
691:
692: if ( linespp > 0 ) /* means something so see where we are */
693: line = vpos / ovmi + 1;
694:
695: if ( vpos > bottommargin || line > linespp )
696: formfeed();
697:
698: } /* End of linefeed */
699:
700: /*****************************************************************************/
701:
702: carriage()
703:
704: {
705:
706: /*
707: *
708: * Handles carriage return character. If crislf is ON we'll generate a line feed
709: * every time we get a carriage return character.
710: *
711: */
712:
713: if ( shadowprint == ON ) /* back to normal mode */
714: changefont(fontname);
715:
716: advance = 1;
717: shadowprint = OFF;
718:
719: hgoto(leftmargin);
720:
721: if ( crislf == ON )
722: linefeed();
723:
724: } /* End of carriage */
725:
726: /*****************************************************************************/
727:
728: htab()
729:
730: {
731:
732: int col; /* 'column' we'll be at next */
733: int i; /* loop index */
734:
735: /*
736: *
737: * Tries to figure out where the next tab stop is. Wasn't positive about this
738: * one, since hmi can change. I'll assume columns are determined by the original
739: * value of hmi. That fixes them on the page, which seems to make more sense than
740: * letting them float all over the place.
741: *
742: */
743:
744: endline();
745:
746: col = hpos/ohmi + 1;
747: for ( i = col; i < ROWS; i++ )
748: if ( htabstops[i] == ON ) {
749: col = i;
750: break;
751: } /* End if */
752:
753: hgoto(col * ohmi);
754: lastx = hpos;
755:
756: } /* End of htab */
757:
758: /*****************************************************************************/
759:
760: vtab()
761:
762: {
763:
764: int line; /* line we'll be at next */
765: int i; /* loop index */
766:
767: /*
768: *
769: * Looks for the next vertical tab stop in the vtabstops[] array and moves to that
770: * line. If we don't find a tab we'll just move down one line - shouldn't happen.
771: *
772: */
773:
774: endline();
775:
776: line = vpos/ovmi + 1;
777: for ( i = line; i < COLUMNS; i++ )
778: if ( vtabstops[i] == ON ) {
779: line = i;
780: break;
781: } /* End if */
782:
783: vgoto(line * ovmi);
784:
785: } /* End of vtab */
786:
787: /*****************************************************************************/
788:
789: backspace()
790:
791: {
792:
793: /*
794: *
795: * Moves backwards a distance equal to the current value of hmi, but don't go
796: * past the left margin.
797: *
798: */
799:
800: endline();
801:
802: if ( hpos - leftmargin >= hmi )
803: hmot(-hmi);
804: else hgoto(leftmargin); /* maybe just ignore the backspace?? */
805:
806: lastx = hpos;
807:
808: } /* End of backspace */
809:
810: /*****************************************************************************/
811:
812: escape()
813:
814: {
815:
816: int ch; /* control character */
817:
818: /*
819: *
820: * Handles special codes that are expected to follow an escape character. The
821: * initial escape character is followed by one or two bytes.
822: *
823: */
824:
825: switch ( ch = getc(fp_in) ) {
826: case 'T': /* top margin */
827: topmargin = vpos;
828: break;
829:
830: case 'L': /* bottom margin */
831: bottommargin = vpos;
832: break;
833:
834: case 'C': /* clear top and bottom margins */
835: bottommargin = BOTTOMMARGIN;
836: topmargin = TOPMARGIN;
837: break;
838:
839: case '9': /* left margin */
840: leftmargin = hpos;
841: break;
842:
843: case '0': /* right margin */
844: rightmargin = hpos;
845: break;
846:
847: case '1': /* set horizontal tab */
848: htabstops[hpos/ohmi] = ON;
849: break;
850:
851: case '8': /* clear horizontal tab at hpos */
852: htabstops[hpos/ohmi] = OFF;
853: break;
854:
855: case '-': /* set vertical tab */
856: vtabstops[vpos/ovmi] = ON;
857: break;
858:
859: case '2': /* clear all tabs */
860: cleartabs();
861: break;
862:
863: case '\014': /* set lines per page */
864: linespp = getc(fp_in);
865: break;
866:
867: case '\037': /* set hmi to next byte minus 1 */
868: hmi = HSCALE * (getc(fp_in) - 1);
869: break;
870:
871: case 'S': /* reset hmi to default */
872: hmi = ohmi;
873: break;
874:
875: case '\011': /* move to column given by next byte */
876: hgoto((getc(fp_in)-1) * ohmi);
877: break;
878:
879: case '?': /* do carriage return after line feed */
880: lfiscr = ON;
881: break;
882:
883: case '!': /* don't generate carriage return */
884: lfiscr = OFF;
885: break;
886:
887: case '5': /* forward print mode */
888: advance = 1;
889: break;
890:
891: case '6': /* backward print mode */
892: advance = -1;
893: break;
894:
895: case '\036': /* set vmi to next byte minus 1 */
896: vmi = VSCALE * (getc(fp_in) - 1);
897: break;
898:
899: case '\013': /* move to line given by next byte */
900: vgoto((getc(fp_in)-1) * ovmi);
901: break;
902:
903: case 'U': /* positive half line feed */
904: vmot(vmi/2);
905: break;
906:
907: case 'D': /* negative half line feed */
908: vmot(-vmi/2);
909: break;
910:
911: case '\012': /* negative line feed */
912: vmot(-vmi);
913: break;
914:
915: case '\015': /* clear all margins */
916: bottommargin = BOTTOMMARGIN;
917: topmargin = TOPMARGIN;
918: leftmargin = BOTTOMMARGIN;
919: rightmargin = RIGHTMARGIN;
920: break;
921:
922: case 'E': /* auto underscore - use italic font */
923: changefont("/Courier-Oblique");
924: break;
925:
926: case 'R': /* disable auto underscore */
927: changefont(fontname);
928: break;
929:
930: case 'O': /* bold/shadow printing */
931: case 'W':
932: changefont("/Courier-Bold");
933: shadowprint = ON;
934: break;
935:
936: case '&': /* disable bold printing */
937: changefont(fontname);
938: shadowprint = OFF;
939: break;
940:
941: case '/': /* ignored 2 byte escapes */
942: case '\\':
943: case '<':
944: case '>':
945: case '%':
946: case '=':
947: case '.':
948: case '4':
949: case 'A':
950: case 'B':
951: case 'M':
952: case 'N':
953: case 'P':
954: case 'Q':
955: case 'X':
956: case '\010':
957: break;
958:
959: case ',': /* ignored 3 byte escapes */
960: case '\016':
961: case '\021':
962: getc(fp_in);
963: break;
964:
965: case '3': /* graphics mode - should quit! */
966: case '7':
967: case 'G':
968: case 'V':
969: case 'Y':
970: case 'Z':
971: error(FATAL, "graphics mode is not implemented");
972: break;
973:
974: default:
975: error(FATAL, "missing case for escape o%o\n", ch);
976: break;
977: } /* End switch */
978:
979: } /* End of escape */
980:
981: /*****************************************************************************/
982:
983: vmot(n)
984:
985: int n; /* move this far vertically */
986:
987: {
988:
989: /*
990: *
991: * Move vertically n units from where we are.
992: *
993: */
994:
995: vpos += n;
996:
997: } /* End of vmot */
998:
999: /*****************************************************************************/
1000:
1001: vgoto(n)
1002:
1003: int n; /* new vertical position */
1004:
1005: {
1006:
1007: /*
1008: *
1009: * Moves to absolute vertical position n.
1010: *
1011: */
1012:
1013: vpos = n;
1014:
1015: } /* End of vgoto */
1016:
1017: /*****************************************************************************/
1018:
1019: hmot(n)
1020:
1021: int n; /* move this horizontally */
1022:
1023: {
1024:
1025: /*
1026: *
1027: * Moves horizontally n units from our current position.
1028: *
1029: */
1030:
1031: hpos += n * advance;
1032:
1033: if ( hpos < leftmargin )
1034: hpos = leftmargin;
1035:
1036: } /* End of hmot */
1037:
1038: /*****************************************************************************/
1039:
1040: hgoto(n)
1041:
1042: int n; /* go to this horizontal position */
1043:
1044: {
1045:
1046: /*
1047: *
1048: * Moves to absolute horizontal position n.
1049: *
1050: */
1051:
1052: hpos = n;
1053:
1054: } /* End of hgoto */
1055:
1056: /*****************************************************************************/
1057:
1058: changefont(name)
1059:
1060: char *name;
1061:
1062: {
1063:
1064: /*
1065: *
1066: * Changes the current font. Used to get in and out of auto underscore and bold
1067: * printing.
1068: *
1069: */
1070:
1071: endline();
1072: fprintf(fp_out, "%s f\n", name);
1073:
1074: } /* End of changefont */
1075:
1076: /*****************************************************************************/
1077:
1078: startline()
1079:
1080: {
1081:
1082: /*
1083: *
1084: * Called whenever we want to be certain we're ready to start pushing characters
1085: * into an open string on the stack. If stringcount is positive we've already
1086: * started, so there's nothing to do. The first string starts in column 1.
1087: *
1088: */
1089:
1090: if ( stringcount < 1 ) {
1091: putc('(', fp_out);
1092: stringstart = lastx = hpos;
1093: lasty = vpos;
1094: lasthmi = hmi;
1095: lastc = -1;
1096: prevx = -1;
1097: stringcount = 1;
1098: } /* End if */
1099:
1100: } /* End of startline */
1101:
1102: /*****************************************************************************/
1103:
1104: endline()
1105:
1106: {
1107:
1108: /*
1109: *
1110: * Generates a call to the PostScript procedure that processes the text on the
1111: * the stack - provided stringcount is positive.
1112: *
1113: */
1114:
1115: if ( stringcount > 0 )
1116: fprintf(fp_out, ")%d %d %d t\n", stringstart, lasty, lasthmi);
1117:
1118: stringcount = 0;
1119:
1120: } /* End of endline */
1121:
1122: /*****************************************************************************/
1123:
1124: endstring()
1125:
1126: {
1127:
1128: /*
1129: *
1130: * Takes the string we've been working on and adds it to the output file. Called
1131: * when we need to adjust our horizontal position before starting a new string.
1132: * Also called from endline() when we're done with the current line.
1133: *
1134: */
1135:
1136: if ( stringcount > 0 ) {
1137: fprintf(fp_out, ")%d(", stringstart);
1138: lastx = stringstart = hpos;
1139: stringcount++;
1140: } /* End if */
1141:
1142: } /* End of endstring */
1143:
1144: /*****************************************************************************/
1145:
1146: oput(ch)
1147:
1148: int ch; /* next output character */
1149:
1150: {
1151:
1152: /*
1153: *
1154: * Responsible for adding all printing characters from the input file to the
1155: * open string on top of the stack. The only other characters that end up in
1156: * that string are the quotes required for special characters. Reverse printing
1157: * mode hasn't been tested but it should be close. hpos and lastx should disagree
1158: * each time (except after startline() does something), and that should force a
1159: * call to endstring() for every character.
1160: *
1161: */
1162:
1163: if ( stringcount > 100 ) /* don't put too much on the stack */
1164: endline();
1165:
1166: if ( vpos != lasty )
1167: endline();
1168:
1169: if ( advance == -1 ) /* for reverse printing - move first */
1170: hmot(hmi);
1171:
1172: startline();
1173:
1174: if ( lastc != ch || hpos != prevx ) {
1175: if ( lastx != hpos )
1176: endstring();
1177:
1178: if ( isascii(ch) && isprint(ch) ) {
1179: if ( ch == '\\' || ch == '(' || ch == ')' )
1180: putc('\\', fp_out);
1181: putc(ch, fp_out);
1182: } else fprintf(fp_out, "\\%.3o", ch & 0377);
1183:
1184: lastc = ch;
1185: prevx = hpos;
1186: lastx += lasthmi;
1187: } /* End if */
1188:
1189: if ( advance != -1 )
1190: hmot(hmi);
1191:
1192: markedpage = TRUE;
1193:
1194: } /* End of oput */
1195:
1196: /*****************************************************************************/
1197:
1198: redirect(pg)
1199:
1200: int pg; /* next page we're printing */
1201:
1202: {
1203:
1204: static FILE *fp_null = NULL; /* if output is turned off */
1205:
1206: /*
1207: *
1208: * If we're not supposed to print page pg, fp_out will be directed to /dev/null,
1209: * otherwise output goes to stdout.
1210: *
1211: */
1212:
1213: if ( pg >= 0 && in_olist(pg) == ON )
1214: fp_out = stdout;
1215: else if ( (fp_out = fp_null) == NULL )
1216: fp_out = fp_null = fopen("/dev/null", "w");
1217:
1218: } /* End of redirect */
1219:
1220: /*****************************************************************************/
1221:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.