|
|
1.1 ! root 1: /* ! 2: * ! 3: * posttek - PostScript translator for tektronix 4014 files ! 4: * ! 5: * A program that can be used to translate tektronix 4014 files into PostScript. ! 6: * Most of the code was borrowed from the tektronix 4014 emulator that was written ! 7: * for DMDs. Things have been cleaned up some, but there's still plently that ! 8: * could be done. ! 9: * ! 10: * The PostScript prologue is copied from *prologue before any of the input files ! 11: * are translated. The program expects that the following PostScript procedures ! 12: * are defined in that file: ! 13: * ! 14: * setup ! 15: * ! 16: * mark ... setup - ! 17: * ! 18: * Handles special initialization stuff that depends on how the program ! 19: * was called. Expects to find a mark followed by key/value pairs on the ! 20: * stack. The def operator is applied to each pair up to the mark, then ! 21: * the default state is set up. ! 22: * ! 23: * pagesetup ! 24: * ! 25: * page pagesetup - ! 26: * ! 27: * Does whatever is needed to set things up for the next page. Expects ! 28: * to find the current page number on the stack. ! 29: * ! 30: * v ! 31: * ! 32: * mark dx1 dy1 ... dxn dyn x y v mark ! 33: * ! 34: * Draws the vector described by the numbers on the stack. The top two ! 35: * numbers are the starting point. The rest are relative displacements ! 36: * from the preceeding point. Must make sure we don't put too much on ! 37: * the stack! ! 38: * ! 39: * t ! 40: * ! 41: * x y string t - ! 42: * ! 43: * Prints the string that's on the top of the stack starting at point ! 44: * (x, y). ! 45: * ! 46: * p ! 47: * ! 48: * x y p - ! 49: * ! 50: * Marks the point (x, y) with a circle whose radius varies with the ! 51: * current intensity setting. ! 52: * ! 53: * i ! 54: * ! 55: * percent focus i - ! 56: * ! 57: * Changes the size of the circle used to mark individual points to ! 58: * percent of maximum for focused mode (focus=1) or defocused mode ! 59: * (focus=0). The implementation leaves much to be desired! ! 60: * ! 61: * l ! 62: * ! 63: * mark array l mark ! 64: * ! 65: * Set the line drawing mode according to the description given in array. ! 66: * The arrays that describe the different line styles are declared in ! 67: * STYLES (file posttek.h). The array really belongs in the prologue! ! 68: * ! 69: * w ! 70: * ! 71: * n w - ! 72: * ! 73: * Adjusts the line width for vector drawing. Used to select normal (n=0) ! 74: * or defocused (n=1) mode. ! 75: * ! 76: * f ! 77: * ! 78: * size f - ! 79: * ! 80: * Changes the size of the font that's used to print characters in alpha ! 81: * mode. size is the tektronix character width and is used to choose an ! 82: * appropriate point size in the current font. ! 83: * ! 84: * done ! 85: * ! 86: * done ! 87: * ! 88: * Makes sure the last page is printed. Only needed when we're printing ! 89: * more than one page on each sheet of paper. ! 90: * ! 91: * The default line width is zero, which forces lines to be one pixel wide. That ! 92: * works well on 'write to black' engines but won't be right for 'write to white' ! 93: * engines. The line width can be changed using the -w option, or you can change ! 94: * the initialization of linewidth in the prologue. ! 95: * ! 96: * Many default values, like the magnification and orientation, are defined in ! 97: * the prologue, which is where they belong. If they're changed (by options), an ! 98: * appropriate definition is made after the prologue is added to the output file. ! 99: * The -P option passes arbitrary PostScript through to the output file. Among ! 100: * other things it can be used to set (or change) values that can't be accessed by ! 101: * other options. ! 102: * ! 103: */ ! 104: ! 105: #include <stdio.h> ! 106: #include <signal.h> ! 107: #include <fcntl.h> ! 108: ! 109: #include "comments.h" /* PostScript file structuring comments */ ! 110: #include "gen.h" /* general purpose definitions */ ! 111: #include "path.h" /* for the prologue */ ! 112: #include "ext.h" /* external variable definitions */ ! 113: #include "posttek.h" /* control codes and other definitions */ ! 114: ! 115: char *optnames = "a:c:f:m:n:o:p:w:x:y:A:C:E:J:L:P:R:DI"; ! 116: ! 117: char *prologue = POSTTEK; /* default PostScript prologue */ ! 118: char *formfile = FORMFILE; /* stuff for multiple pages per sheet */ ! 119: ! 120: int formsperpage = 1; /* page images on each piece of paper */ ! 121: int copies = 1; /* and this many copies of each sheet */ ! 122: ! 123: int charheight[] = CHARHEIGHT; /* height */ ! 124: int charwidth[] = CHARWIDTH; /* and width arrays for tek characters */ ! 125: int tekfont = TEKFONT; /* index into charheight[] and charwidth[] */ ! 126: ! 127: char intensity[] = INTENSITY; /* special point intensity array */ ! 128: char *styles[] = STYLES; /* description of line styles */ ! 129: int linestyle = 0; /* index into styles[] */ ! 130: int linetype = 0; /* 0 for normal, 1 for defocused */ ! 131: ! 132: int dispmode = ALPHA; /* current tektronix state */ ! 133: int points = 0; /* points making up the current vector */ ! 134: int characters = 0; /* characters waiting to be printed */ ! 135: int pen = UP; /* just for point plotting */ ! 136: int margin = 0; /* left edge - ALPHA state */ ! 137: ! 138: Point cursor; /* should be current cursor position */ ! 139: ! 140: Fontmap fontmap[] = FONTMAP; /* for translating font names */ ! 141: char *fontname = "Courier"; /* use this PostScript font */ ! 142: ! 143: int page = 0; /* page we're working on */ ! 144: int printed = 0; /* printed this many pages */ ! 145: ! 146: FILE *fp_in; /* read from this file */ ! 147: FILE *fp_out = stdout; /* and write stuff here */ ! 148: FILE *fp_acct = NULL; /* for accounting data */ ! 149: ! 150: /*****************************************************************************/ ! 151: ! 152: main(agc, agv) ! 153: ! 154: int agc; ! 155: char *agv[]; ! 156: ! 157: { ! 158: ! 159: /* ! 160: * ! 161: * A simple program that can be used to translate tektronix 4014 files into ! 162: * PostScript. Most of the code was taken from the DMD tektronix 4014 emulator, ! 163: * although things have been cleaned up some. ! 164: * ! 165: */ ! 166: ! 167: argv = agv; /* so everyone can use them */ ! 168: argc = agc; ! 169: ! 170: prog_name = argv[0]; /* just for error messages */ ! 171: ! 172: init_signals(); /* sets up interrupt handling */ ! 173: header(); /* PostScript header comments */ ! 174: options(); /* handle the command line options */ ! 175: setup(); /* for PostScript */ ! 176: arguments(); /* followed by each input file */ ! 177: done(); /* print the last page etc. */ ! 178: account(); /* job accounting data */ ! 179: ! 180: exit(x_stat); /* nothing could be wrong */ ! 181: ! 182: } /* End of main */ ! 183: ! 184: /*****************************************************************************/ ! 185: ! 186: init_signals() ! 187: ! 188: { ! 189: ! 190: /* ! 191: * ! 192: * Make sure we handle interrupts. ! 193: * ! 194: */ ! 195: ! 196: if ( signal(SIGINT, interrupt) == SIG_IGN ) { ! 197: signal(SIGINT, SIG_IGN); ! 198: signal(SIGQUIT, SIG_IGN); ! 199: signal(SIGHUP, SIG_IGN); ! 200: } else { ! 201: signal(SIGHUP, interrupt); ! 202: signal(SIGQUIT, interrupt); ! 203: } /* End else */ ! 204: ! 205: signal(SIGTERM, interrupt); ! 206: ! 207: } /* End of init_signals */ ! 208: ! 209: /*****************************************************************************/ ! 210: ! 211: header() ! 212: ! 213: { ! 214: ! 215: int ch; /* return value from getopt() */ ! 216: int old_optind = optind; /* for restoring optind - should be 1 */ ! 217: ! 218: /* ! 219: * ! 220: * Scans the option list looking for things, like the prologue file, that we need ! 221: * right away but could be changed from the default. Doing things this way is an ! 222: * attempt to conform to Adobe's latest file structuring conventions. In particular ! 223: * they now say there should be nothing executed in the prologue, and they have ! 224: * added two new comments that delimit global initialization calls. Once we know ! 225: * where things really are we write out the job header, follow it by the prologue, ! 226: * and then add the ENDPROLOG and BEGINSETUP comments. ! 227: * ! 228: */ ! 229: ! 230: while ( (ch = getopt(argc, argv, optnames)) != EOF ) ! 231: if ( ch == 'L' ) ! 232: prologue = optarg; ! 233: else if ( ch == '?' ) ! 234: error(FATAL, ""); ! 235: ! 236: optind = old_optind; /* get ready for option scanning */ ! 237: ! 238: fprintf(stdout, "%s", CONFORMING); ! 239: fprintf(stdout, "%s %s\n", VERSION, PROGRAMVERSION); ! 240: fprintf(stdout, "%s %s\n", DOCUMENTFONTS, ATEND); ! 241: fprintf(stdout, "%s %s\n", PAGES, ATEND); ! 242: fprintf(stdout, "%s", ENDCOMMENTS); ! 243: ! 244: if ( cat(prologue) == FALSE ) ! 245: error(FATAL, "can't read %s", prologue); ! 246: ! 247: fprintf(stdout, "%s", ENDPROLOG); ! 248: fprintf(stdout, "%s", BEGINSETUP); ! 249: fprintf(stdout, "mark\n"); ! 250: ! 251: } /* End of header */ ! 252: ! 253: /*****************************************************************************/ ! 254: ! 255: options() ! 256: ! 257: { ! 258: ! 259: int ch; /* value returned by getopt() */ ! 260: ! 261: /* ! 262: * ! 263: * Reads and processes the command line options. Added the -P option so arbitrary ! 264: * PostScript code can be passed through. Expect it could be useful for changing ! 265: * definitions in the prologue for which options have not been defined. ! 266: * ! 267: */ ! 268: ! 269: while ( (ch = getopt(argc, argv, optnames)) != EOF ) { ! 270: switch ( ch ) { ! 271: case 'a': /* aspect ratio */ ! 272: fprintf(stdout, "/aspectratio %s def\n", optarg); ! 273: break; ! 274: ! 275: case 'c': /* copies */ ! 276: copies = atoi(optarg); ! 277: fprintf(stdout, "/#copies %s store\n", optarg); ! 278: break; ! 279: ! 280: case 'f': /* use this PostScript font */ ! 281: fontname = get_font(optarg); ! 282: fprintf(stdout, "/font /%s def\n", fontname); ! 283: break; ! 284: ! 285: case 'm': /* magnification */ ! 286: fprintf(stdout, "/magnification %s def\n", optarg); ! 287: break; ! 288: ! 289: case 'n': /* forms per page */ ! 290: formsperpage = atoi(optarg); ! 291: fprintf(stdout, "%s %s\n", FORMSPERPAGE, optarg); ! 292: fprintf(stdout, "/formsperpage %s def\n", optarg); ! 293: break; ! 294: ! 295: case 'o': /* output page list */ ! 296: out_list(optarg); ! 297: break; ! 298: ! 299: case 'p': /* landscape or portrait mode */ ! 300: if ( *optarg == 'l' ) ! 301: fprintf(stdout, "/landscape true def\n"); ! 302: else fprintf(stdout, "/landscape false def\n"); ! 303: break; ! 304: ! 305: case 'w': /* line width */ ! 306: fprintf(stdout, "/linewidth %s def\n", optarg); ! 307: break; ! 308: ! 309: case 'x': /* shift horizontally */ ! 310: fprintf(stdout, "/xoffset %s def\n", optarg); ! 311: break; ! 312: ! 313: case 'y': /* and vertically on the page */ ! 314: fprintf(stdout, "/yoffset %s def\n", optarg); ! 315: break; ! 316: ! 317: case 'A': /* force job accounting */ ! 318: case 'J': ! 319: if ( (fp_acct = fopen(optarg, "a")) == NULL ) ! 320: error(FATAL, "can't open accounting file %s", optarg); ! 321: break; ! 322: ! 323: case 'C': /* copy file straight to output */ ! 324: if ( cat(optarg) == FALSE ) ! 325: error(FATAL, "can't read %s", optarg); ! 326: break; ! 327: ! 328: case 'E': /* text font encoding */ ! 329: fontencoding = optarg; ! 330: break; ! 331: ! 332: case 'L': /* PostScript prologue file */ ! 333: prologue = optarg; ! 334: break; ! 335: ! 336: case 'P': /* PostScript pass through */ ! 337: fprintf(stdout, "%s\n", optarg); ! 338: break; ! 339: ! 340: case 'R': /* special global or page level request */ ! 341: saverequest(optarg); ! 342: break; ! 343: ! 344: case 'D': /* debug flag */ ! 345: debug = ON; ! 346: break; ! 347: ! 348: case 'I': /* ignore FATAL errors */ ! 349: ignore = ON; ! 350: break; ! 351: ! 352: case '?': /* don't know the option */ ! 353: error(FATAL, ""); ! 354: break; ! 355: ! 356: default: /* don't know what to do for ch */ ! 357: error(FATAL, "missing case for option %c", ch); ! 358: break; ! 359: } /* End switch */ ! 360: } /* End while */ ! 361: ! 362: argc -= optind; ! 363: argv += optind; ! 364: ! 365: } /* End of options */ ! 366: ! 367: /*****************************************************************************/ ! 368: ! 369: char *get_font(name) ! 370: ! 371: char *name; /* name the user asked for */ ! 372: ! 373: { ! 374: ! 375: int i; /* for looking through fontmap[] */ ! 376: ! 377: /* ! 378: * ! 379: * Called from options() to map a user's font name into a legal PostScript name. ! 380: * If the lookup fails *name is returned to the caller. That should let you choose ! 381: * any PostScript font. ! 382: * ! 383: */ ! 384: ! 385: for ( i = 0; fontmap[i].name != NULL; i++ ) ! 386: if ( strcmp(name, fontmap[i].name) == 0 ) ! 387: return(fontmap[i].val); ! 388: ! 389: return(name); ! 390: ! 391: } /* End of get_font */ ! 392: ! 393: /*****************************************************************************/ ! 394: ! 395: setup() ! 396: ! 397: { ! 398: ! 399: /* ! 400: * ! 401: * Handles things that must be done after the options are read but before the ! 402: * input files are processed. ! 403: * ! 404: */ ! 405: ! 406: writerequest(0, stdout); /* global requests eg. manual feed */ ! 407: setencoding(fontencoding); ! 408: fprintf(stdout, "setup\n"); ! 409: ! 410: if ( formsperpage > 1 ) { ! 411: if ( cat(formfile) == FALSE ) ! 412: error(FATAL, "can't read %s", formfile); ! 413: fprintf(stdout, "%d setupforms\n", formsperpage); ! 414: } /* End if */ ! 415: ! 416: fprintf(stdout, "%s", ENDSETUP); ! 417: ! 418: } /* End of setup */ ! 419: ! 420: /*****************************************************************************/ ! 421: ! 422: arguments() ! 423: ! 424: { ! 425: ! 426: /* ! 427: * ! 428: * Makes sure all the non-option command line arguments are processed. If we get ! 429: * here and there aren't any arguments left, or if '-' is one of the input files ! 430: * we'll process stdin. ! 431: * ! 432: */ ! 433: ! 434: if ( argc < 1 ) ! 435: statemachine(fp_in = stdin); ! 436: else { /* at least one argument is left */ ! 437: while ( argc > 0 ) { ! 438: if ( strcmp(*argv, "-") == 0 ) ! 439: fp_in = stdin; ! 440: else if ( (fp_in = fopen(*argv, "r")) == NULL ) ! 441: error(FATAL, "can't open %s", *argv); ! 442: statemachine(fp_in); ! 443: if ( fp_in != stdin ) ! 444: fclose(fp_in); ! 445: argc--; ! 446: argv++; ! 447: } /* End while */ ! 448: } /* End else */ ! 449: ! 450: } /* End of arguments */ ! 451: ! 452: /*****************************************************************************/ ! 453: ! 454: done() ! 455: ! 456: { ! 457: ! 458: /* ! 459: * ! 460: * Finished with all the input files, so mark the end of the pages with a TRAILER ! 461: * comment, make sure the last page prints, and add things like the PAGES comment ! 462: * that can only be determined after all the input files have been read. ! 463: * ! 464: */ ! 465: ! 466: fprintf(stdout, "%s", TRAILER); ! 467: fprintf(stdout, "done\n"); ! 468: fprintf(stdout, "%s %s\n", DOCUMENTFONTS, fontname); ! 469: fprintf(stdout, "%s %d\n", PAGES, printed); ! 470: ! 471: } /* End of done */ ! 472: ! 473: /*****************************************************************************/ ! 474: ! 475: account() ! 476: ! 477: { ! 478: ! 479: /* ! 480: * ! 481: * Writes an accounting record to *fp_acct provided it's not NULL. Accounting ! 482: * is requested using the -A or -J options. ! 483: * ! 484: */ ! 485: ! 486: if ( fp_acct != NULL ) ! 487: fprintf(fp_acct, " print %d\n copies %d\n", printed, copies); ! 488: ! 489: } /* End of account */ ! 490: ! 491: /*****************************************************************************/ ! 492: ! 493: statemachine(fp) ! 494: ! 495: FILE *fp; /* used to set fp_in */ ! 496: ! 497: { ! 498: ! 499: /* ! 500: * ! 501: * Controls the translation of the next input file. Tektronix states (dispmode) ! 502: * are typically changed in control() and esc(). ! 503: * ! 504: */ ! 505: ! 506: redirect(-1); /* get ready for the first page */ ! 507: formfeed(); ! 508: dispmode = RESET; ! 509: ! 510: while ( 1 ) ! 511: switch ( dispmode ) { ! 512: case RESET: ! 513: reset(); ! 514: break; ! 515: ! 516: case ALPHA: ! 517: alpha(); ! 518: break; ! 519: ! 520: case GIN: ! 521: gin(); ! 522: break; ! 523: ! 524: case GRAPH: ! 525: graph(); ! 526: break; ! 527: ! 528: case POINT: ! 529: case SPECIALPOINT: ! 530: point(); ! 531: break; ! 532: ! 533: case INCREMENTAL: ! 534: incremental(); ! 535: break; ! 536: ! 537: case EXIT: ! 538: formfeed(); ! 539: return; ! 540: } /* End switch */ ! 541: ! 542: } /* End of statemachine */ ! 543: ! 544: /*****************************************************************************/ ! 545: ! 546: reset() ! 547: ! 548: { ! 549: ! 550: /* ! 551: * ! 552: * Called to reset things, typically only at the beginning of each input file. ! 553: * ! 554: */ ! 555: ! 556: tekfont = -1; ! 557: home(); ! 558: setfont(TEKFONT); ! 559: setmode(ALPHA); ! 560: ! 561: } /* End of reset */ ! 562: ! 563: /*****************************************************************************/ ! 564: ! 565: alpha() ! 566: ! 567: { ! 568: ! 569: int c; /* next character */ ! 570: int x, y; /* cursor will be here when we're done */ ! 571: ! 572: /* ! 573: * ! 574: * Takes care of printing characters in the current font. ! 575: * ! 576: */ ! 577: ! 578: if ( (c = nextchar()) == OUTMODED ) ! 579: return; ! 580: ! 581: if ( (c < 040) && ((c = control(c)) <= 0) ) ! 582: return; ! 583: ! 584: x = cursor.x; /* where the cursor is right now */ ! 585: y = cursor.y; ! 586: ! 587: switch ( c ) { ! 588: case DEL: ! 589: return; ! 590: ! 591: case BS: ! 592: if ((x -= charwidth[tekfont]) < margin) ! 593: x = TEKXMAX - charwidth[tekfont]; ! 594: break; ! 595: ! 596: case NL: ! 597: y -= charheight[tekfont]; ! 598: break; ! 599: ! 600: case CR: ! 601: x = margin; ! 602: break; ! 603: ! 604: case VT: ! 605: if ((y += charheight[tekfont]) >= TEKYMAX) ! 606: y = 0; ! 607: break; ! 608: ! 609: case HT: ! 610: case ' ': ! 611: default: ! 612: if ( characters++ == 0 ) ! 613: fprintf(fp_out, "%d %d (", cursor.x, cursor.y); ! 614: switch ( c ) { ! 615: case '(': ! 616: case ')': ! 617: case '\\': ! 618: putc('\\', fp_out); ! 619: ! 620: default: ! 621: putc(c, fp_out); ! 622: } /* End switch */ ! 623: x += charwidth[tekfont]; ! 624: move(x, y); ! 625: break; ! 626: } /* End switch */ ! 627: ! 628: if (x >= TEKXMAX) { ! 629: x = margin; ! 630: y -= charheight[tekfont]; ! 631: } /* End if */ ! 632: ! 633: if (y < 0) { ! 634: y = TEKYMAX - charheight[tekfont]; ! 635: x -= margin; ! 636: margin = (TEKXMAX/2) - margin; ! 637: if ((x += margin) > TEKXMAX) ! 638: x -= margin; ! 639: } /* End if */ ! 640: ! 641: if ( y != cursor.y || x != cursor.x ) ! 642: text(); ! 643: ! 644: move(x, y); ! 645: ! 646: } /* End of alpha */ ! 647: ! 648: /*****************************************************************************/ ! 649: ! 650: graph() ! 651: ! 652: { ! 653: ! 654: int c; /* next character */ ! 655: int b; /* for figuring out loy */ ! 656: int x, y; /* next point in the vector */ ! 657: static int hix, hiy; /* upper */ ! 658: static int lox, loy; /* and lower part of the address */ ! 659: static int extra; /* for extended addressing */ ! 660: ! 661: /* ! 662: * ! 663: * Handles things when we're in GRAPH, POINT, or SPECIALPOINT mode. ! 664: * ! 665: */ ! 666: ! 667: if ((c = nextchar()) < 040) { ! 668: control(c); ! 669: return; ! 670: } /* End if */ ! 671: ! 672: if ((c & 0140) == 040) { /* new hiy */ ! 673: hiy = c & 037; ! 674: do ! 675: if (((c = nextchar()) < 040) && ((c = control(c)) == OUTMODED)) ! 676: return; ! 677: while (c == 0); ! 678: } /* End if */ ! 679: ! 680: if ((c & 0140) == 0140) { /* new loy */ ! 681: b = c & 037; ! 682: do ! 683: if (((c = nextchar()) < 040) && ((c = control(c)) == OUTMODED)) ! 684: return; ! 685: while (c == 0); ! 686: if ((c & 0140) == 0140) { /* no, it was extra */ ! 687: extra = b; ! 688: loy = c & 037; ! 689: do ! 690: if (((c = nextchar()) < 040) && ((c = control(c)) == OUTMODED)) ! 691: return; ! 692: while (c == 0); ! 693: } else loy = b; ! 694: } /* End if */ ! 695: ! 696: if ((c & 0140) == 040) { /* new hix */ ! 697: hix = c & 037; ! 698: do ! 699: if (((c = nextchar()) < 040) && ((c = control(c)) == OUTMODED)) ! 700: return; ! 701: while (c == 0); ! 702: } /* End if */ ! 703: ! 704: lox = c & 037; /* this should be lox */ ! 705: if (extra & 020) ! 706: margin = TEKXMAX/2; ! 707: ! 708: x = (hix<<7) | (lox<<2) | (extra & 03); ! 709: y = (hiy<<7) | (loy<<2) | ((extra & 014)>>2); ! 710: ! 711: if ( points > 100 ) { /* don't put too much on the stack */ ! 712: draw(); ! 713: points = 1; ! 714: } /* End if */ ! 715: ! 716: if ( points++ ) ! 717: fprintf(fp_out, "%d %d\n", cursor.x - x, cursor.y - y); ! 718: ! 719: move(x, y); /* adjust the cursor */ ! 720: ! 721: } /* End of graph */ ! 722: ! 723: /*****************************************************************************/ ! 724: ! 725: point() ! 726: ! 727: { ! 728: ! 729: int c; /* next input character */ ! 730: ! 731: /* ! 732: * ! 733: * Special point mode permits gray scaling by varying the size of the stored ! 734: * point, which is controlled by an intensity character that preceeds each point ! 735: * address. ! 736: * ! 737: */ ! 738: ! 739: if ( dispmode == SPECIALPOINT ) { ! 740: if ( (c = nextchar()) < 040 || c > 0175 ) ! 741: return(control(c)); ! 742: ! 743: fprintf(fp_out, "%d %d i\n", intensity[c - ' '], c & 0100); ! 744: } /* End if */ ! 745: ! 746: graph(); ! 747: draw(); ! 748: ! 749: } /* End of point */ ! 750: ! 751: /*****************************************************************************/ ! 752: ! 753: incremental() ! 754: ! 755: { ! 756: ! 757: int c; /* for the next few characters */ ! 758: int x, y; /* cursor position when we're done */ ! 759: ! 760: /* ! 761: * ! 762: * Handles incremental plot mode. It's entered after the RS control code and is ! 763: * used to mark points relative to our current position. It's typically followed ! 764: * by one or two bytes that set the pen state and are used to increment the ! 765: * current position. ! 766: * ! 767: */ ! 768: ! 769: if ( (c = nextchar()) == OUTMODED ) ! 770: return; ! 771: ! 772: if ( (c < 040) && ((c = control(c)) <= 0) ) ! 773: return; ! 774: ! 775: x = cursor.x; /* where we are right now */ ! 776: y = cursor.y; ! 777: ! 778: if ( c & 060 ) ! 779: pen = ( c & 040 ) ? UP : DOWN; ! 780: ! 781: if ( c & 04 ) y++; ! 782: if ( c & 010 ) y--; ! 783: if ( c & 01 ) x++; ! 784: if ( c & 02 ) x--; ! 785: ! 786: move(x, y); ! 787: ! 788: if ( pen == DOWN ) { ! 789: points = 1; ! 790: draw(); ! 791: } /* End if */ ! 792: ! 793: } /* End of incremental */ ! 794: ! 795: /*****************************************************************************/ ! 796: ! 797: gin() ! 798: ! 799: { ! 800: ! 801: /* ! 802: * ! 803: * All we really have to do for GIN mode is make sure it's properly ended. ! 804: * ! 805: */ ! 806: ! 807: control(nextchar()); ! 808: ! 809: } /* End of gin */ ! 810: ! 811: /*****************************************************************************/ ! 812: ! 813: control(c) ! 814: ! 815: int c; /* check this control character */ ! 816: ! 817: { ! 818: ! 819: /* ! 820: * ! 821: * Checks character c and does special things, like mode changes, that depend ! 822: * not only on the character, but also on the current state. If the mode changed ! 823: * becuase of c, OUTMODED is returned to the caller. In all other cases the ! 824: * return value is c or 0, if c doesn't make sense in the current mode. ! 825: * ! 826: */ ! 827: ! 828: switch ( c ) { ! 829: case BEL: ! 830: return(0); ! 831: ! 832: case BS: ! 833: case HT: ! 834: case VT: ! 835: return(dispmode == ALPHA ? c : 0); ! 836: ! 837: case CR: ! 838: if ( dispmode != ALPHA ) { ! 839: setmode(ALPHA); ! 840: ungetc(c, fp_in); ! 841: return(OUTMODED); ! 842: } else return(c); ! 843: ! 844: case FS: ! 845: if ( (dispmode == ALPHA) || (dispmode == GRAPH) ) { ! 846: setmode(POINT); ! 847: return(OUTMODED); ! 848: } /* End if */ ! 849: return(0); ! 850: ! 851: case GS: ! 852: if ( (dispmode == ALPHA) || (dispmode == GRAPH) ) { ! 853: setmode(GRAPH); ! 854: return(OUTMODED); ! 855: } /* End if */ ! 856: return(0); ! 857: ! 858: case NL: ! 859: ungetc(CR, fp_in); ! 860: return(dispmode == ALPHA ? c : 0); ! 861: ! 862: case RS: ! 863: if ( dispmode != GIN ) { ! 864: setmode(INCREMENTAL); ! 865: return(OUTMODED); ! 866: } /* End if */ ! 867: return(0); ! 868: ! 869: case US: ! 870: if ( dispmode == ALPHA ) ! 871: return(0); ! 872: setmode(ALPHA); ! 873: return(OUTMODED); ! 874: ! 875: case ESC: ! 876: return(esc()); ! 877: ! 878: case OUTMODED: ! 879: return(c); ! 880: ! 881: default: ! 882: return(c < 040 ? 0 : c); ! 883: } /* End switch */ ! 884: ! 885: } /* End of control */ ! 886: ! 887: /*****************************************************************************/ ! 888: ! 889: esc() ! 890: ! 891: { ! 892: ! 893: int c; /* next input character */ ! 894: int ignore; /* skip it if nonzero */ ! 895: ! 896: /* ! 897: * ! 898: * Handles tektronix escape code. Called from control() whenever an ESC character ! 899: * is found in the input file. ! 900: * ! 901: */ ! 902: ! 903: do { ! 904: c = nextchar(); ! 905: ignore = 0; ! 906: switch ( c ) { ! 907: case CAN: ! 908: return(0); ! 909: ! 910: case CR: ! 911: ignore = 1; ! 912: break; ! 913: ! 914: case ENQ: ! 915: setmode(ALPHA); ! 916: return(OUTMODED); ! 917: ! 918: case ETB: ! 919: return(0); ! 920: ! 921: case FF: ! 922: formfeed(); ! 923: setmode(ALPHA); ! 924: return(OUTMODED); ! 925: ! 926: case FS: ! 927: if ( (dispmode == INCREMENTAL) || ( dispmode == GIN) ) ! 928: return(0); ! 929: setmode(SPECIALPOINT); ! 930: return(OUTMODED); ! 931: ! 932: case SI: ! 933: case SO: ! 934: return(0); ! 935: ! 936: case SUB: ! 937: setmode(GIN); ! 938: return(OUTMODED); ! 939: ! 940: case OUTMODED: ! 941: return(OUTMODED); ! 942: ! 943: case '8': ! 944: case '9': ! 945: case ':': ! 946: case ';': ! 947: setfont(c - '8'); ! 948: return(0); ! 949: ! 950: default: ! 951: if ( c == '?' && dispmode == GRAPH ) ! 952: return(DEL); ! 953: if ( (c<'`') || (c>'w') ) ! 954: break; ! 955: c -= '`'; ! 956: if ( (c & 010) != linetype ) ! 957: fprintf(fp_out, "%d w\n", (linetype = (c & 010))/010); ! 958: if ( ((c + 1) & 7) >= 6 ) ! 959: break; ! 960: if ( (c + 1) & 7 ) ! 961: if ( (c & 7) != linestyle ) { ! 962: linestyle = c & 7; ! 963: setmode(dispmode); ! 964: fprintf(fp_out, "%s l\n", styles[linestyle]); ! 965: } /* End if */ ! 966: return(0); ! 967: } /* End switch */ ! 968: ! 969: } while (ignore); ! 970: ! 971: return(0); ! 972: ! 973: } /* End of esc */ ! 974: ! 975: /*****************************************************************************/ ! 976: ! 977: move(x, y) ! 978: ! 979: int x, y; /* move the cursor here */ ! 980: ! 981: { ! 982: ! 983: /* ! 984: * ! 985: * Moves the cursor to the point (x, y). ! 986: * ! 987: */ ! 988: ! 989: cursor.x = x; ! 990: cursor.y = y; ! 991: ! 992: } /* End of move */ ! 993: ! 994: /*****************************************************************************/ ! 995: ! 996: setmode(mode) ! 997: ! 998: int mode; /* this should be the new mode */ ! 999: ! 1000: { ! 1001: ! 1002: /* ! 1003: * ! 1004: * Makes sure the current mode is properly ended and then sets dispmode to mode. ! 1005: * ! 1006: */ ! 1007: ! 1008: switch ( dispmode ) { ! 1009: case ALPHA: ! 1010: text(); ! 1011: break; ! 1012: ! 1013: case GRAPH: ! 1014: draw(); ! 1015: break; ! 1016: ! 1017: case INCREMENTAL: ! 1018: pen = UP; ! 1019: break; ! 1020: } /* End switch */ ! 1021: ! 1022: dispmode = mode; ! 1023: ! 1024: } /* End of setmode */ ! 1025: ! 1026: /*****************************************************************************/ ! 1027: ! 1028: home() ! 1029: ! 1030: { ! 1031: ! 1032: /* ! 1033: * ! 1034: * Makes sure the cursor is positioned at the upper left corner of the page. ! 1035: * ! 1036: */ ! 1037: ! 1038: margin = 0; ! 1039: move(0, TEKYMAX); ! 1040: ! 1041: } /* End of home */ ! 1042: ! 1043: /*****************************************************************************/ ! 1044: ! 1045: setfont(newfont) ! 1046: ! 1047: int newfont; /* use this font next */ ! 1048: ! 1049: { ! 1050: ! 1051: /* ! 1052: * ! 1053: * Generates the call to the procedure that's responsible for changing the ! 1054: * tektronix font (really just the size). ! 1055: * ! 1056: */ ! 1057: ! 1058: if ( newfont != tekfont ) { ! 1059: setmode(dispmode); ! 1060: fprintf(fp_out, "%d f\n", charwidth[newfont]); ! 1061: } /* End if */ ! 1062: ! 1063: tekfont = newfont; ! 1064: ! 1065: } /* End of setfont */ ! 1066: ! 1067: /*****************************************************************************/ ! 1068: ! 1069: text() ! 1070: ! 1071: { ! 1072: ! 1073: /* ! 1074: * ! 1075: * Makes sure any text we've put on the stack is printed. ! 1076: * ! 1077: */ ! 1078: ! 1079: if ( dispmode == ALPHA && characters > 0 ) ! 1080: fprintf(fp_out, ") t\n"); ! 1081: ! 1082: characters = 0; ! 1083: ! 1084: } /* End of text */ ! 1085: ! 1086: /*****************************************************************************/ ! 1087: ! 1088: draw() ! 1089: ! 1090: { ! 1091: ! 1092: /* ! 1093: * ! 1094: * Called whenever we need to draw a vector or plot a point. Nothing will be ! 1095: * done if points is 0 or if it's 1 and we're in GRAPH mode. ! 1096: * ! 1097: */ ! 1098: ! 1099: if ( points > 1 ) /* it's a vector */ ! 1100: fprintf(fp_out, "%d %d v\n", cursor.x, cursor.y); ! 1101: else if ( points == 1 && dispmode != GRAPH ) ! 1102: fprintf(fp_out, "%d %d p\n", cursor.x, cursor.y); ! 1103: ! 1104: points = 0; ! 1105: ! 1106: } /* End of draw */ ! 1107: ! 1108: /*****************************************************************************/ ! 1109: ! 1110: formfeed() ! 1111: ! 1112: { ! 1113: ! 1114: /* ! 1115: * ! 1116: * Usually called when we've finished the last page and want to get ready for the ! 1117: * next one. Also used at the beginning and end of each input file, so we have to ! 1118: * be careful about exactly what's done. ! 1119: * ! 1120: */ ! 1121: ! 1122: setmode(dispmode); /* end any outstanding text or graphics */ ! 1123: ! 1124: if ( fp_out == stdout ) /* count the last page */ ! 1125: printed++; ! 1126: ! 1127: fprintf(fp_out, "cleartomark\n"); ! 1128: fprintf(fp_out, "showpage\n"); ! 1129: fprintf(fp_out, "saveobj restore\n"); ! 1130: fprintf(fp_out, "%s %d %d\n", ENDPAGE, page, printed); ! 1131: ! 1132: if ( ungetc(getc(fp_in), fp_in) == EOF ) ! 1133: redirect(-1); ! 1134: else redirect(++page); ! 1135: ! 1136: fprintf(fp_out, "%s %d %d\n", PAGE, page, printed+1); ! 1137: fprintf(fp_out, "/saveobj save def\n"); ! 1138: fprintf(fp_out, "mark\n"); ! 1139: writerequest(printed+1, fp_out); ! 1140: fprintf(fp_out, "%d pagesetup\n", printed+1); ! 1141: fprintf(fp_out, "%d f\n", charwidth[tekfont]); ! 1142: fprintf(fp_out, "%s l\n", styles[linestyle]); ! 1143: ! 1144: home(); ! 1145: ! 1146: } /* End of formfeed */ ! 1147: ! 1148: /*****************************************************************************/ ! 1149: ! 1150: nextchar() ! 1151: ! 1152: { ! 1153: ! 1154: int ch; /* next input character */ ! 1155: ! 1156: /* ! 1157: * ! 1158: * Reads the next character from the current input file and returns it to the ! 1159: * caller. When we're finished with the file dispmode is set to EXIT and OUTMODED ! 1160: * is returned to the caller. ! 1161: * ! 1162: */ ! 1163: ! 1164: if ( (ch = getc(fp_in)) == EOF ) { ! 1165: setmode(EXIT); ! 1166: ch = OUTMODED; ! 1167: } /* End if */ ! 1168: ! 1169: return(ch); ! 1170: ! 1171: } /* End of nextchar */ ! 1172: ! 1173: /*****************************************************************************/ ! 1174: ! 1175: redirect(pg) ! 1176: ! 1177: int pg; /* next page we're printing */ ! 1178: ! 1179: { ! 1180: ! 1181: static FILE *fp_null = NULL; /* if output is turned off */ ! 1182: ! 1183: /* ! 1184: * ! 1185: * If we're not supposed to print page pg, fp_out will be directed to /dev/null, ! 1186: * otherwise output goes to stdout. ! 1187: * ! 1188: */ ! 1189: ! 1190: if ( pg >= 0 && in_olist(pg) == ON ) ! 1191: fp_out = stdout; ! 1192: else if ( (fp_out = fp_null) == NULL ) ! 1193: fp_out = fp_null = fopen("/dev/null", "w"); ! 1194: ! 1195: } /* End of redirect */ ! 1196: ! 1197: /*****************************************************************************/ ! 1198:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.