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

unix.superglobalmegacorp.com

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