|
|
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.