Annotation of researchv10no/cmd/post.src/download/download.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  *
                      3:  * download - host resident font downloader
                      4:  *
                      5:  * Prepends host resident fonts to PostScript input files. The program assumes
                      6:  * the input files are part of a single PostScript job and that requested fonts
                      7:  * can be downloaded at the start of each input file. Downloaded fonts are the
                      8:  * ones named in a %%DocumentFonts: comment and listed in a special map table.
                      9:  * Map table pathnames (supplied using the -m option) that begin with a / are
                     10:  * taken as is. Otherwise the final pathname is built using *hostfontdir (-H
                     11:  * option), *mapname (-m option), and *suffix.
                     12:  *
                     13:  * The map table consists of fontname-filename pairs, separated by white space.
                     14:  * Comments are introduced by % (as in PostScript) and extend to the end of the
                     15:  * current line. The only fonts that can be downloaded are the ones listed in
                     16:  * the active map table that point the program to a readable Unix file. A request
                     17:  * for an unlisted font or inaccessible file is ignored. All font requests are
                     18:  * ignored if the map table can't be read. In that case the program simply copies
                     19:  * the input files to stdout.
                     20:  *
                     21:  * An example (but not one to follow) of what can be in a map table is,
                     22:  *
                     23:  *     %
                     24:  *     % Map requests for Bookman-Light to file *hostfontdir/KR
                     25:  *     %
                     26:  *
                     27:  *       Bookman-Light         KR      % Keeping everything (including the map
                     28:  *                                     % table) in *hostfontdir seems like the
                     29:  *                                     % cleanest approach.
                     30:  *
                     31:  *     %
                     32:  *     % Map Palatino-Roman to file *hostfontdir/palatino/Roman
                     33:  *     %
                     34:  *       Palatino-Roman        palatino/Roman
                     35:  *
                     36:  *     % Map ZapfDingbats to file /usr/lib/host/dingbats
                     37:  *
                     38:  *       ZapfDingbats          /usr/lib/host/dingbats
                     39:  *
                     40:  * Once again, file names that begin with a / are taken as is. All others have
                     41:  * *hostfontdir/ prepended to the file string associated with a particular font.
                     42:  *
                     43:  * Map table can be associated with a printer model (e.g. a LaserWriter), a
                     44:  * printer destination, or whatever - the choice is up to an administrator.
                     45:  * By destination may be best if your spooler is running several private
                     46:  * printers. Host resident fonts are usually purchased under a license that
                     47:  * restricts their use to a limited number of printers. A font licensed for
                     48:  * a single printer should only be used on that printer.
                     49:  *
                     50:  * Was written quickly, so there's much room for improvement. Undoubtedly should
                     51:  * be a more general program (e.g. scan for other comments).
                     52:  *
                     53:  */
                     54: 
                     55: #include <stdio.h>
                     56: #include <signal.h>
                     57: #include <fcntl.h>
                     58: #include <sys/types.h>
                     59: #include <sys/stat.h>
                     60: 
                     61: #include "comments.h"                  /* PostScript file structuring comments */
                     62: #include "gen.h"                       /* general purpose definitions */
                     63: #include "path.h"                      /* for temporary directory */
                     64: #include "ext.h"                       /* external variable declarations */
                     65: #include "download.h"                  /* a few special definitions */
                     66: 
                     67: char   *temp_dir = TEMPDIR;            /* temp directory - for copying stdin */
                     68: char   *hostfontdir = HOSTDIR;         /* host resident directory */
                     69: char   *mapname = "map";               /* map table - usually in *hostfontdir */
                     70: char   *suffix = "";                   /* appended to the map table pathname */
                     71: Map    *map = NULL;                    /* device font map table */
                     72: char   *stringspace = NULL;            /* for storing font and file strings */
                     73: int    next = 0;                       /* next free slot in map[] */
                     74: 
                     75: char   *residentfonts = NULL;          /* list of printer resident fonts */
                     76: char   *printer = NULL;                /* printer name - only for Unix 4.0 lp */
                     77: 
                     78: char   buf[2048];                      /* input file line buffer */
                     79: char   *comment = DOCUMENTFONTS;       /* look for this comment */
                     80: int    atend = FALSE;                  /* TRUE only if a comment says so */
                     81: 
                     82: FILE   *fp_in = stdin;                 /* next input file */
                     83: FILE   *fp_temp = NULL;                /* for copying stdin */
                     84: 
                     85: /*****************************************************************************/
                     86: 
                     87: main(agc, agv)
                     88: 
                     89:     int                agc;
                     90:     char       *agv[];
                     91: 
                     92: {
                     93: 
                     94: /*
                     95:  *
                     96:  * Host resident font downloader. The input files are assumed to be part of a
                     97:  * single PostScript job.
                     98:  *
                     99:  */
                    100: 
                    101:     argc = agc;                                /* other routines may want them */
                    102:     argv = agv;
                    103: 
                    104:     prog_name = argv[0];               /* just for error messages */
                    105: 
                    106:     init_signals();                    /* sets up interrupt handling */
                    107:     options();                         /* first get command line options */
                    108:     readmap();                         /* read the font map table */
                    109:     readresident();                    /* and the optional resident font list */
                    110:     arguments();                       /* then process non-option arguments */
                    111:     done();                            /* and clean things up */
                    112: 
                    113:     exit(x_stat);                      /* not much could be wrong */
                    114: 
                    115: }   /* End of main */
                    116: 
                    117: /*****************************************************************************/
                    118: 
                    119: init_signals()
                    120: 
                    121: {
                    122: 
                    123: /*
                    124:  *
                    125:  * Makes sure we handle interrupts properly.
                    126:  *
                    127:  */
                    128: 
                    129:     if ( signal(SIGINT, interrupt) == SIG_IGN ) {
                    130:        signal(SIGINT, SIG_IGN);
                    131:        signal(SIGQUIT, SIG_IGN);
                    132:        signal(SIGHUP, SIG_IGN);
                    133:     } else {
                    134:        signal(SIGHUP, interrupt);
                    135:        signal(SIGQUIT, interrupt);
                    136:     }   /* End else */
                    137: 
                    138:     signal(SIGTERM, interrupt);
                    139: 
                    140: }   /* End of init_signals */
                    141: 
                    142: /*****************************************************************************/
                    143: 
                    144: options()
                    145: 
                    146: {
                    147: 
                    148:     int                ch;                     /* return value from getopt() */
                    149:     char       *optnames = "c:fm:p:r:H:T:DI";
                    150: 
                    151:     extern char        *optarg;                /* used by getopt() */
                    152:     extern int optind;
                    153: 
                    154: /*
                    155:  *
                    156:  * Reads and processes the command line options.
                    157:  *
                    158:  */
                    159: 
                    160:     while ( (ch = getopt(argc, argv, optnames)) != EOF ) {
                    161:        switch ( ch ) {
                    162:            case 'c':                   /* look for this comment */
                    163:                    comment = optarg;
                    164:                    break;
                    165: 
                    166:            case 'f':                   /* force a complete input file scan */
                    167:                    atend = TRUE;
                    168:                    break;
                    169: 
                    170:            case 'm':                   /* printer map table name */
                    171:                    mapname = optarg;
                    172:                    break;
                    173: 
                    174:            case 'p':                   /* printer name - for Unix 4.0 lp */
                    175:                    printer = optarg;
                    176:                    break;
                    177: 
                    178:            case 'r':                   /* resident font list */
                    179:                    residentfonts = optarg;
                    180:                    break;
                    181: 
                    182:            case 'H':                   /* host resident font directory */
                    183:                    hostfontdir = optarg;
                    184:                    break;
                    185: 
                    186:            case 'T':                   /* temporary file directory */
                    187:                    temp_dir = optarg;
                    188:                    break;
                    189: 
                    190:            case 'D':                   /* debug flag */
                    191:                    debug = ON;
                    192:                    break;
                    193: 
                    194:            case 'I':                   /* ignore FATAL errors */
                    195:                    ignore = ON;
                    196:                    break;
                    197: 
                    198:            case '?':                   /* don't understand the option */
                    199:                    error(FATAL, "");
                    200:                    break;
                    201: 
                    202:            default:                    /* don't know what to do for ch */
                    203:                    error(FATAL, "missing case for option %c\n", ch);
                    204:                    break;
                    205:        }   /* End switch */
                    206:     }   /* End while */
                    207: 
                    208:     argc -= optind;                    /* get ready for non-option args */
                    209:     argv += optind;
                    210: 
                    211: }   /* End of options */
                    212: 
                    213: /*****************************************************************************/
                    214: 
                    215: readmap()
                    216: 
                    217: {
                    218: 
                    219:     char       *path;
                    220:     char       *ptr;
                    221:     int                fd;
                    222:     struct stat        sbuf;
                    223: 
                    224: /*
                    225:  *
                    226:  * Initializes the map table by reading an ASCII mapping file. If mapname begins
                    227:  * with a / it's the map table. Otherwise hostfontdir, mapname, and suffix are
                    228:  * combined to build the final pathname. If we can open the file we read it all
                    229:  * into memory, erase comments, and separate the font and file name pairs. When
                    230:  * we leave next points to the next free slot in the map[] array. If it's zero
                    231:  * nothing was in the file or we couldn't open it.
                    232:  *
                    233:  */
                    234: 
                    235:     if ( hostfontdir == NULL || mapname == NULL )
                    236:        return;
                    237: 
                    238:     if ( *mapname != '/' ) {
                    239:        if ( (path = malloc(strlen(hostfontdir) + strlen(mapname) +
                    240:                                                strlen(suffix) + 2)) == NULL )
                    241:            error(FATAL, "no memory");
                    242:        sprintf(path, "%s/%s%s", hostfontdir, mapname, suffix);
                    243:     } else path = mapname;
                    244: 
                    245:     if ( (fd = open(path, 0)) != -1 ) {
                    246:        if ( fstat(fd, &sbuf) == -1 )
                    247:            error(FATAL, "can't fstat %s", path);
                    248:        if ( (stringspace = malloc(sbuf.st_size + 2)) == NULL )
                    249:            error(FATAL, "no memory");
                    250:        if ( read(fd, stringspace, sbuf.st_size) == -1 )
                    251:            error(FATAL, "can't read %s", path);
                    252:        close(fd);
                    253: 
                    254:        stringspace[sbuf.st_size] = '\n';       /* just to be safe */
                    255:        stringspace[sbuf.st_size+1] = '\0';
                    256:        for ( ptr = stringspace; *ptr != '\0'; ptr++ )  /* erase comments */
                    257:            if ( *ptr == '%' )
                    258:                for ( ; *ptr != '\n' ; ptr++ )
                    259:                    *ptr = ' ';
                    260: 
                    261:        for ( ptr = stringspace; ; next++ ) {
                    262:            if ( (next % 50) == 0 )
                    263:                map = allocate(map, next+50);
                    264:            map[next].downloaded = FALSE;
                    265:            map[next].font = strtok(ptr, " \t\n");
                    266:            map[next].file = strtok(ptr = NULL, " \t\n");
                    267:            if ( map[next].font == NULL )
                    268:                break;
                    269:            if ( map[next].file == NULL )
                    270:                error(FATAL, "map table format error - check %s", path);
                    271:        }   /* End for */
                    272:     }  /* End if */
                    273: 
                    274: }   /* End of readmap */
                    275: 
                    276: /*****************************************************************************/
                    277: 
                    278: readresident()
                    279: 
                    280: {
                    281: 
                    282:     FILE       *fp;
                    283:     char       *path;
                    284:     int                ch;
                    285:     int                n;
                    286: 
                    287: /*
                    288:  *
                    289:  * Reads a file that lists the resident fonts for a particular printer and marks
                    290:  * each font as already downloaded. Nothing's done if the file can't be read or
                    291:  * there's no mapping file. Comments, as in the map file, begin with a % and
                    292:  * extend to the end of the line. Added for Unix 4.0 lp.
                    293:  *
                    294:  */
                    295: 
                    296:     if ( next == 0 || (printer == NULL && residentfonts == NULL) )
                    297:        return;
                    298: 
                    299:     if ( printer != NULL ) {           /* use Unix 4.0 lp pathnames */
                    300:        sprintf(buf, "/etc/lp/printers/%s/residentfonts", printer);
                    301:        path = buf;
                    302:     } else path = residentfonts;
                    303: 
                    304:     if ( (fp = fopen(path, "r")) != NULL ) {
                    305:        while ( fscanf(fp, "%s", buf) != EOF )
                    306:            if ( buf[0] == '%' )
                    307:                while ( (ch = getc(fp)) != EOF && ch != '\n' ) ;
                    308:            else if ( (n = lookup(buf)) < next )
                    309:                map[n].downloaded = TRUE;
                    310:        fclose(fp);
                    311:     }  /* End if */
                    312: 
                    313: }   /* End of readresident */
                    314: 
                    315: /*****************************************************************************/
                    316: 
                    317: arguments()
                    318: 
                    319: {
                    320: 
                    321: /*
                    322:  *
                    323:  * Makes sure all the non-option command line arguments are processed. If we get
                    324:  * here and there aren't any arguments left, or if '-' is one of the input files
                    325:  * we'll translate stdin. Assumes input files are part of a single PostScript
                    326:  * job and fonts can be downloaded at the start of each file.
                    327:  *
                    328:  */
                    329: 
                    330:     if ( argc < 1 )
                    331:        download();
                    332:     else {
                    333:        while ( argc > 0 ) {
                    334:            fp_temp = NULL;
                    335:            if ( strcmp(*argv, "-") == 0 )
                    336:                fp_in = stdin;
                    337:            else if ( (fp_in = fopen(*argv, "r")) == NULL )
                    338:                error(FATAL, "can't open %s", *argv);
                    339:            download();
                    340:            if ( fp_in != stdin )
                    341:                fclose(fp_in);
                    342:            if ( fp_temp != NULL )
                    343:                fclose(fp_temp);
                    344:            argc--;
                    345:            argv++;
                    346:        }   /* End while */
                    347:     }  /* End else */
                    348: 
                    349: }   /* End of arguments */
                    350: 
                    351: /*****************************************************************************/
                    352: 
                    353: done()
                    354: 
                    355: {
                    356: 
                    357: /*
                    358:  *
                    359:  * Clean things up before we quit.
                    360:  *
                    361:  */
                    362: 
                    363:     if ( temp_file != NULL )
                    364:        unlink(temp_file);
                    365: 
                    366: }   /* End of done */
                    367: 
                    368: /*****************************************************************************/
                    369: 
                    370: download()
                    371: 
                    372: {
                    373: 
                    374:     int                infontlist = FALSE;
                    375: 
                    376: /*
                    377:  *
                    378:  * If next is zero the map table is empty and all we do is copy the input file
                    379:  * to stdout. Otherwise we read the input file looking for %%DocumentFonts: or
                    380:  * continuation comments, add any accessible fonts to the output file, and then
                    381:  * append the input file. When reading stdin we append lines to fp_temp and
                    382:  * recover them when we're ready to copy the input file. fp_temp will often
                    383:  * only contain part of stdin - if there's no %%DocumentFonts: (atend) comment
                    384:  * we stop reading fp_in after the header.
                    385:  *
                    386:  */
                    387: 
                    388:     if ( next > 0 ) {
                    389:        if ( fp_in == stdin ) {
                    390:            if ( (temp_file = tempnam(temp_dir, "post")) == NULL )
                    391:                error(FATAL, "can't generate temp file name");
                    392:            if ( (fp_temp = fopen(temp_file, "w+r")) == NULL )
                    393:                error(FATAL, "can't open %s", temp_file);
                    394:            unlink(temp_file);
                    395:            temp_file = NULL;
                    396:        }   /* End if */
                    397: 
                    398:        while ( fgets(buf, sizeof(buf), fp_in) != NULL ) {
                    399:            if ( fp_temp != NULL )
                    400:                fprintf(fp_temp, "%s", buf);
                    401:            if ( buf[0] != '%' || buf[1] != '%' ) {
                    402:                if ( (buf[0] != '%' || buf[1] != '!') && atend == FALSE )
                    403:                    break;
                    404:                infontlist = FALSE;
                    405:            } else if ( strncmp(buf, comment, strlen(comment)) == 0 ) {
                    406:                copyfonts(buf);
                    407:                infontlist = TRUE;
                    408:            } else if ( buf[2] == '+' && infontlist == TRUE )
                    409:                copyfonts(buf);
                    410:            else infontlist = FALSE;
                    411:        }   /* End while */
                    412:     }  /* End if */
                    413: 
                    414:     copyinput();
                    415: 
                    416: }   /* End of download */
                    417: 
                    418: /*****************************************************************************/
                    419: 
                    420: copyfonts(list)
                    421: 
                    422:     char       *list;
                    423: 
                    424: {
                    425: 
                    426:     char       *font;
                    427:     char       *path;
                    428:     int                n;
                    429: 
                    430: /*
                    431:  *
                    432:  * list points to a %%DocumentFonts: or continuation comment. What follows the
                    433:  * the keyword will be a list of fonts separated by white space (or (atend)).
                    434:  * Look for each font in the map table and if it's found copy the font file to
                    435:  * stdout (once only).
                    436:  *
                    437:  */
                    438: 
                    439:     strtok(list, " \n");               /* skip to the font list */
                    440: 
                    441:     while ( (font = strtok(NULL, " \t\n")) != NULL ) {
                    442:        if ( strcmp(font, ATEND) == 0 ) {
                    443:            atend = TRUE;
                    444:            break;
                    445:        }   /* End if */
                    446:        if ( (n = lookup(font)) < next ) {
                    447:            if ( *map[n].file != '/' ) {
                    448:                if ( (path = malloc(strlen(hostfontdir)+strlen(map[n].file)+2)) == NULL )
                    449:                    error(FATAL, "no memory");
                    450:                sprintf(path, "%s/%s", hostfontdir, map[n].file);
                    451:                cat(path);
                    452:                free(path);
                    453:            } else cat(map[n].file);
                    454:            map[n].downloaded = TRUE;
                    455:        }   /* End if */
                    456:     }  /* End while */
                    457: 
                    458: }   /* End of copyfonts */
                    459: 
                    460: /*****************************************************************************/
                    461: 
                    462: copyinput()
                    463: 
                    464: {
                    465: 
                    466: /*
                    467:  *
                    468:  * Copies the input file to stdout. If fp_temp isn't NULL seek to the start and
                    469:  * add it to the output file - it's a partial (or complete) copy of stdin made
                    470:  * by download(). Then copy fp_in, but only seek to the start if it's not stdin.
                    471:  *
                    472:  */
                    473: 
                    474:     if ( fp_temp != NULL ) {
                    475:        fseek(fp_temp, 0L, 0);
                    476:        while ( fgets(buf, sizeof(buf), fp_temp) != NULL )
                    477:            printf("%s", buf);
                    478:     }  /* End if */
                    479: 
                    480:     if ( fp_in != stdin )
                    481:        fseek(fp_in, 0L, 0);
                    482: 
                    483:     while ( fgets(buf, sizeof(buf), fp_in) != NULL )
                    484:        printf("%s", buf);
                    485: 
                    486: }   /* End of copyinput */
                    487: 
                    488: /*****************************************************************************/
                    489: 
                    490: lookup(font)
                    491: 
                    492:     char       *font;
                    493: 
                    494: {
                    495: 
                    496:     int                i;
                    497: 
                    498: /*
                    499:  *
                    500:  * Looks for *font in the map table. Return the map table index if found and
                    501:  * not yet downloaded - otherwise return next.
                    502:  *
                    503:  */
                    504: 
                    505:     for ( i = 0; i < next; i++ )
                    506:        if ( strcmp(font, map[i].font) == 0 ) {
                    507:            if ( map[i].downloaded == TRUE )
                    508:                i = next;
                    509:            break;
                    510:        }   /* End if */
                    511: 
                    512:     return(i);
                    513: 
                    514: }   /* End of lookup */
                    515: 
                    516: /*****************************************************************************/
                    517: 
                    518: Map *allocate(ptr, num)
                    519: 
                    520:     Map                *ptr;
                    521:     int                num;
                    522: 
                    523: {
                    524: 
                    525: /*
                    526:  *
                    527:  * Allocates space for num Map elements. Calls malloc() if ptr is NULL and
                    528:  * realloc() otherwise.
                    529:  *
                    530:  */
                    531: 
                    532:     if ( ptr == NULL )
                    533:        ptr = (Map *)malloc(num * sizeof(Map));
                    534:     else ptr = (Map *)realloc(ptr, num * sizeof(Map));
                    535: 
                    536:     if ( ptr == NULL )
                    537:        error(FATAL, "no map memory");
                    538: 
                    539:     return(ptr);
                    540: 
                    541: }   /* End of allocate */
                    542: 
                    543: /*****************************************************************************/
                    544: 

unix.superglobalmegacorp.com

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