Annotation of researchv10no/cmd/post.src/download/download.c, revision 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.