⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 download.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
/* * * download - host resident font downloader * * Prepends host resident fonts to PostScript input files. The program assumes * the input files are part of a single PostScript job and that requested fonts * can be downloaded at the start of each input file. Downloaded fonts are the * ones named in a %%DocumentFonts: comment and listed in a special map table. * Map table pathnames (supplied using the -m option) that begin with a / are * taken as is. Otherwise the final pathname is built using *hostfontdir (-H * option), *mapname (-m option), and *suffix. * * The map table consists of fontname-filename pairs, separated by white space. * Comments are introduced by % (as in PostScript) and extend to the end of the * current line. The only fonts that can be downloaded are the ones listed in * the active map table that point the program to a readable Unix file. A request * for an unlisted font or inaccessible file is ignored. All font requests are * ignored if the map table can't be read. In that case the program simply copies * the input files to stdout. * * An example (but not one to follow) of what can be in a map table is, * *	% *	% Map requests for Bookman-Light to file *hostfontdir/KR *	% * *	  Bookman-Light		KR	% Keeping everything (including the map *					% table) in *hostfontdir seems like the *					% cleanest approach. * *	% *	% Map Palatino-Roman to file *hostfontdir/palatino/Roman *	% *	  Palatino-Roman	palatino/Roman * *	% Map ZapfDingbats to file /usr/lib/host/dingbats * *	  ZapfDingbats		/usr/lib/host/dingbats * * Once again, file names that begin with a / are taken as is. All others have * *hostfontdir/ prepended to the file string associated with a particular font. * * Map table can be associated with a printer model (e.g. a LaserWriter), a * printer destination, or whatever - the choice is up to an administrator. * By destination may be best if your spooler is running several private * printers. Host resident fonts are usually purchased under a license that * restricts their use to a limited number of printers. A font licensed for * a single printer should only be used on that printer. * * Was written quickly, so there's much room for improvement. Undoubtedly should * be a more general program (e.g. scan for other comments). * */#include <stdio.h>#include <signal.h>#include <sys/types.h>#include <fcntl.h>#include <sys/stat.h>#include <string.h>#include "comments.h"			/* PostScript file structuring comments */#include "gen.h"			/* general purpose definitions */#include "path.h"			/* for temporary directory */#include "ext.h"			/* external variable declarations */#include "download.h"			/* a few special definitions */char	*temp_dir = TEMPDIR;		/* temp directory - for copying stdin */char	*hostfontdir = HOSTDIR;		/* host resident directory */char	*mapname = "map";		/* map table - usually in *hostfontdir */char	*suffix = "";			/* appended to the map table pathname */Map	*map = NULL;			/* device font map table */char	*stringspace = NULL;		/* for storing font and file strings */int	next = 0;			/* next free slot in map[] */char	*residentfonts = NULL;		/* list of printer resident fonts */char	*printer = NULL;		/* printer name - only for Unix 4.0 lp */char	buf[2048];			/* input file line buffer */char	*comment = DOCUMENTFONTS;	/* look for this comment */int	atend = FALSE;			/* TRUE only if a comment says so */FILE	*fp_in = stdin;			/* next input file */FILE	*fp_temp = NULL;		/* for copying stdin *//*****************************************************************************/main(agc, agv)    int		agc;    char	*agv[];{/* * * 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(){/* * * 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(){    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(){    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 = (char *)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 = (char *)malloc(sbuf.st_size + 2)) == NULL )	    error(FATAL, "no memory");	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(){    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(){/* * * 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(){/* * * Clean things up before we quit. * */    if ( temp_file != NULL )	unlink(temp_file);}   /* End of done *//*****************************************************************************/download(){    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);	}   /* 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;{    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;	}   /* End if */	if ( (n = lookup(font)) < next ) {	    if ( *map[n].file != '/' ) {		if ( (path = (char *)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(){/* * * 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;{    int		i;/* * * 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 *//*****************************************************************************/Map *allocate(ptr, num)    Map		*ptr;    int		num;{/* * * Allocates space for num Map elements. Calls malloc() if ptr is NULL and * realloc() otherwise. * */    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);}   /* End of allocate *//*****************************************************************************/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -