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

unix.superglobalmegacorp.com

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