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

1.1     ! root        1: /*
        !             2:  *
        !             3:  * picpack - picture packing pre-processor
        !             4:  *
        !             5:  * A trivial troff pre-processor that copies files to stdout, expanding picture
        !             6:  * requests into an in-line format that's passed transparently through troff and
        !             7:  * handled by dpost. The program is an attempt to address requirements, expressed
        !             8:  * by several organizations, of being able to store a document as a single file
        !             9:  * (usually troff input) that can then be sent through dpost and ultimately to
        !            10:  * a PostScript printer.
        !            11:  *
        !            12:  * The program looks for strings listed in the keys[] array at the start of each
        !            13:  * line. When a picture request (as listed in keys[]) is found the second string
        !            14:  * on the line is taken to be a picture file pathname that's added (in transparent
        !            15:  * mode) to the output file. In addition each in-line picture file is preceeded by
        !            16:  * device control command (again passed through in transparent mode) that looks
        !            17:  * like,
        !            18:  *
        !            19:  *     x X InlinePicture filename bytes
        !            20:  *
        !            21:  * where bytes is the size of the picture file (which begins on the next line)
        !            22:  * and filename is the pathname of the picture file. dpost uses both arguments to
        !            23:  * manage in-line pictures (in a big temp file). To handle pictures in diversions
        !            24:  * picpack reads each input file twice. The first pass looks for picture inclusion
        !            25:  * requests and copies each picture file transparently to the output file, while
        !            26:  * second pass just copies the input file to the output file. Things could still
        !            27:  * break, but the two pass method should handle most jobs.
        !            28:  *
        !            29:  * The recognized in-line picture requests are saved in keys[] and by default only
        !            30:  * expand .BP and .PI macro calls. The -k option changes the recognized strings,
        !            31:  * and may be needed if you've built your own picture inclusion macros on top of
        !            32:  * .BP or .PI or decided to list each picture file at the start of your input file
        !            33:  * using a dummy macro. For example you could require every in-line picture be
        !            34:  * named by a dummy macro (say .iP), then the command line,
        !            35:  *
        !            36:  *     picpack -k.iP file > file.pack
        !            37:  *
        !            38:  * hits on lines that begin with .iP (rather than .BP or .PI), and the only files
        !            39:  * pulled in would be ones named as the second argument to the new .iP macro. The
        !            40:  * -k option accepts a space or comma separated list of up to 10 different key
        !            41:  * strings. picpack imposes no contraints on key strings, other than not allowing
        !            42:  * spaces or commas. A key string can begin with \" and in that case it would be
        !            43:  * troff comment.
        !            44:  *
        !            45:  * Although the program will help some users, there are obvious disadvantages.
        !            46:  * Perhaps the most important is that troff output files (with in-line pictures
        !            47:  * included) don't fit the device independent language accepted by important post
        !            48:  * processors like proof, and that means you won't be able to reliably preview a
        !            49:  * packed file on your 5620 or whatever. Another potential problem is that picture
        !            50:  * files can be large. Packing everything together in a single file at an early
        !            51:  * stage has a better chance of exceeding your system's ulimit.
        !            52:  *
        !            53:  */
        !            54: 
        !            55: #include       <stdio.h>
        !            56: #include       <sys/types.h>
        !            57: #include       <sys/stat.h>
        !            58: 
        !            59: #include       "gen.h"                 /* general purpose definitions */
        !            60: #include       "ext.h"                 /* external variable definitions */
        !            61: #include       "path.h"                /* just for TEMPDIR definition */
        !            62: 
        !            63: char           *keys[11] = {".BP", ".PI", NULL};
        !            64: int            quiet = FALSE;
        !            65: 
        !            66: FILE           *fp_in = stdin;         /* input */
        !            67: FILE           *fp_out = stdout;       /* and output files */
        !            68: 
        !            69: /*****************************************************************************/
        !            70: 
        !            71: main(agc, agv)
        !            72: 
        !            73:     int                agc;
        !            74:     char       *agv[];
        !            75: 
        !            76: {
        !            77: 
        !            78: /*
        !            79:  *
        !            80:  * A picture packing pre-processor that copies input files to stdout, expanding
        !            81:  * picture requests (as listed in keys[]) to an in-line format that can be passed
        !            82:  * through troff (using transparent mode) and handled later by dpost.
        !            83:  *
        !            84:  */
        !            85: 
        !            86:     argc = agc;                                /* global so everyone can use them */
        !            87:     argv = agv;
        !            88: 
        !            89:     prog_name = argv[0];               /* just for error messages */
        !            90: 
        !            91:     options();                         /* command line options */
        !            92:     arguments();                       /* translate all the input files */
        !            93:     done();                            /* clean things up */
        !            94: 
        !            95:     exit(x_stat);                      /* everything probably went OK */
        !            96: 
        !            97: }   /* End of main */
        !            98: 
        !            99: /*****************************************************************************/
        !           100: 
        !           101: options()
        !           102: 
        !           103: {
        !           104: 
        !           105:     int                ch;                     /* name returned by getopt() */
        !           106: 
        !           107:     extern char        *optarg;                /* option argument set by getopt() */
        !           108:     extern int optind;
        !           109: 
        !           110: /*
        !           111:  *
        !           112:  * Handles the command line options.
        !           113:  *
        !           114:  */
        !           115: 
        !           116:     while ( (ch = getopt(argc, argv, "k:qDI")) != EOF )  {
        !           117:        switch ( ch )  {
        !           118:            case 'k':                   /* new expansion key strings */
        !           119:                    newkeys(optarg);
        !           120:                    break;
        !           121: 
        !           122:            case 'q':                   /* disables "missing picture" messages */
        !           123:                    quiet = TRUE;
        !           124:                    break;
        !           125: 
        !           126:            case 'D':                   /* debug flag */
        !           127:                    debug = ON;
        !           128:                    break;
        !           129: 
        !           130:            case 'I':                   /* ignore FATAL errors */
        !           131:                    ignore = ON;
        !           132:                    break;
        !           133: 
        !           134:            case '?':                   /* don't know the option */
        !           135:                    error(FATAL, "");
        !           136:                    break;
        !           137: 
        !           138:            default:
        !           139:                    error(FATAL, "missing case for option %c", ch);
        !           140:                    break;
        !           141:        }   /* End switch */
        !           142:     }  /* End while */
        !           143: 
        !           144:     argc -= optind;                    /* get ready for non-options args */
        !           145:     argv += optind;
        !           146: 
        !           147: }   /* End of options */
        !           148: 
        !           149: /*****************************************************************************/
        !           150: 
        !           151: newkeys(list)
        !           152: 
        !           153:     char       *list;                  /* comma or space separated key strings */
        !           154: 
        !           155: {
        !           156: 
        !           157:     char       *p;                     /* next key string from *list */
        !           158:     int                i;                      /* goes in keys[i] */
        !           159:     int                n;                      /* last key string slot in keys[] */
        !           160: 
        !           161: /*
        !           162:  *
        !           163:  * Separates *list into space or comma separated strings and adds each to the
        !           164:  * keys[] array. The strings in keys[] are used to locate the picture inclusion
        !           165:  * requests that are translated to the in-line format. The keys array must end
        !           166:  * with a NULL pointer and by default only expands .BP and .PI macro calls.
        !           167:  *
        !           168:  */
        !           169: 
        !           170:     n = (sizeof(keys) / sizeof(char *)) - 1;
        !           171: 
        !           172:     for ( i = 0, p = strtok(list, " ,"); p != NULL; i++, p = strtok(NULL, " ,") )
        !           173:        if ( i >= n )
        !           174:            error(FATAL, "too many key strings");
        !           175:        else keys[i] = p;
        !           176: 
        !           177:     keys[i] = NULL;
        !           178: 
        !           179: }   /* End of newkeys */
        !           180: 
        !           181: /*****************************************************************************/
        !           182: 
        !           183: arguments()
        !           184: 
        !           185: {
        !           186: 
        !           187:     FILE       *copystdin();
        !           188: 
        !           189: /*
        !           190:  *
        !           191:  * Makes sure all the non-option command line arguments are processed. If we get
        !           192:  * here and there aren't any arguments left, or if '-' is one of the input files
        !           193:  * we process stdin, after copying it to a temporary file.
        !           194:  *
        !           195:  */
        !           196: 
        !           197:     if ( argc < 1 )  {
        !           198:        fp_in = copystdin();
        !           199:        picpack();
        !           200:     } else
        !           201:        while ( argc > 0 ) {
        !           202:            if ( strcmp(*argv, "-") == 0 )
        !           203:                fp_in = copystdin();
        !           204:            else if ( (fp_in = fopen(*argv, "r")) == NULL )
        !           205:                error(FATAL, "can't open %s", *argv);
        !           206:            picpack();
        !           207:            fclose(fp_in);
        !           208:            argc--;
        !           209:            argv++;
        !           210:        }   /* End while */
        !           211: 
        !           212: }   /* End of arguments */
        !           213: 
        !           214: /*****************************************************************************/
        !           215: 
        !           216: FILE *copystdin()
        !           217: 
        !           218: {
        !           219: 
        !           220:     char       *tfile;                 /* temporary file name */
        !           221:     int                fd_out;                 /* and its file descriptor */
        !           222:     FILE       *fp;                    /* return value - the new input file */
        !           223: 
        !           224: /*
        !           225:  *
        !           226:  * Copies stdin to a temp file, unlinks the file, and returns the file pointer
        !           227:  * for the new temporary file to the caller. Needed because we read each input
        !           228:  * file twice in an attempt to handle pictures in diversions.
        !           229:  *
        !           230:  */
        !           231: 
        !           232:     if ( (tfile = tempnam(TEMPDIR, "post")) == NULL )
        !           233:        error(FATAL, "can't generate temp file name");
        !           234: 
        !           235:     if ( (fd_out = creat(tfile, 0660)) == -1 )
        !           236:        error(FATAL, "can't create %s", tfile);
        !           237: 
        !           238:     copyfile(fileno(stdin), fd_out);
        !           239:     close(fd_out);
        !           240: 
        !           241:     if ( (fp = fopen(tfile, "r")) == NULL )
        !           242:        error(FATAL, "can't open %s", tfile);
        !           243: 
        !           244:     unlink(tfile);
        !           245:     return(fp);
        !           246: 
        !           247: }   /* End of copystdin */
        !           248: 
        !           249: /*****************************************************************************/
        !           250: 
        !           251: copyfile(fd_in, fd_out)
        !           252: 
        !           253:     int                fd_in;                  /* input */
        !           254:     int                fd_out;                 /* and output files */
        !           255: 
        !           256: {
        !           257: 
        !           258:     char       buf[512];               /* internal buffer for reads and writes */
        !           259:     int                count;                  /* number of bytes put in buf[] */
        !           260: 
        !           261: /*
        !           262:  *
        !           263:  * Copies file fd_in to fd_out. Handles the second pass for each input file and
        !           264:  * also used to copy stdin to a temporary file.
        !           265:  *
        !           266:  */
        !           267: 
        !           268:     while ( (count = read(fd_in, buf, sizeof(buf))) > 0 )
        !           269:        if ( write(fd_out, buf, count) != count )
        !           270:            error(FATAL, "write error");
        !           271: 
        !           272: }   /* End of copyfile */
        !           273: 
        !           274: /*****************************************************************************/
        !           275: 
        !           276: done()
        !           277: 
        !           278: {
        !           279: 
        !           280: /*
        !           281:  *
        !           282:  * Finished with all the input files - unlink the temporary file that was used
        !           283:  * to record the in-line picture file pathnames.
        !           284:  *
        !           285:  */
        !           286: 
        !           287:     if ( temp_file != NULL )
        !           288:        unlink(temp_file);
        !           289: 
        !           290: }   /* End of done */
        !           291: 
        !           292: /*****************************************************************************/
        !           293: 
        !           294: picpack()
        !           295: 
        !           296: {
        !           297: 
        !           298:     char       line[512];              /* next input line */
        !           299:     char       name[100];              /* picture file names - from BP or PI */
        !           300:     int                i;                      /* for looking through keys[] */
        !           301: 
        !           302: /*
        !           303:  *
        !           304:  * Handles the two passes over the next input file. First pass compares the start
        !           305:  * of each line in *fp_in with the key strings saved in the keys[] array. If a
        !           306:  * match is found inline() is called to copy the picture file (ie. the file named
        !           307:  * as the second string in line[]) to stdout, provided the file hasn't previously
        !           308:  * been copied. The second pass goes back to the start of fp_in and copies it all
        !           309:  * to the output file.
        !           310:  *
        !           311:  */
        !           312: 
        !           313:     while ( fgets(line, sizeof(line), fp_in) != NULL )  {
        !           314:        for ( i = 0; keys[i] != NULL; i++ )
        !           315:            if ( strncmp(line, keys[i], strlen(keys[i])) == 0 )  {
        !           316:                if ( sscanf(line, "%*s %s", name) == 1 )  {
        !           317:                    strtok(name, "(");
        !           318:                    if ( gotpicfile(name) == FALSE )
        !           319:                        inline(name);
        !           320:                }   /* End if */
        !           321:            }   /* End if */
        !           322:     }  /* End while */
        !           323: 
        !           324:     fflush(fp_out);                    /* second pass - copy fp_in to fp_out */
        !           325:     fseek(fp_in, 0L, 0);
        !           326:     copyfile(fileno(fp_in), fileno(fp_out));
        !           327: 
        !           328: }   /* End of picpack */
        !           329: 
        !           330: /*****************************************************************************/
        !           331: 
        !           332: inline(name)
        !           333: 
        !           334:     char       *name;                  /* name of the in-line picture file */
        !           335: 
        !           336: {
        !           337: 
        !           338:     long       size;                   /* size in bytes - from fstat */
        !           339:     FILE       *fp;                    /* for reading *name */
        !           340:     int                ch;                     /* next character from picture file */
        !           341:     int                lastch = '\n';          /* so we know when to put out \! */
        !           342: 
        !           343:     struct stat        sbuf;                   /* for the picture file size */
        !           344: 
        !           345: /*
        !           346:  *
        !           347:  * Copies the picture file *name to the output file in an in-line format that can
        !           348:  * be passed through troff and recovered later by dpost. Transparent mode is used
        !           349:  * so each line starts with \! and all \ characters must be escaped. The in-line
        !           350:  * picture sequence begins with an "x X InlinePicture" device control command that
        !           351:  * names the picture file and gives its size (in bytes).
        !           352:  *
        !           353:  */
        !           354: 
        !           355:     if ( (fp = fopen(name, "r")) != NULL )  {
        !           356:        fstat(fileno(fp), &sbuf);
        !           357:        if ( (size = sbuf.st_size) > 0 )  {
        !           358:            fprintf(fp_out, "\\!x X InlinePicture %s %ld\n", name, size);
        !           359:            while ( (ch = getc(fp)) != EOF )  {
        !           360:                if ( lastch == '\n' )
        !           361:                    fprintf(fp_out, "\\!");
        !           362:                if ( ch == '\\' )
        !           363:                    putc('\\', fp_out);
        !           364:                putc(lastch = ch, fp_out);
        !           365:            }   /* End while */
        !           366:            if ( lastch != '\n' )
        !           367:                putc('\n', fp_out);
        !           368:        }    /* End if */
        !           369:        fclose(fp);
        !           370:        addpicfile(name);
        !           371:     } else if ( quiet == FALSE )
        !           372:        error(NON_FATAL, "can't read picture file %s", name);
        !           373: 
        !           374: }   /* End of inline */
        !           375: 
        !           376: /*****************************************************************************/
        !           377: 
        !           378: gotpicfile(name)
        !           379: 
        !           380:     char       *name;
        !           381: 
        !           382: {
        !           383: 
        !           384:     char       buf[100];
        !           385:     FILE       *fp_pic;
        !           386: 
        !           387: /*
        !           388:  *
        !           389:  * Checks the list of previously added picture files in *temp_file and returns
        !           390:  * FALSE if it's a new file and TRUE otherwise. Probably should open the temp
        !           391:  * file once for update and leave it open, rather than opening and closing it
        !           392:  * every time.
        !           393:  *
        !           394:  */
        !           395: 
        !           396:     if ( temp_file != NULL )
        !           397:        if ( (fp_pic = fopen(temp_file, "r")) != NULL )  {
        !           398:            while ( fscanf(fp_pic, "%s", buf) != EOF )
        !           399:                if ( strcmp(buf, name) == 0 )  {
        !           400:                    fclose(fp_pic);
        !           401:                    return(TRUE);
        !           402:                }   /* End if */
        !           403:            fclose(fp_pic);
        !           404:        }   /* End if */
        !           405: 
        !           406:     return(FALSE);
        !           407: 
        !           408: }   /* End of gotpicfile */
        !           409: 
        !           410: /*****************************************************************************/
        !           411: 
        !           412: addpicfile(name)
        !           413: 
        !           414:     char       *name;
        !           415: 
        !           416: {
        !           417: 
        !           418:     FILE       *fp_pic;
        !           419: 
        !           420: /*
        !           421:  *
        !           422:  * Adds string *name to the list of in-line picture files that's maintained in
        !           423:  * *temp_file. Should undoubtedly open the file once for update and use fseek()
        !           424:  * to move around in the file!
        !           425:  *
        !           426:  */
        !           427: 
        !           428:     if ( temp_file == NULL )
        !           429:        if ( (temp_file = tempnam(TEMPDIR, "picpac")) == NULL )
        !           430:            return;
        !           431: 
        !           432:     if ( (fp_pic = fopen(temp_file, "a")) != NULL )  {
        !           433:        fprintf(fp_pic, "%s\n", name);
        !           434:        fclose(fp_pic);
        !           435:     }  /* End if */
        !           436: 
        !           437: }   /* End of addpicfile */
        !           438: 
        !           439: /*****************************************************************************/
        !           440: 

unix.superglobalmegacorp.com

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