|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.