just sync with sources Reference: /n/atom/patch/applied2013/psdown Date: Tue Jun 18 21:09:21 CES 2013 Signed-off-by: quanstro@quanstro.net --- /sys/src/cmd/postscript/download/download.c Tue Jun 18 21:09:21 2013 +++ /sys/src/cmd/postscript/download/download.c Tue Jun 18 21:09:21 2013 @@ -1,5 +1,4 @@ /* - * * download - host resident font downloader * * Prepends host resident fonts to PostScript input files. The program assumes @@ -49,15 +48,16 @@ * * Was written quickly, so there's much room for improvement. Undoubtedly should * be a more general program (e.g. scan for other comments). - * */ #include +#include +#include +#include +#include #include #include -#include #include -#include #include "comments.h" /* PostScript file structuring comments */ #include "gen.h" /* general purpose definitions */ @@ -83,369 +83,447 @@ FILE *fp_in = stdin; /* next input file */ FILE *fp_temp = NULL; /* for copying stdin */ -void download(void); -void copyinput(void); -extern getcallerpc(void*); - -void -init_signals(void) -{ - if ( signal(SIGINT, interrupt) == SIG_IGN ) { - signal(SIGINT, SIG_IGN); - signal(SIGQUIT, SIG_IGN); - signal(SIGHUP, SIG_IGN); - } else { - signal(SIGHUP, interrupt); - signal(SIGQUIT, interrupt); - } - signal(SIGTERM, interrupt); +/*****************************************************************************/ -} +main(agc, agv) -void -options(void) -{ - char *optnames = "c:fm:p:r:H:T:DI"; - int ch; - extern char *optarg; - extern int optind; - - /* - * - * Reads and processes the command line options. - * - */ - - while((ch = getopt(argc, argv, optnames))!= EOF){ - switch(ch){ - case 'c': /* look for this comment */ - comment = optarg; - break; - case 'f': /* force a complete input file scan */ - atend = TRUE; - break; - case 'm': /* printer map table name */ - mapname = optarg; - break; - case 'p': /* printer name - for Unix 4.0 lp */ - printer = optarg; - break; - case 'r': /* resident font list */ - residentfonts = optarg; - break; - case 'H': /* host resident font directory */ - hostfontdir = optarg; - break; - case 'T': /* temporary file directory */ - temp_dir = optarg; - break; - case 'D': /* debug flag */ - debug = ON; - break; - case 'I': /* ignore FATAL errors */ - ignore = ON; - break; - case '?': /* don't understand the option */ - error(FATAL, ""); - break; - default: /* don't know what to do for ch */ - error(FATAL, "missing case for option %c\n", ch); - break; - } - } - argc -= optind; /* get ready for non-option args */ - argv += optind; -} + int agc; + char *agv[]; -void* -emalloc(long n) { - void *v; - v = (void*)malloc(n); - if(v == 0){ -// sysfatal("malloc: %r from %p %ld\n", getcallerpc(&n), n); - fprintf(stderr, "malloc: %r for %ld bytes\n", n); - abort(); - } -// setmalloctag(v, getcallerpc(&n)); - return v; -} +/* + * + * Host resident font downloader. The input files are assumed to be part of a + * single PostScript job. + * + */ + + argc = agc; /* other routines may want them */ + argv = agv; + + prog_name = argv[0]; /* just for error messages */ + + init_signals(); /* sets up interrupt handling */ + options(); /* first get command line options */ + readmap(); /* read the font map table */ + readresident(); /* and the optional resident font list */ + arguments(); /* then process non-option arguments */ + done(); /* and clean things up */ + exit(x_stat); /* not much could be wrong */ + +} /* End of main */ + +/*****************************************************************************/ + +init_signals() -void -readmap(void) { - char *path, *ptr; - int fd; - struct stat sbuf; - - /* - * Initializes the map table by reading an ASCII mapping file. If mapname begins - * with a / it's the map table. Otherwise hostfontdir, mapname, and suffix are - * combined to build the final pathname. If we can open the file we read it all - * into memory, erase comments, and separate the font and file name pairs. When - * we leave next points to the next free slot in the map[] array. If it's zero - * nothing was in the file or we couldn't open it. - * - */ - - if(hostfontdir == NULL || mapname == NULL) - return; - - if(*mapname != '/'){ - path = emalloc(strlen(hostfontdir) + strlen(mapname) + - strlen(suffix) + 2); - sprintf(path, "%s/%s%s", hostfontdir, mapname, suffix); - } else path = mapname; - - if((fd = open(path, 0))!= -1){ - if(fstat(fd, &sbuf)== -1) - error(FATAL, "can't fstat %s", path); - stringspace = emalloc(sbuf.st_size + 2); - if(read(fd, stringspace, sbuf.st_size)== -1) - error(FATAL, "can't read %s", path); - close(fd); - - stringspace[sbuf.st_size] = '\n'; /* just to be safe */ - stringspace[sbuf.st_size+1] = '\0'; - for(ptr = stringspace; *ptr != '\0'; ptr++) /* erase comments */ - if(*ptr == '%') - for(; *ptr != '\n' ; ptr++) - *ptr = ' '; - - for(ptr = stringspace; ; next++){ - if((next % 50)== 0) - map = allocate(map, next+50); - map[next].downloaded = FALSE; - map[next].font = strtok(ptr, " \t\n"); - map[next].file = strtok(ptr = NULL, " \t\n"); - if(map[next].font == NULL) - break; - if(map[next].file == NULL) - error(FATAL, "map table format error - check %s", path); - } - } -} +/* + * + * Makes sure we handle interrupts properly. + * + */ + + if ( signal(SIGINT, interrupt) == SIG_IGN ) { + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGHUP, SIG_IGN); + } else { + signal(SIGHUP, interrupt); + signal(SIGQUIT, interrupt); + } /* End else */ + + signal(SIGTERM, interrupt); + +} /* End of init_signals */ + +/*****************************************************************************/ + +options() -void -readresident(void) { - char *path; - int ch, n; - FILE *fp; - - /* - * - * Reads a file that lists the resident fonts for a particular printer and marks - * each font as already downloaded. Nothing's done if the file can't be read or - * there's no mapping file. Comments, as in the map file, begin with a % and - * extend to the end of the line. Added for Unix 4.0 lp. - * - */ - if(next == 0 ||(printer == NULL && residentfonts == NULL)) - return; - - if(printer != NULL){ /* use Unix 4.0 lp pathnames */ - sprintf(buf, "%s/printers/%s", HOSTDIR, printer); - path = buf; - } else - path = residentfonts; - - if((fp = fopen(path, "r"))!= NULL){ - while(fscanf(fp, "%s", buf)!= EOF) - if(buf[0] == '%') - while((ch = getc(fp))!= EOF && ch != '\n'); - else if((n = lookup(buf))< next) - map[n].downloaded = TRUE; - fclose(fp); - } -} -void -arguments(void) + int ch; /* return value from getopt() */ + char *optnames = "c:fm:p:r:H:T:DI"; + + extern char *optarg; /* used by getopt() */ + extern int optind; + +/* + * + * Reads and processes the command line options. + * + */ + + while ( (ch = getopt(argc, argv, optnames)) != EOF ) { + switch ( ch ) { + case 'c': /* look for this comment */ + comment = optarg; + break; + + case 'f': /* force a complete input file scan */ + atend = TRUE; + break; + + case 'm': /* printer map table name */ + mapname = optarg; + break; + + case 'p': /* printer name - for Unix 4.0 lp */ + printer = optarg; + break; + + case 'r': /* resident font list */ + residentfonts = optarg; + break; + + case 'H': /* host resident font directory */ + hostfontdir = optarg; + break; + + case 'T': /* temporary file directory */ + temp_dir = optarg; + break; + + case 'D': /* debug flag */ + debug = ON; + break; + + case 'I': /* ignore FATAL errors */ + ignore = ON; + break; + + case '?': /* don't understand the option */ + error(FATAL, ""); + break; + + default: /* don't know what to do for ch */ + error(FATAL, "missing case for option %c\n", ch); + break; + } /* End switch */ + } /* End while */ + + argc -= optind; /* get ready for non-option args */ + argv += optind; + +} /* End of options */ + +/*****************************************************************************/ + +readmap() + { - /* - * - * Makes sure all the non-option command line arguments are processed. If we get - * here and there aren't any arguments left, or if '-' is one of the input files - * we'll translate stdin. Assumes input files are part of a single PostScript - * job and fonts can be downloaded at the start of each file. - * - */ - - if(argc < 1) - download(); - else { - while(argc > 0){ - fp_temp = NULL; - if(strcmp(*argv, "-")== 0) - fp_in = stdin; - else if((fp_in = fopen(*argv, "r"))== NULL) - error(FATAL, "can't open %s", *argv); - download(); - if(fp_in != stdin) - fclose(fp_in); - if(fp_temp != NULL) - fclose(fp_temp); - argc--; - argv++; - } - } -} -void -done(void) + char *path; + char *ptr; + int fd; + struct stat sbuf; + +/* + * + * Initializes the map table by reading an ASCII mapping file. If mapname begins + * with a / it's the map table. Otherwise hostfontdir, mapname, and suffix are + * combined to build the final pathname. If we can open the file we read it all + * into memory, erase comments, and separate the font and file name pairs. When + * we leave next points to the next free slot in the map[] array. If it's zero + * nothing was in the file or we couldn't open it. + * + */ + + if ( hostfontdir == NULL || mapname == NULL ) + return; + + if ( *mapname != '/' ) { + if ( (path = malloc(strlen(hostfontdir) + strlen(mapname) + + strlen(suffix) + 2)) == NULL ) + error(FATAL, "no memory"); + sprintf(path, "%s/%s%s", hostfontdir, mapname, suffix); + } else path = mapname; + + if ( (fd = open(path, 0)) != -1 ) { + if ( fstat(fd, &sbuf) == -1 ) + error(FATAL, "can't fstat %s", path); + if ( (stringspace = malloc(sbuf.st_size + 2)) == NULL ) + error(FATAL, "no memory for %s (%d bytes)", path, sbuf.st_size + 2); + if ( read(fd, stringspace, sbuf.st_size) == -1 ) + error(FATAL, "can't read %s", path); + close(fd); + + stringspace[sbuf.st_size] = '\n'; /* just to be safe */ + stringspace[sbuf.st_size+1] = '\0'; + for ( ptr = stringspace; *ptr != '\0'; ptr++ ) /* erase comments */ + if ( *ptr == '%' ) + for ( ; *ptr != '\n' ; ptr++ ) + *ptr = ' '; + + for ( ptr = stringspace; ; next++ ) { + if ( (next % 50) == 0 ) + map = allocate(map, next+50); + map[next].downloaded = FALSE; + map[next].font = strtok(ptr, " \t\n"); + map[next].file = strtok(ptr = NULL, " \t\n"); + if ( map[next].font == NULL ) + break; + if ( map[next].file == NULL ) + error(FATAL, "map table format error - check %s", path); + } /* End for */ + } /* End if */ + +} /* End of readmap */ + +/*****************************************************************************/ + +readresident() + { - if(temp_file != NULL) - unlink(temp_file); -} -void -download(void) + FILE *fp; + char *path; + int ch; + int n; + +/* + * + * Reads a file that lists the resident fonts for a particular printer and marks + * each font as already downloaded. Nothing's done if the file can't be read or + * there's no mapping file. Comments, as in the map file, begin with a % and + * extend to the end of the line. Added for Unix 4.0 lp. + * + */ + + if ( next == 0 || (printer == NULL && residentfonts == NULL) ) + return; + + if ( printer != NULL ) { /* use Unix 4.0 lp pathnames */ + sprintf(buf, "%s/printers/%s", HOSTDIR, printer); + path = buf; + } else path = residentfonts; + + if ( (fp = fopen(path, "r")) != NULL ) { + while ( fscanf(fp, "%s", buf) != EOF ) + if ( buf[0] == '%' ) + while ( (ch = getc(fp)) != EOF && ch != '\n' ) ; + else if ( (n = lookup(buf)) < next ) + map[n].downloaded = TRUE; + fclose(fp); + } /* End if */ + +} /* End of readresident */ + +/*****************************************************************************/ + +arguments() + { - int infontlist = FALSE; - /* - * - * If next is zero the map table is empty and all we do is copy the input file - * to stdout. Otherwise we read the input file looking for %%DocumentFonts: or - * continuation comments, add any accessible fonts to the output file, and then - * append the input file. When reading stdin we append lines to fp_temp and - * recover them when we're ready to copy the input file. fp_temp will often - * only contain part of stdin - if there's no %%DocumentFonts:(atend)comment - * we stop reading fp_in after the header. - * - */ - - if(next > 0){ - if(fp_in == stdin){ - if((temp_file = tempnam(temp_dir, "post"))== NULL) - error(FATAL, "can't generate temp file name"); - if((fp_temp = fopen(temp_file, "w+r"))== NULL) - error(FATAL, "can't open %s", temp_file); - unlink(temp_file); - } - - while(fgets(buf, sizeof(buf), fp_in)!= NULL){ - if(fp_temp != NULL) - fprintf(fp_temp, "%s", buf); - if(buf[0] != '%' || buf[1] != '%'){ - if((buf[0] != '%' || buf[1] != '!')&& atend == FALSE) - break; - infontlist = FALSE; - } else if(strncmp(buf, comment, strlen(comment))== 0){ - copyfonts(buf); - infontlist = TRUE; - } else if(buf[2] == '+' && infontlist == TRUE) - copyfonts(buf); - else - infontlist = FALSE; - } - } - copyinput(); -} +/* + * + * Makes sure all the non-option command line arguments are processed. If we get + * here and there aren't any arguments left, or if '-' is one of the input files + * we'll translate stdin. Assumes input files are part of a single PostScript + * job and fonts can be downloaded at the start of each file. + * + */ + + if ( argc < 1 ) + download(); + else { + while ( argc > 0 ) { + fp_temp = NULL; + if ( strcmp(*argv, "-") == 0 ) + fp_in = stdin; + else if ( (fp_in = fopen(*argv, "r")) == NULL ) + error(FATAL, "can't open %s", *argv); + download(); + if ( fp_in != stdin ) + fclose(fp_in); + if ( fp_temp != NULL ) + fclose(fp_temp); + argc--; + argv++; + } /* End while */ + } /* End else */ + +} /* End of arguments */ + +/*****************************************************************************/ + +done() -int -copyfonts(char *list) { - char *font; - char *path; - int n; - - /* - * - * list points to a %%DocumentFonts: or continuation comment. What follows the - * the keyword will be a list of fonts separated by white space(or(atend)). - * Look for each font in the map table and if it's found copy the font file to - * stdout(once only). - * - */ - - strtok(list, " \n"); /* skip to the font list */ - while((font = strtok(NULL, " \t\n"))!= NULL){ - if(strcmp(font, ATEND)== 0){ - atend = TRUE; - break; - } - if((n = lookup(font))< next){ - if(*map[n].file != '/'){ - path = emalloc(strlen(hostfontdir)+strlen(map[n].file)+2); - sprintf(path, "%s/%s", hostfontdir, map[n].file); - cat(path); - free(path); - } else - cat(map[n].file); - map[n].downloaded = TRUE; - } - } +/* + * + * Clean things up before we quit. + * + */ + + if ( temp_file != NULL ) + unlink(temp_file); -} +} /* End of done */ + +/*****************************************************************************/ + +download() -void -copyinput(void) { - /* - * - * Copies the input file to stdout. If fp_temp isn't NULL seek to the start and - * add it to the output file - it's a partial (or complete) copy of stdin made - * by download(). Then copy fp_in, but only seek to the start if it's not stdin. - * - */ - if(fp_temp != NULL){ - fseek(fp_temp, 0L, 0); - while(fgets(buf, sizeof(buf), fp_temp)!= NULL) - printf("%s", buf); - } - if(fp_in != stdin) - fseek(fp_in, 0L, 0); + int infontlist = FALSE; - while(fgets(buf, sizeof(buf), fp_in)!= NULL) - printf("%s", buf); -} +/* + * + * If next is zero the map table is empty and all we do is copy the input file + * to stdout. Otherwise we read the input file looking for %%DocumentFonts: or + * continuation comments, add any accessible fonts to the output file, and then + * append the input file. When reading stdin we append lines to fp_temp and + * recover them when we're ready to copy the input file. fp_temp will often + * only contain part of stdin - if there's no %%DocumentFonts: (atend) comment + * we stop reading fp_in after the header. + * + */ + + if ( next > 0 ) { + if ( fp_in == stdin ) { + if ( (temp_file = tempnam(temp_dir, "post")) == NULL ) + error(FATAL, "can't generate temp file name"); + if ( (fp_temp = fopen(temp_file, "w+r")) == NULL ) + error(FATAL, "can't open %s", temp_file); + unlink(temp_file); + } /* End if */ + + while ( fgets(buf, sizeof(buf), fp_in) != NULL ) { + if ( fp_temp != NULL ) + fprintf(fp_temp, "%s", buf); + if ( buf[0] != '%' || buf[1] != '%' ) { + if ( (buf[0] != '%' || buf[1] != '!') && atend == FALSE ) + break; + infontlist = FALSE; + } else if ( strncmp(buf, comment, strlen(comment)) == 0 ) { + copyfonts(buf); + infontlist = TRUE; + } else if ( buf[2] == '+' && infontlist == TRUE ) + copyfonts(buf); + else infontlist = FALSE; + } /* End while */ + } /* End if */ + + copyinput(); + +} /* End of download */ + +/*****************************************************************************/ + +copyfonts(list) + + char *list; -int -lookup(char *font) { - int i; - for(i = 0; i < next; i++) - if(strcmp(font, map[i].font)== 0){ - if(map[i].downloaded == TRUE) - i = next; - break; - } + char *font; + char *path; + int n; + +/* + * + * list points to a %%DocumentFonts: or continuation comment. What follows the + * the keyword will be a list of fonts separated by white space (or (atend)). + * Look for each font in the map table and if it's found copy the font file to + * stdout (once only). + * + */ - return i; + strtok(list, " \n"); /* skip to the font list */ -} + while ( (font = strtok(NULL, " \t\n")) != NULL ) { + if ( strcmp(font, ATEND) == 0 ) { + atend = TRUE; + break; + } /* End if */ + if ( (n = lookup(font)) < next ) { + if ( *map[n].file != '/' ) { + if ( (path = malloc(strlen(hostfontdir)+strlen(map[n].file)+2)) == NULL ) + error(FATAL, "no memory"); + sprintf(path, "%s/%s", hostfontdir, map[n].file); + cat(path); + free(path); + } else cat(map[n].file); + map[n].downloaded = TRUE; + } /* End if */ + } /* End while */ + +} /* End of copyfonts */ + +/*****************************************************************************/ + +copyinput() -Map* -allocate(Map *ptr, int num) { - ptr = (Map *)realloc(ptr, num * sizeof(Map)); - if ( ptr == NULL ) - error(FATAL, "no map memory"); - return ptr; -} -int -main(int agc, char **agv) +/* + * + * Copies the input file to stdout. If fp_temp isn't NULL seek to the start and + * add it to the output file - it's a partial (or complete) copy of stdin made + * by download(). Then copy fp_in, but only seek to the start if it's not stdin. + * + */ + + if ( fp_temp != NULL ) { + fseek(fp_temp, 0L, 0); + while ( fgets(buf, sizeof(buf), fp_temp) != NULL ) + printf("%s", buf); + } /* End if */ + + if ( fp_in != stdin ) + fseek(fp_in, 0L, 0); + + while ( fgets(buf, sizeof(buf), fp_in) != NULL ) + printf("%s", buf); + +} /* End of copyinput */ + +/*****************************************************************************/ + +lookup(font) + + char *font; + { - argc = agc; /* other routines may want them */ - argv = agv; - prog_name = argv[0]; /* just for error messages */ + int i; - init_signals(); /* sets up interrupt handling */ - options(); /* first get command line options */ - readmap(); /* read the font map table */ - readresident(); /* and the optional resident font list */ - arguments(); /* then process non-option arguments */ - done(); /* and clean things up */ - exit(x_stat); /* not much could be wrong */ +/* + * + * Looks for *font in the map table. Return the map table index if found and + * not yet downloaded - otherwise return next. + * + */ + for ( i = 0; i < next; i++ ) + if ( strcmp(font, map[i].font) == 0 ) { + if ( map[i].downloaded == TRUE ) + i = next; + break; + } /* End if */ + + return(i); + +} /* End of lookup */ + +/* + * Allocates space for num Map elements. Calls malloc() if ptr is NULL and + * realloc() otherwise. + */ +Map * +allocate(Map *ptr, int num) +{ + if (ptr == NULL) + ptr = (Map *)malloc(num * sizeof(Map)); + else + ptr = (Map *)realloc(ptr, num * sizeof(Map)); + if (ptr == NULL) + error(FATAL, "no map memory"); + return ptr; } -