Annotation of researchv10no/cmd/postscript/postprint/postprint.c, revision 1.1

1.1     ! root        1: /*
        !             2:  *
        !             3:  * postprint - PostScript translator for ASCII files.
        !             4:  *
        !             5:  * A simple program that translates ASCII files into PostScript. All it really
        !             6:  * does is expand tabs and backspaces, handle character quoting, print text lines,
        !             7:  * and control when pages are started based on the requested number of lines per
        !             8:  * page.
        !             9:  *
        !            10:  * The PostScript prologue is copied from *prologue before any of the input files
        !            11:  * are translated. The program expects that the following procedures are defined
        !            12:  * in that file:
        !            13:  *
        !            14:  *     setup
        !            15:  *
        !            16:  *       mark ... setup -
        !            17:  *
        !            18:  *         Handles special initialization stuff that depends on how the program
        !            19:  *         was called. Expects to find a mark followed by key/value pairs on the
        !            20:  *         stack. The def operator is applied to each pair up to the mark, then
        !            21:  *         the default state is set up.
        !            22:  *
        !            23:  *     pagesetup
        !            24:  *
        !            25:  *       page pagesetup -
        !            26:  *
        !            27:  *         Does whatever is needed to set things up for the next page. Expects
        !            28:  *         to find the current page number on the stack.
        !            29:  *
        !            30:  *     l
        !            31:  *
        !            32:  *       string l -
        !            33:  *
        !            34:  *         Prints string starting in the first column and then goes to the next
        !            35:  *         line.
        !            36:  *
        !            37:  *     L
        !            38:  *
        !            39:  *       mark string column string column ... L mark
        !            40:  *
        !            41:  *         Prints each string on the stack starting at the horizontal position
        !            42:  *         selected by column. Used when tabs and spaces can be sufficiently well
        !            43:  *         compressed to make the printer overhead worthwhile. Always used when
        !            44:  *         we have to back up.
        !            45:  *
        !            46:  *     LL
        !            47:  *
        !            48:  *       mark string column string column ... LL mark
        !            49:  *
        !            50:  *         Like L, but only used to prevent potential PostScript stack overflow
        !            51:  *         from too many string/column pairs. Stays on the current line. It will
        !            52:  *         not be needed often!!
        !            53:  *
        !            54:  *     done
        !            55:  *
        !            56:  *       done
        !            57:  *
        !            58:  *         Makes sure the last page is printed. Only needed when we're printing
        !            59:  *         more than one page on each sheet of paper.
        !            60:  *
        !            61:  * Almost everything has been changed in this version of postprint. The program
        !            62:  * is more intelligent, especially about tabs, spaces, and backspacing, and as a
        !            63:  * result output files usually print faster. Output files also now conform to
        !            64:  * Adobe's file structuring conventions, which is undoubtedly something I should
        !            65:  * have done in the first version of the program. If the number of lines per page
        !            66:  * is set to 0, which can be done using the -l option, pointsize will be used to
        !            67:  * guess a reasonable value. The estimate is based on the values of LINESPP,
        !            68:  * POINTSIZE, and pointsize, and assumes LINESPP lines would fit on a page if
        !            69:  * we printed in size POINTSIZE. Selecting a point size using the -s option and
        !            70:  * adding -l0 to the command line forces the guess to be made.
        !            71:  *
        !            72:  * Many default values, like the magnification and orientation, are defined in 
        !            73:  * the prologue, which is where they belong. If they're changed (by options), an
        !            74:  * appropriate definition is made after the prologue is added to the output file.
        !            75:  * The -P option passes arbitrary PostScript through to the output file. Among
        !            76:  * other things it can be used to set (or change) values that can't be accessed by
        !            77:  * other options.
        !            78:  *
        !            79:  */
        !            80: 
        !            81: #include <stdio.h>
        !            82: #include <signal.h>
        !            83: #include <ctype.h>
        !            84: #include <fcntl.h>
        !            85: 
        !            86: #include "comments.h"                  /* PostScript file structuring comments */
        !            87: #include "gen.h"                       /* general purpose definitions */
        !            88: #include "path.h"                      /* for the prologue */
        !            89: #include "ext.h"                       /* external variable declarations */
        !            90: #include "postprint.h"                 /* a few special definitions */
        !            91: 
        !            92: char   *optnames = "a:c:ef:l:m:n:o:p:r:s:t:x:y:A:C:E:J:L:P:R:DI";
        !            93: 
        !            94: char   *prologue = POSTPRINT;          /* default PostScript prologue */
        !            95: char   *formfile = FORMFILE;           /* stuff for multiple pages per sheet */
        !            96: 
        !            97: int    formsperpage = 1;               /* page images on each piece of paper */
        !            98: int    copies = 1;                     /* and this many copies of each sheet */
        !            99: 
        !           100: int    linespp = LINESPP;              /* number of lines per page */
        !           101: int    pointsize = POINTSIZE;          /* in this point size */
        !           102: int    tabstops = TABSTOPS;            /* tabs set at these columns */
        !           103: int    crmode = 0;                     /* carriage return mode - 0, 1, or 2 */
        !           104: int    extended = TRUE;                /* use escapes for unprintable chars */
        !           105: 
        !           106: int    col = 1;                        /* next character goes in this column */
        !           107: int    line = 1;                       /* on this line */
        !           108: 
        !           109: int    stringcount = 0;                /* number of strings on the stack */
        !           110: int    stringstart = 1;                /* column where current one starts */
        !           111: 
        !           112: Fontmap        fontmap[] = FONTMAP;            /* for translating font names */
        !           113: char   *fontname = "Courier";          /* use this PostScript font */
        !           114: 
        !           115: int    page = 0;                       /* page we're working on */
        !           116: int    printed = 0;                    /* printed this many pages */
        !           117: 
        !           118: FILE   *fp_in = stdin;                 /* read from this file */
        !           119: FILE   *fp_out = stdout;               /* and write stuff here */
        !           120: FILE   *fp_acct = NULL;                /* for accounting data */
        !           121: 
        !           122: /*****************************************************************************/
        !           123: 
        !           124: main(agc, agv)
        !           125: 
        !           126:     int                agc;
        !           127:     char       *agv[];
        !           128: 
        !           129: {
        !           130: 
        !           131: /*
        !           132:  *
        !           133:  * A simple program that translates ASCII files into PostScript. If there's more
        !           134:  * than one input file, each begins on a new page.
        !           135:  *
        !           136:  */
        !           137: 
        !           138:     argc = agc;                                /* other routines may want them */
        !           139:     argv = agv;
        !           140: 
        !           141:     prog_name = argv[0];               /* really just for error messages */
        !           142: 
        !           143:     init_signals();                    /* sets up interrupt handling */
        !           144:     header();                          /* PostScript header and prologue */
        !           145:     options();                         /* handle the command line options */
        !           146:     setup();                           /* for PostScript */
        !           147:     arguments();                       /* followed by each input file */
        !           148:     done();                            /* print the last page etc. */
        !           149:     account();                         /* job accounting data */
        !           150: 
        !           151:     exit(x_stat);                      /* not much could be wrong */
        !           152: 
        !           153: }   /* End of main */
        !           154: 
        !           155: /*****************************************************************************/
        !           156: 
        !           157: init_signals()
        !           158: 
        !           159: {
        !           160: 
        !           161: /*
        !           162:  *
        !           163:  * Makes sure we handle interrupts.
        !           164:  *
        !           165:  */
        !           166: 
        !           167:     if ( signal(SIGINT, interrupt) == SIG_IGN ) {
        !           168:        signal(SIGINT, SIG_IGN);
        !           169:        signal(SIGQUIT, SIG_IGN);
        !           170:        signal(SIGHUP, SIG_IGN);
        !           171:     } else {
        !           172:        signal(SIGHUP, interrupt);
        !           173:        signal(SIGQUIT, interrupt);
        !           174:     }   /* End else */
        !           175: 
        !           176:     signal(SIGTERM, interrupt);
        !           177: 
        !           178: }   /* End of init_signals */
        !           179: 
        !           180: /*****************************************************************************/
        !           181: 
        !           182: header()
        !           183: 
        !           184: {
        !           185: 
        !           186:     int                ch;                     /* return value from getopt() */
        !           187:     int                old_optind = optind;    /* for restoring optind - should be 1 */
        !           188: 
        !           189: /*
        !           190:  *
        !           191:  * Scans the option list looking for things, like the prologue file, that we need
        !           192:  * right away but could be changed from the default. Doing things this way is an
        !           193:  * attempt to conform to Adobe's latest file structuring conventions. In particular
        !           194:  * they now say there should be nothing executed in the prologue, and they have
        !           195:  * added two new comments that delimit global initialization calls. Once we know
        !           196:  * where things really are we write out the job header, follow it by the prologue,
        !           197:  * and then add the ENDPROLOG and BEGINSETUP comments.
        !           198:  *
        !           199:  */
        !           200: 
        !           201:     while ( (ch = getopt(argc, argv, optnames)) != EOF )
        !           202:        if ( ch == 'L' )
        !           203:            prologue = optarg;
        !           204:        else if ( ch == '?' )
        !           205:            error(FATAL, "");
        !           206: 
        !           207:     optind = old_optind;               /* get ready for option scanning */
        !           208: 
        !           209:     fprintf(stdout, "%s", CONFORMING);
        !           210:     fprintf(stdout, "%s %s\n", VERSION, PROGRAMVERSION);
        !           211:     fprintf(stdout, "%s %s\n", DOCUMENTFONTS, ATEND);
        !           212:     fprintf(stdout, "%s %s\n", PAGES, ATEND);
        !           213:     fprintf(stdout, "%s", ENDCOMMENTS);
        !           214: 
        !           215:     if ( cat(prologue) == FALSE )
        !           216:        error(FATAL, "can't read %s", prologue);
        !           217: 
        !           218:     if ( DOROUND )
        !           219:        cat(ROUNDPAGE);
        !           220: 
        !           221:     fprintf(stdout, "%s", ENDPROLOG);
        !           222:     fprintf(stdout, "%s", BEGINSETUP);
        !           223:     fprintf(stdout, "mark\n");
        !           224: 
        !           225: }   /* End of header */
        !           226: 
        !           227: /*****************************************************************************/
        !           228: 
        !           229: options()
        !           230: 
        !           231: {
        !           232: 
        !           233:     int                ch;                     /* return value from getopt() */
        !           234: 
        !           235: /*
        !           236:  *
        !           237:  * Reads and processes the command line options. Added the -P option so arbitrary
        !           238:  * PostScript code can be passed through. Expect it could be useful for changing
        !           239:  * definitions in the prologue for which options have not been defined.
        !           240:  *
        !           241:  * Although any PostScript font can be used, things will only work well for
        !           242:  * constant width fonts.
        !           243:  *
        !           244:  */
        !           245: 
        !           246:     while ( (ch = getopt(argc, argv, optnames)) != EOF ) {
        !           247:        switch ( ch ) {
        !           248: 
        !           249:            case 'a':                   /* aspect ratio */
        !           250:                    fprintf(stdout, "/aspectratio %s def\n", optarg);
        !           251:                    break;
        !           252: 
        !           253:            case 'c':                   /* copies */
        !           254:                    copies = atoi(optarg);
        !           255:                    fprintf(stdout, "/#copies %s store\n", optarg);
        !           256:                    break;
        !           257: 
        !           258:            case 'e':                   /* obsolete - it's now always on */
        !           259:                    extended = TRUE;
        !           260:                    break;
        !           261: 
        !           262:            case 'f':                   /* use this PostScript font */
        !           263:                    fontname = get_font(optarg);
        !           264:                    fprintf(stdout, "/font /%s def\n", fontname);
        !           265:                    break;
        !           266: 
        !           267:            case 'l':                   /* lines per page */
        !           268:                    linespp = atoi(optarg);
        !           269:                    break;
        !           270: 
        !           271:            case 'm':                   /* magnification */
        !           272:                    fprintf(stdout, "/magnification %s def\n", optarg);
        !           273:                    break;
        !           274: 
        !           275:            case 'n':                   /* forms per page */
        !           276:                    formsperpage = atoi(optarg);
        !           277:                    fprintf(stdout, "%s %s\n", FORMSPERPAGE, optarg);
        !           278:                    fprintf(stdout, "/formsperpage %s def\n", optarg);
        !           279:                    break;
        !           280: 
        !           281:            case 'o':                   /* output page list */
        !           282:                    out_list(optarg);
        !           283:                    break;
        !           284: 
        !           285:            case 'p':                   /* landscape or portrait mode */
        !           286:                    if ( *optarg == 'l' )
        !           287:                        fprintf(stdout, "/landscape true def\n");
        !           288:                    else fprintf(stdout, "/landscape false def\n");
        !           289:                    break;
        !           290: 
        !           291:            case 'r':                   /* carriage return mode */
        !           292:                    crmode = atoi(optarg);
        !           293:                    break;
        !           294: 
        !           295:            case 's':                   /* point size */
        !           296:                    pointsize = atoi(optarg);
        !           297:                    fprintf(stdout, "/pointsize %s def\n", optarg);
        !           298:                    break;
        !           299: 
        !           300:            case 't':                   /* tabstops */
        !           301:                    tabstops = atoi(optarg);
        !           302:                    break;
        !           303: 
        !           304:            case 'x':                   /* shift things horizontally */
        !           305:                    fprintf(stdout, "/xoffset %s def\n", optarg);
        !           306:                    break;
        !           307: 
        !           308:            case 'y':                   /* and vertically on the page */
        !           309:                    fprintf(stdout, "/yoffset %s def\n", optarg);
        !           310:                    break;
        !           311: 
        !           312:            case 'A':                   /* force job accounting */
        !           313:            case 'J':
        !           314:                    if ( (fp_acct = fopen(optarg, "a")) == NULL )
        !           315:                        error(FATAL, "can't open accounting file %s", optarg);
        !           316:                    break;
        !           317: 
        !           318:            case 'C':                   /* copy file straight to output */
        !           319:                    if ( cat(optarg) == FALSE )
        !           320:                        error(FATAL, "can't read %s", optarg);
        !           321:                    break;
        !           322: 
        !           323:            case 'E':                   /* text font encoding */
        !           324:                    fontencoding = optarg;
        !           325:                    break;
        !           326: 
        !           327:            case 'L':                   /* PostScript prologue file */
        !           328:                    prologue = optarg;
        !           329:                    break;
        !           330: 
        !           331:            case 'P':                   /* PostScript pass through */
        !           332:                    fprintf(stdout, "%s\n", optarg);
        !           333:                    break;
        !           334: 
        !           335:            case 'R':                   /* special global or page level request */
        !           336:                    saverequest(optarg);
        !           337:                    break;
        !           338: 
        !           339:            case 'D':                   /* debug flag */
        !           340:                    debug = ON;
        !           341:                    break;
        !           342: 
        !           343:            case 'I':                   /* ignore FATAL errors */
        !           344:                    ignore = ON;
        !           345:                    break;
        !           346: 
        !           347:            case '?':                   /* don't understand the option */
        !           348:                    error(FATAL, "");
        !           349:                    break;
        !           350: 
        !           351:            default:                    /* don't know what to do for ch */
        !           352:                    error(FATAL, "missing case for option %c\n", ch);
        !           353:                    break;
        !           354:        }   /* End switch */
        !           355:     }   /* End while */
        !           356: 
        !           357:     argc -= optind;                    /* get ready for non-option args */
        !           358:     argv += optind;
        !           359: 
        !           360: }   /* End of options */
        !           361: 
        !           362: /*****************************************************************************/
        !           363: 
        !           364: char *get_font(name)
        !           365: 
        !           366:     char       *name;                  /* name the user asked for */
        !           367: 
        !           368: {
        !           369: 
        !           370:     int                i;                      /* for looking through fontmap[] */
        !           371: 
        !           372: /*
        !           373:  *
        !           374:  * Called from options() to map a user's font name into a legal PostScript name.
        !           375:  * If the lookup fails *name is returned to the caller. That should let you choose
        !           376:  * any PostScript font, although things will only work well for constant width
        !           377:  * fonts.
        !           378:  *
        !           379:  */
        !           380: 
        !           381:     for ( i = 0; fontmap[i].name != NULL; i++ )
        !           382:        if ( strcmp(name, fontmap[i].name) == 0 )
        !           383:            return(fontmap[i].val);
        !           384: 
        !           385:     return(name);
        !           386: 
        !           387: }   /* End of get_font */
        !           388: 
        !           389: /*****************************************************************************/
        !           390: 
        !           391: setup()
        !           392: 
        !           393: {
        !           394: 
        !           395: /*
        !           396:  *
        !           397:  * Handles things that must be done after the options are read but before the
        !           398:  * input files are processed. linespp (lines per page) can be set using the -l
        !           399:  * option. If it's not positive we calculate a reasonable value using the
        !           400:  * requested point size - assuming LINESPP lines fit on a page in point size
        !           401:  * POINTSIZE.
        !           402:  *
        !           403:  */
        !           404: 
        !           405:     writerequest(0, stdout);           /* global requests eg. manual feed */
        !           406:     setencoding(fontencoding);
        !           407:     fprintf(stdout, "setup\n");
        !           408: 
        !           409:     if ( formsperpage > 1 ) {
        !           410:        if ( cat(formfile) == FALSE )
        !           411:            error(FATAL, "can't read %s", formfile);
        !           412:        fprintf(stdout, "%d setupforms\n", formsperpage);
        !           413:     }  /* End if */
        !           414: 
        !           415:     fprintf(stdout, "%s", ENDSETUP);
        !           416: 
        !           417:     if ( linespp <= 0 )
        !           418:        linespp = LINESPP * POINTSIZE / pointsize;
        !           419: 
        !           420: }   /* End of setup */
        !           421: 
        !           422: /*****************************************************************************/
        !           423: 
        !           424: arguments()
        !           425: 
        !           426: {
        !           427: 
        !           428: /*
        !           429:  *
        !           430:  * Makes sure all the non-option command line arguments are processed. If we get
        !           431:  * here and there aren't any arguments left, or if '-' is one of the input files
        !           432:  * we'll translate stdin.
        !           433:  *
        !           434:  */
        !           435: 
        !           436:     if ( argc < 1 )
        !           437:        text();
        !           438:     else {                             /* at least one argument is left */
        !           439:        while ( argc > 0 ) {
        !           440:            if ( strcmp(*argv, "-") == 0 )
        !           441:                fp_in = stdin;
        !           442:            else if ( (fp_in = fopen(*argv, "r")) == NULL )
        !           443:                error(FATAL, "can't open %s", *argv);
        !           444:            text();
        !           445:            if ( fp_in != stdin )
        !           446:                fclose(fp_in);
        !           447:            argc--;
        !           448:            argv++;
        !           449:        }   /* End while */
        !           450:     }   /* End else */
        !           451: 
        !           452: }   /* End of arguments */
        !           453: 
        !           454: /*****************************************************************************/
        !           455: 
        !           456: done()
        !           457: 
        !           458: {
        !           459: 
        !           460: /*
        !           461:  *
        !           462:  * Finished with all the input files, so mark the end of the pages with a TRAILER
        !           463:  * comment, make sure the last page prints, and add things like the PAGES comment
        !           464:  * that can only be determined after all the input files have been read.
        !           465:  *
        !           466:  */
        !           467: 
        !           468:     fprintf(stdout, "%s", TRAILER);
        !           469:     fprintf(stdout, "done\n");
        !           470:     fprintf(stdout, "%s %s\n", DOCUMENTFONTS, fontname);
        !           471:     fprintf(stdout, "%s %d\n", PAGES, printed);
        !           472: 
        !           473: }   /* End of done */
        !           474: 
        !           475: /*****************************************************************************/
        !           476: 
        !           477: account()
        !           478: 
        !           479: {
        !           480: 
        !           481: /*
        !           482:  *
        !           483:  * Writes an accounting record to *fp_acct provided it's not NULL. Accounting is
        !           484:  * requested using the -A or -J options.
        !           485:  *
        !           486:  */
        !           487: 
        !           488:     if ( fp_acct != NULL )
        !           489:        fprintf(fp_acct, " print %d\n copies %d\n", printed, copies);
        !           490: 
        !           491: }   /* End of account */
        !           492: 
        !           493: /*****************************************************************************/
        !           494: 
        !           495: text()
        !           496: 
        !           497: {
        !           498: 
        !           499:     int                ch;                     /* next input character */
        !           500: 
        !           501: /*
        !           502:  *
        !           503:  * Translates *fp_in into PostScript. Intercepts space, tab, backspace, newline,
        !           504:  * return, and formfeed. Everything else goes to oput(), which handles quoting
        !           505:  * (if needed) and escapes for nonascii characters if extended is TRUE. The
        !           506:  * redirect(-1) call forces the initial output to go to /dev/null - so stuff
        !           507:  * that formfeed() does at the end of each page goes to /dev/null rather than
        !           508:  * the real output file.
        !           509:  *
        !           510:  */
        !           511: 
        !           512:     redirect(-1);                      /* get ready for the first page */
        !           513:     formfeed();                                /* force PAGE comment etc. */
        !           514: 
        !           515:     while ( (ch = getc(fp_in)) != EOF )
        !           516:        switch ( ch ) {
        !           517:            case '\n':
        !           518:                    newline();
        !           519:                    break;
        !           520: 
        !           521:            case '\t':
        !           522:            case '\b':
        !           523:            case ' ':
        !           524:                    spaces(ch);
        !           525:                    break;
        !           526: 
        !           527:            case '\014':
        !           528:                    formfeed();
        !           529:                    break;
        !           530: 
        !           531:            case '\r':
        !           532:                    if ( crmode == 1 )
        !           533:                        spaces(ch);
        !           534:                    else if ( crmode == 2 )
        !           535:                        newline();
        !           536:                    break;
        !           537: 
        !           538:            default:
        !           539:                    oput(ch);
        !           540:                    break;
        !           541:        }   /* End switch */
        !           542: 
        !           543:     formfeed();                                /* next file starts on a new page? */
        !           544: 
        !           545: }   /* End of text */
        !           546: 
        !           547: /*****************************************************************************/
        !           548: 
        !           549: formfeed()
        !           550: 
        !           551: {
        !           552: 
        !           553: /*
        !           554:  *
        !           555:  * Called whenever we've finished with the last page and want to get ready for the
        !           556:  * next one. Also used at the beginning and end of each input file, so we have to
        !           557:  * be careful about what's done. The first time through (up to the redirect() call)
        !           558:  * output goes to /dev/null.
        !           559:  *
        !           560:  * Adobe now recommends that the showpage operator occur after the page level
        !           561:  * restore so it can be easily redefined to have side-effects in the printer's VM.
        !           562:  * Although it seems reasonable I haven't implemented it, because it makes other
        !           563:  * things, like selectively setting manual feed or choosing an alternate paper
        !           564:  * tray, clumsy - at least on a per page basis. 
        !           565:  *
        !           566:  */
        !           567: 
        !           568:     if ( fp_out == stdout )            /* count the last page */
        !           569:        printed++;
        !           570: 
        !           571:     endline();                         /* print the last line */
        !           572: 
        !           573:     fprintf(fp_out, "cleartomark\n");
        !           574:     fprintf(fp_out, "showpage\n");
        !           575:     fprintf(fp_out, "saveobj restore\n");
        !           576:     fprintf(fp_out, "%s %d %d\n", ENDPAGE, page, printed);
        !           577: 
        !           578:     if ( ungetc(getc(fp_in), fp_in) == EOF )
        !           579:        redirect(-1);
        !           580:     else redirect(++page);
        !           581: 
        !           582:     fprintf(fp_out, "%s %d %d\n", PAGE, page, printed+1);
        !           583:     fprintf(fp_out, "/saveobj save def\n");
        !           584:     fprintf(fp_out, "mark\n");
        !           585:     writerequest(printed+1, fp_out);
        !           586:     fprintf(fp_out, "%d pagesetup\n", printed+1);
        !           587: 
        !           588:     line = 1;
        !           589: 
        !           590: }   /* End of formfeed */
        !           591: 
        !           592: /*****************************************************************************/
        !           593: 
        !           594: newline()
        !           595: 
        !           596: {
        !           597: 
        !           598: /*
        !           599:  *
        !           600:  * Called when we've read a newline character. The call to startline() ensures
        !           601:  * that at least an empty string is on the stack.
        !           602:  *
        !           603:  */
        !           604: 
        !           605:     startline();
        !           606:     endline();                         /* print the current line */
        !           607: 
        !           608:     if ( ++line > linespp )            /* done with this page */
        !           609:        formfeed();
        !           610: 
        !           611: }   /* End of newline */
        !           612: 
        !           613: /*****************************************************************************/
        !           614: 
        !           615: spaces(ch)
        !           616: 
        !           617:     int                ch;                     /* next input character */
        !           618: 
        !           619: {
        !           620: 
        !           621:     int                endcol;                 /* ending column */
        !           622:     int                i;                      /* final distance - in spaces */
        !           623: 
        !           624: /*
        !           625:  *
        !           626:  * Counts consecutive spaces, tabs, and backspaces and figures out where the next
        !           627:  * string should start. Once that's been done we try to choose an efficient way
        !           628:  * to output the required number of spaces. The choice is between using procedure
        !           629:  * l with a single string on the stack and L with several string and column pairs.
        !           630:  * We usually break even, in terms of the size of the output file, if we need four
        !           631:  * consecutive spaces. More means using L decreases the size of the file. For now
        !           632:  * if there are less than 6 consecutive spaces we just add them to the current
        !           633:  * string, otherwise we end that string, follow it by its starting position, and
        !           634:  * begin a new one that starts at endcol. Backspacing is always handled this way.
        !           635:  *
        !           636:  */
        !           637: 
        !           638:     startline();                       /* so col makes sense */
        !           639:     endcol = col;
        !           640: 
        !           641:     do {
        !           642:        if ( ch == ' ' )
        !           643:            endcol++;
        !           644:        else if ( ch == '\t' )
        !           645:            endcol += tabstops - ((endcol - 1) % tabstops);
        !           646:        else if ( ch == '\b' )
        !           647:            endcol--;
        !           648:        else if ( ch == '\r' )
        !           649:            endcol = 1;
        !           650:        else break;
        !           651:     } while ( ch = getc(fp_in) );      /* if ch is 0 we'd quit anyway */
        !           652: 
        !           653:     ungetc(ch, fp_in);                 /* wasn't a space, tab, or backspace */
        !           654: 
        !           655:     if ( endcol < 1 )                  /* can't move past left edge */
        !           656:        endcol = 1;
        !           657: 
        !           658:     if ( (i = endcol - col) >= 0 && i < 6 )
        !           659:        for ( ; i > 0; i-- )
        !           660:            oput((int)' ');
        !           661:     else {
        !           662:        endstring();
        !           663:        col = stringstart = endcol;
        !           664:     }  /* End else */
        !           665: 
        !           666: }   /* End of spaces */
        !           667: 
        !           668: /*****************************************************************************/
        !           669: 
        !           670: startline()
        !           671: 
        !           672: {
        !           673: 
        !           674: /*
        !           675:  *
        !           676:  * Called whenever we want to be certain we're ready to start pushing characters
        !           677:  * into an open string on the stack. If stringcount is positive we've already
        !           678:  * started, so there's nothing to do. The first string starts in column 1.
        !           679:  *
        !           680:  */
        !           681: 
        !           682:     if ( stringcount < 1 ) {
        !           683:        putc('(', fp_out);
        !           684:        stringstart = col = 1;
        !           685:        stringcount = 1;
        !           686:     }  /* End if */
        !           687: 
        !           688: }   /* End of startline */
        !           689: 
        !           690: /*****************************************************************************/
        !           691: 
        !           692: endstring()
        !           693: 
        !           694: {
        !           695: 
        !           696: /*
        !           697:  *
        !           698:  * End the current string and start a new one.
        !           699:  *
        !           700:  */
        !           701: 
        !           702:     if ( stringcount > 100 ) {         /* don't put too much on the stack */
        !           703:        fprintf(fp_out, ")%d LL\n(", stringstart-1);
        !           704:        stringcount = 2;                /* kludge - don't let endline() use l */
        !           705:     } else {
        !           706:        fprintf(fp_out, ")%d(", stringstart-1);
        !           707:        stringcount++;
        !           708:     }   /* End else */
        !           709: 
        !           710: }   /* End of endstring */
        !           711: 
        !           712: /*****************************************************************************/
        !           713: 
        !           714: endline()
        !           715: 
        !           716: {
        !           717: 
        !           718: /*
        !           719:  *
        !           720:  * Generates a call to the PostScript procedure that processes all the text on
        !           721:  * the stack - provided stringcount is positive. If one string is on the stack
        !           722:  * the fast procedure (ie. l) is used to print the line, otherwise the slower
        !           723:  * one that processes string and column pairs is used.
        !           724:  *
        !           725:  */
        !           726: 
        !           727:     if ( stringcount == 1 )
        !           728:        fprintf(fp_out, ")l\n");
        !           729:     else if ( stringcount > 1 )
        !           730:        fprintf(fp_out, ")%d L\n", stringstart-1);
        !           731: 
        !           732:     stringcount = 0;
        !           733: 
        !           734: }   /* End of endline */
        !           735: 
        !           736: /*****************************************************************************/
        !           737: 
        !           738: oput(ch)
        !           739: 
        !           740:     int                ch;                     /* next output character */
        !           741: 
        !           742: {
        !           743: 
        !           744: /*
        !           745:  *
        !           746:  * Responsible for adding all printing characters from the input file to the
        !           747:  * open string on top of the stack.
        !           748:  *
        !           749:  */
        !           750: 
        !           751:     if ( isascii(ch) && isprint(ch) ) {
        !           752:        startline();
        !           753:        if ( ch == '(' || ch == ')' || ch == '\\' )
        !           754:            putc('\\', fp_out);
        !           755:        putc(ch, fp_out);
        !           756:        col++;
        !           757:     } else if ( extended == TRUE ) {
        !           758:        startline();
        !           759:        fprintf(fp_out, "\\%.3o", ch & 0377);
        !           760:        col++;
        !           761:     }  /* End if */
        !           762: 
        !           763: }   /* End of oput */
        !           764: 
        !           765: /*****************************************************************************/
        !           766: 
        !           767: redirect(pg)
        !           768: 
        !           769:     int                pg;                     /* next page we're printing */
        !           770: 
        !           771: {
        !           772: 
        !           773:     static FILE        *fp_null = NULL;        /* if output is turned off */
        !           774: 
        !           775: /*
        !           776:  *
        !           777:  * If we're not supposed to print page pg, fp_out will be directed to /dev/null,
        !           778:  * otherwise output goes to stdout.
        !           779:  *
        !           780:  */
        !           781: 
        !           782:     if ( pg >= 0 && in_olist(pg) == ON )
        !           783:        fp_out = stdout;
        !           784:     else if ( (fp_out = fp_null) == NULL )
        !           785:        fp_out = fp_null = fopen("/dev/null", "w");
        !           786: 
        !           787: }   /* End of redirect */
        !           788: 
        !           789: /*****************************************************************************/
        !           790: 

unix.superglobalmegacorp.com

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