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