Annotation of researchv10no/cmd/postscript/picpack/picpack.c, revision 1.1.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.