|
|
1.1 ! root 1: /* ! 2: * ! 3: * postbgi - BGI (Basic Graphical Instructions) to PostScript translator. ! 4: * ! 5: * A simple program that translates BGI files into PostScript. Probably only ! 6: * useful in Computer Centers that support STARE or PRISM plotters. Most of the ! 7: * code was borrowed from the corresponding program that was written for printers ! 8: * that understand Impress. ! 9: * ! 10: * Extending the original program to handle PRISM jobs was not trivial. Graphics ! 11: * packages that support PRISM occasionally use BGI commands that I ignored in the ! 12: * STARE implementation. Subroutines, color requests, patterns (for filling), and ! 13: * filled trapeziods were the most important omissions. All are now implemented, ! 14: * and at present only repeats, filled slices, and raster rectangles are missing. ! 15: * ! 16: * Pattern filling results were not always predictable or even good, unless the ! 17: * halftone screen definitions were changed and scaling was adjusted so one pixel ! 18: * in user space mapped into an integral number of device space pixels. Doing that ! 19: * makes the resulting PostScript output device dependent, but was often necessary. ! 20: * I've added two booleans to the PostScript prologue (fixscreen and scaletodevice) ! 21: * that control what's done. By default both are false (check postbgi.ps) but can ! 22: * be set to true on the command line using the -P option or by hand by changing ! 23: * the definitions in the prologue. A command line that would set fixscreen and ! 24: * scaletodevice true would look like, ! 25: * ! 26: * postbgi -P"/fixscreen true" -P"/scaletodevice true" file >file.ps ! 27: * ! 28: * Several other approaches are available if you want to have your spooler handle ! 29: * STARE and PRISM jobs differently. A boolean called prism is defined in the ! 30: * prologue (postbgi.ps) and if it's set to true PostScript procedure setup will ! 31: * set fixscreen and scaletodevice to true before anything important is done. That ! 32: * means the following command line, ! 33: * ! 34: * postbgi -P"/prism true" file >file.ps ! 35: * ! 36: * accomplishes the same things as the last example. Two different prologue files, ! 37: * one for STARE jobs and the other for PRISM, could be used and the spooler could ! 38: * point postbgi to the appropriate one using the -L option. In that case the only ! 39: * important difference in the two prologues would be the definition of prism. The ! 40: * prologue used for PRISM jobs would have prism set to true, while the STARE ! 41: * prologue would have it set to false. ! 42: * ! 43: * Also included is code that ties lines to device space coordinates. What you get ! 44: * is a consistent line thickness, but placement of lines won't be exact. It's a ! 45: * trade-off that should be right for most jobs. Everything is implemented in the ! 46: * prologue (postbgi.ps) and nothing will be done if the linewidth is zero or if ! 47: * the boolean fixlinewidth (again in postbgi.ps) is false. Once again the -P ! 48: * option can be used to set fixlinewidth to whatever you choose. ! 49: * ! 50: * BGI supports color mixing but PostScript doesn't. BGI files that expect to mix ! 51: * colors won't print properly. PostScript's fill operator overlays whatever has ! 52: * already been put down. Implementing color mixing would have been a terribly ! 53: * difficult job - not worth the effort! ! 54: * ! 55: * The PostScript prologue is copied from *prologue before any of the input files ! 56: * are translated. The program expects that the following PostScript procedures ! 57: * are defined in that file: ! 58: * ! 59: * setup ! 60: * ! 61: * mark ... setup - ! 62: * ! 63: * Handles special initialization stuff that depends on how the program ! 64: * was called. Expects to find a mark followed by key/value pairs on the ! 65: * stack. The def operator is applied to each pair up to the mark, then ! 66: * the default state is set up. ! 67: * ! 68: * pagesetup ! 69: * ! 70: * page pagesetup - ! 71: * ! 72: * Does whatever is needed to set things up for the next page. Expects ! 73: * to find the current page number on the stack. ! 74: * ! 75: * v ! 76: * ! 77: * dx1 dy1 ... dxn dyn x y v - ! 78: * ! 79: * Draws the vector described by the numbers on the stack. The top two ! 80: * numbers are the coordinates of the starting point. The rest of the ! 81: * numbers are relative displacements from the preceeding point. ! 82: * ! 83: * pp ! 84: * ! 85: * x1 y1 ... xn yn string pp - ! 86: * ! 87: * Prints string, which is always a single character, at the points ! 88: * represented by the rest of the numbers on the stack. ! 89: * ! 90: * R ! 91: * ! 92: * n deltax deltay x y R - ! 93: * ! 94: * Creates a rectangular path with its lower left corner at (x, y) and ! 95: * sides of length deltax and deltay. The resulting path is stroked if ! 96: * n is 0 and filled otherwise. ! 97: * ! 98: * T ! 99: * ! 100: * dx3 dy3 dx2 dy2 dx1 dy1 x y T - ! 101: * ! 102: * Fills a trapezoid starting at (x, y) and having relative displacements ! 103: * given by the (dx, dy) pairs. ! 104: * ! 105: * t ! 106: * ! 107: * angle x y string t - ! 108: * ! 109: * Prints string starting at (x, y) using an orientation of angle degrees. ! 110: * The PostScript procedure can handle any angle, but BGI files will only ! 111: * request 0 or 90 degrees. Text printed at any other orientation will be ! 112: * vector generated. ! 113: * ! 114: * p ! 115: * ! 116: * x y p - ! 117: * ! 118: * Called to mark the point (x, y). It fills a small circle, that right ! 119: * now has a constant radius. This stuff could probably be much more ! 120: * efficient? ! 121: * ! 122: * l ! 123: * ! 124: * array l - ! 125: * ! 126: * Sets the line drawing mode according to the description given in ! 127: * array. The arrays that describe the different line styles are declared ! 128: * in STYLES (file posttek.h), although it would be better to have them ! 129: * defined in the prologue. ! 130: * ! 131: * c ! 132: * ! 133: * red green blue c - ! 134: * ! 135: * Sets the current PostScript RGB color using setrgbcolor. Also used for ! 136: * selecting appropriate patterns as colors. ! 137: * ! 138: * f ! 139: * ! 140: * bgisize f - ! 141: * ! 142: * Changes the size of the font that's used to print text. bgisize is a ! 143: * grid separation in a 5 by 7 array in which characters are assumed to ! 144: * be built. ! 145: * ! 146: * done ! 147: * ! 148: * done ! 149: * ! 150: * Makes sure the last page is printed. Only needed when we're printing ! 151: * more than one page on each sheet of paper. ! 152: * ! 153: * The default line width is zero, which forces lines to be one pixel wide. That ! 154: * works well for 'write to black' engines but won't be right for 'write to white' ! 155: * engines. The line width can be changed using the -w option, or you can change ! 156: * the initialization of linewidth in the prologue. Code in the prologue supports ! 157: * the generation of uniform width lines when linewidth is non-zero and boolean ! 158: * fixlinewidth is true. ! 159: * ! 160: * Many default values, like the magnification and orientation, are defined in ! 161: * the prologue, which is where they belong. If they're changed (by options), an ! 162: * appropriate definition is made after the prologue is added to the output file. ! 163: * The -P option passes arbitrary PostScript through to the output file. Among ! 164: * other things it can be used to set (or change) values that can't be accessed by ! 165: * other options. ! 166: * ! 167: */ ! 168: ! 169: #include <stdio.h> ! 170: #include <fcntl.h> ! 171: #include <signal.h> ! 172: #include <math.h> ! 173: #include <ctype.h> ! 174: ! 175: #include "comments.h" /* PostScript file structuring comments */ ! 176: #include "gen.h" /* general purpose definitions */ ! 177: #include "path.h" /* for the prologue */ ! 178: #include "ext.h" /* external variable declarations */ ! 179: #include "postbgi.h" /* a few definitions just used here */ ! 180: ! 181: char *optnames = "a:c:f:m:n:o:p:w:x:y:A:C:E:J:L:P:R:DI"; ! 182: ! 183: char *prologue = POSTBGI; /* default PostScript prologue */ ! 184: char *formfile = FORMFILE; /* stuff for multiple pages per sheet */ ! 185: ! 186: int formsperpage = 1; /* page images on each piece of paper */ ! 187: int copies = 1; /* and this many copies of each sheet */ ! 188: ! 189: char *styles[] = STYLES; /* descriptions of line styles */ ! 190: ! 191: int hpos = 0; /* current horizontal */ ! 192: int vpos = 0; /* and vertical position */ ! 193: ! 194: int bgisize = BGISIZE; /* just the character grid spacing */ ! 195: int linespace; /* distance between lines of text */ ! 196: ! 197: int bgimode; /* character or graph mode */ ! 198: ! 199: int in_subr = FALSE; /* currently defining a subroutine */ ! 200: int in_global = FALSE; /* to save space with subroutine defs */ ! 201: int subr_id = 0; /* defining this subroutine */ ! 202: int shpos = 0; /* starting horizontal */ ! 203: int svpos = 0; /* and vertical positions - subroutines */ ! 204: Disp displacement[64]; /* dx and dy after a subroutine call */ ! 205: ! 206: Fontmap fontmap[] = FONTMAP; /* for translating font names */ ! 207: char *fontname = "Courier"; /* use this PostScript font */ ! 208: ! 209: int page = 0; /* page we're working on */ ! 210: int printed = 0; /* printed this many pages */ ! 211: ! 212: FILE *fp_in = stdin; /* read from this file */ ! 213: FILE *fp_out = NULL; /* and write stuff here */ ! 214: FILE *fp_acct = NULL; /* for accounting data */ ! 215: ! 216: /*****************************************************************************/ ! 217: ! 218: main(agc, agv) ! 219: ! 220: int agc; ! 221: char *agv[]; ! 222: ! 223: { ! 224: ! 225: /* ! 226: * ! 227: * A program that converts BGI (Basic Graphical Instructions) files generated by ! 228: * packages like GRAFPAC and DISSPLA into PostScript. It does an adequate job but ! 229: * is far from perfect. A few things still haven't been implemented (eg. repeats ! 230: * and raster rectangles), but what's here should be good enough for most of our ! 231: * STARE and PRISM jobs. Color mixing (in PRISM jobs) won't work on PostScript ! 232: * printers, and there's no chance I'll implement it! ! 233: * ! 234: */ ! 235: ! 236: argc = agc; /* global so everyone can use them */ ! 237: argv = agv; ! 238: ! 239: prog_name = argv[0]; /* just for error messages */ ! 240: ! 241: init_signals(); /* set up interrupt handling */ ! 242: header(); /* PostScript header comments */ ! 243: options(); /* command line options */ ! 244: setup(); /* for PostScript */ ! 245: arguments(); /* followed by each input file */ ! 246: done(); /* print the last page etc. */ ! 247: account(); /* job accounting data */ ! 248: ! 249: exit(x_stat); /* everything probably went OK */ ! 250: ! 251: } /* End of main */ ! 252: ! 253: /*****************************************************************************/ ! 254: ! 255: init_signals() ! 256: ! 257: { ! 258: ! 259: /* ! 260: * ! 261: * Make sure we handle interrupts. ! 262: * ! 263: */ ! 264: ! 265: if ( signal(SIGINT, interrupt) == SIG_IGN ) { ! 266: signal(SIGINT, SIG_IGN); ! 267: signal(SIGQUIT, SIG_IGN); ! 268: signal(SIGHUP, SIG_IGN); ! 269: } else { ! 270: signal(SIGHUP, interrupt); ! 271: signal(SIGQUIT, interrupt); ! 272: } /* End else */ ! 273: ! 274: signal(SIGTERM, interrupt); ! 275: ! 276: } /* End of init_signals */ ! 277: ! 278: /*****************************************************************************/ ! 279: ! 280: header() ! 281: ! 282: { ! 283: ! 284: int ch; /* return value from getopt() */ ! 285: int old_optind = optind; /* for restoring optind - should be 1 */ ! 286: ! 287: /* ! 288: * ! 289: * Scans the option list looking for things, like the prologue file, that we need ! 290: * right away but could be changed from the default. Doing things this way is an ! 291: * attempt to conform to Adobe's latest file structuring conventions. In particular ! 292: * they now say there should be nothing executed in the prologue, and they have ! 293: * added two new comments that delimit global initialization calls. Once we know ! 294: * where things really are we write out the job header, follow it by the prologue, ! 295: * and then add the ENDPROLOG and BEGINSETUP comments. ! 296: * ! 297: */ ! 298: ! 299: while ( (ch = getopt(argc, argv, optnames)) != EOF ) ! 300: if ( ch == 'L' ) ! 301: prologue = optarg; ! 302: else if ( ch == '?' ) ! 303: error(FATAL, ""); ! 304: ! 305: optind = old_optind; /* get ready for option scanning */ ! 306: ! 307: fprintf(stdout, "%s", CONFORMING); ! 308: fprintf(stdout, "%s %s\n", VERSION, PROGRAMVERSION); ! 309: fprintf(stdout, "%s %s\n", DOCUMENTFONTS, ATEND); ! 310: fprintf(stdout, "%s %s\n", PAGES, ATEND); ! 311: fprintf(stdout, "%s", ENDCOMMENTS); ! 312: ! 313: if ( cat(prologue) == FALSE ) ! 314: error(FATAL, "can't read %s", prologue); ! 315: ! 316: fprintf(stdout, "%s", ENDPROLOG); ! 317: fprintf(stdout, "%s", BEGINSETUP); ! 318: fprintf(stdout, "mark\n"); ! 319: ! 320: } /* End of header */ ! 321: ! 322: /*****************************************************************************/ ! 323: ! 324: options() ! 325: ! 326: { ! 327: ! 328: int ch; /* option name - from getopt() */ ! 329: ! 330: /* ! 331: * ! 332: * Reads and processes the command line options. ! 333: * ! 334: */ ! 335: ! 336: while ( (ch = getopt(argc, argv, optnames)) != EOF ) { ! 337: switch ( ch ) { ! 338: case 'a': /* aspect ratio */ ! 339: fprintf(stdout, "/aspectratio %s def\n", optarg); ! 340: break; ! 341: ! 342: case 'c': /* copies */ ! 343: copies = atoi(optarg); ! 344: fprintf(stdout, "/#copies %s def\n", optarg); ! 345: break; ! 346: ! 347: case 'f': /* new font */ ! 348: fontname = get_font(optarg); ! 349: fprintf(stdout, "/font /%s def\n", fontname); ! 350: break; ! 351: ! 352: case 'm': /* magnification */ ! 353: fprintf(stdout, "/magnification %s def\n", optarg); ! 354: break; ! 355: ! 356: case 'n': /* forms per page */ ! 357: formsperpage = atoi(optarg); ! 358: fprintf(stdout, "%s %s\n", FORMSPERPAGE, optarg); ! 359: fprintf(stdout, "/formsperpage %s def\n", optarg); ! 360: break; ! 361: ! 362: case 'o': /* output page list */ ! 363: out_list(optarg); ! 364: break; ! 365: ! 366: case 'p': /* landscape or portrait mode */ ! 367: if ( *optarg == 'l' ) ! 368: fprintf(stdout, "/landscape true def\n"); ! 369: else fprintf(stdout, "/landscape false def\n"); ! 370: break; ! 371: ! 372: case 'w': /* line width */ ! 373: fprintf(stdout, "/linewidth %s def\n", optarg); ! 374: break; ! 375: ! 376: case 'x': /* shift horizontally */ ! 377: fprintf(stdout, "/xoffset %s def\n", optarg); ! 378: break; ! 379: ! 380: case 'y': /* and vertically on the page */ ! 381: fprintf(stdout, "/yoffset %s def\n", optarg); ! 382: break; ! 383: ! 384: case 'A': /* force job accounting */ ! 385: case 'J': ! 386: if ( (fp_acct = fopen(optarg, "a")) == NULL ) ! 387: error(FATAL, "can't open accounting file %s", optarg); ! 388: break; ! 389: ! 390: case 'C': /* copy file straight to output */ ! 391: if ( cat(optarg) == FALSE ) ! 392: error(FATAL, "can't read %s", optarg); ! 393: break; ! 394: ! 395: case 'E': /* text font encoding */ ! 396: fontencoding = optarg; ! 397: break; ! 398: ! 399: case 'L': /* Postscript prologue file */ ! 400: prologue = optarg; ! 401: break; ! 402: ! 403: case 'P': /* PostScript pass through */ ! 404: fprintf(stdout, "%s\n", optarg); ! 405: break; ! 406: ! 407: case 'R': /* special global or page level request */ ! 408: saverequest(optarg); ! 409: break; ! 410: ! 411: case 'D': /* debug flag */ ! 412: debug = ON; ! 413: break; ! 414: ! 415: case 'I': /* ignore FATAL errors */ ! 416: ignore = ON; ! 417: break; ! 418: ! 419: case '?': /* don't know the option */ ! 420: error(FATAL, ""); ! 421: break; ! 422: ! 423: default: /* don't know what to do for ch */ ! 424: error(FATAL, "missing case for option %c", ch); ! 425: break; ! 426: } /* End switch */ ! 427: } /* End while */ ! 428: ! 429: argc -= optind; /* get ready for non-option args */ ! 430: argv += optind; ! 431: ! 432: } /* End of options */ ! 433: ! 434: /*****************************************************************************/ ! 435: ! 436: char *get_font(name) ! 437: ! 438: char *name; /* name the user asked for */ ! 439: ! 440: { ! 441: ! 442: int i; /* for looking through fontmap[] */ ! 443: ! 444: /* ! 445: * ! 446: * Called from options() to map a user's font name into a legal PostScript name. ! 447: * If the lookup fails *name is returned to the caller. That should let you choose ! 448: * any PostScript font. ! 449: * ! 450: */ ! 451: ! 452: for ( i = 0; fontmap[i].name != NULL; i++ ) ! 453: if ( strcmp(name, fontmap[i].name) == 0 ) ! 454: return(fontmap[i].val); ! 455: ! 456: return(name); ! 457: ! 458: } /* End of get_font */ ! 459: ! 460: /*****************************************************************************/ ! 461: ! 462: setup() ! 463: ! 464: { ! 465: ! 466: /* ! 467: * ! 468: * Handles things that must be done after the options are read but before the ! 469: * input files are processed. ! 470: * ! 471: */ ! 472: ! 473: writerequest(0, stdout); /* global requests eg. manual feed */ ! 474: setencoding(fontencoding); ! 475: fprintf(stdout, "setup\n"); ! 476: ! 477: if ( formsperpage > 1 ) { ! 478: if ( cat(formfile) == FALSE ) ! 479: error(FATAL, "can't read %s", formfile); ! 480: fprintf(stdout, "%d setupforms\n", formsperpage); ! 481: } /* End if */ ! 482: ! 483: fprintf(stdout, "%s", ENDSETUP); ! 484: ! 485: } /* End of setup */ ! 486: ! 487: /*****************************************************************************/ ! 488: ! 489: arguments() ! 490: ! 491: { ! 492: ! 493: /* ! 494: * ! 495: * Makes sure all the non-option command line options are processed. If we get ! 496: * here and there aren't any arguments left, or if '-' is one of the input files ! 497: * we'll process stdin. ! 498: * ! 499: */ ! 500: ! 501: if ( argc < 1 ) ! 502: conv(); ! 503: else ! 504: while ( argc > 0 ) { ! 505: if ( strcmp(*argv, "-") == 0 ) ! 506: fp_in = stdin; ! 507: else if ( (fp_in = fopen(*argv, "r")) == NULL ) ! 508: error(FATAL, "can't open %s", *argv); ! 509: conv(); ! 510: if ( fp_in != stdin ) ! 511: fclose(fp_in); ! 512: argc--; ! 513: argv++; ! 514: } /* End while */ ! 515: ! 516: } /* End of arguments */ ! 517: ! 518: /*****************************************************************************/ ! 519: ! 520: done() ! 521: ! 522: { ! 523: ! 524: /* ! 525: * ! 526: * Finished with the last input file, so mark the end of the pages, make sure the ! 527: * last page is printed, and restore the initial environment. ! 528: * ! 529: */ ! 530: ! 531: fprintf(stdout, "%s", TRAILER); ! 532: fprintf(stdout, "done\n"); ! 533: fprintf(stdout, "%s %s\n", DOCUMENTFONTS, fontname); ! 534: fprintf(stdout, "%s %d\n", PAGES, printed); ! 535: ! 536: } /* End of done */ ! 537: ! 538: /*****************************************************************************/ ! 539: ! 540: account() ! 541: ! 542: { ! 543: ! 544: /* ! 545: * ! 546: * Writes an accounting record to *fp_acct, provided it's not NULL. ! 547: * ! 548: */ ! 549: ! 550: if ( fp_acct != NULL ) ! 551: fprintf(fp_acct, " print %d\n copies %d\n", printed, copies); ! 552: ! 553: } /* End of account */ ! 554: ! 555: /*****************************************************************************/ ! 556: ! 557: conv() ! 558: ! 559: { ! 560: ! 561: int ch; /* next input character */ ! 562: ! 563: /* ! 564: * ! 565: * Controls the conversion of BGI files into PostScript. Not everything has been ! 566: * implemented, but what's been done should be good enough for our purposes. ! 567: * ! 568: */ ! 569: ! 570: redirect(-1); /* get ready for the first page */ ! 571: bgimode = 0; ! 572: formfeed(); ! 573: ! 574: while ( (ch = get_char()) != EOF ) { ! 575: switch ( ch ) { ! 576: case BRCHAR: /* rotated character mode */ ! 577: bgimode = ch; ! 578: text(90); ! 579: break; ! 580: ! 581: case BCHAR: /* graphical character mode */ ! 582: bgimode = ch; ! 583: text(0); ! 584: break; ! 585: ! 586: case BGRAPH: /* graphical master mode */ ! 587: bgimode = ch; ! 588: break; ! 589: ! 590: case BSUB: /* subroutine definition */ ! 591: subr_def(); ! 592: break; ! 593: ! 594: case BRET: /* end of subroutine */ ! 595: subr_end(); ! 596: break; ! 597: ! 598: case BCALL: /* subroutine call */ ! 599: subr_call(); ! 600: break; ! 601: ! 602: case BEND: /* end display - page */ ! 603: formfeed(); ! 604: break; ! 605: ! 606: case BERASE: /* erase - shouldn't be used */ ! 607: error(FATAL, "BGI erase opcode obsolete"); ! 608: break; ! 609: ! 610: case BREP: /* repeat */ ! 611: error(FATAL, "Repeat not implemented"); ! 612: repeat(); ! 613: break; ! 614: ! 615: case BSETX: /* new x coordinate */ ! 616: hgoto(get_int(0)); ! 617: break; ! 618: ! 619: case BSETY: /* new y coordinate */ ! 620: vgoto(get_int(0)); ! 621: break; ! 622: ! 623: case BSETXY: /* new x and y coordinates */ ! 624: hgoto(get_int(0)); ! 625: vgoto(get_int(0)); ! 626: break; ! 627: ! 628: case BINTEN: /* mark the current point */ ! 629: fprintf(fp_out, "%d %d p\n", hpos, vpos); ! 630: break; ! 631: ! 632: case BVISX: /* visible x */ ! 633: vector(X_COORD, VISIBLE); ! 634: break; ! 635: ! 636: case BINVISX: /* invisible x */ ! 637: vector(X_COORD, INVISIBLE); ! 638: break; ! 639: ! 640: case BVISY: /* visible y */ ! 641: vector(Y_COORD, VISIBLE); ! 642: break; ! 643: ! 644: case BINVISY: /* invisible y */ ! 645: vector(Y_COORD, INVISIBLE); ! 646: break; ! 647: ! 648: case BVEC: /* arbitrary vector */ ! 649: vector(LONGVECTOR, VISIBLE); ! 650: break; ! 651: ! 652: case BSVEC: /* short vector */ ! 653: vector(SHORTVECTOR, VISIBLE); ! 654: break; ! 655: ! 656: case BRECT: /* draw rectangle */ ! 657: rectangle(OUTLINE); ! 658: break; ! 659: ! 660: case BPOINT1: /* point plot 1 */ ! 661: case BPOINT: /* point plot 2 */ ! 662: point_plot(ch, get_char()); ! 663: break; ! 664: ! 665: case BLINE: /* line plot */ ! 666: line_plot(); ! 667: break; ! 668: ! 669: case BLTY: /* line type */ ! 670: fprintf(fp_out, "%s l\n", styles[get_data()]); ! 671: break; ! 672: ! 673: case BARC: /* circular arc */ ! 674: arc(OUTLINE); ! 675: break; ! 676: ! 677: case BFARC: /* filled circle */ ! 678: arc(FILL); ! 679: break; ! 680: ! 681: case BFRECT: /* filled rectangle */ ! 682: rectangle(FILL); ! 683: break; ! 684: ! 685: case BRASRECT: /* raster rectangle */ ! 686: error(FATAL, "Raster Rectangle not implemented"); ! 687: break; ! 688: ! 689: case BCOL: /* select color */ ! 690: set_color(get_data()); ! 691: break; ! 692: ! 693: case BFTRAPH: /* filled trapezoid */ ! 694: trapezoid(); ! 695: break; ! 696: ! 697: case BPAT: /* pattern for area filling */ ! 698: pattern(); ! 699: break; ! 700: ! 701: case BCSZ: /* change BGI character 'size' */ ! 702: setsize(get_data()); ! 703: break; ! 704: ! 705: case BNOISE: /* from bad file format */ ! 706: break; ! 707: ! 708: default: /* don't recognize the code */ ! 709: error(FATAL, "bad BGI command %d (0%o)", ch, ch); ! 710: break; ! 711: } /* End switch */ ! 712: ! 713: if ( debug == ON ) ! 714: fprintf(stderr, "\n"); ! 715: } /* End while */ ! 716: ! 717: formfeed(); /* in case BEND was missing */ ! 718: ! 719: } /* End of conv */ ! 720: ! 721: /*****************************************************************************/ ! 722: ! 723: hgoto(n) ! 724: ! 725: int n; /* new horizontal position */ ! 726: ! 727: { ! 728: ! 729: /* ! 730: * ! 731: * Sets the current BGI horizontal position to n. ! 732: * ! 733: */ ! 734: ! 735: hpos = n; ! 736: ! 737: } /* End of hgoto */ ! 738: ! 739: /*****************************************************************************/ ! 740: ! 741: vgoto(n) ! 742: ! 743: int n; /* move to this vertical position */ ! 744: ! 745: { ! 746: ! 747: /* ! 748: * ! 749: * Sets the absolute vertical position to n. ! 750: * ! 751: */ ! 752: ! 753: vpos = n; ! 754: ! 755: } /* End of vgoto */ ! 756: ! 757: /*****************************************************************************/ ! 758: ! 759: setsize(n) ! 760: ! 761: int n; /* BGI size - just a grid separation */ ! 762: ! 763: { ! 764: ! 765: /* ! 766: * ! 767: * Called when we're supposed to change the BGI character size to n. The BGI ! 768: * size is the grid separation in a 5 by 7 array in which characters are assumed ! 769: * to be built. ! 770: * ! 771: */ ! 772: ! 773: bgisize = n; ! 774: linespace = LINESPACE(bgisize); ! 775: ! 776: fprintf(fp_out, "%d f\n", bgisize); ! 777: ! 778: if ( debug == ON ) ! 779: fprintf(stderr, "BGI size = %d\n", n); ! 780: ! 781: } /* End of setsize */ ! 782: ! 783: /*****************************************************************************/ ! 784: ! 785: repeat() ! 786: ! 787: { ! 788: ! 789: int count; /* repeat this many times */ ! 790: int ch; /* next input character */ ! 791: ! 792: /* ! 793: * ! 794: * Haven't implemented repeats, although it wouldn't be difficult. Apparently it's ! 795: * not used by any graphics packages that generate BGI. ! 796: * ! 797: */ ! 798: ! 799: count = get_int(); /* get the repeat count */ ! 800: ! 801: while ( (ch = get_char()) != EOF && ch != BENDR ) ; ! 802: ! 803: } /* End of repeat */ ! 804: ! 805: /*****************************************************************************/ ! 806: ! 807: text(angle) ! 808: ! 809: int angle; /* either 0 or 90 degrees */ ! 810: ! 811: { ! 812: ! 813: int ch; /* next character from file *fp_in */ ! 814: ! 815: /* ! 816: * ! 817: * Called from conv() after we've entered one of the graphical character modes. ! 818: * Characters are read from the input file and printed until the next mode change ! 819: * opcode is found (or until EOF). angle will be 90 for rotated character mode ! 820: * and 0 otherwise. ! 821: * ! 822: * ! 823: */ ! 824: ! 825: fprintf(fp_out, "%d %d %d(", angle, hpos, vpos); ! 826: ! 827: while ( (ch = get_char()) != EOF ) { ! 828: if ( ch == BGRAPH || ch == BCHAR || ch == BRCHAR ) { ! 829: ungetc(ch, fp_in); ! 830: position--; ! 831: break; ! 832: } /* End if */ ! 833: ! 834: switch ( ch ) { ! 835: case '\012': ! 836: vgoto(vpos - linespace); ! 837: ! 838: case '\015': ! 839: hgoto(0); ! 840: fprintf(fp_out, ")t\n%d %d %d(", angle, hpos, vpos); ! 841: break; ! 842: ! 843: case '(': ! 844: case ')': ! 845: case '\\': ! 846: putc('\\', fp_out); ! 847: ! 848: default: ! 849: if ( isascii(ch) && isprint(ch) ) ! 850: putc(ch, fp_out); ! 851: else fprintf(fp_out, "\\%.3o", ch & 0377); ! 852: break; ! 853: } /* End switch */ ! 854: } /* End while */ ! 855: ! 856: fprintf(fp_out, ") t\n"); ! 857: ! 858: } /* End of text */ ! 859: ! 860: /*****************************************************************************/ ! 861: ! 862: formfeed() ! 863: ! 864: { ! 865: ! 866: int ch; /* repeat count for this page */ ! 867: ! 868: /* ! 869: * ! 870: * Does whatever is needed to print the last page and get ready for the next one. ! 871: * It's called, from conv(), after a BEND code is processed. I'm ignoring the ! 872: * copy count that's expected to follow each page. ! 873: * ! 874: */ ! 875: ! 876: if ( bgimode == BGRAPH && (ch = get_char()) != EOF && ! (ch & MSB) ) { ! 877: ungetc(ch, fp_in); ! 878: position--; ! 879: } /* End if */ ! 880: ! 881: if ( fp_out == stdout ) /* count the last page */ ! 882: printed++; ! 883: ! 884: fprintf(fp_out, "cleartomark\n"); ! 885: fprintf(fp_out, "showpage\n"); ! 886: fprintf(fp_out, "saveobj restore\n"); ! 887: fprintf(fp_out, "%s %d %d\n", ENDPAGE, page, printed); ! 888: ! 889: while ( (ch = get_char()) == 0 ) ; /* skip any NULL characters */ ! 890: ungetc(ch, fp_in); ! 891: position--; ! 892: ! 893: if ( ungetc(getc(fp_in), fp_in) == EOF ) ! 894: redirect(-1); ! 895: else redirect(++page); ! 896: ! 897: fprintf(fp_out, "%s %d %d\n", PAGE, page, printed+1); ! 898: fprintf(fp_out, "/saveobj save def\n"); ! 899: fprintf(fp_out, "mark\n"); ! 900: writerequest(printed+1, fp_out); ! 901: fprintf(fp_out, "%d pagesetup\n", printed+1); ! 902: ! 903: setsize(bgisize); ! 904: hpos = vpos = 0; ! 905: ! 906: } /* End of formfeed */ ! 907: ! 908: /*****************************************************************************/ ! 909: ! 910: subr_def() ! 911: ! 912: { ! 913: ! 914: /* ! 915: * ! 916: * Starts a subroutine definition. All subroutines are defined as PostScript ! 917: * procedures that begin with the character S and end with the subroutine's id ! 918: * (a number between 0 and 63 - I guess). The primary, and perhaps only use of ! 919: * subroutines is in special color plots produced by several graphics libraries, ! 920: * and even there it's not all that common. I've also chosen not to worry about ! 921: * nested subroutine definitions - that would certainly be overkill! ! 922: * ! 923: * All subroutines set up their own (translated) coordinate system, do their work ! 924: * in that system, and restore things when they exit. To make everything work ! 925: * properly we save the current point (in shpos and svpos), set our position to ! 926: * (0, 0), and restore things at the end of the subroutine definition. That means ! 927: * hpos and vpos measure the relative displacement after a subroutine returns, and ! 928: * we save those values in the displacement[] array. The displacements are used ! 929: * (in subr_call()) to properly adjust our position after each subroutine call, ! 930: * and all subroutines are called with the current x and y coordinates on top of ! 931: * the stack. ! 932: * ! 933: */ ! 934: ! 935: if ( in_subr == TRUE ) /* a nested subroutine definition?? */ ! 936: error(FATAL, "can't handle nested subroutine definitions"); ! 937: ! 938: if ( (subr_id = get_data()) == EOF ) ! 939: error(FATAL, "missing subroutine identifier"); ! 940: ! 941: if ( in_global == FALSE ) { /* just used to reduce file size some */ ! 942: fprintf(fp_out, "cleartomark\n"); ! 943: fprintf(fp_out, "saveobj restore\n"); ! 944: fprintf(fp_out, "%s", BEGINGLOBAL); ! 945: in_global = TRUE; ! 946: } /* End if */ ! 947: ! 948: fprintf(fp_out, "/S%d {\n", subr_id); ! 949: fprintf(fp_out, "gsave translate\n"); ! 950: ! 951: shpos = hpos; /* save our current position */ ! 952: svpos = vpos; ! 953: ! 954: hgoto(0); /* start at the origin */ ! 955: vgoto(0); ! 956: ! 957: in_subr = TRUE; /* in a subroutine definition */ ! 958: ! 959: } /* End of subr_def */ ! 960: ! 961: /*****************************************************************************/ ! 962: ! 963: subr_end() ! 964: ! 965: { ! 966: ! 967: int ch; /* for looking at next opcode */ ! 968: ! 969: /* ! 970: * ! 971: * Handles stuff needed at the end of each subroutine. Want to remember the change ! 972: * in horizontal and vertical positions for each subroutine so we can adjust our ! 973: * position after each call - just in case. The current position was set to (0, 0) ! 974: * before we started the subroutine definition, so when we get here hpos and vpos ! 975: * are the relative displacements after the subroutine is called. They're saved in ! 976: * the displacement[] array and used to adjust the current position when we return ! 977: * from a subroutine. ! 978: * ! 979: */ ! 980: ! 981: if ( in_subr == FALSE ) /* not in a subroutine definition?? */ ! 982: error(FATAL, "subroutine end without corresponding start"); ! 983: ! 984: fprintf(fp_out, "grestore\n"); ! 985: fprintf(fp_out, "} def\n"); ! 986: ! 987: if ( in_global == TRUE && (ch = get_char()) != BSUB ) { ! 988: fprintf(fp_out, "%s", ENDGLOBAL); ! 989: fprintf(fp_out, "/saveobj save def\n"); ! 990: fprintf(fp_out, "mark\n"); ! 991: in_global = FALSE; ! 992: } /* End if */ ! 993: ! 994: ungetc(ch, fp_in); /* put back the next opcode */ ! 995: ! 996: displacement[subr_id].dx = hpos; ! 997: displacement[subr_id].dy = vpos; ! 998: ! 999: hgoto(shpos); /* back to where we started */ ! 1000: vgoto(svpos); ! 1001: ! 1002: in_subr = FALSE; /* done with the definition */ ! 1003: ! 1004: } /* End of subr_end */ ! 1005: ! 1006: /*****************************************************************************/ ! 1007: ! 1008: subr_call() ! 1009: ! 1010: { ! 1011: ! 1012: int ch; /* next byte from *fp_in */ ! 1013: int id; /* subroutine id if ch wasn't an opcode */ ! 1014: ! 1015: /* ! 1016: * ! 1017: * Handles subroutine calls. Everything that follows the BCALL opcode (up to the ! 1018: * next opcode) is taken as a subroutine identifier - thus the loop that generates ! 1019: * the subroutine calls. ! 1020: * ! 1021: */ ! 1022: ! 1023: while ( (ch = get_char()) != EOF && (ch & MSB) ) { ! 1024: id = ch & DMASK; ! 1025: fprintf(fp_out, "%d %d S%d\n", hpos, vpos, id); ! 1026: ! 1027: hgoto(hpos + displacement[id].dx); /* adjust our position */ ! 1028: vgoto(vpos + displacement[id].dy); ! 1029: } /* End while */ ! 1030: ! 1031: ungetc(ch, fp_in); ! 1032: ! 1033: } /* End of subr_call */ ! 1034: ! 1035: /*****************************************************************************/ ! 1036: ! 1037: vector(var, mode) ! 1038: ! 1039: int var; /* coordinate that varies next? */ ! 1040: int mode; /* VISIBLE or INVISIBLE vectors */ ! 1041: ! 1042: { ! 1043: ! 1044: int ch; /* next character from *fp_in */ ! 1045: int x, y; /* line drawn to this point */ ! 1046: int count = 0; /* number of points so far */ ! 1047: ! 1048: /* ! 1049: * ! 1050: * Handles plotting of all types of BGI vectors. If it's a manhattan vector var ! 1051: * specifies which coordinate will be changed by the next number in the input ! 1052: * file. ! 1053: * ! 1054: */ ! 1055: ! 1056: x = hpos; /* set up the first point */ ! 1057: y = vpos; ! 1058: ! 1059: while ( (ch = get_char()) != EOF && ch & MSB ) { ! 1060: if ( var == X_COORD ) /* next length is change in x */ ! 1061: x += get_int(ch); ! 1062: else if ( var == Y_COORD ) /* it's the change in y */ ! 1063: y += get_int(ch); ! 1064: else if ( var == LONGVECTOR ) { /* long vector */ ! 1065: x += get_int(ch); ! 1066: y += get_int(0); ! 1067: } else { /* must be a short vector */ ! 1068: x += ((ch & MSBMAG) * ((ch & SGNB) ? -1 : 1)); ! 1069: y += (((ch = get_data()) & MSBMAG) * ((ch & SGNB) ? -1 : 1)); ! 1070: } /* End else */ ! 1071: ! 1072: if ( mode == VISIBLE ) { /* draw the line segment */ ! 1073: fprintf(fp_out, "%d %d\n", hpos - x, vpos - y); ! 1074: count++; ! 1075: } /* End if */ ! 1076: ! 1077: hgoto(x); /* adjust the current BGI position */ ! 1078: vgoto(y); ! 1079: ! 1080: if ( var == X_COORD ) /* vertical length comes next */ ! 1081: var = Y_COORD; ! 1082: else if ( var == Y_COORD ) /* change horizontal next */ ! 1083: var = X_COORD; ! 1084: } /* End while */ ! 1085: ! 1086: if ( count > 0 ) ! 1087: fprintf(fp_out, "%d %d v\n", hpos, vpos); ! 1088: ! 1089: ungetc(ch, fp_in); /* it wasn't part of the vector */ ! 1090: position--; ! 1091: ! 1092: } /* End of vector */ ! 1093: ! 1094: /*****************************************************************************/ ! 1095: ! 1096: rectangle(mode) ! 1097: ! 1098: int mode; /* FILL or OUTLINE the rectangle */ ! 1099: ! 1100: { ! 1101: ! 1102: int deltax; /* displacement for horizontal side */ ! 1103: int deltay; /* same but for vertical sides */ ! 1104: ! 1105: /* ! 1106: * ! 1107: * Draws a rectangle and either outlines or fills it, depending on the value of ! 1108: * mode. Would be clearer, and perhaps better, if {stroke} or {fill} were put on ! 1109: * the stack instead of 0 or 1. R could then define the path and just do an exec ! 1110: * to fill or stroke it. ! 1111: * ! 1112: */ ! 1113: ! 1114: deltax = get_int(0); /* get the height and width */ ! 1115: deltay = get_int(0); ! 1116: ! 1117: if ( mode == OUTLINE ) ! 1118: fprintf(fp_out, "0 %d %d %d %d R\n", deltax, deltay, hpos, vpos); ! 1119: else fprintf(fp_out, "1 %d %d %d %d R\n", deltax, deltay, hpos, vpos); ! 1120: ! 1121: } /* End of rectangle */ ! 1122: ! 1123: /*****************************************************************************/ ! 1124: ! 1125: trapezoid() ! 1126: ! 1127: { ! 1128: ! 1129: int kind; /* which sides are parallel */ ! 1130: int d[6]; /* true displacements - depends on kind */ ! 1131: ! 1132: /* ! 1133: * ! 1134: * Handles filled trapeziods. A data byte of 0101 following the opcode means the ! 1135: * horizontal sides are parallel, 0102 means the vertical sides are parallel. ! 1136: * Filling is handled by eofill so we don't need to get things in the right order. ! 1137: * ! 1138: */ ! 1139: ! 1140: kind = get_data(); ! 1141: ! 1142: d[0] = get_int(0); ! 1143: d[1] = 0; ! 1144: d[2] = get_int(0); ! 1145: d[3] = get_int(0); ! 1146: d[4] = get_int(0); ! 1147: d[5] = 0; ! 1148: ! 1149: if ( kind == 2 ) { /* parallel sides are vertical */ ! 1150: d[1] = d[0]; ! 1151: d[0] = 0; ! 1152: d[5] = d[4]; ! 1153: d[4] = 0; ! 1154: } /* End if */ ! 1155: ! 1156: fprintf(fp_out, "%d %d %d %d %d %d %d %d T\n", d[4], d[5], d[2], d[3], d[0], d[1], hpos, vpos); ! 1157: ! 1158: } /* End of trapezoid */ ! 1159: ! 1160: /*****************************************************************************/ ! 1161: ! 1162: point_plot(mode, ch) ! 1163: ! 1164: int mode; /* plotting mode BPOINT or BPOINT1 */ ! 1165: int ch; /* will be placed at the points */ ! 1166: ! 1167: { ! 1168: ! 1169: int c; /* next character from input file */ ! 1170: int x, y; /* ch gets put here next */ ! 1171: int deltax; /* x increment for BPOINT1 mode */ ! 1172: ! 1173: /* ! 1174: * ! 1175: * The two point plot modes are used to place a character at selected points. The ! 1176: * difference in the two modes, namely BPOINT and BPOINT1, is the way we get the ! 1177: * coordinates of the next point. In BPOINT1 the two bytes immediately following ! 1178: * ch select a constant horizontal change, while both coordinates are given for ! 1179: * all points in BPOINT mode. ! 1180: * ! 1181: */ ! 1182: ! 1183: if ( mode == BPOINT1 ) { /* first integer is change in x */ ! 1184: deltax = get_int(0); ! 1185: x = hpos - deltax; ! 1186: } /* End if */ ! 1187: ! 1188: while ( (c = get_char()) != EOF && (c & MSB) ) { ! 1189: if ( mode == BPOINT1 ) { /* only read y coordinate */ ! 1190: y = get_int(c); ! 1191: x += deltax; ! 1192: } else { /* get new x and y from input file */ ! 1193: x = get_int(c); ! 1194: y = get_int(0); ! 1195: } /* End else */ ! 1196: ! 1197: hgoto(x); /* adjust BGI position */ ! 1198: vgoto(y); ! 1199: ! 1200: fprintf(fp_out, "%d %d\n", hpos, vpos); ! 1201: } /* End while */ ! 1202: ! 1203: putc('(', fp_out); ! 1204: ! 1205: switch ( ch ) { ! 1206: case '(': ! 1207: case ')': ! 1208: case '\\': ! 1209: putc('\\', fp_out); ! 1210: ! 1211: default: ! 1212: putc(ch, fp_out); ! 1213: } /* End switch */ ! 1214: ! 1215: fprintf(fp_out, ")pp\n"); ! 1216: ! 1217: ungetc(c, fp_in); /* it wasn't part of the point plot */ ! 1218: position--; ! 1219: ! 1220: } /* End of point_plot */ ! 1221: ! 1222: /*****************************************************************************/ ! 1223: ! 1224: line_plot() ! 1225: ! 1226: { ! 1227: ! 1228: int c; /* next input character from fp_in */ ! 1229: int deltax; /* change in x coordinate */ ! 1230: int x0, y0; /* starting point for next segment */ ! 1231: int x1, y1; /* endpoint of the line */ ! 1232: int count = 0; /* number of points so far */ ! 1233: ! 1234: /* ! 1235: * ! 1236: * Essentially the same format as BPOINT1, except that in this case we connect ! 1237: * pairs of points by line segments. ! 1238: * ! 1239: */ ! 1240: ! 1241: deltax = get_int(0); /* again the change in x is first */ ! 1242: ! 1243: x1 = hpos; /* so it works first time through */ ! 1244: y1 = get_int(0); ! 1245: ! 1246: while ( (c = get_char()) != EOF && (c & MSB) ) { ! 1247: x0 = x1; /* line starts here */ ! 1248: y0 = y1; ! 1249: ! 1250: x1 += deltax; /* and ends at this point */ ! 1251: y1 = get_int(c); ! 1252: ! 1253: fprintf(fp_out, "%d %d\n", -deltax, y0 - y1); ! 1254: count++; ! 1255: } /* End while */ ! 1256: ! 1257: hgoto(x1); /* adjust current BGI position */ ! 1258: vgoto(y1); ! 1259: ! 1260: if ( count > 0 ) ! 1261: fprintf(fp_out, "%d %d v\n", hpos, vpos); ! 1262: ! 1263: ungetc(c, fp_in); /* wasn't part of the line */ ! 1264: position--; ! 1265: ! 1266: } /* End of line_plot */ ! 1267: ! 1268: /*****************************************************************************/ ! 1269: ! 1270: arc(mode) ! 1271: ! 1272: int mode; /* FILL or OUTLINE the path */ ! 1273: ! 1274: { ! 1275: ! 1276: int dx1, dy1; /* displacements for first point */ ! 1277: int dx2, dy2; /* same for the second point */ ! 1278: int radius; /* of the arc */ ! 1279: int angle1, angle2; /* starting and ending angles */ ! 1280: ! 1281: /* ! 1282: * ! 1283: * Called whenever we need to draw an arc. I'm ignoring filled slices for now. ! 1284: * ! 1285: */ ! 1286: ! 1287: dx1 = get_int(0); /* displacements relative to center */ ! 1288: dy1 = get_int(0); ! 1289: dx2 = get_int(0); ! 1290: dy2 = get_int(0); ! 1291: ! 1292: radius = get_int(0); /* and the radius */ ! 1293: ! 1294: if ( radius == 0 ) /* nothing to do */ ! 1295: return; ! 1296: ! 1297: angle1 = (atan2((double) dy1, (double) dx1) * 360) / (2 * PI) + .5; ! 1298: angle2 = (atan2((double) dy2, (double) dx2) * 360) / (2 * PI) + .5; ! 1299: ! 1300: fprintf(fp_out, "%d %d %d %d %d arcn stroke\n", hpos, vpos, radius, angle1, angle2); ! 1301: ! 1302: } /* End of arc */ ! 1303: ! 1304: /*****************************************************************************/ ! 1305: ! 1306: pattern() ! 1307: ! 1308: { ! 1309: ! 1310: double red = 0; /* color components */ ! 1311: double green = 0; ! 1312: double blue = 0; ! 1313: int kind; /* corse or fine pattern */ ! 1314: int val; /* next color data byte */ ! 1315: int i; /* loop index */ ! 1316: ! 1317: /* ! 1318: * ! 1319: * Handles patterns by setting the current color based of the values assigned to ! 1320: * the next four data bytes. BGI supports two kinds of patterns (fine or coarse) ! 1321: * but I'm handling each in the same way - for now. In a fine pattern the four ! 1322: * data bytes assign a color to four individual pixels (upperleft first) while ! 1323: * in a coarse pattern the four colors are assigned to groups of four pixels, ! 1324: * for a total of 16. Again the first color goes to the group in the upper left ! 1325: * corner. The byte immediately following the BPAT opcode selects fine (040) or ! 1326: * coarse (041) patterns. The PostScript RGB color is assigned by averaging the ! 1327: * RED, GREEN, and BLUE components assigned to the four pixels (or groups of ! 1328: * pixels). Acceptable results, but there's no distinction between fine and ! 1329: * coarse patterns. ! 1330: * ! 1331: */ ! 1332: ! 1333: if ( (kind = get_char()) == EOF ) ! 1334: error(FATAL, "bad pattern command"); ! 1335: ! 1336: for ( i = 0; i < 4; i++ ) { ! 1337: val = get_data(); ! 1338: red += get_color(val, RED); ! 1339: green += get_color(val, GREEN); ! 1340: blue += get_color(val, BLUE); ! 1341: } /* End for */ ! 1342: ! 1343: fprintf(fp_out, "%g %g %g c\n", red/4, green/4, blue/4); ! 1344: ! 1345: } /* End of pattern */ ! 1346: ! 1347: /*****************************************************************************/ ! 1348: ! 1349: get_color(val, component) ! 1350: ! 1351: int val; /* color data byte */ ! 1352: int component; /* RED, GREEN, or BLUE component */ ! 1353: ! 1354: { ! 1355: ! 1356: ! 1357: int primary; /* color mixing mode - bits 2 to 4 */ ! 1358: int plane; /* primary color plane - bits 5 to 7 */ ! 1359: unsigned rgbcolor; /* PostScript expects an RGB triple */ ! 1360: ! 1361: /* ! 1362: * ! 1363: * Picks the requested color component (RED, GREEN, or BLUE) from val and returns ! 1364: * the result to the caller. BGI works with Cyan, Yellow, and Magenta so the one's ! 1365: * complement stuff (following the exclusive or'ing) recovers the RED, BLUE, and ! 1366: * GREEN components that PostScript's setrgbcolor operator needs. The PostScript ! 1367: * interpreter in the ColorScript 100 has a setcmycolor operator, but it's not ! 1368: * generally available so I've decided to stick with setrgbcolor. ! 1369: * ! 1370: */ ! 1371: ! 1372: primary = (val >> 3) & 07; ! 1373: plane = val & 07; ! 1374: rgbcolor = (~(primary ^ plane)) & 07; ! 1375: ! 1376: if ( debug == ON ) ! 1377: fprintf(stderr, "val = %o, primary = %o, plane = %o, rgbcolor = %o\n", ! 1378: val, primary, plane, rgbcolor); ! 1379: ! 1380: switch ( component ) { ! 1381: case RED: ! 1382: return(rgbcolor>>2); ! 1383: ! 1384: case GREEN: ! 1385: return(rgbcolor&01); ! 1386: ! 1387: case BLUE: ! 1388: return((rgbcolor>>1)&01); ! 1389: ! 1390: default: ! 1391: error(FATAL, "unknown color component"); ! 1392: return(0); ! 1393: } /* End switch */ ! 1394: ! 1395: } /* End of get_color */ ! 1396: ! 1397: /*****************************************************************************/ ! 1398: ! 1399: set_color(val) ! 1400: ! 1401: int val; /* color data byte */ ! 1402: ! 1403: { ! 1404: ! 1405: /* ! 1406: * ! 1407: * Arranges to have the color set to the value requested in the BGI data byte val. ! 1408: * ! 1409: */ ! 1410: ! 1411: fprintf(fp_out, "%d %d %d c\n", get_color(val, RED), get_color(val, GREEN), get_color(val, BLUE)); ! 1412: ! 1413: } /* End of set_color */ ! 1414: ! 1415: /*****************************************************************************/ ! 1416: ! 1417: get_int(highbyte) ! 1418: ! 1419: int highbyte; /* already read this byte */ ! 1420: ! 1421: { ! 1422: ! 1423: int lowbyte; /* this and highbyte make the int */ ! 1424: ! 1425: /* ! 1426: * ! 1427: * Figures out the value on the integer (sign magnitude form) that's next in the ! 1428: * input file. If highbyte is nonzero we'll use it and the next byte to build the ! 1429: * integer, otherwise two bytes are read from fp_in. ! 1430: * ! 1431: */ ! 1432: ! 1433: ! 1434: if ( highbyte == 0 ) /* need to read the first byte */ ! 1435: highbyte = get_data(); ! 1436: ! 1437: lowbyte = get_data(); /* always need the second byte */ ! 1438: ! 1439: return(highbyte & SGNB ? -MAG(highbyte, lowbyte) : MAG(highbyte, lowbyte)); ! 1440: ! 1441: } /* End of get_int */ ! 1442: ! 1443: /*****************************************************************************/ ! 1444: ! 1445: get_data() ! 1446: ! 1447: { ! 1448: ! 1449: int val; /* data value returned to caller */ ! 1450: ! 1451: /* ! 1452: * ! 1453: * Called when we expect to find a single data character in the input file. The ! 1454: * data bit is turned off and the resulting value is returned to the caller. ! 1455: * ! 1456: */ ! 1457: ! 1458: if ( (val = get_char()) == EOF || ! (val & MSB) ) ! 1459: error(FATAL, "missing data value"); ! 1460: ! 1461: return(val & DMASK); ! 1462: ! 1463: } /* End of get_data */ ! 1464: ! 1465: /*****************************************************************************/ ! 1466: ! 1467: get_char() ! 1468: ! 1469: { ! 1470: ! 1471: int ch; /* character we just read */ ! 1472: ! 1473: /* ! 1474: * ! 1475: * Reads the next character from file *fp_in and returns the value to the caller. ! 1476: * This routine isn't really needed, but we may want to deal directly with some ! 1477: * screwball file formats so I thought it would probably be a good idea to isolate ! 1478: * all the input in one routine that could be easily changed. ! 1479: * ! 1480: */ ! 1481: ! 1482: if ( (ch = getc(fp_in)) != EOF ) { ! 1483: position++; ! 1484: ch &= CHMASK; ! 1485: } /* End if */ ! 1486: ! 1487: if ( debug == ON ) ! 1488: fprintf(stderr, "%o ", ch); ! 1489: ! 1490: return(ch); ! 1491: ! 1492: } /* End of get_char */ ! 1493: ! 1494: /*****************************************************************************/ ! 1495: ! 1496: redirect(pg) ! 1497: ! 1498: int pg; /* next page we're printing */ ! 1499: ! 1500: { ! 1501: ! 1502: static FILE *fp_null = NULL; /* if output is turned off */ ! 1503: ! 1504: /* ! 1505: * ! 1506: * If we're not supposed to print page pg, fp_out will be directed to /dev/null, ! 1507: * otherwise output goes to stdout. ! 1508: * ! 1509: */ ! 1510: ! 1511: if ( pg >= 0 && in_olist(pg) == ON ) ! 1512: fp_out = stdout; ! 1513: else if ( (fp_out = fp_null) == NULL ) ! 1514: fp_out = fp_null = fopen("/dev/null", "w"); ! 1515: ! 1516: } /* End of redirect */ ! 1517: ! 1518: /*****************************************************************************/ ! 1519:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.