xref: /plan9/sys/src/cmd/postscript/download/download.c (revision 14f51593fd82e19ba95969a8c07ff71131015979)
1219b2ee8SDavid du Colombier /*
2219b2ee8SDavid du Colombier  * download - host resident font downloader
3219b2ee8SDavid du Colombier  *
4219b2ee8SDavid du Colombier  * Prepends host resident fonts to PostScript input files. The program assumes
5219b2ee8SDavid du Colombier  * the input files are part of a single PostScript job and that requested fonts
6219b2ee8SDavid du Colombier  * can be downloaded at the start of each input file. Downloaded fonts are the
7219b2ee8SDavid du Colombier  * ones named in a %%DocumentFonts: comment and listed in a special map table.
8219b2ee8SDavid du Colombier  * Map table pathnames (supplied using the -m option) that begin with a / are
9219b2ee8SDavid du Colombier  * taken as is. Otherwise the final pathname is built using *hostfontdir (-H
10219b2ee8SDavid du Colombier  * option), *mapname (-m option), and *suffix.
11219b2ee8SDavid du Colombier  *
12219b2ee8SDavid du Colombier  * The map table consists of fontname-filename pairs, separated by white space.
13219b2ee8SDavid du Colombier  * Comments are introduced by % (as in PostScript) and extend to the end of the
14219b2ee8SDavid du Colombier  * current line. The only fonts that can be downloaded are the ones listed in
15219b2ee8SDavid du Colombier  * the active map table that point the program to a readable Unix file. A request
16219b2ee8SDavid du Colombier  * for an unlisted font or inaccessible file is ignored. All font requests are
17219b2ee8SDavid du Colombier  * ignored if the map table can't be read. In that case the program simply copies
18219b2ee8SDavid du Colombier  * the input files to stdout.
19219b2ee8SDavid du Colombier  *
20219b2ee8SDavid du Colombier  * An example (but not one to follow) of what can be in a map table is,
21219b2ee8SDavid du Colombier  *
22219b2ee8SDavid du Colombier  *	%
23219b2ee8SDavid du Colombier  *	% Map requests for Bookman-Light to file *hostfontdir/KR
24219b2ee8SDavid du Colombier  *	%
25219b2ee8SDavid du Colombier  *
26219b2ee8SDavid du Colombier  *	  Bookman-Light		KR	% Keeping everything (including the map
27219b2ee8SDavid du Colombier  *					% table) in *hostfontdir seems like the
28219b2ee8SDavid du Colombier  *					% cleanest approach.
29219b2ee8SDavid du Colombier  *
30219b2ee8SDavid du Colombier  *	%
31219b2ee8SDavid du Colombier  *	% Map Palatino-Roman to file *hostfontdir/palatino/Roman
32219b2ee8SDavid du Colombier  *	%
33219b2ee8SDavid du Colombier  *	  Palatino-Roman	palatino/Roman
34219b2ee8SDavid du Colombier  *
35219b2ee8SDavid du Colombier  *	% Map ZapfDingbats to file /usr/lib/host/dingbats
36219b2ee8SDavid du Colombier  *
37219b2ee8SDavid du Colombier  *	  ZapfDingbats		/usr/lib/host/dingbats
38219b2ee8SDavid du Colombier  *
39219b2ee8SDavid du Colombier  * Once again, file names that begin with a / are taken as is. All others have
40219b2ee8SDavid du Colombier  * *hostfontdir/ prepended to the file string associated with a particular font.
41219b2ee8SDavid du Colombier  *
42219b2ee8SDavid du Colombier  * Map table can be associated with a printer model (e.g. a LaserWriter), a
43219b2ee8SDavid du Colombier  * printer destination, or whatever - the choice is up to an administrator.
44219b2ee8SDavid du Colombier  * By destination may be best if your spooler is running several private
45219b2ee8SDavid du Colombier  * printers. Host resident fonts are usually purchased under a license that
46219b2ee8SDavid du Colombier  * restricts their use to a limited number of printers. A font licensed for
47219b2ee8SDavid du Colombier  * a single printer should only be used on that printer.
48219b2ee8SDavid du Colombier  *
49219b2ee8SDavid du Colombier  * Was written quickly, so there's much room for improvement. Undoubtedly should
50219b2ee8SDavid du Colombier  * be a more general program (e.g. scan for other comments).
51219b2ee8SDavid du Colombier  */
52219b2ee8SDavid du Colombier 
53*14f51593SDavid du Colombier #define _BSD_EXTENSION
54*14f51593SDavid du Colombier 
55219b2ee8SDavid du Colombier #include <stdio.h>
564e3613abSDavid du Colombier #include <stdlib.h>
574e3613abSDavid du Colombier #include <unistd.h>
584e3613abSDavid du Colombier #include <fcntl.h>
594e3613abSDavid du Colombier #include <string.h>
60219b2ee8SDavid du Colombier #include <signal.h>
61219b2ee8SDavid du Colombier #include <sys/types.h>
62219b2ee8SDavid du Colombier #include <sys/stat.h>
63219b2ee8SDavid du Colombier 
64219b2ee8SDavid du Colombier #include "comments.h"			/* PostScript file structuring comments */
65219b2ee8SDavid du Colombier #include "gen.h"			/* general purpose definitions */
66219b2ee8SDavid du Colombier #include "path.h"			/* for temporary directory */
67219b2ee8SDavid du Colombier #include "ext.h"			/* external variable declarations */
68219b2ee8SDavid du Colombier #include "download.h"			/* a few special definitions */
69219b2ee8SDavid du Colombier 
70219b2ee8SDavid du Colombier char	*temp_dir = TEMPDIR;		/* temp directory - for copying stdin */
71219b2ee8SDavid du Colombier char	*hostfontdir = HOSTDIR;		/* host resident directory */
72219b2ee8SDavid du Colombier char	*mapname = "map";		/* map table - usually in *hostfontdir */
73219b2ee8SDavid du Colombier char	*suffix = "";			/* appended to the map table pathname */
74219b2ee8SDavid du Colombier Map	*map = NULL;			/* device font map table */
75219b2ee8SDavid du Colombier char	*stringspace = NULL;		/* for storing font and file strings */
76219b2ee8SDavid du Colombier int	next = 0;			/* next free slot in map[] */
77219b2ee8SDavid du Colombier 
78219b2ee8SDavid du Colombier char	*residentfonts = NULL;		/* list of printer resident fonts */
79219b2ee8SDavid du Colombier char	*printer = NULL;		/* printer name - only for Unix 4.0 lp */
80219b2ee8SDavid du Colombier 
81219b2ee8SDavid du Colombier char	buf[2048];			/* input file line buffer */
82219b2ee8SDavid du Colombier char	*comment = DOCUMENTFONTS;	/* look for this comment */
83219b2ee8SDavid du Colombier int	atend = FALSE;			/* TRUE only if a comment says so */
84219b2ee8SDavid du Colombier 
85219b2ee8SDavid du Colombier FILE	*fp_in = stdin;			/* next input file */
86219b2ee8SDavid du Colombier FILE	*fp_temp = NULL;		/* for copying stdin */
87219b2ee8SDavid du Colombier 
88*14f51593SDavid du Colombier void	arguments(void);
89*14f51593SDavid du Colombier void	copyfonts(char *);
90*14f51593SDavid du Colombier void	copyinput(void);
91*14f51593SDavid du Colombier void	done(void);
92*14f51593SDavid du Colombier void	download(void);
93*14f51593SDavid du Colombier void	init_signals(void);
94*14f51593SDavid du Colombier void	options(void);
95*14f51593SDavid du Colombier void	readmap(void);
96*14f51593SDavid du Colombier void	readresident(void);
97219b2ee8SDavid du Colombier 
main(agc,agv)98219b2ee8SDavid du Colombier main(agc, agv)
99219b2ee8SDavid du Colombier     int		agc;
100219b2ee8SDavid du Colombier     char	*agv[];
101219b2ee8SDavid du Colombier {
102219b2ee8SDavid du Colombier /*
103219b2ee8SDavid du Colombier  *
104219b2ee8SDavid du Colombier  * Host resident font downloader. The input files are assumed to be part of a
105219b2ee8SDavid du Colombier  * single PostScript job.
106219b2ee8SDavid du Colombier  *
107219b2ee8SDavid du Colombier  */
108219b2ee8SDavid du Colombier 
109219b2ee8SDavid du Colombier     argc = agc;				/* other routines may want them */
110219b2ee8SDavid du Colombier     argv = agv;
111219b2ee8SDavid du Colombier 
112219b2ee8SDavid du Colombier     prog_name = argv[0];		/* just for error messages */
113219b2ee8SDavid du Colombier 
114219b2ee8SDavid du Colombier     init_signals();			/* sets up interrupt handling */
115219b2ee8SDavid du Colombier     options();				/* first get command line options */
116219b2ee8SDavid du Colombier     readmap();				/* read the font map table */
117219b2ee8SDavid du Colombier     readresident();			/* and the optional resident font list */
118219b2ee8SDavid du Colombier     arguments();			/* then process non-option arguments */
119219b2ee8SDavid du Colombier     done();				/* and clean things up */
120219b2ee8SDavid du Colombier     exit(x_stat);			/* not much could be wrong */
121*14f51593SDavid du Colombier     return 0;
122*14f51593SDavid du Colombier }
123219b2ee8SDavid du Colombier 
124*14f51593SDavid du Colombier void
init_signals(void)125*14f51593SDavid du Colombier init_signals(void)
126219b2ee8SDavid du Colombier {
127219b2ee8SDavid du Colombier /*
128219b2ee8SDavid du Colombier  * Makes sure we handle interrupts properly.
129219b2ee8SDavid du Colombier  */
130219b2ee8SDavid du Colombier 
131219b2ee8SDavid du Colombier     if ( signal(SIGINT, interrupt) == SIG_IGN ) {
132219b2ee8SDavid du Colombier 	signal(SIGINT, SIG_IGN);
133219b2ee8SDavid du Colombier 	signal(SIGQUIT, SIG_IGN);
134219b2ee8SDavid du Colombier 	signal(SIGHUP, SIG_IGN);
135219b2ee8SDavid du Colombier     } else {
136219b2ee8SDavid du Colombier 	signal(SIGHUP, interrupt);
137219b2ee8SDavid du Colombier 	signal(SIGQUIT, interrupt);
138*14f51593SDavid du Colombier     }
139219b2ee8SDavid du Colombier 
140219b2ee8SDavid du Colombier     signal(SIGTERM, interrupt);
141*14f51593SDavid du Colombier }
142219b2ee8SDavid du Colombier 
143*14f51593SDavid du Colombier void
options(void)144*14f51593SDavid du Colombier options(void)
145219b2ee8SDavid du Colombier {
146219b2ee8SDavid du Colombier     int		ch;			/* return value from getopt() */
147219b2ee8SDavid du Colombier     char	*optnames = "c:fm:p:r:H:T:DI";
148219b2ee8SDavid du Colombier 
149219b2ee8SDavid du Colombier     extern char	*optarg;		/* used by getopt() */
150219b2ee8SDavid du Colombier     extern int	optind;
151219b2ee8SDavid du Colombier 
152219b2ee8SDavid du Colombier /*
153219b2ee8SDavid du Colombier  *
154219b2ee8SDavid du Colombier  * Reads and processes the command line options.
155219b2ee8SDavid du Colombier  *
156219b2ee8SDavid du Colombier  */
157219b2ee8SDavid du Colombier 
158219b2ee8SDavid du Colombier     while ( (ch = getopt(argc, argv, optnames)) != EOF ) {
159219b2ee8SDavid du Colombier 	switch ( ch ) {
160219b2ee8SDavid du Colombier 	    case 'c':			/* look for this comment */
161219b2ee8SDavid du Colombier 		    comment = optarg;
162219b2ee8SDavid du Colombier 		    break;
163219b2ee8SDavid du Colombier 
164219b2ee8SDavid du Colombier 	    case 'f':			/* force a complete input file scan */
165219b2ee8SDavid du Colombier 		    atend = TRUE;
166219b2ee8SDavid du Colombier 		    break;
167219b2ee8SDavid du Colombier 
168219b2ee8SDavid du Colombier 	    case 'm':			/* printer map table name */
169219b2ee8SDavid du Colombier 		    mapname = optarg;
170219b2ee8SDavid du Colombier 		    break;
171219b2ee8SDavid du Colombier 
172219b2ee8SDavid du Colombier 	    case 'p':			/* printer name - for Unix 4.0 lp */
173219b2ee8SDavid du Colombier 		    printer = optarg;
174219b2ee8SDavid du Colombier 		    break;
175219b2ee8SDavid du Colombier 
176219b2ee8SDavid du Colombier 	    case 'r':			/* resident font list */
177219b2ee8SDavid du Colombier 		    residentfonts = optarg;
178219b2ee8SDavid du Colombier 		    break;
179219b2ee8SDavid du Colombier 
180219b2ee8SDavid du Colombier 	    case 'H':			/* host resident font directory */
181219b2ee8SDavid du Colombier 		    hostfontdir = optarg;
182219b2ee8SDavid du Colombier 		    break;
183219b2ee8SDavid du Colombier 
184219b2ee8SDavid du Colombier 	    case 'T':			/* temporary file directory */
185219b2ee8SDavid du Colombier 		    temp_dir = optarg;
186219b2ee8SDavid du Colombier 		    break;
187219b2ee8SDavid du Colombier 
188219b2ee8SDavid du Colombier 	    case 'D':			/* debug flag */
189219b2ee8SDavid du Colombier 		    debug = ON;
190219b2ee8SDavid du Colombier 		    break;
191219b2ee8SDavid du Colombier 
192219b2ee8SDavid du Colombier 	    case 'I':			/* ignore FATAL errors */
193219b2ee8SDavid du Colombier 		    ignore = ON;
194219b2ee8SDavid du Colombier 		    break;
195219b2ee8SDavid du Colombier 
196219b2ee8SDavid du Colombier 	    case '?':			/* don't understand the option */
197219b2ee8SDavid du Colombier 		    error(FATAL, "");
198219b2ee8SDavid du Colombier 		    break;
199219b2ee8SDavid du Colombier 
200219b2ee8SDavid du Colombier 	    default:			/* don't know what to do for ch */
201219b2ee8SDavid du Colombier 		    error(FATAL, "missing case for option %c\n", ch);
202219b2ee8SDavid du Colombier 		    break;
203219b2ee8SDavid du Colombier 	}   /* End switch */
204219b2ee8SDavid du Colombier     }   /* End while */
205219b2ee8SDavid du Colombier 
206219b2ee8SDavid du Colombier     argc -= optind;			/* get ready for non-option args */
207219b2ee8SDavid du Colombier     argv += optind;
208*14f51593SDavid du Colombier }
209219b2ee8SDavid du Colombier 
210*14f51593SDavid du Colombier void
readmap(void)211*14f51593SDavid du Colombier readmap(void)
212219b2ee8SDavid du Colombier {
213219b2ee8SDavid du Colombier     char	*path;
214219b2ee8SDavid du Colombier     char	*ptr;
215219b2ee8SDavid du Colombier     int		fd;
216219b2ee8SDavid du Colombier     struct stat	sbuf;
217219b2ee8SDavid du Colombier 
218219b2ee8SDavid du Colombier /*
219219b2ee8SDavid du Colombier  * Initializes the map table by reading an ASCII mapping file. If mapname begins
220219b2ee8SDavid du Colombier  * with a / it's the map table. Otherwise hostfontdir, mapname, and suffix are
221219b2ee8SDavid du Colombier  * combined to build the final pathname. If we can open the file we read it all
222219b2ee8SDavid du Colombier  * into memory, erase comments, and separate the font and file name pairs. When
223219b2ee8SDavid du Colombier  * we leave next points to the next free slot in the map[] array. If it's zero
224219b2ee8SDavid du Colombier  * nothing was in the file or we couldn't open it.
225219b2ee8SDavid du Colombier  */
226219b2ee8SDavid du Colombier 
227219b2ee8SDavid du Colombier     if ( hostfontdir == NULL || mapname == NULL )
228219b2ee8SDavid du Colombier 	return;
229219b2ee8SDavid du Colombier 
230219b2ee8SDavid du Colombier     if ( *mapname != '/' ) {
2314e3613abSDavid du Colombier 	if ( (path = malloc(strlen(hostfontdir) + strlen(mapname) +
232219b2ee8SDavid du Colombier 						strlen(suffix) + 2)) == NULL )
233219b2ee8SDavid du Colombier 	    error(FATAL, "no memory");
234219b2ee8SDavid du Colombier 	sprintf(path, "%s/%s%s", hostfontdir, mapname, suffix);
235219b2ee8SDavid du Colombier     } else path = mapname;
236219b2ee8SDavid du Colombier 
237219b2ee8SDavid du Colombier     if ( (fd = open(path, 0)) != -1 ) {
238219b2ee8SDavid du Colombier 	if ( fstat(fd, &sbuf) == -1 )
239219b2ee8SDavid du Colombier 	    error(FATAL, "can't fstat %s", path);
2404e3613abSDavid du Colombier 	if ( (stringspace = malloc(sbuf.st_size + 2)) == NULL )
2414e3613abSDavid du Colombier 	    error(FATAL, "no memory for %s (%d bytes)", path, sbuf.st_size + 2);
242219b2ee8SDavid du Colombier 	if ( read(fd, stringspace, sbuf.st_size) == -1 )
243219b2ee8SDavid du Colombier 	    error(FATAL, "can't read %s", path);
244219b2ee8SDavid du Colombier 	close(fd);
245219b2ee8SDavid du Colombier 
246219b2ee8SDavid du Colombier 	stringspace[sbuf.st_size] = '\n';	/* just to be safe */
247219b2ee8SDavid du Colombier 	stringspace[sbuf.st_size+1] = '\0';
248219b2ee8SDavid du Colombier 	for ( ptr = stringspace; *ptr != '\0'; ptr++ )	/* erase comments */
249219b2ee8SDavid du Colombier 	    if ( *ptr == '%' )
250219b2ee8SDavid du Colombier 		for ( ; *ptr != '\n' ; ptr++ )
251219b2ee8SDavid du Colombier 		    *ptr = ' ';
252219b2ee8SDavid du Colombier 
253219b2ee8SDavid du Colombier 	for ( ptr = stringspace; ; next++ ) {
254219b2ee8SDavid du Colombier 	    if ( (next % 50) == 0 )
255219b2ee8SDavid du Colombier 		map = allocate(map, next+50);
256219b2ee8SDavid du Colombier 	    map[next].downloaded = FALSE;
257219b2ee8SDavid du Colombier 	    map[next].font = strtok(ptr, " \t\n");
258219b2ee8SDavid du Colombier 	    map[next].file = strtok(ptr = NULL, " \t\n");
259219b2ee8SDavid du Colombier 	    if ( map[next].font == NULL )
260219b2ee8SDavid du Colombier 		break;
261219b2ee8SDavid du Colombier 	    if ( map[next].file == NULL )
262219b2ee8SDavid du Colombier 		error(FATAL, "map table format error - check %s", path);
263*14f51593SDavid du Colombier 	}
264*14f51593SDavid du Colombier     }
265*14f51593SDavid du Colombier }
266219b2ee8SDavid du Colombier 
267*14f51593SDavid du Colombier void
readresident(void)268*14f51593SDavid du Colombier readresident(void)
269219b2ee8SDavid du Colombier {
270219b2ee8SDavid du Colombier     FILE	*fp;
271219b2ee8SDavid du Colombier     char	*path;
272219b2ee8SDavid du Colombier     int		ch;
273219b2ee8SDavid du Colombier     int		n;
274219b2ee8SDavid du Colombier 
275219b2ee8SDavid du Colombier /*
276219b2ee8SDavid du Colombier  * Reads a file that lists the resident fonts for a particular printer and marks
277219b2ee8SDavid du Colombier  * each font as already downloaded. Nothing's done if the file can't be read or
278219b2ee8SDavid du Colombier  * there's no mapping file. Comments, as in the map file, begin with a % and
279219b2ee8SDavid du Colombier  * extend to the end of the line. Added for Unix 4.0 lp.
280219b2ee8SDavid du Colombier  */
281219b2ee8SDavid du Colombier 
282219b2ee8SDavid du Colombier     if ( next == 0 || (printer == NULL && residentfonts == NULL) )
283219b2ee8SDavid du Colombier 	return;
284219b2ee8SDavid du Colombier 
285219b2ee8SDavid du Colombier     if ( printer != NULL ) {		/* use Unix 4.0 lp pathnames */
28680ee5cbfSDavid du Colombier 	sprintf(buf, "%s/printers/%s", HOSTDIR, printer);
287219b2ee8SDavid du Colombier 	path = buf;
288219b2ee8SDavid du Colombier     } else path = residentfonts;
289219b2ee8SDavid du Colombier 
290219b2ee8SDavid du Colombier     if ( (fp = fopen(path, "r")) != NULL ) {
291219b2ee8SDavid du Colombier 	while ( fscanf(fp, "%s", buf) != EOF )
292219b2ee8SDavid du Colombier 	    if ( buf[0] == '%' )
293219b2ee8SDavid du Colombier 		while ( (ch = getc(fp)) != EOF && ch != '\n' ) ;
294219b2ee8SDavid du Colombier 	    else if ( (n = lookup(buf)) < next )
295219b2ee8SDavid du Colombier 		map[n].downloaded = TRUE;
296219b2ee8SDavid du Colombier 	fclose(fp);
297*14f51593SDavid du Colombier     }
298*14f51593SDavid du Colombier }
299219b2ee8SDavid du Colombier 
300*14f51593SDavid du Colombier void
arguments(void)301*14f51593SDavid du Colombier arguments(void)
302219b2ee8SDavid du Colombier {
303219b2ee8SDavid du Colombier /*
304219b2ee8SDavid du Colombier  *
305219b2ee8SDavid du Colombier  * Makes sure all the non-option command line arguments are processed. If we get
306219b2ee8SDavid du Colombier  * here and there aren't any arguments left, or if '-' is one of the input files
307219b2ee8SDavid du Colombier  * we'll translate stdin. Assumes input files are part of a single PostScript
308219b2ee8SDavid du Colombier  * job and fonts can be downloaded at the start of each file.
309219b2ee8SDavid du Colombier  *
310219b2ee8SDavid du Colombier  */
311219b2ee8SDavid du Colombier 
312219b2ee8SDavid du Colombier     if ( argc < 1 )
313219b2ee8SDavid du Colombier 	download();
314219b2ee8SDavid du Colombier     else {
315219b2ee8SDavid du Colombier 	while ( argc > 0 ) {
316219b2ee8SDavid du Colombier 	    fp_temp = NULL;
317219b2ee8SDavid du Colombier 	    if ( strcmp(*argv, "-") == 0 )
318219b2ee8SDavid du Colombier 		fp_in = stdin;
319219b2ee8SDavid du Colombier 	    else if ( (fp_in = fopen(*argv, "r")) == NULL )
320219b2ee8SDavid du Colombier 		error(FATAL, "can't open %s", *argv);
321219b2ee8SDavid du Colombier 	    download();
322219b2ee8SDavid du Colombier 	    if ( fp_in != stdin )
323219b2ee8SDavid du Colombier 		fclose(fp_in);
324219b2ee8SDavid du Colombier 	    if ( fp_temp != NULL )
325219b2ee8SDavid du Colombier 		fclose(fp_temp);
326219b2ee8SDavid du Colombier 	    argc--;
327219b2ee8SDavid du Colombier 	    argv++;
328*14f51593SDavid du Colombier 	}
329*14f51593SDavid du Colombier     }
330*14f51593SDavid du Colombier }
331219b2ee8SDavid du Colombier 
332*14f51593SDavid du Colombier void
done(void)333*14f51593SDavid du Colombier done(void)
334219b2ee8SDavid du Colombier {
335219b2ee8SDavid du Colombier /*
336219b2ee8SDavid du Colombier  * Clean things up before we quit.
337219b2ee8SDavid du Colombier  */
338219b2ee8SDavid du Colombier     if ( temp_file != NULL )
339219b2ee8SDavid du Colombier 	unlink(temp_file);
340*14f51593SDavid du Colombier }
341219b2ee8SDavid du Colombier 
342*14f51593SDavid du Colombier void
download(void)343*14f51593SDavid du Colombier download(void)
344219b2ee8SDavid du Colombier {
345219b2ee8SDavid du Colombier     int		infontlist = FALSE;
346219b2ee8SDavid du Colombier 
347219b2ee8SDavid du Colombier /*
348219b2ee8SDavid du Colombier  *
349219b2ee8SDavid du Colombier  * If next is zero the map table is empty and all we do is copy the input file
350219b2ee8SDavid du Colombier  * to stdout. Otherwise we read the input file looking for %%DocumentFonts: or
351219b2ee8SDavid du Colombier  * continuation comments, add any accessible fonts to the output file, and then
352219b2ee8SDavid du Colombier  * append the input file. When reading stdin we append lines to fp_temp and
353219b2ee8SDavid du Colombier  * recover them when we're ready to copy the input file. fp_temp will often
354219b2ee8SDavid du Colombier  * only contain part of stdin - if there's no %%DocumentFonts: (atend) comment
355219b2ee8SDavid du Colombier  * we stop reading fp_in after the header.
356219b2ee8SDavid du Colombier  *
357219b2ee8SDavid du Colombier  */
358219b2ee8SDavid du Colombier 
359219b2ee8SDavid du Colombier     if ( next > 0 ) {
360219b2ee8SDavid du Colombier 	if ( fp_in == stdin ) {
361219b2ee8SDavid du Colombier 	    if ( (temp_file = tempnam(temp_dir, "post")) == NULL )
362219b2ee8SDavid du Colombier 		error(FATAL, "can't generate temp file name");
363219b2ee8SDavid du Colombier 	    if ( (fp_temp = fopen(temp_file, "w+r")) == NULL )
364219b2ee8SDavid du Colombier 		error(FATAL, "can't open %s", temp_file);
365219b2ee8SDavid du Colombier 	    unlink(temp_file);
366219b2ee8SDavid du Colombier 	}   /* End if */
367219b2ee8SDavid du Colombier 
368219b2ee8SDavid du Colombier 	while ( fgets(buf, sizeof(buf), fp_in) != NULL ) {
369219b2ee8SDavid du Colombier 	    if ( fp_temp != NULL )
370219b2ee8SDavid du Colombier 		fprintf(fp_temp, "%s", buf);
371219b2ee8SDavid du Colombier 	    if ( buf[0] != '%' || buf[1] != '%' ) {
372219b2ee8SDavid du Colombier 		if ( (buf[0] != '%' || buf[1] != '!') && atend == FALSE )
373219b2ee8SDavid du Colombier 		    break;
374219b2ee8SDavid du Colombier 		infontlist = FALSE;
375219b2ee8SDavid du Colombier 	    } else if ( strncmp(buf, comment, strlen(comment)) == 0 ) {
376219b2ee8SDavid du Colombier 		copyfonts(buf);
377219b2ee8SDavid du Colombier 		infontlist = TRUE;
378219b2ee8SDavid du Colombier 	    } else if ( buf[2] == '+' && infontlist == TRUE )
379219b2ee8SDavid du Colombier 		copyfonts(buf);
380219b2ee8SDavid du Colombier 	    else infontlist = FALSE;
381*14f51593SDavid du Colombier 	}
382*14f51593SDavid du Colombier     }
383219b2ee8SDavid du Colombier     copyinput();
384*14f51593SDavid du Colombier }
385219b2ee8SDavid du Colombier 
386*14f51593SDavid du Colombier void
copyfonts(list)387219b2ee8SDavid du Colombier copyfonts(list)
388219b2ee8SDavid du Colombier     char	*list;
389219b2ee8SDavid du Colombier {
390219b2ee8SDavid du Colombier     char	*font;
391219b2ee8SDavid du Colombier     char	*path;
392219b2ee8SDavid du Colombier     int		n;
393219b2ee8SDavid du Colombier 
394219b2ee8SDavid du Colombier /*
395219b2ee8SDavid du Colombier  * list points to a %%DocumentFonts: or continuation comment. What follows the
396219b2ee8SDavid du Colombier  * the keyword will be a list of fonts separated by white space (or (atend)).
397219b2ee8SDavid du Colombier  * Look for each font in the map table and if it's found copy the font file to
398219b2ee8SDavid du Colombier  * stdout (once only).
399219b2ee8SDavid du Colombier  */
400219b2ee8SDavid du Colombier 
401219b2ee8SDavid du Colombier     strtok(list, " \n");		/* skip to the font list */
402219b2ee8SDavid du Colombier 
403219b2ee8SDavid du Colombier     while ( (font = strtok(NULL, " \t\n")) != NULL ) {
404219b2ee8SDavid du Colombier 	if ( strcmp(font, ATEND) == 0 ) {
405219b2ee8SDavid du Colombier 	    atend = TRUE;
406219b2ee8SDavid du Colombier 	    break;
407*14f51593SDavid du Colombier 	}
408219b2ee8SDavid du Colombier 	if ( (n = lookup(font)) < next ) {
409219b2ee8SDavid du Colombier 	    if ( *map[n].file != '/' ) {
4104e3613abSDavid du Colombier 		if ( (path = malloc(strlen(hostfontdir)+strlen(map[n].file)+2)) == NULL )
411219b2ee8SDavid du Colombier 		    error(FATAL, "no memory");
412219b2ee8SDavid du Colombier 		sprintf(path, "%s/%s", hostfontdir, map[n].file);
413219b2ee8SDavid du Colombier 		cat(path);
414219b2ee8SDavid du Colombier 		free(path);
415219b2ee8SDavid du Colombier 	    } else cat(map[n].file);
416219b2ee8SDavid du Colombier 	    map[n].downloaded = TRUE;
417*14f51593SDavid du Colombier 	}
418*14f51593SDavid du Colombier     }
419*14f51593SDavid du Colombier }
420219b2ee8SDavid du Colombier 
421*14f51593SDavid du Colombier void
copyinput(void)422*14f51593SDavid du Colombier copyinput(void)
423219b2ee8SDavid du Colombier {
424219b2ee8SDavid du Colombier /*
425219b2ee8SDavid du Colombier  *
426219b2ee8SDavid du Colombier  * Copies the input file to stdout. If fp_temp isn't NULL seek to the start and
427219b2ee8SDavid du Colombier  * add it to the output file - it's a partial (or complete) copy of stdin made
428219b2ee8SDavid du Colombier  * by download(). Then copy fp_in, but only seek to the start if it's not stdin.
429219b2ee8SDavid du Colombier  *
430219b2ee8SDavid du Colombier  */
431219b2ee8SDavid du Colombier 
432219b2ee8SDavid du Colombier     if ( fp_temp != NULL ) {
433219b2ee8SDavid du Colombier 	fseek(fp_temp, 0L, 0);
434219b2ee8SDavid du Colombier 	while ( fgets(buf, sizeof(buf), fp_temp) != NULL )
435219b2ee8SDavid du Colombier 	    printf("%s", buf);
436219b2ee8SDavid du Colombier     }	/* End if */
437219b2ee8SDavid du Colombier 
438219b2ee8SDavid du Colombier     if ( fp_in != stdin )
439219b2ee8SDavid du Colombier 	fseek(fp_in, 0L, 0);
440219b2ee8SDavid du Colombier 
441219b2ee8SDavid du Colombier     while ( fgets(buf, sizeof(buf), fp_in) != NULL )
442219b2ee8SDavid du Colombier 	printf("%s", buf);
443*14f51593SDavid du Colombier }
444219b2ee8SDavid du Colombier 
lookup(font)445219b2ee8SDavid du Colombier lookup(font)
446219b2ee8SDavid du Colombier     char	*font;
447219b2ee8SDavid du Colombier {
448219b2ee8SDavid du Colombier     int		i;
449219b2ee8SDavid du Colombier 
450219b2ee8SDavid du Colombier /*
451219b2ee8SDavid du Colombier  *
452219b2ee8SDavid du Colombier  * Looks for *font in the map table. Return the map table index if found and
453219b2ee8SDavid du Colombier  * not yet downloaded - otherwise return next.
454219b2ee8SDavid du Colombier  *
455219b2ee8SDavid du Colombier  */
456219b2ee8SDavid du Colombier 
457219b2ee8SDavid du Colombier     for ( i = 0; i < next; i++ )
458219b2ee8SDavid du Colombier 	if ( strcmp(font, map[i].font) == 0 ) {
459219b2ee8SDavid du Colombier 	    if ( map[i].downloaded == TRUE )
460219b2ee8SDavid du Colombier 		i = next;
461219b2ee8SDavid du Colombier 	    break;
462219b2ee8SDavid du Colombier 	}   /* End if */
463219b2ee8SDavid du Colombier 
464219b2ee8SDavid du Colombier     return(i);
465219b2ee8SDavid du Colombier 
466219b2ee8SDavid du Colombier }   /* End of lookup */
467219b2ee8SDavid du Colombier 
468219b2ee8SDavid du Colombier /*
469219b2ee8SDavid du Colombier  * Allocates space for num Map elements. Calls malloc() if ptr is NULL and
470219b2ee8SDavid du Colombier  * realloc() otherwise.
471219b2ee8SDavid du Colombier  */
4724e3613abSDavid du Colombier Map *
allocate(Map * ptr,int num)4734e3613abSDavid du Colombier allocate(Map *ptr, int num)
4744e3613abSDavid du Colombier {
475219b2ee8SDavid du Colombier 	if (ptr == NULL)
476219b2ee8SDavid du Colombier 		ptr = (Map *)malloc(num * sizeof(Map));
4774e3613abSDavid du Colombier 	else
4784e3613abSDavid du Colombier 		ptr = (Map *)realloc(ptr, num * sizeof(Map));
479219b2ee8SDavid du Colombier 	if (ptr == NULL)
480219b2ee8SDavid du Colombier 		error(FATAL, "no map memory");
4814e3613abSDavid du Colombier 	return ptr;
4824e3613abSDavid du Colombier }
483