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