Annotation of researchv10no/cmd/postscript/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:                break;
        !           852:        }   /* End switch */
        !           853:     }  /* End while */
        !           854: 
        !           855:     fprintf(fp_out, ") t\n");
        !           856: 
        !           857: }   /* End of text */
        !           858: 
        !           859: /*****************************************************************************/
        !           860: 
        !           861: formfeed()
        !           862: 
        !           863: {
        !           864: 
        !           865:     int                ch;                     /* repeat count for this page */
        !           866: 
        !           867: /*
        !           868:  *
        !           869:  * Does whatever is needed to print the last page and get ready for the next one.
        !           870:  * It's called, from conv(), after a BEND code is processed. I'm ignoring the
        !           871:  * copy count that's expected to follow each page.
        !           872:  *
        !           873:  */
        !           874: 
        !           875:     if ( bgimode == BGRAPH && (ch = get_char()) != EOF  &&  ! (ch & MSB) )  {
        !           876:        ungetc(ch, fp_in);
        !           877:        position--;
        !           878:     }  /* End if */
        !           879: 
        !           880:     if ( fp_out == stdout )            /* count the last page */
        !           881:        printed++;
        !           882: 
        !           883:     fprintf(fp_out, "cleartomark\n");
        !           884:     fprintf(fp_out, "showpage\n");
        !           885:     fprintf(fp_out, "saveobj restore\n");
        !           886:     fprintf(fp_out, "%s %d %d\n", ENDPAGE, page, printed);
        !           887: 
        !           888:     while ( (ch = get_char()) == 0 ) ; /* skip any NULL characters */
        !           889:     ungetc(ch, fp_in);
        !           890:     position--;
        !           891: 
        !           892:     if ( ungetc(getc(fp_in), fp_in) == EOF )
        !           893:        redirect(-1);
        !           894:     else redirect(++page);
        !           895: 
        !           896:     fprintf(fp_out, "%s %d %d\n", PAGE, page, printed+1);
        !           897:     fprintf(fp_out, "/saveobj save def\n");
        !           898:     fprintf(fp_out, "mark\n");
        !           899:     writerequest(printed+1, fp_out);
        !           900:     fprintf(fp_out, "%d pagesetup\n", printed+1);
        !           901: 
        !           902:     setsize(bgisize);
        !           903:     hpos = vpos = 0;
        !           904: 
        !           905: }    /* End of formfeed */
        !           906: 
        !           907: /*****************************************************************************/
        !           908: 
        !           909: subr_def()
        !           910: 
        !           911: {
        !           912: 
        !           913: /*
        !           914:  *
        !           915:  * Starts a subroutine definition. All subroutines are defined as PostScript
        !           916:  * procedures that begin with the character S and end with the subroutine's id
        !           917:  * (a number between 0 and 63 - I guess). The primary, and perhaps only use of
        !           918:  * subroutines is in special color plots produced by several graphics libraries,
        !           919:  * and even there it's not all that common. I've also chosen not to worry about
        !           920:  * nested subroutine definitions - that would certainly be overkill!
        !           921:  *
        !           922:  * All subroutines set up their own (translated) coordinate system, do their work
        !           923:  * in that system, and restore things when they exit. To make everything work
        !           924:  * properly we save the current point (in shpos and svpos), set our position to
        !           925:  * (0, 0), and restore things at the end of the subroutine definition. That means
        !           926:  * hpos and vpos measure the relative displacement after a subroutine returns, and
        !           927:  * we save those values in the displacement[] array. The displacements are used
        !           928:  * (in subr_call()) to properly adjust our position after each subroutine call,
        !           929:  * and all subroutines are called with the current x and y coordinates on top of
        !           930:  * the stack.
        !           931:  *
        !           932:  */
        !           933: 
        !           934:     if ( in_subr == TRUE )             /* a nested subroutine definition?? */
        !           935:        error(FATAL, "can't handle nested subroutine definitions");
        !           936: 
        !           937:     if ( (subr_id = get_data()) == EOF )
        !           938:        error(FATAL, "missing subroutine identifier");
        !           939: 
        !           940:     if ( in_global == FALSE )  {       /* just used to reduce file size some */
        !           941:        fprintf(fp_out, "cleartomark\n");
        !           942:        fprintf(fp_out, "saveobj restore\n");
        !           943:        fprintf(fp_out, "%s", BEGINGLOBAL);
        !           944:        in_global = TRUE;
        !           945:     }  /* End if */
        !           946: 
        !           947:     fprintf(fp_out, "/S%d {\n", subr_id);
        !           948:     fprintf(fp_out, "gsave translate\n");
        !           949: 
        !           950:     shpos = hpos;                      /* save our current position */
        !           951:     svpos = vpos;
        !           952: 
        !           953:     hgoto(0);                          /* start at the origin */
        !           954:     vgoto(0);
        !           955: 
        !           956:     in_subr = TRUE;                    /* in a subroutine definition */
        !           957: 
        !           958: }   /* End of subr_def */
        !           959: 
        !           960: /*****************************************************************************/
        !           961: 
        !           962: subr_end()
        !           963: 
        !           964: {
        !           965: 
        !           966:     int                ch;                     /* for looking at next opcode */
        !           967: 
        !           968: /*
        !           969:  *
        !           970:  * Handles stuff needed at the end of each subroutine. Want to remember the change
        !           971:  * in horizontal and vertical positions for each subroutine so we can adjust our
        !           972:  * position after each call - just in case. The current position was set to (0, 0)
        !           973:  * before we started the subroutine definition, so when we get here hpos and vpos
        !           974:  * are the relative displacements after the subroutine is called. They're saved in
        !           975:  * the displacement[] array and used to adjust the current position when we return
        !           976:  * from a subroutine.
        !           977:  *
        !           978:  */
        !           979: 
        !           980:     if ( in_subr == FALSE )            /* not in a subroutine definition?? */
        !           981:        error(FATAL, "subroutine end without corresponding start");
        !           982: 
        !           983:     fprintf(fp_out, "grestore\n");
        !           984:     fprintf(fp_out, "} def\n");
        !           985: 
        !           986:     if ( in_global == TRUE && (ch = get_char()) != BSUB )  {
        !           987:        fprintf(fp_out, "%s", ENDGLOBAL);
        !           988:        fprintf(fp_out, "/saveobj save def\n");
        !           989:        fprintf(fp_out, "mark\n");
        !           990:        in_global = FALSE;
        !           991:     }  /* End if */
        !           992: 
        !           993:     ungetc(ch, fp_in);                 /* put back the next opcode */
        !           994: 
        !           995:     displacement[subr_id].dx = hpos;
        !           996:     displacement[subr_id].dy = vpos;
        !           997: 
        !           998:     hgoto(shpos);                      /* back to where we started */
        !           999:     vgoto(svpos);
        !          1000: 
        !          1001:     in_subr = FALSE;                   /* done with the definition */
        !          1002: 
        !          1003: }   /* End of subr_end */
        !          1004: 
        !          1005: /*****************************************************************************/
        !          1006: 
        !          1007: subr_call()
        !          1008: 
        !          1009: {
        !          1010: 
        !          1011:     int                ch;                     /* next byte from *fp_in */
        !          1012:     int                id;                     /* subroutine id if ch wasn't an opcode */
        !          1013: 
        !          1014: /*
        !          1015:  *
        !          1016:  * Handles subroutine calls. Everything that follows the BCALL opcode (up to the
        !          1017:  * next opcode) is taken as a subroutine identifier - thus the loop that generates
        !          1018:  * the subroutine calls.
        !          1019:  *
        !          1020:  */
        !          1021: 
        !          1022:     while ( (ch = get_char()) != EOF && (ch & MSB) )  {
        !          1023:        id = ch & DMASK;
        !          1024:        fprintf(fp_out, "%d %d S%d\n", hpos, vpos, id);
        !          1025: 
        !          1026:        hgoto(hpos + displacement[id].dx);      /* adjust our position */
        !          1027:        vgoto(vpos + displacement[id].dy);
        !          1028:     }  /* End while */
        !          1029: 
        !          1030:     ungetc(ch, fp_in);
        !          1031: 
        !          1032: }   /* End of subr_call */
        !          1033: 
        !          1034: /*****************************************************************************/
        !          1035: 
        !          1036: vector(var, mode)
        !          1037: 
        !          1038:     int                var;                    /* coordinate that varies next? */
        !          1039:     int                mode;                   /* VISIBLE or INVISIBLE vectors */
        !          1040: 
        !          1041: {
        !          1042: 
        !          1043:     int                ch;                     /* next character from *fp_in */
        !          1044:     int                x, y;                   /* line drawn to this point */
        !          1045:     int                count = 0;              /* number of points so far */
        !          1046: 
        !          1047: /*
        !          1048:  *
        !          1049:  * Handles plotting of all types of BGI vectors. If it's a manhattan vector var
        !          1050:  * specifies which coordinate will be changed by the next number in the input
        !          1051:  * file.
        !          1052:  *
        !          1053:  */
        !          1054: 
        !          1055:     x = hpos;                          /* set up the first point */
        !          1056:     y = vpos;
        !          1057: 
        !          1058:     while ( (ch = get_char()) != EOF  &&  ch & MSB )  {
        !          1059:        if ( var == X_COORD )           /* next length is change in x */
        !          1060:            x += get_int(ch);
        !          1061:        else if ( var == Y_COORD )      /* it's the change in y */
        !          1062:            y += get_int(ch);
        !          1063:        else if ( var == LONGVECTOR )  {        /* long vector */
        !          1064:            x += get_int(ch);
        !          1065:            y += get_int(0);
        !          1066:        } else {                        /* must be a short vector */
        !          1067:            x += ((ch & MSBMAG) * ((ch & SGNB) ? -1 : 1));
        !          1068:            y += (((ch = get_data()) & MSBMAG) * ((ch & SGNB) ? -1 : 1));
        !          1069:        }   /* End else */
        !          1070: 
        !          1071:        if ( mode == VISIBLE )  {       /* draw the line segment */
        !          1072:            fprintf(fp_out, "%d %d\n", hpos - x, vpos - y);
        !          1073:            count++;
        !          1074:        }   /* End if */
        !          1075: 
        !          1076:        hgoto(x);                       /* adjust the current BGI position */
        !          1077:        vgoto(y);
        !          1078: 
        !          1079:        if ( var == X_COORD )           /* vertical length comes next */
        !          1080:            var = Y_COORD;
        !          1081:        else if ( var == Y_COORD )      /* change horizontal next */
        !          1082:            var = X_COORD;
        !          1083:     }  /* End while */
        !          1084: 
        !          1085:     if ( count > 0 )
        !          1086:        fprintf(fp_out, "%d %d v\n", hpos, vpos);
        !          1087: 
        !          1088:     ungetc(ch, fp_in);                 /* it wasn't part of the vector */
        !          1089:     position--;
        !          1090: 
        !          1091: }   /* End of vector */
        !          1092: 
        !          1093: /*****************************************************************************/
        !          1094: 
        !          1095: rectangle(mode)
        !          1096: 
        !          1097:     int                mode;                   /* FILL or OUTLINE the rectangle */
        !          1098: 
        !          1099: {
        !          1100: 
        !          1101:     int                deltax;                 /* displacement for horizontal side */
        !          1102:     int                deltay;                 /* same but for vertical sides */
        !          1103: 
        !          1104: /*
        !          1105:  *
        !          1106:  * Draws a rectangle and either outlines or fills it, depending on the value of
        !          1107:  * mode. Would be clearer, and perhaps better, if {stroke} or {fill} were put on
        !          1108:  * the stack instead of 0 or 1. R could then define the path and just do an exec
        !          1109:  * to fill or stroke it.
        !          1110:  *
        !          1111:  */
        !          1112: 
        !          1113:     deltax = get_int(0);               /* get the height and width */
        !          1114:     deltay = get_int(0);
        !          1115: 
        !          1116:     if ( mode == OUTLINE )
        !          1117:        fprintf(fp_out, "0 %d %d %d %d R\n", deltax, deltay, hpos, vpos);
        !          1118:     else fprintf(fp_out, "1 %d %d %d %d R\n", deltax, deltay, hpos, vpos);
        !          1119: 
        !          1120: }   /* End of rectangle */
        !          1121: 
        !          1122: /*****************************************************************************/
        !          1123: 
        !          1124: trapezoid()
        !          1125: 
        !          1126: {
        !          1127: 
        !          1128:     int                kind;                   /* which sides are parallel */
        !          1129:     int                d[6];                   /* true displacements - depends on kind */
        !          1130: 
        !          1131: /*
        !          1132:  *
        !          1133:  * Handles filled trapeziods. A data byte of 0101 following the opcode means the
        !          1134:  * horizontal sides are parallel, 0102 means the vertical sides are parallel.
        !          1135:  * Filling is handled by eofill so we don't need to get things in the right order.
        !          1136:  *
        !          1137:  */
        !          1138: 
        !          1139:     kind = get_data();
        !          1140: 
        !          1141:     d[0] = get_int(0);
        !          1142:     d[1] = 0;
        !          1143:     d[2] = get_int(0);
        !          1144:     d[3] = get_int(0);
        !          1145:     d[4] = get_int(0);
        !          1146:     d[5] = 0;
        !          1147: 
        !          1148:     if ( kind == 2 )  {                        /* parallel sides are vertical */
        !          1149:        d[1] = d[0];
        !          1150:        d[0] = 0;
        !          1151:        d[5] = d[4];
        !          1152:        d[4] = 0;
        !          1153:     }  /* End if */
        !          1154: 
        !          1155:     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);
        !          1156: 
        !          1157: }   /* End of trapezoid */
        !          1158: 
        !          1159: /*****************************************************************************/
        !          1160: 
        !          1161: point_plot(mode, ch)
        !          1162: 
        !          1163:     int                mode;                   /* plotting mode BPOINT or BPOINT1 */
        !          1164:     int                ch;                     /* will be placed at the points */
        !          1165: 
        !          1166: {
        !          1167: 
        !          1168:     int                c;                      /* next character from input file */
        !          1169:     int                x, y;                   /* ch gets put here next */
        !          1170:     int                deltax;                 /* x increment for BPOINT1 mode */
        !          1171: 
        !          1172: /*
        !          1173:  *
        !          1174:  * The two point plot modes are used to place a character at selected points. The
        !          1175:  * difference in the two modes, namely BPOINT and BPOINT1, is the way we get the
        !          1176:  * coordinates of the next point. In BPOINT1 the two bytes immediately following
        !          1177:  * ch select a constant horizontal change, while both coordinates are given for
        !          1178:  * all points in BPOINT mode.
        !          1179:  *
        !          1180:  */
        !          1181: 
        !          1182:     if ( mode == BPOINT1 )  {          /* first integer is change in x */
        !          1183:        deltax = get_int(0);
        !          1184:        x = hpos - deltax;
        !          1185:     }  /* End if */
        !          1186: 
        !          1187:     while ( (c = get_char()) != EOF  &&  (c & MSB) )  {
        !          1188:        if ( mode == BPOINT1 )  {       /* only read y coordinate */
        !          1189:            y = get_int(c);
        !          1190:            x += deltax;
        !          1191:        } else {                        /* get new x and y from input file */
        !          1192:            x = get_int(c);
        !          1193:            y = get_int(0);
        !          1194:        }   /* End else */
        !          1195: 
        !          1196:        hgoto(x);                       /* adjust BGI position */
        !          1197:        vgoto(y);
        !          1198: 
        !          1199:        fprintf(fp_out, "%d %d\n", hpos, vpos);
        !          1200:     }  /* End while */
        !          1201: 
        !          1202:     putc('(', fp_out);
        !          1203: 
        !          1204:     switch ( ch )  {
        !          1205:        case '(':
        !          1206:        case ')':
        !          1207:        case '\\':
        !          1208:                putc('\\', fp_out);
        !          1209: 
        !          1210:        default:
        !          1211:                putc(ch, fp_out);
        !          1212:     }  /* End switch */
        !          1213: 
        !          1214:     fprintf(fp_out, ")pp\n");
        !          1215: 
        !          1216:     ungetc(c, fp_in);                  /* it wasn't part of the point plot */
        !          1217:     position--;
        !          1218: 
        !          1219: }   /* End of point_plot */
        !          1220: 
        !          1221: /*****************************************************************************/
        !          1222: 
        !          1223: line_plot()
        !          1224: 
        !          1225: {
        !          1226: 
        !          1227:     int                c;                      /* next input character from fp_in */
        !          1228:     int                deltax;                 /* change in x coordinate */
        !          1229:     int                x0, y0;                 /* starting point for next segment */
        !          1230:     int                x1, y1;                 /* endpoint of the line */
        !          1231:     int                count = 0;              /* number of points so far */
        !          1232: 
        !          1233: /*
        !          1234:  *
        !          1235:  * Essentially the same format as BPOINT1, except that in this case we connect
        !          1236:  * pairs of points by line segments.
        !          1237:  *
        !          1238:  */
        !          1239: 
        !          1240:     deltax = get_int(0);               /* again the change in x is first */
        !          1241: 
        !          1242:     x1 = hpos;                         /* so it works first time through */
        !          1243:     y1 = get_int(0);
        !          1244: 
        !          1245:     while ( (c = get_char()) != EOF  &&  (c & MSB) )  {
        !          1246:        x0 = x1;                        /* line starts here */
        !          1247:        y0 = y1;
        !          1248: 
        !          1249:        x1 += deltax;                   /* and ends at this point */
        !          1250:        y1 = get_int(c);
        !          1251: 
        !          1252:        fprintf(fp_out, "%d %d\n", -deltax, y0 - y1);
        !          1253:        count++;
        !          1254:     }  /* End while */
        !          1255: 
        !          1256:     hgoto(x1);                         /* adjust current BGI position */
        !          1257:     vgoto(y1);
        !          1258: 
        !          1259:     if ( count > 0 )
        !          1260:        fprintf(fp_out, "%d %d v\n", hpos, vpos);
        !          1261: 
        !          1262:     ungetc(c, fp_in);                  /* wasn't part of the line */
        !          1263:     position--;
        !          1264: 
        !          1265: }   /* End of line_plot */
        !          1266: 
        !          1267: /*****************************************************************************/
        !          1268: 
        !          1269: arc(mode)
        !          1270: 
        !          1271:     int                mode;                   /* FILL or OUTLINE the path */
        !          1272: 
        !          1273: {
        !          1274: 
        !          1275:     int                dx1, dy1;               /* displacements for first point */
        !          1276:     int                dx2, dy2;               /* same for the second point */
        !          1277:     int                radius;                 /* of the arc */
        !          1278:     int                angle1, angle2;         /* starting and ending angles */
        !          1279: 
        !          1280: /*
        !          1281:  *
        !          1282:  * Called whenever we need to draw an arc. I'm ignoring filled slices for now.
        !          1283:  *
        !          1284:  */
        !          1285: 
        !          1286:     dx1 = get_int(0);                  /* displacements relative to center */
        !          1287:     dy1 = get_int(0);
        !          1288:     dx2 = get_int(0);
        !          1289:     dy2 = get_int(0);
        !          1290: 
        !          1291:     radius = get_int(0);               /* and the radius */
        !          1292: 
        !          1293:     if ( radius == 0 )                 /* nothing to do */
        !          1294:        return;
        !          1295: 
        !          1296:     angle1 = (atan2((double) dy1, (double) dx1) * 360) / (2 * PI) + .5;
        !          1297:     angle2 = (atan2((double) dy2, (double) dx2) * 360) / (2 * PI) + .5;
        !          1298: 
        !          1299:     fprintf(fp_out, "%d %d %d %d %d arcn stroke\n", hpos, vpos, radius, angle1, angle2);
        !          1300: 
        !          1301: }   /* End of arc */
        !          1302: 
        !          1303: /*****************************************************************************/
        !          1304: 
        !          1305: pattern()
        !          1306: 
        !          1307: {
        !          1308: 
        !          1309:     double     red = 0;                /* color components */
        !          1310:     double     green = 0;
        !          1311:     double     blue = 0;
        !          1312:     int                kind;                   /* corse or fine pattern */
        !          1313:     int                val;                    /* next color data byte */
        !          1314:     int                i;                      /* loop index */
        !          1315: 
        !          1316: /*
        !          1317:  *
        !          1318:  * Handles patterns by setting the current color based of the values assigned to
        !          1319:  * the next four data bytes. BGI supports two kinds of patterns (fine or coarse)
        !          1320:  * but I'm handling each in the same way - for now. In a fine pattern the four
        !          1321:  * data bytes assign a color to four individual pixels (upperleft first) while
        !          1322:  * in a coarse pattern the four colors are assigned to groups of four pixels,
        !          1323:  * for a total of 16. Again the first color goes to the group in the upper left
        !          1324:  * corner. The byte immediately following the BPAT opcode selects fine (040) or
        !          1325:  * coarse (041) patterns. The PostScript RGB color is assigned by averaging the
        !          1326:  * RED, GREEN, and BLUE components assigned to the four pixels (or groups of
        !          1327:  * pixels). Acceptable results, but there's no distinction between fine and
        !          1328:  * coarse patterns.
        !          1329:  *
        !          1330:  */
        !          1331: 
        !          1332:     if ( (kind = get_char()) == EOF )
        !          1333:        error(FATAL, "bad pattern command");
        !          1334: 
        !          1335:     for ( i = 0; i < 4; i++ )  {
        !          1336:        val = get_data();
        !          1337:        red += get_color(val, RED);
        !          1338:        green += get_color(val, GREEN);
        !          1339:        blue += get_color(val, BLUE);
        !          1340:     }  /* End for */
        !          1341: 
        !          1342:     fprintf(fp_out, "%g %g %g c\n", red/4, green/4, blue/4);
        !          1343: 
        !          1344: }   /* End of pattern */
        !          1345: 
        !          1346: /*****************************************************************************/
        !          1347: 
        !          1348: get_color(val, component)
        !          1349: 
        !          1350:     int                val;                    /* color data byte */
        !          1351:     int                component;              /* RED, GREEN, or BLUE component */
        !          1352: 
        !          1353: {
        !          1354: 
        !          1355: 
        !          1356:     int                primary;                /* color mixing mode - bits 2 to 4 */
        !          1357:     int                plane;                  /* primary color plane - bits 5 to 7 */
        !          1358:     unsigned   rgbcolor;               /* PostScript expects an RGB triple */
        !          1359: 
        !          1360: /*
        !          1361:  *
        !          1362:  * Picks the requested color component (RED, GREEN, or BLUE) from val and returns
        !          1363:  * the result to the caller. BGI works with Cyan, Yellow, and Magenta so the one's
        !          1364:  * complement stuff (following the exclusive or'ing) recovers the RED, BLUE, and
        !          1365:  * GREEN components that PostScript's setrgbcolor operator needs. The PostScript
        !          1366:  * interpreter in the ColorScript 100 has a setcmycolor operator, but it's not
        !          1367:  * generally available so I've decided to stick with setrgbcolor.
        !          1368:  *
        !          1369:  */
        !          1370: 
        !          1371:     primary = (val >> 3) & 07;
        !          1372:     plane = val & 07;
        !          1373:     rgbcolor = (~(primary ^ plane)) & 07;
        !          1374: 
        !          1375:     if ( debug == ON )
        !          1376:        fprintf(stderr, "val = %o, primary = %o, plane = %o, rgbcolor = %o\n",
        !          1377:                val, primary, plane, rgbcolor);
        !          1378: 
        !          1379:     switch ( component )  {
        !          1380:        case RED:
        !          1381:                return(rgbcolor>>2);
        !          1382: 
        !          1383:        case GREEN:
        !          1384:                return(rgbcolor&01);
        !          1385: 
        !          1386:        case BLUE:
        !          1387:                return((rgbcolor>>1)&01);
        !          1388: 
        !          1389:        default:
        !          1390:                error(FATAL, "unknown color component");
        !          1391:                return(0);
        !          1392:     }  /* End switch */
        !          1393: 
        !          1394: }   /* End of get_color */
        !          1395: 
        !          1396: /*****************************************************************************/
        !          1397: 
        !          1398: set_color(val)
        !          1399: 
        !          1400:     int                val;                    /* color data byte */
        !          1401: 
        !          1402: {
        !          1403: 
        !          1404: /*
        !          1405:  *
        !          1406:  * Arranges to have the color set to the value requested in the BGI data byte val.
        !          1407:  *
        !          1408:  */
        !          1409: 
        !          1410:     fprintf(fp_out, "%d %d %d c\n", get_color(val, RED), get_color(val, GREEN), get_color(val, BLUE));
        !          1411: 
        !          1412: }   /* End of set_color */
        !          1413: 
        !          1414: /*****************************************************************************/
        !          1415: 
        !          1416: get_int(highbyte)
        !          1417: 
        !          1418:     int                highbyte;               /* already read this byte */
        !          1419: 
        !          1420: {
        !          1421: 
        !          1422:     int                lowbyte;                /* this and highbyte make the int */
        !          1423: 
        !          1424: /*
        !          1425:  *
        !          1426:  * Figures out the value on the integer (sign magnitude form) that's next in the
        !          1427:  * input file. If highbyte is nonzero we'll use it and the next byte to build the
        !          1428:  * integer, otherwise two bytes are read from fp_in.
        !          1429:  *
        !          1430:  */
        !          1431: 
        !          1432: 
        !          1433:     if ( highbyte == 0 )               /* need to read the first byte */
        !          1434:        highbyte = get_data();
        !          1435: 
        !          1436:     lowbyte = get_data();              /* always need the second byte */
        !          1437: 
        !          1438:     return(highbyte & SGNB ? -MAG(highbyte, lowbyte) : MAG(highbyte, lowbyte));
        !          1439: 
        !          1440: }   /* End of get_int */
        !          1441: 
        !          1442: /*****************************************************************************/
        !          1443: 
        !          1444: get_data()
        !          1445: 
        !          1446: {
        !          1447: 
        !          1448:     int                val;                    /* data value returned to caller */
        !          1449: 
        !          1450: /*
        !          1451:  *
        !          1452:  * Called when we expect to find a single data character in the input file. The
        !          1453:  * data bit is turned off and the resulting value is returned to the caller.
        !          1454:  *
        !          1455:  */
        !          1456: 
        !          1457:     if ( (val = get_char()) == EOF  ||  ! (val & MSB) )
        !          1458:        error(FATAL, "missing data value");
        !          1459: 
        !          1460:     return(val & DMASK);
        !          1461: 
        !          1462: }   /* End of get_data */
        !          1463: 
        !          1464: /*****************************************************************************/
        !          1465: 
        !          1466: get_char()
        !          1467: 
        !          1468: {
        !          1469: 
        !          1470:     int                ch;                     /* character we just read */
        !          1471: 
        !          1472: /*
        !          1473:  *
        !          1474:  * Reads the next character from file *fp_in and returns the value to the caller.
        !          1475:  * This routine isn't really needed, but we may want to deal directly with some
        !          1476:  * screwball file formats so I thought it would probably be a good idea to isolate
        !          1477:  * all the input in one routine that could be easily changed.
        !          1478:  *
        !          1479:  */
        !          1480: 
        !          1481:     if ( (ch = getc(fp_in)) != EOF )  {
        !          1482:        position++;
        !          1483:        ch &= CHMASK;
        !          1484:     }  /* End if */
        !          1485: 
        !          1486:     if ( debug == ON )
        !          1487:        fprintf(stderr, "%o ", ch);
        !          1488: 
        !          1489:     return(ch);
        !          1490: 
        !          1491: }   /* End of get_char */
        !          1492: 
        !          1493: /*****************************************************************************/
        !          1494: 
        !          1495: redirect(pg)
        !          1496: 
        !          1497:     int                pg;                     /* next page we're printing */
        !          1498: 
        !          1499: {
        !          1500: 
        !          1501:     static FILE        *fp_null = NULL;        /* if output is turned off */
        !          1502: 
        !          1503: /*
        !          1504:  *
        !          1505:  * If we're not supposed to print page pg, fp_out will be directed to /dev/null,
        !          1506:  * otherwise output goes to stdout.
        !          1507:  *
        !          1508:  */
        !          1509: 
        !          1510:     if ( pg >= 0 && in_olist(pg) == ON )
        !          1511:        fp_out = stdout;
        !          1512:     else if ( (fp_out = fp_null) == NULL )
        !          1513:        fp_out = fp_null = fopen("/dev/null", "w");
        !          1514: 
        !          1515: }   /* End of redirect */
        !          1516: 
        !          1517: /*****************************************************************************/
        !          1518: 

unix.superglobalmegacorp.com

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