Annotation of researchv10no/cmd/post.src/postbgi/postbgi.c, revision 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.