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