Annotation of researchv10no/cmd/post.src/postbgi/postbgi.c, revision 1.1.1.1

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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.