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