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