Annotation of researchv10no/cmd/picasso/dpost.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  *
                      3:  * dpost - troff post-processor for PostScript printers.
                      4:  *
                      5:  * A program that translates output generated by the device independent troff
                      6:  * into PostScript. Much was borrowed from dimpress and dps (formally dlzw),
                      7:  * and even though the code has changed, credit has to be given to Richard
                      8:  * Flood for his early work on the PostScript driver.
                      9:  *
                     10:  * The big change is in the font table routines. The old binary format and
                     11:  * makedev are gone. dpost and troff now read ASCII tables, and both skip
                     12:  * unrecognized entries in the ASCII tables. That means problems, like where
                     13:  * to put the real name of the PostScript font, have disappeared. The added
                     14:  * flexibility means some overhead translating the ASCII tables, but the
                     15:  * overhead isn't too bad.
                     16:  *
                     17:  * dpost can also now calculate a reasonably tight BoundingBox, which helps
                     18:  * picture inclusion. The calculations, by default, are disabled. Couldn't
                     19:  * justify the overhead for a comment, particularly one that's only needed
                     20:  * occasionally. Use the -B option to get the comment.
                     21:  *
                     22:  * Output produced by dpost is still nonconforming. Definitions made in pages
                     23:  * and exported to the job's global environment are the primary problem. It's
                     24:  * an efficient approach, but means pages are not independent. Violations are
                     25:  * bracketed by %%BeginGlobal and %%EndGlobal comments and can be pulled into
                     26:  * the prologue by utility programs (like postreverse) that recognize the new
                     27:  * comments.
                     28:  *
                     29:  * The program handles files formatted for any device, although the best and
                     30:  * most efficient output is generated when the font and description files
                     31:  * match PostScript's resident fonts. Emulation is relatively expensive, and
                     32:  * can produce output files that are more than twice the size of the input
                     33:  * files.
                     34:  *
                     35:  * Several different methods can be used to encode lines of text. What's done
                     36:  * depends on the value assigned to encoding. Print time should decrease as
                     37:  * encoding increases (up to MAXENCODING). Setting encoding to 3 (or higher)
                     38:  * is not normally recommended. It's fast and produces very compact output,
                     39:  * but rounding errors in troff's width tables can accumulate and lead to a
                     40:  * ragged right margin. encoding can be changed on the command line using the
                     41:  * -e option.
                     42:  *
                     43:  * PostScript fonts don't support all of troff's characters. Some are built
                     44:  * by special PostScript procedures in directory *fontdir/devpost/charlib.
                     45:  * The charlib approach is not meant to replace user defined fonts. It was
                     46:  * a quick implementation designed to handle characters that aren't used
                     47:  * often - charlib should not be overused! The charlib lookup is triggered
                     48:  * when a character in a font table is assigned a code less than 32.
                     49:  *
                     50:  * Most defaults are set in the prologue, but can be changed by options. The
                     51:  * -P option passes arbitrary PostScript into the setup section of the output
                     52:  * file. It can be used to set (or change) values that can't be accessed by
                     53:  * other options. For example,
                     54:  *
                     55:  *     dpost -P'/useclippath false def' file > file.ps
                     56:  *
                     57:  * defines useclippath to be false. Everything passed through using the -P
                     58:  * (-C to copy a file) options become part of the job's global environment.
                     59:  * Definitions override defaults in the prologue.
                     60:  *
                     61:  * dpost expects to find the following procedures in the prologue:
                     62:  *
                     63:  *     setup
                     64:  *
                     65:  *       mark ... setup -
                     66:  *
                     67:  *         Initialization procedure mainly responsible for setting up an
                     68:  *         appropriate coordinate system.
                     69:  *
                     70:  *     pagesetup
                     71:  *
                     72:  *       page pagesetup -
                     73:  *
                     74:  *         Called at the start of each page, immediately after the page
                     75:  *         level save. Argument is the current page number.
                     76:  *
                     77:  *     setdecoding
                     78:  *
                     79:  *       num setdecoding -
                     80:  *
                     81:  *         Select the decoding procedure used to print text strings encoded
                     82:  *         by dpost. num is whatever has been assigned to encoding.
                     83:  *
                     84:  *     f
                     85:  *
                     86:  *       size font f -
                     87:  *
                     88:  *         Set the font and size used for character imaging. The font name
                     89:  *         argument is (normally) the name troff used. Mapping to the real
                     90:  *         PostScript font name is made using the fontname field in the
                     91:  *         ASCII width tables.
                     92:  *
                     93:  *     m
                     94:  *
                     95:  *       x y m -
                     96:  *
                     97:  *         Move to point (x, y). Not used for positioning words in text
                     98:  *         strings.
                     99:  *
                    100:  *     t
                    101:  *
                    102:  *       mark text t mark
                    103:  *
                    104:  *         Everything on the stack (up to the mark) is treated as a line
                    105:  *         of text to be decoded and printed. What's on the stack depends
                    106:  *         on encoding.
                    107:  *
                    108:  *     w
                    109:  *
                    110:  *       string x y w -
                    111:  *
                    112:  *         Print a single word starting at position (x, y). Only used in
                    113:  *         the more complicated encoding schemes, like the ones based on
                    114:  *         widthshow.
                    115:  *
                    116:  *     done
                    117:  *
                    118:  *         Make sure the last page prints. Always called, but only needed
                    119:  *         when printing more than one page on each sheet of paper.
                    120:  *
                    121:  * output language from troff:
                    122:  * all numbers are character strings
                    123:  * 
                    124:  * sn  size in points
                    125:  * fn  font as number from 1-n
                    126:  * cx  ascii character x
                    127:  * Cxyz        funny char xyz. terminated by white space
                    128:  * Hn  go to absolute horizontal position n
                    129:  * Vn  go to absolute vertical position n (down is positive)
                    130:  * hn  go n units horizontally (relative)
                    131:  * vn  ditto vertically
                    132:  * nnc move right nn, then print c (exactly 2 digits!)
                    133:  *             (this wart is an optimization that shrinks output file size
                    134:  *              about 35% and run-time about 15% while preserving ascii-ness)
                    135:  * Dt ...\n    draw operation 't':
                    136:  *     Dl x y          line from here by x,y
                    137:  *     Dc d            circle of diameter d with left side here
                    138:  *     De x y          ellipse of axes x,y with left side here
                    139:  *     Da x1 y1 x2 y2  arc counter-clockwise from current point (x, y) to
                    140:  *                     (x + x1 + x2, y + y1 + y2)
                    141:  *     D~ x y x y ...  wiggly line by x,y then x,y ...
                    142:  * nb a        end of line (information only -- no action needed)
                    143:  *     b = space before line, a = after
                    144:  * p   new page begins -- set v to 0
                    145:  * #...\n      comment
                    146:  * x ...\n     device control functions:
                    147:  *     x i     init
                    148:  *     x T s   name of device is s
                    149:  *     x r n h v       resolution is n/inch
                    150:  *             h = min horizontal motion, v = min vert
                    151:  *     x p     pause (can restart)
                    152:  *     x s     stop -- done forever
                    153:  *     x t     generate trailer
                    154:  *     x f n s font position n contains font s
                    155:  *     x H n   set character height to n
                    156:  *     x S n   set slant to N
                    157:  * 
                    158:  *     Subcommands like "i" are often spelled out like "init".
                    159:  *
                    160:  */
                    161: 
                    162: #include       <stdio.h>
                    163: #include       <fcntl.h>
                    164: #include       <signal.h>
                    165: #include       <math.h>
                    166: #include       <ctype.h>
                    167: #include       <time.h>
                    168: 
                    169: #include       "comments.h"            /* structuring comments */
                    170: #include       "gen.h"                 /* general purpose definitions */
                    171: #include       "path.h"                /* prologue and a few other files */
                    172: #include       "ext.h"                 /* external variable declarations */
                    173: #include       "font.h"                /* font table definitions */
                    174: #include       "dpost.h"               /* a few definitions just used here */
                    175: #include       "motion.h"              /* positioning macros */
                    176: 
                    177: char   *prologue = DPOST;              /* the PostScript prologue */
                    178: char   *colorfile = COLOR;             /* color support */
                    179: char   *drawfile = DRAW;               /* drawing routines */
                    180: char   *formfile = FORMFILE;           /* multiple pages on each sheet */
                    181: char   *baselinefile = BASELINE;       /* for text along curved baseline */
                    182: 
                    183: char   *fontdir = FONTDIR;             /* font table directories */
                    184: char   *hostfontdir = NULL;            /* host resident font directory */
                    185: 
                    186: char   *realdev = DEVNAME;             /* use these width tables */
                    187: char   devname[20] = "";               /* job formatted for this device */
                    188: int    emulate = FALSE;                /* TRUE if devname != realdev */
                    189: Fontmap        fontmap[] = FONTMAP;            /* font translation table - emulation */
                    190: 
                    191: int    copies = 1;                     /* copies of each sheet */
                    192: int    printed = 0;                    /* pages processed and printed */
                    193: int    formsperpage = 1;               /* pages on each sheet of paper */
                    194: int    picflag = ON;                   /* enable/disable picture inclusion */
                    195: 
                    196: int    encoding = DFLTENCODING;        /* how text is translated to PostScript */
                    197: int    realencoding = DFLTENCODING;    /* where we started */
                    198: int    maxencoding = MAXENCODING;      /* max that users can select */
                    199: 
                    200: int    landscape = FALSE;              /* for BoundingBox calculations only */
                    201: double magnification = 1.0;
                    202: double xoffset = 0.0;
                    203: double yoffset = 0.0;
                    204: 
                    205: int    smnt;                           /* special fonts start here */
                    206: int    devres;                         /* device resolution */
                    207: int    unitwidth;                      /* and unitwidth - from DESC file */
                    208: 
                    209: char   downloaded[MAXCH+32];           /* status of charlib characters */
                    210: 
                    211: int    nfonts = 0;                     /* number of font positions */
                    212: int    size = 10;                      /* current point size */
                    213: int    font = 0;                       /* and font position */
                    214: int    hpos = 0;                       /* where troff wants to be */
                    215: int    vpos = 0;
                    216: float  lastw = 0;                      /* width of the last input character */
                    217: int    lastc = 0;                      /* its name (or index) - for charlib() */
                    218: 
                    219: int    fontheight = 0;                 /* points from x H ... */
                    220: int    fontslant = 0;                  /* angle from x S ... */
                    221: 
                    222: int    res;                            /* resolution assumed in input file */
                    223: float  widthfac = 1.0;                 /* for emulation = res/devres */
                    224: 
                    225: int    lastsize = -1;                  /* for tracking printer's current size */
                    226: int    lastfont = -1;                  /* current font */
                    227: float  lastx = -1;                     /* and current position */
                    228: int    lasty = -1;
                    229: int    lastend;                        /* where last character on this line was */
                    230: 
                    231: int    seenpage = FALSE;               /* expect fonts are now all mounted */
                    232: int    gotspecial = FALSE;             /* append special fonts - emulation */
                    233: 
                    234: float  pointslop = SLOP;               /* horizontal error in points */
                    235: int    slop;                           /* and machine units */
                    236: int    rvslop;                         /* to extend box in reverse video mode */
                    237: 
                    238: int    textcount = 0;                  /* strings accumulated so far */
                    239: int    stringstart = 0;                /* where the next one starts */
                    240: int    spacecount = 0;                 /* spaces in current string */
                    241: 
                    242: Line   line[MAXSTACK+3];               /* data about words accumulated so far */
                    243: char   strings[STRINGSPACE];           /* strings temporarily saved here */
                    244: char   *strptr;                        /* next free slot in strings[] */
                    245: 
                    246: FILE   *tf = NULL;                     /* most output goes here */
                    247: FILE   *fp_acct = NULL;                /* accounting file */
                    248: 
                    249: char   *optnames = "a:c:e:m:n:o:p:tw:x:y:A:BC:J:F:H:L:OP:R:S:T:DI";
                    250: 
                    251: extern int     gotcolor;               /* read *colorfile when TRUE */
                    252: extern Font    fonts[];                /* data about every font we see */
                    253: extern Font    *mount[];               /* troff mounts fonts here */
                    254: 
                    255: /*****************************************************************************/
                    256: 
                    257: main(agc, agv)
                    258: 
                    259:     int                agc;
                    260:     char       *agv[];
                    261: 
                    262: {
                    263: 
                    264: /*
                    265:  *
                    266:  * Translates output from troff into PostScript. Input files must be formatted
                    267:  * for the same device. Each input file begins on a new page.
                    268:  *
                    269:  */
                    270: 
                    271:     argc = agc;                                /* global so everyone can use them */
                    272:     argv = agv;
                    273: 
                    274:     prog_name = argv[0];               /* for error messages */
                    275: 
                    276:     init_signals();                    /* interrupt handling */
                    277:     header();                          /* structuring comments */
                    278:     options();                         /* command line options */
                    279:     arguments();                       /* translate the input files */
                    280:     done();                            /* add trailing comments etc. */
                    281:     account();                         /* job accounting data */
                    282: 
                    283:     exit(x_stat);
                    284: 
                    285: }   /* End of main */
                    286: 
                    287: /*****************************************************************************/
                    288: 
                    289: init_signals()
                    290: 
                    291: {
                    292: 
                    293:     int                interrupt();
                    294: 
                    295: /*
                    296:  *
                    297:  * Make sure we handle interrupts.
                    298:  *
                    299:  */
                    300: 
                    301:     if ( signal(SIGINT, interrupt) == SIG_IGN ) {
                    302:        signal(SIGINT, SIG_IGN);
                    303:        signal(SIGQUIT, SIG_IGN);
                    304:        signal(SIGHUP, SIG_IGN);
                    305:     } else {
                    306:        signal(SIGHUP, interrupt);
                    307:        signal(SIGQUIT, interrupt);
                    308:     }   /* End else */
                    309: 
                    310:     signal(SIGTERM, interrupt);
                    311: 
                    312: }   /* End of init_signals */
                    313: 
                    314: /*****************************************************************************/
                    315: 
                    316: header()
                    317: 
                    318: {
                    319: 
                    320:     int                ch;
                    321:     int                old_optind = optind;
                    322: 
                    323: /*
                    324:  *
                    325:  * Scan the option list for things needed now (e.g. prologue file), but could
                    326:  * be changed from defaults. An attempt to follow to Adobe's 2.0 structuring
                    327:  * conventions.
                    328:  *
                    329:  */
                    330: 
                    331:     while ( (ch = getopt(argc, argv, optnames)) != EOF )
                    332:        if ( ch == 'L' )
                    333:            setpaths(optarg);
                    334:        else if ( ch == 'B' )
                    335:            dobbox = TRUE;
                    336:        else if ( ch == '?' )
                    337:            error(FATAL, "");
                    338: 
                    339:     optind = old_optind;               /* restored for options() */
                    340: 
                    341:     fprintf(stdout, "%s", NONCONFORMING);
                    342:     fprintf(stdout, "%s %s\n", VERSION, PROGRAMVERSION);
                    343:     fprintf(stdout, "%s %s\n", DOCUMENTFONTS, ATEND);
                    344:     fprintf(stdout, "%s %s\n", PAGES, ATEND);
                    345:     if ( dobbox == TRUE )
                    346:        fprintf(stdout, "%s %s\n", BOUNDINGBOX, ATEND);
                    347:     fprintf(stdout, "%s", ENDCOMMENTS);
                    348: 
                    349:     if ( cat(prologue) == FALSE )
                    350:        error(FATAL, "can't read %s", prologue);
                    351: 
                    352:     if ( DOROUND )
                    353:        cat(ROUNDPAGE);
                    354: 
                    355:     fprintf(stdout, "%s", ENDPROLOG);
                    356:     fprintf(stdout, "%s", BEGINSETUP);
                    357:     fprintf(stdout, "mark\n");
                    358: 
                    359: }   /* End of header */
                    360: 
                    361: /*****************************************************************************/
                    362: 
                    363: options()
                    364: 
                    365: {
                    366: 
                    367:     int                ch;
                    368: 
                    369:     extern char        *optarg;
                    370:     extern int optind;
                    371: 
                    372: /*
                    373:  *
                    374:  * Command line options - there are too many!
                    375:  *
                    376:  */
                    377: 
                    378:     while ( (ch = getopt(argc, argv, optnames)) != EOF ) {
                    379:        switch ( ch ) {
                    380:            case 'a':                   /* aspect ratio */
                    381:                    fprintf(stdout, "/aspectratio %s def\n", optarg);
                    382:                    break;
                    383: 
                    384:            case 'c':                   /* number of copies */
                    385:                    copies = atoi(optarg);
                    386:                    fprintf(stdout, "/#copies %s store\n", optarg);
                    387:                    break;
                    388: 
                    389:            case 'e':                   /* select the encoding scheme */
                    390:                    if ( (encoding = atoi(optarg)) < 0 || encoding > MAXENCODING )
                    391:                        encoding = DFLTENCODING;
                    392:                    realencoding = encoding;
                    393:                    break;
                    394: 
                    395:            case 'm':                   /* magnification */
                    396:                    magnification = atof(optarg);
                    397:                    fprintf(stdout, "/magnification %s def\n", optarg);
                    398:                    break;
                    399: 
                    400:            case 'n':                   /* forms per page */
                    401:                    formsperpage = atoi(optarg);
                    402:                    fprintf(stdout, "%s %s\n", FORMSPERPAGE, optarg);
                    403:                    fprintf(stdout, "/formsperpage %s def\n", optarg);
                    404:                    break;
                    405: 
                    406:            case 'o':                   /* output page list */
                    407:                    out_list(optarg);
                    408:                    break;
                    409: 
                    410:            case 'p':                   /* landscape or portrait mode */
                    411:                    landscape = (*optarg == 'l') ? TRUE : FALSE;
                    412:                    if ( landscape == TRUE )
                    413:                        fprintf(stdout, "/landscape true def\n");
                    414:                    else fprintf(stdout, "/landscape false def\n");
                    415:                    break;
                    416: 
                    417:            case 't':                   /* compatibility */
                    418:                    break;
                    419: 
                    420:            case 'w':                   /* line width - for drawing */
                    421:                    fprintf(stdout, "/linewidth %s def\n", optarg);
                    422:                    break;
                    423: 
                    424:            case 'x':                   /* shift horizontally */
                    425:                    xoffset = atof(optarg);
                    426:                    fprintf(stdout, "/xoffset %s def\n", optarg);
                    427:                    break;
                    428: 
                    429:            case 'y':                   /* shift vertically */
                    430:                    yoffset = atof(optarg);
                    431:                    fprintf(stdout, "/yoffset %s def\n", optarg);
                    432:                    break;
                    433: 
                    434:            case 'A':                   /* job accounting */
                    435:            case 'J':
                    436:                    if ( (fp_acct = fopen(optarg, "a")) == NULL )
                    437:                        error(FATAL, "can't open accounting file %s", optarg);
                    438:                    break;
                    439: 
                    440:            case 'B':                   /* enable BoundingBox calculations */
                    441:                    dobbox = TRUE;
                    442:                    fprintf(stdout, "/rotation 1 def\n");
                    443:                    fprintf(stdout, "/gotpagebbox true def\n");
                    444:                    break;
                    445: 
                    446:            case 'C':                   /* copy file to output */
                    447:                    if ( cat(optarg) == FALSE )
                    448:                        error(FATAL, "can't read %s", optarg);
                    449:                    break;
                    450: 
                    451:            case 'F':                   /* font table directory */
                    452:                    fontdir = optarg;
                    453:                    break;
                    454: 
                    455:            case 'H':                   /* host resident font directory */
                    456:                    hostfontdir = optarg;
                    457:                    break;
                    458: 
                    459:            case 'L':                   /* prologue file */
                    460:                    setpaths(optarg);   /* already been done in header() */
                    461:                    break;
                    462: 
                    463:            case 'O':                   /* disable picture inclusion */
                    464:                    picflag = OFF;
                    465:                    break;
                    466: 
                    467:            case 'P':                   /* copy string to output */
                    468:                    fprintf(stdout, "%s\n", optarg);
                    469:                    break;
                    470: 
                    471:            case 'R':                   /* global or page level request */
                    472:                    saverequest(optarg);
                    473:                    break;
                    474: 
                    475:            case 'S':                   /* horizontal position error */
                    476:                    if ( (pointslop = atof(optarg)) < 0 )
                    477:                        pointslop = 0;
                    478:                    break;
                    479: 
                    480:            case 'T':                   /* target printer */
                    481:                    realdev = optarg;
                    482:                    break;
                    483: 
                    484:            case 'D':                   /* debug flag */
                    485:                    debug = ON;
                    486:                    tf = stdout;
                    487:                    break;
                    488: 
                    489:            case 'I':                   /* ignore FATAL errors */
                    490:                    ignore = ON;
                    491:                    break;
                    492: 
                    493:            case '?':                   /* don't know the option */
                    494:                    error(FATAL, "");
                    495:                    break;
                    496: 
                    497:            default:
                    498:                    error(FATAL, "missing case for option %c", ch);
                    499:                    break;
                    500:        }   /* End switch */
                    501:     }  /* End while */
                    502: 
                    503:     argc -= optind;
                    504:     argv += optind;
                    505: 
                    506: }   /* End of options */
                    507: 
                    508: /*****************************************************************************/
                    509: 
                    510: setpaths(name)
                    511: 
                    512:     char       *name;
                    513: 
                    514: {
                    515: 
                    516:     char       *path;
                    517: 
                    518: /*
                    519:  *
                    520:  * Extends the -L option to permit modification of more than just the prologue
                    521:  * file pathname. Syntax is -Lpath or -Lname:path. For debugging and development
                    522:  * only!
                    523:  *
                    524:  */
                    525: 
                    526:     for ( path = name; *path; path++ )
                    527:        if ( *path == ':' || *path == ' ' ) {
                    528:            while ( *path == ':' || *path == ' ' ) path++;
                    529:            break;
                    530:        }   /* End if */
                    531: 
                    532:     if ( *path == '\0' )               /* didn't find "name:" prefix */
                    533:        path = name;
                    534: 
                    535:     if ( path == name || strncmp(name, "prologue", strlen("prologue")) == 0 )
                    536:        prologue = path;
                    537:     else if ( strncmp(name, "draw", strlen("draw")) == 0 )
                    538:        drawfile = path;
                    539:     else if ( strncmp(name, "color", strlen("color")) == 0 )
                    540:        colorfile = path;
                    541:     else if ( strncmp(name, "form", strlen("form")) == 0 )
                    542:        formfile = path;
                    543:     else if ( strncmp(name, "baseline", strlen("baseline")) == 0 )
                    544:        baselinefile = path;
                    545: 
                    546: }   /* End of setpaths */
                    547: 
                    548: /*****************************************************************************/
                    549: 
                    550: setup()
                    551: 
                    552: {
                    553: 
                    554:     double     t;
                    555: 
                    556: /*
                    557:  *
                    558:  * Job and BoundingBox initialization. Called once from t_init() - must know
                    559:  * the resolution before generating the PostScript call to setup.
                    560:  *
                    561:  */
                    562: 
                    563:     writerequest(0, stdout);           /* global requests e.g. manual feed */
                    564:     fprintf(stdout, "/resolution %d def\n", res);
                    565:     fprintf(stdout, "setup\n");
                    566:     fprintf(stdout, "%d setdecoding\n", realencoding);
                    567: 
                    568:     if ( formsperpage > 1 ) {          /* multiple pages */
                    569:        if ( cat(formfile) == FALSE )
                    570:            error(FATAL, "can't read %s", formfile);
                    571:        fprintf(stdout, "%d setupforms\n", formsperpage);
                    572:     }  /* End if */
                    573: 
                    574:     fprintf(stdout, "%s", ENDSETUP);
                    575: 
                    576:     if ( dobbox == TRUE ) {            /* ctm[] - must agree with prologue */
                    577:        translate(pagewidth/2.0, pageheight/2.0);
                    578:        if ( landscape == TRUE ) {
                    579:            rotate(90.0);
                    580:            t = pagewidth;
                    581:            pagewidth = pageheight;
                    582:            pageheight = t;
                    583:        }   /* End if */
                    584:        translate(-pagewidth/2.0, pageheight/2.0);
                    585:        translate(72.0 * xoffset, -72.0 * yoffset);
                    586:        scale(magnification, magnification);
                    587:        scale(72.0/devres, 72.0/devres);
                    588:     }  /* End if */
                    589: 
                    590: }   /* End of setup */
                    591: 
                    592: /*****************************************************************************/
                    593: 
                    594: arguments()
                    595: 
                    596: {
                    597: 
                    598:     FILE       *fp;
                    599: 
                    600: /*
                    601:  *
                    602:  * Everything else is an input file. No arguments or '-' means stdin.
                    603:  *
                    604:  */
                    605: 
                    606:     if ( argc < 1 )
                    607:        conv(stdin);
                    608:     else
                    609:        while ( argc > 0 ) {
                    610:            if ( strcmp(*argv, "-") == 0 )
                    611:                fp = stdin;
                    612:            else if ( (fp = fopen(*argv, "r")) == NULL )
                    613:                error(FATAL, "can't open %s", *argv);
                    614:            conv(fp);
                    615:            if ( fp != stdin )
                    616:                fclose(fp);
                    617:            argc--;
                    618:            argv++;
                    619:        }   /* End while */
                    620: 
                    621: }   /* End of arguments */
                    622: 
                    623: /*****************************************************************************/
                    624: 
                    625: done()
                    626: 
                    627: {
                    628: 
                    629:     int                i;
                    630:     int                n;
                    631: 
                    632: /*
                    633:  *
                    634:  * Force out the last page and add trailing comments.
                    635:  *
                    636:  */
                    637: 
                    638:     fprintf(stdout, "%s", TRAILER);
                    639:     fprintf(stdout, "done\n");
                    640:     fprintf(stdout, "%s %d\n", PAGES, printed);
                    641: 
                    642:     for ( i = 0, n = 0; i < MAXFONTS+1; i++ )
                    643:        if ( (fonts[i].flags & USED) && fonts[i].fontname != NULL ) {
                    644:            if ( n++ == 0 )
                    645:                fprintf(stdout, "%s", DOCUMENTFONTS);
                    646:            else if ( (n - 1) % 8 == 0 )
                    647:                fprintf(stdout, "\n%s", CONTINUECOMMENT);
                    648:            fprintf(stdout, " %s", fonts[i].fontname);
                    649:        }   /* End if */
                    650:     if ( n > 0 )
                    651:        putc('\n', stdout);
                    652: 
                    653:     if ( dobbox == TRUE )
                    654:        writebbox(stdout, BOUNDINGBOX, 10);
                    655: 
                    656: }   /* End of done */
                    657: 
                    658: /*****************************************************************************/
                    659: 
                    660: account()
                    661: 
                    662: {
                    663: 
                    664: /*
                    665:  *
                    666:  * Accounting record to fp_acct - provided it's not NULL.
                    667:  *
                    668:  */
                    669: 
                    670:     if ( fp_acct != NULL )
                    671:        fprintf(fp_acct, " print %d\n copies %d\n", printed, copies);
                    672: 
                    673: }   /* End of account */
                    674: 
                    675: /*****************************************************************************/
                    676: 
                    677: conv(fp)
                    678: 
                    679:     register FILE      *fp;
                    680: 
                    681: {
                    682: 
                    683:     register int       c;
                    684:     int                        m, n, n1, m1;
                    685:     char               str[50];
                    686: 
                    687: /*
                    688:  *
                    689:  * Read troff output from file fp and translate it into PostScript. The final
                    690:  * t_page() call means input files start on a new page.
                    691:  *
                    692:  */
                    693: 
                    694:     redirect(-1);                      /* do output only after a page command */
                    695:     lineno = 1;
                    696: 
                    697:     while ((c = getc(fp)) != EOF) {
                    698:        switch (c) {
                    699:            case '\n':                  /* just count this line */
                    700:                    lineno++;
                    701:                    break;
                    702: 
                    703:            case ' ':                   /* when input is text */
                    704:            case 0:                     /* occasional noise creeps in */
                    705:                    break;
                    706: 
                    707:            case '0': case '1': case '2': case '3': case '4':
                    708:            case '5': case '6': case '7': case '8': case '9':
                    709:                    /* two motion digits plus a character */
                    710:                    hmot((c-'0')*10 + getc(fp)-'0');
                    711:                    put1(getc(fp));
                    712:                    break;
                    713: 
                    714:            case 'c':                   /* single ascii character */
                    715:                    put1(getc(fp));
                    716:                    break;
                    717: 
                    718:            case 'C':                   /* special character */
                    719:                    fscanf(fp, "%s", str);
                    720:                    put1(chindex(str));
                    721:                    break;
                    722: 
                    723:            case 'N':                   /* character at position n */
                    724:                    fscanf(fp, "%d", &m);
                    725:                    flushtext();
                    726:                    oput(m);
                    727:                    break;
                    728: 
                    729:            case 'D':                   /* drawing functions */
                    730:                    flushtext();
                    731:                    getdraw();
                    732:                    if ( size != lastsize )
                    733:                        t_sf();
                    734:                    switch ((c=getc(fp))) {
                    735:                        case 'p':       /* draw a path */
                    736:                            while (fscanf(fp, "%d %d", &n, &m) == 2)
                    737:                                drawline(n, m);
                    738:                            lineno++;
                    739:                            break;
                    740: 
                    741:                        case 'l':       /* draw a line */
                    742:                            fscanf(fp, "%d %d %c", &n, &m, &n1);
                    743:                            drawline(n, m);
                    744:                            break;
                    745: 
                    746:                        case 'c':       /* circle */
                    747:                            fscanf(fp, "%d", &n);
                    748:                            drawcirc(n);
                    749:                            break;
                    750: 
                    751:                        case 'e':       /* ellipse */
                    752:                            fscanf(fp, "%d %d", &m, &n);
                    753:                            drawellip(m, n);
                    754:                            break;
                    755: 
                    756:                        case 'a':       /* counter-clockwise arc */
                    757:                        case 'A':       /* clockwise arc */
                    758:                            fscanf(fp, "%d %d %d %d", &n, &m, &n1, &m1);
                    759:                            drawarc(n, m, n1, m1, c);
                    760:                            break;
                    761: 
                    762:                        case 'q':       /* spline without end points */
                    763:                            drawspline(fp, 1);
                    764:                            lineno++;
                    765:                            break;
                    766: 
                    767:                        case '~':       /* wiggly line */
                    768:                            drawspline(fp, 2);
                    769:                            lineno++;
                    770:                            break;
                    771: 
                    772:                        default:
                    773:                            error(FATAL, "unknown drawing function %c", c);
                    774:                            break;
                    775:                    }   /* End switch */
                    776:                    break;
                    777: 
                    778:            case 's':                   /* use this point size */
                    779:                    fscanf(fp, "%d", &size);    /* ignore fractional sizes */
                    780:                    break;
                    781: 
                    782:            case 'f':                   /* use font mounted here */
                    783:                    fscanf(fp, "%s", str);
                    784:                    setfont(t_font(str));
                    785:                    break;
                    786: 
                    787:            case 'H':                   /* absolute horizontal motion */
                    788:                    fscanf(fp, "%d", &n);
                    789:                    hgoto(n);
                    790:                    break;
                    791: 
                    792:            case 'h':                   /* relative horizontal motion */
                    793:                    fscanf(fp, "%d", &n);
                    794:                    hmot(n);
                    795:                    break;
                    796: 
                    797:            case 'w':                   /* word space */
                    798:                    break;
                    799: 
                    800:            case 'V':                   /* absolute vertical position */
                    801:                    fscanf(fp, "%d", &n);
                    802:                    vgoto(n);
                    803:                    break;
                    804: 
                    805:            case 'v':                   /* relative vertical motion */
                    806:                    fscanf(fp, "%d", &n);
                    807:                    vmot(n);
                    808:                    break;
                    809: 
                    810:            case 'p':                   /* new page */
                    811:                    fscanf(fp, "%d", &n);
                    812:                    t_page(n);
                    813:                    break;
                    814: 
                    815:            case 'n':                   /* end of line */
                    816:                    while ( (c = getc(fp)) != '\n' && c != EOF ) ;
                    817:                    hgoto(0);
                    818:                    lineno++;
                    819:                    break;
                    820: 
                    821:            case '#':                   /* comment */
                    822:                    while ( (c = getc(fp)) != '\n' && c != EOF ) ;
                    823:                    lineno++;
                    824:                    break;
                    825: 
                    826:            case 'x':                   /* device control function */
                    827:                    devcntrl(fp);
                    828:                    lineno++;
                    829:                    break;
                    830: 
                    831:            default:
                    832:                    error(FATAL, "unknown input character %o %c", c, c);
                    833:                    done();
                    834:        }   /* End switch */
                    835:     }  /* End while */
                    836: 
                    837:     t_page(-1);                                /* print the last page */
                    838:     flushtext();
                    839: 
                    840: }   /* End of conv */
                    841: 
                    842: /*****************************************************************************/
                    843: 
                    844: devcntrl(fp)
                    845: 
                    846:     FILE       *fp;
                    847: 
                    848: {
                    849: 
                    850:     char       str[50], buf[256], str1[50];
                    851:     int                c, n;
                    852: 
                    853: /*
                    854:  *
                    855:  * Interpret device control commands, ignoring any we don't recognize. The
                    856:  * "x X ..." commands are a device dependent collection generated by troff's
                    857:  * \X'...' request.
                    858:  *
                    859:  */
                    860: 
                    861:     fscanf(fp, "%s", str);
                    862: 
                    863:     switch ( str[0] ) {
                    864:        case 'f':                       /* load font in a position */
                    865:                fscanf(fp, "%d %s", &n, str);
                    866:                fgets(buf, sizeof buf, fp);     /* in case there's a filename */
                    867:                ungetc('\n', fp);       /* fgets() goes too far */
                    868:                str1[0] = '\0';         /* in case there's nothing to come in */
                    869:                sscanf(buf, "%s", str1);
                    870:                loadfont(n, str, str1);
                    871:                break;
                    872: 
                    873:        case 'i':                       /* initialize */
                    874:                t_init();
                    875:                break;
                    876: 
                    877:        case 'p':                       /* pause */
                    878:                break;
                    879: 
                    880:        case 'r':                       /* resolution assumed when prepared */
                    881:                fscanf(fp, "%d", &res);
                    882:                break;
                    883: 
                    884:        case 's':                       /* stop */
                    885:        case 't':                       /* trailer */
                    886:                flushtext();
                    887:                break;
                    888: 
                    889:        case 'H':                       /* char height */
                    890:                fscanf(fp, "%d", &n);
                    891:                t_charht(n);
                    892:                break;
                    893: 
                    894:        case 'S':                       /* slant */
                    895:                fscanf(fp, "%d", &n);
                    896:                t_slant(n);
                    897:                break;
                    898: 
                    899:        case 'T':                       /* device name - set emulating here */
                    900:                fscanf(fp, "%s", devname);
                    901:                emulate = strcmp(devname, realdev) ? TRUE : FALSE;
                    902:                break;
                    903: 
                    904:        case 'X':                       /* copy through - from troff */
                    905:                fscanf(fp, " %[^: \n]:", str);
                    906:                fgets(buf, sizeof(buf), fp);
                    907:                ungetc('\n', fp);
                    908:                if ( strcmp(str, "PI") == 0 || strcmp(str, "PictureInclusion") == 0 )
                    909:                    picture(buf);
                    910:                else if ( strcmp(str, "InlinePicture") == 0 )
                    911:                    inlinepic(fp, buf);
                    912:                else if ( strcmp(str, "BeginPath") == 0 )
                    913:                    beginpath(buf, FALSE);
                    914:                else if ( strcmp(str, "DrawPath") == 0 )
                    915:                    drawpath(buf, FALSE);
                    916:                else if ( strcmp(str, "BeginObject") == 0 )
                    917:                    beginpath(buf, TRUE);
                    918:                else if ( strcmp(str, "EndObject") == 0 )
                    919:                    drawpath(buf, TRUE);
                    920:                else if ( strcmp(str, "NewBaseline") == 0 )
                    921:                    newbaseline(buf);
                    922:                else if ( strcmp(str, "DrawText") == 0 )
                    923:                    drawtext(buf);
                    924:                else if ( strcmp(str, "SetText") == 0 )
                    925:                    settext(buf);
                    926:                else if ( strcmp(str, "SetColor") == 0 ) {
                    927:                    newcolor(buf);
                    928:                    setcolor();
                    929:                } else if ( strcmp(str, "PS") == 0 || strcmp(str, "PostScript") == 0 ) {
                    930:                    flushtext();
                    931:                    xymove(hpos, vpos);
                    932:                    fprintf(tf, "%s", buf);
                    933:                }   /* End else */
                    934:                break;
                    935:     }  /* End switch */
                    936: 
                    937:     while ( (c = getc(fp)) != '\n' && c != EOF ) ;
                    938: 
                    939: }   /* End of devcntrl */
                    940: 
                    941: /*****************************************************************************/
                    942: 
                    943: loadfont(m, f, dir)
                    944: 
                    945:     int                m;
                    946:     char       *f;
                    947:     char       *dir;
                    948: 
                    949: {
                    950: 
                    951:     char       path[150];
                    952: 
                    953: /*
                    954:  *
                    955:  * Load position m with font f. Font file pathname is *fontdir/dev*realdev/*f
                    956:  * or *dir/*f, if dir isn't empty. Use mapfont() to replace the missing font
                    957:  * if we're emulating another device, dir is empty, and the first mount fails.
                    958:  *
                    959:  */
                    960: 
                    961:     if ( dir[0] == '\0' )
                    962:        sprintf(path, "%s/dev%s/%s", fontdir, realdev, f);
                    963:     else sprintf(path, "%s/%s", dir, f);
                    964: 
                    965:     if ( mountfont(path, m) == -1 ) {
                    966:        if ( dir[0] == '\0' ) {
                    967:            sprintf(path, "%s/dev%s/%s", fontdir, realdev, mapfont(f));
                    968:            if ( mountfont(path, m) == -1 ) {
                    969:                sprintf(path, "%s/dev%s/%s", fontdir, realdev, f);
                    970:                error(FATAL, "can't load %s at %d", path, m);
                    971:            }   /* End if */
                    972:        } else error(FATAL, "can't load %s at %d", path, m);
                    973:     }  /* End if */
                    974: 
                    975:     if ( smnt == 0 && mount[m]->specfont )
                    976:        smnt = m;
                    977: 
                    978:     if ( m == lastfont )               /* force a call to t_sf() */
                    979:        lastfont = -1;
                    980: 
                    981:     if ( m > nfonts ) {                        /* got more positions */
                    982:        nfonts = m;
                    983:        gotspecial = FALSE;
                    984:     }  /* End if */
                    985: 
                    986: }   /* End of loadfont */
                    987: 
                    988: /*****************************************************************************/
                    989: 
                    990: char *mapfont(name)
                    991: 
                    992:     char       *name;
                    993: 
                    994: {
                    995: 
                    996:     int                i;
                    997: 
                    998: /*
                    999:  *
                   1000:  * Map a missing font name into one that should be available. Only used when
                   1001:  * we're emulating another device and the first mount fails. Consider deleting
                   1002:  * this routine.
                   1003:  *
                   1004:  */
                   1005: 
                   1006:     for ( i = 0; fontmap[i].name != NULL; i++ )
                   1007:        if ( strcmp(name, fontmap[i].name) == 0 )
                   1008:            return(fontmap[i].use);
                   1009: 
                   1010:     switch ( *++name ) {
                   1011:        case 'I': return("I");
                   1012:        case 'B': return("B");
                   1013:        case 'X': return("BI");
                   1014:        default:  return("R");
                   1015:     }  /* End switch */
                   1016: 
                   1017: }   /* End of mapfont */
                   1018: 
                   1019: /*****************************************************************************/
                   1020: 
                   1021: loadspecial()
                   1022: 
                   1023: {
                   1024: 
                   1025: /*
                   1026:  *
                   1027:  * Fix - later.
                   1028:  *
                   1029:  */
                   1030: 
                   1031:     gotspecial = TRUE;
                   1032: 
                   1033: }   /* End of loadspecial */
                   1034: 
                   1035: /*****************************************************************************/
                   1036: 
                   1037: t_init()
                   1038: 
                   1039: {
                   1040: 
                   1041:     char       path[150];
                   1042:     static int initialized = FALSE;
                   1043: 
                   1044: /*
                   1045:  *
                   1046:  * Finish initialization - just read an "x init" command. Assumes we already
                   1047:  * know the input file resolution.
                   1048:  *
                   1049:  */
                   1050: 
                   1051:     flushtext();                       /* moved - for cat'ed troff files */
                   1052: 
                   1053:     if ( initialized == FALSE ) {
                   1054:        sprintf(path, "%s/dev%s/DESC", fontdir, realdev);
                   1055:        if ( getdesc(path) == -1 )
                   1056:            error(FATAL, "can't open %s", path);
                   1057:        nfonts = 0;
                   1058:        gotspecial = FALSE;
                   1059:        widthfac = (float) res /devres;
                   1060:        slop = pointslop * res / POINTS + .5;
                   1061:        rvslop = res * .025;
                   1062:        setup();
                   1063:        initialized = TRUE;
                   1064:     }  /* End if */
                   1065: 
                   1066:     hpos = vpos = 0;
                   1067:     size = 10;
                   1068:     reset();
                   1069: 
                   1070: }   /* End of t_init */
                   1071: 
                   1072: /*****************************************************************************/
                   1073: 
                   1074: t_page(pg)
                   1075: 
                   1076:     int                pg;
                   1077: 
                   1078: {
                   1079: 
                   1080:     static int lastpg = 0;
                   1081: 
                   1082: /*
                   1083:  *
                   1084:  * Finish the previous page and get ready for the next one. End page output
                   1085:  * goes to /dev/null at the start of each input file. Start page output goes
                   1086:  * to /dev/null at the end of each input file.
                   1087:  *
                   1088:  * Consider doing showpage after page level restore (as Adobe recommends). If
                   1089:  * the order is changed use restore() and save(). forms.ps will likely also
                   1090:  * need fixing.
                   1091:  *
                   1092:  */
                   1093: 
                   1094:     if ( tf == stdout )
                   1095:        printed++;
                   1096: 
                   1097:     flushtext();                       /* just in case */
                   1098: 
                   1099:     fprintf(tf, "cleartomark\n");
                   1100:     fprintf(tf, "showpage\n");
                   1101:     fprintf(tf, "saveobj restore\n");
                   1102:     if ( dobbox == TRUE )
                   1103:        writebbox(tf, PAGEBOUNDINGBOX, 10);
                   1104:     fprintf(tf, "%s %d %d\n", ENDPAGE, lastpg, printed);
                   1105: 
                   1106:     redirect(pg);
                   1107: 
                   1108:     fprintf(tf, "%s %d %d\n", PAGE, pg, printed+1);
                   1109:     if ( dobbox == TRUE )
                   1110:        fprintf(tf, "%s %s\n", PAGEBOUNDINGBOX, ATEND);
                   1111:     fprintf(tf, "/saveobj save def\n");
                   1112:     fprintf(tf, "mark\n");
                   1113:     writerequest(printed+1, tf);
                   1114:     fprintf(tf, "%d pagesetup\n", printed+1);
                   1115: 
                   1116:     if ( encoding != realencoding )
                   1117:        fprintf(tf, "%d setdecoding\n", encoding);
                   1118: 
                   1119:     if ( gotcolor == TRUE )
                   1120:        setcolor();
                   1121: 
                   1122:     lastpg = pg;                       /* for the next ENDPAGE comment */
                   1123:     hpos = vpos = 0;                   /* get ready for the next page */
                   1124:     reset();                           /* force position and font stuff - later */
                   1125: 
                   1126:     seenpage = TRUE;
                   1127: 
                   1128: }   /* End of t_page */
                   1129: 
                   1130: /*****************************************************************************/
                   1131: 
                   1132: t_font(s)
                   1133: 
                   1134:     char       *s;
                   1135: 
                   1136: {
                   1137: 
                   1138:     int                n;
                   1139: 
                   1140: /*
                   1141:  *
                   1142:  * Converts the string *s into an integer and checks to make sure it's a legal
                   1143:  * font position. Also arranges to mount all the special fonts after the last
                   1144:  * legitimate font (by calling loadspecial()), provided it hasn't already been
                   1145:  * done.
                   1146:  *
                   1147:  */
                   1148: 
                   1149:     n = atoi(s);
                   1150: 
                   1151:     if ( seenpage == TRUE ) {
                   1152:        if ( n < 0 || n > nfonts )
                   1153:            error(FATAL, "illegal font position %d", n);
                   1154: 
                   1155:        if ( gotspecial == FALSE )
                   1156:            loadspecial();
                   1157:     }  /* End if */
                   1158: 
                   1159:     return(n);
                   1160: 
                   1161: }   /* End of t_font */
                   1162: 
                   1163: /*****************************************************************************/
                   1164: 
                   1165: setfont(m)
                   1166: 
                   1167:     int                m;
                   1168: 
                   1169: {
                   1170: 
                   1171: /*
                   1172:  *
                   1173:  * Use the font mounted at position m. Bounds checks are probably unnecessary.
                   1174:  * Changing the font and size used by the printer is handled in t_sf().
                   1175:  *
                   1176:  */
                   1177: 
                   1178:     if ( m < 0 || m > MAXFONTS )
                   1179:        error(FATAL, "illegal font %d", m);
                   1180:     font = m;
                   1181: 
                   1182: }   /* End of setfont */
                   1183: 
                   1184: /*****************************************************************************/
                   1185: 
                   1186: t_sf()
                   1187: 
                   1188: {
                   1189: 
                   1190:     Font       *fpos;
                   1191:     char       temp[150];
                   1192: 
                   1193: /*
                   1194:  *
                   1195:  * Force a new font or size. Generates name definitions for fonts that haven't
                   1196:  * been named, grabs host resident font files and keeps track of the fonts used
                   1197:  * by this job. When necessary also adjusts the font's height and slant. Should
                   1198:  * only be called immediately before printing a character.
                   1199:  *
                   1200:  */
                   1201: 
                   1202:     if ( tf == stdout && mounted(font) ) {
                   1203:        flushtext();
                   1204: 
                   1205:        fpos = mount[font];
                   1206:        if ( (fpos->flags & USED) == 0 ) {
                   1207:            if ( (fpos->flags & NAMED) == 0 && fpos->fontname != NULL ) {
                   1208:                sprintf(temp, "/%s /%s def\n", fpos->name, fpos->fontname);
                   1209:                exportstring(temp);
                   1210:                fpos->flags |= NAMED;           /* unnecessary */
                   1211:            }   /* End if */
                   1212: 
                   1213:            if ( hostfontdir != NULL ) {
                   1214:                sprintf(temp, "%s/%s", hostfontdir, fpos->name);
                   1215:                exportfile(temp);
                   1216:            }   /* End if */
                   1217:        }   /* End if */
                   1218: 
                   1219:        fprintf(tf, "%d %s f\n", size, fpos->name);
                   1220:        if ( fontheight != 0 || fontslant != 0 )
                   1221:            fprintf(tf, "%d %d changefont\n", fontslant, (fontheight != 0) ? fontheight : size);
                   1222: 
                   1223:        lastfont = font;
                   1224:        lastsize = size;
                   1225:        fpos->flags |= USED;
                   1226:     }  /* End if */
                   1227: 
                   1228: }   /* End of t_sf */
                   1229: 
                   1230: /*****************************************************************************/
                   1231: 
                   1232: t_charht(n)
                   1233: 
                   1234:     int                n;
                   1235: 
                   1236: {
                   1237: 
                   1238: /*
                   1239:  *
                   1240:  * Set character height to n points. Disabled if n is 0 or the current size.
                   1241:  *
                   1242:  */
                   1243: 
                   1244:     fontheight = (n == size) ? 0 : n;
                   1245:     lastfont = -1;
                   1246: 
                   1247: }   /* End of t_charht */
                   1248: 
                   1249: /*****************************************************************************/
                   1250: 
                   1251: t_slant(n)
                   1252: 
                   1253:     int                n;
                   1254: 
                   1255: {
                   1256: 
                   1257: /*
                   1258:  *
                   1259:  * Set slant to n degrees. Disable slanting if n is 0.
                   1260:  *
                   1261:  */
                   1262: 
                   1263:     fontslant = n;
                   1264:     lastfont = -1;
                   1265: 
                   1266: }   /* End of t_slant */
                   1267: 
                   1268: /*****************************************************************************/
                   1269: 
                   1270: xymove(x, y)
                   1271: 
                   1272:     int                x, y;
                   1273: 
                   1274: {
                   1275: 
                   1276: /*
                   1277:  *
                   1278:  * Make the the printer and post-processor agree about the current position.
                   1279:  *
                   1280:  */
                   1281: 
                   1282:     flushtext();
                   1283: 
                   1284:     hgoto(x);
                   1285:     vgoto(y);
                   1286: 
                   1287:     fprintf(tf, "%d %d m\n", hpos, vpos);
                   1288: 
                   1289:     lastx = hpos;
                   1290:     lasty = vpos;
                   1291: 
                   1292: }   /* End of xymove */
                   1293: 
                   1294: /*****************************************************************************/
                   1295: 
                   1296: put1(c)
                   1297: 
                   1298:     register int       c;
                   1299: 
                   1300: {
                   1301: 
                   1302:     register int       i;
                   1303:     register int       j;
                   1304:     register int       k;
                   1305:     int                        code;
                   1306:     int                        ofont;
                   1307: 
                   1308: /*
                   1309:  *
                   1310:  * Print character c. ASCII character if c < 128, otherwise it's special. Look
                   1311:  * for c in the current font, then in all others starting at the first special
                   1312:  * font. Save c in lastc so it's available when oput() runs. Restore original
                   1313:  * font before leaving.
                   1314:  *
                   1315:  */
                   1316: 
                   1317:     lastc = c;                         /* charlib() needs name not code */
                   1318:     if ( (c -= 32) <= 0 )
                   1319:        return;
                   1320: 
                   1321:     k = ofont = font;
                   1322: 
                   1323:     if ( (i = onfont(lastc, k)) == -1 && smnt > 0 )
                   1324:        for ( k = smnt, j = 0; j < nfonts; j++, k = k % nfonts + 1 ) {
                   1325:            if ( (i = onfont(lastc, k)) != -1 ) {
                   1326:                setfont(k);
                   1327:                break;
                   1328:            }   /* End if */
                   1329:        }   /* End for */
                   1330: 
                   1331:     if ( i != -1 && (code = mount[k]->wp[i].code) != 0 ) {
                   1332:        lastw = widthfac * ((mount[k]->wp[i].wid * size + unitwidth/2) / unitwidth);
                   1333:        oput(code);
                   1334:     }  /* End if */
                   1335: 
                   1336:     if ( font != ofont )
                   1337:        setfont(ofont);
                   1338: 
                   1339: }   /* End of put1 */
                   1340: 
                   1341: /*****************************************************************************/
                   1342: 
                   1343: oput(c)
                   1344: 
                   1345:     int                c;
                   1346: 
                   1347: {
                   1348: 
                   1349:     double     llx, lly, urx, ury;     /* boundingbox corners */
                   1350: 
                   1351: /*
                   1352:  *
                   1353:  * Arranges to print the character whose code is c in the current font. All the
                   1354:  * actual positioning is done here, in charlib(), or in the drawing routines.
                   1355:  *
                   1356:  */
                   1357: 
                   1358:     if ( textcount > MAXSTACK )                /* don't put too much on the stack? */
                   1359:        flushtext();
                   1360: 
                   1361:     if ( font != lastfont || size != lastsize )
                   1362:        t_sf();
                   1363: 
                   1364:     if ( vpos != lasty )
                   1365:        endline();
                   1366: 
                   1367:     starttext();
                   1368: 
                   1369:     if ( ABS(hpos - lastx) > slop )
                   1370:        endstring();
                   1371: 
                   1372:     if ( isascii(c) && isprint(c) )
                   1373:        switch ( c ) {
                   1374:            case '(':
                   1375:            case ')':
                   1376:            case '\\':
                   1377:                    addchar('\\');
                   1378: 
                   1379:            default:
                   1380:                    addchar(c);
                   1381:        }   /* End switch */
                   1382:     else if ( c > 040 )
                   1383:        addoctal(c);
                   1384:     else charlib(c);
                   1385: 
                   1386:     if ( dobbox == TRUE ) {
                   1387:        llx = lastx;
                   1388:        lly = -(vpos + 0.5 * (devres * size / 72.0));
                   1389:        urx = lastx + lastw;
                   1390:        ury = -(vpos - (devres * size / 72.0));
                   1391:        cover(llx, lly);
                   1392:        cover(urx, ury);
                   1393:     }  /* End if */
                   1394: 
                   1395:     lastx += lastw;
                   1396: 
                   1397: }   /* End of oput */
                   1398: 
                   1399: /*****************************************************************************/
                   1400: 
                   1401: starttext()
                   1402: 
                   1403: {
                   1404: 
                   1405: /*
                   1406:  * Called whenever we want to be sure we're ready to start collecting characters
                   1407:  * for the next call to PostScript procedure t (ie. the one that prints them). If
                   1408:  * textcount is positive we've already started, so there's nothing to do. The more
                   1409:  * complicated encoding schemes save text strings in the strings[] array and need
                   1410:  * detailed information about the strings when they're written to the output file
                   1411:  * in flushtext().
                   1412:  *
                   1413:  */
                   1414: 
                   1415:     if ( textcount < 1 ) {
                   1416:        switch ( encoding ) {
                   1417:            case 0:
                   1418:            case 1:
                   1419:                putc('(', tf);
                   1420:                break;
                   1421: 
                   1422:            case 2:
                   1423:            case 3:
                   1424:                strptr = strings;
                   1425:                spacecount = 0;
                   1426:                line[1].str = strptr;
                   1427:                line[1].dx = 0;
                   1428:                line[1].spaces = 0;
                   1429:                line[1].start = hpos;
                   1430:                line[1].width = 0;
                   1431:                break;
                   1432: 
                   1433:            case MAXENCODING+1:                 /* reverse video */
                   1434:                if ( lastend == -1 )
                   1435:                    lastend = hpos;
                   1436:                putc('(', tf);
                   1437:                break;
                   1438: 
                   1439:            case MAXENCODING+2:                 /* follow a funny baseline */
                   1440:                putc('(', tf);
                   1441:                break;
                   1442:        }   /* End switch */
                   1443: 
                   1444:        textcount = 1;
                   1445:        lastx = stringstart = hpos;
                   1446:     }  /* End if */
                   1447: 
                   1448: }   /* End of starttext */
                   1449: 
                   1450: /*****************************************************************************/
                   1451: 
                   1452: flushtext()
                   1453: 
                   1454: {
                   1455: 
                   1456:     int                i;
                   1457: 
                   1458: /*
                   1459:  *
                   1460:  * Generates a call to the PostScript procedure that processes all the text we've
                   1461:  * accumulated - provided textcount is positive.
                   1462:  *
                   1463:  */
                   1464: 
                   1465:     if ( textcount > 0 ) {
                   1466:        switch ( encoding ) {
                   1467:            case 0:
                   1468:                fprintf(tf, ")%d t\n", stringstart);
                   1469:                break;
                   1470: 
                   1471:            case 1:
                   1472:                fprintf(tf, ")%d %d t\n", stringstart, lasty);
                   1473:                break;
                   1474: 
                   1475:            case 2:
                   1476:                *strptr = '\0';
                   1477:                line[textcount].width = lastx - line[textcount].start;
                   1478:                if ( spacecount != 0 || textcount != 1 ) {
                   1479:                    for ( i = textcount; i > 0; i-- )
                   1480:                        fprintf(tf, "(%s)%d %d", line[i].str, line[i].spaces, line[i].width);
                   1481:                    fprintf(tf, " %d %d %d t\n", textcount, stringstart, lasty);
                   1482:                } else fprintf(tf, "(%s)%d %d w\n", line[1].str, stringstart, lasty);
                   1483:                break;
                   1484: 
                   1485:            case 3:
                   1486:                *strptr = '\0';
                   1487:                if ( spacecount != 0 || textcount != 1 ) {
                   1488:                    for ( i = textcount; i > 0; i-- )
                   1489:                        fprintf(tf, "(%s)%d", line[i].str, line[i].dx);
                   1490:                    fprintf(tf, " %d %d %d t\n", textcount, stringstart, lasty);
                   1491:                } else fprintf(tf, "(%s)%d %d w\n", line[1].str, stringstart, lasty);
                   1492:                break;
                   1493: 
                   1494:            case MAXENCODING+1:
                   1495:                fprintf(tf, ")%d ", stringstart);
                   1496:                fprintf(tf, "%d %d drawrvbox ", lastend - rvslop, (int)(lastx + .5) + rvslop);
                   1497:                fprintf(tf, "t\n", stringstart);
                   1498:                lastend = (lastx + .5) + 2 * rvslop;
                   1499:                break;
                   1500: 
                   1501:            case MAXENCODING+2:
                   1502:                fprintf(tf, ")%d %d t\n", stringstart, lasty);
                   1503:                break;
                   1504:        }   /* End switch */
                   1505:     }  /* End if */
                   1506: 
                   1507:     textcount = 0;
                   1508: 
                   1509: }   /* End of flushtext */
                   1510: 
                   1511: /*****************************************************************************/
                   1512: 
                   1513: endstring()
                   1514: 
                   1515: {
                   1516: 
                   1517:     int                dx;
                   1518: 
                   1519: /*
                   1520:  *
                   1521:  * Horizontal positions are out of sync. End the last open string, adjust the
                   1522:  * printer's position, and start a new string. Assumes we've already started
                   1523:  * accumulating text.
                   1524:  *
                   1525:  */
                   1526: 
                   1527:     switch ( encoding ) {
                   1528:        case 0:
                   1529:        case 1:
                   1530:            fprintf(tf, ")%d(", stringstart);
                   1531:            textcount++;
                   1532:            lastx = stringstart = hpos;
                   1533:            break;
                   1534: 
                   1535:        case 2:
                   1536:        case 3:
                   1537:            dx = hpos - lastx;
                   1538:            if ( spacecount++ == 0 )
                   1539:                line[textcount].dx = dx;
                   1540:            if ( line[textcount].dx != dx ) {
                   1541:                *strptr++ = '\0';
                   1542:                line[textcount].width = lastx - line[textcount].start;
                   1543:                line[++textcount].str = strptr;
                   1544:                *strptr++ = ' ';
                   1545:                line[textcount].dx = dx;
                   1546:                line[textcount].start = lastx;
                   1547:                line[textcount].width = 0;
                   1548:                line[textcount].spaces = 1;
                   1549:            } else {
                   1550:                *strptr++ = ' ';
                   1551:                line[textcount].spaces++;
                   1552:            }   /* End else */
                   1553:            lastx += dx;
                   1554:            break;
                   1555: 
                   1556:        case MAXENCODING+1:
                   1557:            fprintf(tf, ")%d(", stringstart);
                   1558:            textcount++;
                   1559:            lastx = stringstart = hpos;
                   1560:            break;
                   1561: 
                   1562:        case MAXENCODING+2:
                   1563:            flushtext();
                   1564:            starttext();
                   1565:            break;
                   1566:     }  /* End switch */
                   1567: 
                   1568: }   /* End of endstring */
                   1569: 
                   1570: /*****************************************************************************/
                   1571: 
                   1572: endline()
                   1573: 
                   1574: {
                   1575: 
                   1576: /*
                   1577:  *
                   1578:  * The vertical position has changed. Dump any accumulated text, then adjust
                   1579:  * the printer's vertical position.
                   1580:  *
                   1581:  */
                   1582: 
                   1583:     flushtext();
                   1584: 
                   1585:     if ( encoding == 0 || encoding == MAXENCODING+1 )
                   1586:        fprintf(tf, "%d %d m\n", hpos, vpos);
                   1587: 
                   1588:     lastx = stringstart = lastend = hpos;
                   1589:     lasty = vpos;
                   1590: 
                   1591: }   /* End of endline */
                   1592: 
                   1593: /*****************************************************************************/
                   1594: 
                   1595: addchar(c)
                   1596: 
                   1597:     int                c;
                   1598: 
                   1599: {
                   1600: 
                   1601: /*
                   1602:  *
                   1603:  * Does whatever is needed to add character c to the current string.
                   1604:  *
                   1605:  */
                   1606: 
                   1607:     switch ( encoding ) {
                   1608:        case 0:
                   1609:        case 1:
                   1610:            putc(c, tf);
                   1611:            break;
                   1612: 
                   1613:        case 2:
                   1614:        case 3:
                   1615:            *strptr++ = c;
                   1616:            break;
                   1617: 
                   1618:        case MAXENCODING+1:
                   1619:        case MAXENCODING+2:
                   1620:            putc(c, tf);
                   1621:            break;
                   1622:     }  /* End switch */
                   1623: 
                   1624: }   /* End of addchar */
                   1625: 
                   1626: /*****************************************************************************/
                   1627: 
                   1628: addoctal(c)
                   1629: 
                   1630:     int                c;
                   1631: 
                   1632: {
                   1633: 
                   1634: /*
                   1635:  *
                   1636:  * Add c to the current string as an octal escape.
                   1637:  *
                   1638:  */
                   1639: 
                   1640:     switch ( encoding ) {
                   1641:        case 0:
                   1642:        case 1:
                   1643:            fprintf(tf, "\\%o", c);
                   1644:            break;
                   1645: 
                   1646:        case 2:
                   1647:        case 3:
                   1648:            sprintf(strptr, "\\%o", c);
                   1649:            strptr += strlen(strptr);
                   1650:            break;
                   1651: 
                   1652:        case MAXENCODING+1:
                   1653:        case MAXENCODING+2:
                   1654:            fprintf(tf, "\\%o", c);
                   1655:            break;
                   1656:     }  /* End switch */
                   1657: 
                   1658: }   /* End of addoctal */
                   1659: 
                   1660: /*****************************************************************************/
                   1661: 
                   1662: charlib(code)
                   1663: 
                   1664:     int                code;                   /* either 1 or 2 */
                   1665: 
                   1666: {
                   1667: 
                   1668:     char       *name;                  /* name of the character */
                   1669:     char       tname[10];              /* in case it's a single ASCII character */
                   1670:     char       temp[150];
                   1671: 
                   1672: /*
                   1673:  *
                   1674:  * Called from oput() for characters having codes less than 040. Special files
                   1675:  * that define PostScript procedures for certain characters can be found in
                   1676:  * directory *fontdir/devpost/charlib. If there's a file that has the same name as
                   1677:  * the character we're trying to print it's copied to the output file, otherwise
                   1678:  * nothing, except some positioning, is done.
                   1679:  *
                   1680:  * All character definitions are only made once. Subsequent requests to print the
                   1681:  * character generate a call to a procedure that begins with the prefix build_ and
                   1682:  * ends with the character's name. Special characters that are assigned codes
                   1683:  * other than 1 are assumed to have additional data files that should be copied
                   1684:  * to the output file immediately after the build_ call. Those data files should
                   1685:  * end in the suffix .map, and usually will be a hex representation of a bitmap.
                   1686:  *
                   1687:  */
                   1688: 
                   1689:     flushtext();
                   1690: 
                   1691:     if ( lastc < 128 ) {               /* just a simple ASCII character */
                   1692:        sprintf(tname, "%.3o", lastc);
                   1693:        name = tname;
                   1694:     } else name = chname(lastc);
                   1695: 
                   1696:     if ( downloaded[lastc] == 0 ) {
                   1697:        sprintf(temp, "%s/dev%s/charlib/%s", fontdir, realdev, name);
                   1698:        if ( exportfile(temp) == TRUE ) {
                   1699:            downloaded[lastc] = 1;
                   1700:            t_sf();
                   1701:        }   /* End if */
                   1702:     }  /* End if */
                   1703: 
                   1704:     if ( downloaded[lastc] == 1 ) {
                   1705:        xymove(hpos, vpos);
                   1706:        fprintf(tf, "%d build_%s\n", (int) lastw, name);
                   1707:        if ( code != 1 ) {              /* get the bitmap or whatever */
                   1708:            sprintf(temp, "%s/dev%s/charlib/%s.map", fontdir, realdev, name);
                   1709:            if ( access(temp, 04) == 0 && tf == stdout )
                   1710:                cat(temp);
                   1711:        }   /* End if */
                   1712:        fprintf(tf, "%d %d m\n", stringstart = hpos + lastw, vpos);
                   1713:     }  /* End if */
                   1714: 
                   1715: }   /* End of charlib */
                   1716: 
                   1717: /*****************************************************************************/
                   1718: 
                   1719: reset()
                   1720: 
                   1721: {
                   1722: 
                   1723: /*
                   1724:  *
                   1725:  * Reset variables that keep track of the printer's current position, size and
                   1726:  * font. Eventually forces things back in sync before oput() prints the next
                   1727:  * character.
                   1728:  *
                   1729:  */
                   1730: 
                   1731:     lastx = -(slop + 1);
                   1732:     lasty = -1;
                   1733:     lastfont = lastsize = -1;
                   1734: 
                   1735: }   /* End of reset */
                   1736: 
                   1737: /*****************************************************************************/
                   1738: 
                   1739: resetpos()
                   1740: 
                   1741: {
                   1742: 
                   1743: /*
                   1744:  *
                   1745:  * Reset the position tracking variables. Forces oput() to get positions back
                   1746:  * in sync before printing the next character.
                   1747:  *
                   1748:  */
                   1749: 
                   1750:     lastx = -(slop + 1);
                   1751:     lasty = -1;
                   1752: 
                   1753: }   /* End of resetpos */
                   1754: 
                   1755: /*****************************************************************************/
                   1756: 
                   1757: save()
                   1758: 
                   1759: {
                   1760: 
                   1761: /*
                   1762:  *
                   1763:  * Save the current PostScript environment. Initialize things that may have
                   1764:  * disappeared after the preceeding restore.
                   1765:  *
                   1766:  */
                   1767: 
                   1768:     fprintf(tf, "/saveobj save def\n");
                   1769:     fprintf(tf, "mark\n");
                   1770: 
                   1771:     if ( encoding != realencoding )
                   1772:        fprintf(tf, "%d setdecoding\n", encoding);
                   1773: 
                   1774:     if ( gotcolor == TRUE )            /* prevent getcolor() recursion */
                   1775:        setcolor();
                   1776: 
                   1777: }   /* End of save */
                   1778: 
                   1779: /*****************************************************************************/
                   1780: 
                   1781: restore()
                   1782: 
                   1783: {
                   1784: 
                   1785: /*
                   1786:  *
                   1787:  * Restore the previous PostScript environment.
                   1788:  *
                   1789:  */
                   1790: 
                   1791:     flushtext();
                   1792:     fprintf(tf, "cleartomark\n");
                   1793:     fprintf(tf, "saveobj restore\n");
                   1794:     reset();
                   1795: 
                   1796: }   /* End of restore */
                   1797: 
                   1798: /*****************************************************************************/
                   1799: 
                   1800: exportfile(path)
                   1801: 
                   1802:     char       *path;
                   1803: 
                   1804: {
                   1805: 
                   1806:     int                val = FALSE;
                   1807: 
                   1808: /*
                   1809:  *
                   1810:  * Exports the contents of file path to the global environment. Returns TRUE
                   1811:  * if we're doing output (i.e. tf == stdout) and the copy worked.
                   1812:  *
                   1813:  */
                   1814: 
                   1815:     if ( tf == stdout && access(path, 04) == 0 ) {
                   1816:        restore();
                   1817:        fprintf(tf, "%s", BEGINGLOBAL);
                   1818:        val = cat(path);
                   1819:        fprintf(tf, "%s", ENDGLOBAL);
                   1820:        save();
                   1821:     }  /* End if */
                   1822: 
                   1823:     return(val);
                   1824: 
                   1825: }   /* End of exportfile */
                   1826: 
                   1827: /*****************************************************************************/
                   1828: 
                   1829: exportstring(str)
                   1830: 
                   1831:     char       *str;
                   1832: 
                   1833: {
                   1834: 
                   1835: /*
                   1836:  *
                   1837:  * Exports string str to the global environment. No return value needed yet.
                   1838:  *
                   1839:  */
                   1840: 
                   1841:     if ( tf == stdout && str != NULL && *str != '\0' ) {
                   1842:        restore();
                   1843:        fprintf(tf, "%s", BEGINGLOBAL);
                   1844:        fprintf(tf, "%s", str);
                   1845:        fprintf(tf, "%s", ENDGLOBAL);
                   1846:        save();
                   1847:     }  /* End if */
                   1848: 
                   1849: }   /* End of exportstring */
                   1850: 
                   1851: /*****************************************************************************/
                   1852: 
                   1853: redirect(pg)
                   1854: 
                   1855:     int                pg;
                   1856: 
                   1857: {
                   1858: 
                   1859:     static FILE        *fp_null = NULL;
                   1860: 
                   1861: /*
                   1862:  *
                   1863:  * If we're not supposed to print page pg, tf will be directed to /dev/null,
                   1864:  * otherwise output goes to stdout.
                   1865:  *
                   1866:  */
                   1867: 
                   1868:     if ( pg >= 0 && in_olist(pg) == ON )
                   1869:        tf = stdout;
                   1870:     else if ( (tf = fp_null) == NULL )
                   1871:        tf = fp_null = fopen("/dev/null", "w");
                   1872: 
                   1873: }   /* End of redirect */
                   1874: 
                   1875: /*****************************************************************************/
                   1876: 

unix.superglobalmegacorp.com

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