|
|
1.1 root 1: /*
2: *
3: * picpack - picture packing pre-processor
4: *
5: * A trivial troff pre-processor that copies files to stdout, expanding picture
6: * requests into an in-line format that's passed transparently through troff and
7: * handled by dpost. The program is an attempt to address requirements, expressed
8: * by several organizations, of being able to store a document as a single file
9: * (usually troff input) that can then be sent through dpost and ultimately to
10: * a PostScript printer.
11: *
12: * The program looks for strings listed in the keys[] array at the start of each
13: * line. When a picture request (as listed in keys[]) is found the second string
14: * on the line is taken to be a picture file pathname that's added (in transparent
15: * mode) to the output file. In addition each in-line picture file is preceeded by
16: * device control command (again passed through in transparent mode) that looks
17: * like,
18: *
19: * x X InlinePicture filename bytes
20: *
21: * where bytes is the size of the picture file (which begins on the next line)
22: * and filename is the pathname of the picture file. dpost uses both arguments to
23: * manage in-line pictures (in a big temp file). To handle pictures in diversions
24: * picpack reads each input file twice. The first pass looks for picture inclusion
25: * requests and copies each picture file transparently to the output file, while
26: * second pass just copies the input file to the output file. Things could still
27: * break, but the two pass method should handle most jobs.
28: *
29: * The recognized in-line picture requests are saved in keys[] and by default only
30: * expand .BP and .PI macro calls. The -k option changes the recognized strings,
31: * and may be needed if you've built your own picture inclusion macros on top of
32: * .BP or .PI or decided to list each picture file at the start of your input file
33: * using a dummy macro. For example you could require every in-line picture be
34: * named by a dummy macro (say .iP), then the command line,
35: *
36: * picpack -k.iP file > file.pack
37: *
38: * hits on lines that begin with .iP (rather than .BP or .PI), and the only files
39: * pulled in would be ones named as the second argument to the new .iP macro. The
40: * -k option accepts a space or comma separated list of up to 10 different key
41: * strings. picpack imposes no contraints on key strings, other than not allowing
42: * spaces or commas. A key string can begin with \" and in that case it would be
43: * troff comment.
44: *
45: * Although the program will help some users, there are obvious disadvantages.
46: * Perhaps the most important is that troff output files (with in-line pictures
47: * included) don't fit the device independent language accepted by important post
48: * processors like proof, and that means you won't be able to reliably preview a
49: * packed file on your 5620 or whatever. Another potential problem is that picture
50: * files can be large. Packing everything together in a single file at an early
51: * stage has a better chance of exceeding your system's ulimit.
52: *
53: */
54:
55: #include <stdio.h>
56: #include <sys/types.h>
57: #include <sys/stat.h>
58:
59: #include "gen.h" /* general purpose definitions */
60: #include "ext.h" /* external variable definitions */
61: #include "path.h" /* just for TEMPDIR definition */
62:
63: char *keys[11] = {".BP", ".PI", NULL};
64: int quiet = FALSE;
65:
66: FILE *fp_in = stdin; /* input */
67: FILE *fp_out = stdout; /* and output files */
68:
69: /*****************************************************************************/
70:
71: main(agc, agv)
72:
73: int agc;
74: char *agv[];
75:
76: {
77:
78: /*
79: *
80: * A picture packing pre-processor that copies input files to stdout, expanding
81: * picture requests (as listed in keys[]) to an in-line format that can be passed
82: * through troff (using transparent mode) and handled later by dpost.
83: *
84: */
85:
86: argc = agc; /* global so everyone can use them */
87: argv = agv;
88:
89: prog_name = argv[0]; /* just for error messages */
90:
91: options(); /* command line options */
92: arguments(); /* translate all the input files */
93: done(); /* clean things up */
94:
95: exit(x_stat); /* everything probably went OK */
96:
97: } /* End of main */
98:
99: /*****************************************************************************/
100:
101: options()
102:
103: {
104:
105: int ch; /* name returned by getopt() */
106:
107: extern char *optarg; /* option argument set by getopt() */
108: extern int optind;
109:
110: /*
111: *
112: * Handles the command line options.
113: *
114: */
115:
116: while ( (ch = getopt(argc, argv, "k:qDI")) != EOF ) {
117: switch ( ch ) {
118: case 'k': /* new expansion key strings */
119: newkeys(optarg);
120: break;
121:
122: case 'q': /* disables "missing picture" messages */
123: quiet = TRUE;
124: break;
125:
126: case 'D': /* debug flag */
127: debug = ON;
128: break;
129:
130: case 'I': /* ignore FATAL errors */
131: ignore = ON;
132: break;
133:
134: case '?': /* don't know the option */
135: error(FATAL, "");
136: break;
137:
138: default:
139: error(FATAL, "missing case for option %c", ch);
140: break;
141: } /* End switch */
142: } /* End while */
143:
144: argc -= optind; /* get ready for non-options args */
145: argv += optind;
146:
147: } /* End of options */
148:
149: /*****************************************************************************/
150:
151: newkeys(list)
152:
153: char *list; /* comma or space separated key strings */
154:
155: {
156:
157: char *p; /* next key string from *list */
158: int i; /* goes in keys[i] */
159: int n; /* last key string slot in keys[] */
160:
161: /*
162: *
163: * Separates *list into space or comma separated strings and adds each to the
164: * keys[] array. The strings in keys[] are used to locate the picture inclusion
165: * requests that are translated to the in-line format. The keys array must end
166: * with a NULL pointer and by default only expands .BP and .PI macro calls.
167: *
168: */
169:
170: n = (sizeof(keys) / sizeof(char *)) - 1;
171:
172: for ( i = 0, p = strtok(list, " ,"); p != NULL; i++, p = strtok(NULL, " ,") )
173: if ( i >= n )
174: error(FATAL, "too many key strings");
175: else keys[i] = p;
176:
177: keys[i] = NULL;
178:
179: } /* End of newkeys */
180:
181: /*****************************************************************************/
182:
183: arguments()
184:
185: {
186:
187: FILE *copystdin();
188:
189: /*
190: *
191: * Makes sure all the non-option command line arguments are processed. If we get
192: * here and there aren't any arguments left, or if '-' is one of the input files
193: * we process stdin, after copying it to a temporary file.
194: *
195: */
196:
197: if ( argc < 1 ) {
198: fp_in = copystdin();
199: picpack();
200: } else
201: while ( argc > 0 ) {
202: if ( strcmp(*argv, "-") == 0 )
203: fp_in = copystdin();
204: else if ( (fp_in = fopen(*argv, "r")) == NULL )
205: error(FATAL, "can't open %s", *argv);
206: picpack();
207: fclose(fp_in);
208: argc--;
209: argv++;
210: } /* End while */
211:
212: } /* End of arguments */
213:
214: /*****************************************************************************/
215:
216: FILE *copystdin()
217:
218: {
219:
220: char *tfile; /* temporary file name */
221: int fd_out; /* and its file descriptor */
222: FILE *fp; /* return value - the new input file */
223:
224: /*
225: *
226: * Copies stdin to a temp file, unlinks the file, and returns the file pointer
227: * for the new temporary file to the caller. Needed because we read each input
228: * file twice in an attempt to handle pictures in diversions.
229: *
230: */
231:
232: if ( (tfile = tempnam(TEMPDIR, "post")) == NULL )
233: error(FATAL, "can't generate temp file name");
234:
235: if ( (fd_out = creat(tfile, 0660)) == -1 )
236: error(FATAL, "can't create %s", tfile);
237:
238: copyfile(fileno(stdin), fd_out);
239: close(fd_out);
240:
241: if ( (fp = fopen(tfile, "r")) == NULL )
242: error(FATAL, "can't open %s", tfile);
243:
244: unlink(tfile);
245: return(fp);
246:
247: } /* End of copystdin */
248:
249: /*****************************************************************************/
250:
251: copyfile(fd_in, fd_out)
252:
253: int fd_in; /* input */
254: int fd_out; /* and output files */
255:
256: {
257:
258: char buf[512]; /* internal buffer for reads and writes */
259: int count; /* number of bytes put in buf[] */
260:
261: /*
262: *
263: * Copies file fd_in to fd_out. Handles the second pass for each input file and
264: * also used to copy stdin to a temporary file.
265: *
266: */
267:
268: while ( (count = read(fd_in, buf, sizeof(buf))) > 0 )
269: if ( write(fd_out, buf, count) != count )
270: error(FATAL, "write error");
271:
272: } /* End of copyfile */
273:
274: /*****************************************************************************/
275:
276: done()
277:
278: {
279:
280: /*
281: *
282: * Finished with all the input files - unlink the temporary file that was used
283: * to record the in-line picture file pathnames.
284: *
285: */
286:
287: if ( temp_file != NULL )
288: unlink(temp_file);
289:
290: } /* End of done */
291:
292: /*****************************************************************************/
293:
294: picpack()
295:
296: {
297:
298: char line[512]; /* next input line */
299: char name[100]; /* picture file names - from BP or PI */
300: int i; /* for looking through keys[] */
301:
302: /*
303: *
304: * Handles the two passes over the next input file. First pass compares the start
305: * of each line in *fp_in with the key strings saved in the keys[] array. If a
306: * match is found inline() is called to copy the picture file (ie. the file named
307: * as the second string in line[]) to stdout, provided the file hasn't previously
308: * been copied. The second pass goes back to the start of fp_in and copies it all
309: * to the output file.
310: *
311: */
312:
313: while ( fgets(line, sizeof(line), fp_in) != NULL ) {
314: for ( i = 0; keys[i] != NULL; i++ )
315: if ( strncmp(line, keys[i], strlen(keys[i])) == 0 ) {
316: if ( sscanf(line, "%*s %s", name) == 1 ) {
317: strtok(name, "(");
318: if ( gotpicfile(name) == FALSE )
319: inline(name);
320: } /* End if */
321: } /* End if */
322: } /* End while */
323:
324: fflush(fp_out); /* second pass - copy fp_in to fp_out */
325: fseek(fp_in, 0L, 0);
326: copyfile(fileno(fp_in), fileno(fp_out));
327:
328: } /* End of picpack */
329:
330: /*****************************************************************************/
331:
332: inline(name)
333:
334: char *name; /* name of the in-line picture file */
335:
336: {
337:
338: long size; /* size in bytes - from fstat */
339: FILE *fp; /* for reading *name */
340: int ch; /* next character from picture file */
341: int lastch = '\n'; /* so we know when to put out \! */
342:
343: struct stat sbuf; /* for the picture file size */
344:
345: /*
346: *
347: * Copies the picture file *name to the output file in an in-line format that can
348: * be passed through troff and recovered later by dpost. Transparent mode is used
349: * so each line starts with \! and all \ characters must be escaped. The in-line
350: * picture sequence begins with an "x X InlinePicture" device control command that
351: * names the picture file and gives its size (in bytes).
352: *
353: */
354:
355: if ( (fp = fopen(name, "r")) != NULL ) {
356: fstat(fileno(fp), &sbuf);
357: if ( (size = sbuf.st_size) > 0 ) {
358: fprintf(fp_out, "\\!x X InlinePicture %s %ld\n", name, size);
359: while ( (ch = getc(fp)) != EOF ) {
360: if ( lastch == '\n' )
361: fprintf(fp_out, "\\!");
362: if ( ch == '\\' )
363: putc('\\', fp_out);
364: putc(lastch = ch, fp_out);
365: } /* End while */
366: if ( lastch != '\n' )
367: putc('\n', fp_out);
368: } /* End if */
369: fclose(fp);
370: addpicfile(name);
371: } else if ( quiet == FALSE )
372: error(NON_FATAL, "can't read picture file %s", name);
373:
374: } /* End of inline */
375:
376: /*****************************************************************************/
377:
378: gotpicfile(name)
379:
380: char *name;
381:
382: {
383:
384: char buf[100];
385: FILE *fp_pic;
386:
387: /*
388: *
389: * Checks the list of previously added picture files in *temp_file and returns
390: * FALSE if it's a new file and TRUE otherwise. Probably should open the temp
391: * file once for update and leave it open, rather than opening and closing it
392: * every time.
393: *
394: */
395:
396: if ( temp_file != NULL )
397: if ( (fp_pic = fopen(temp_file, "r")) != NULL ) {
398: while ( fscanf(fp_pic, "%s", buf) != EOF )
399: if ( strcmp(buf, name) == 0 ) {
400: fclose(fp_pic);
401: return(TRUE);
402: } /* End if */
403: fclose(fp_pic);
404: } /* End if */
405:
406: return(FALSE);
407:
408: } /* End of gotpicfile */
409:
410: /*****************************************************************************/
411:
412: addpicfile(name)
413:
414: char *name;
415:
416: {
417:
418: FILE *fp_pic;
419:
420: /*
421: *
422: * Adds string *name to the list of in-line picture files that's maintained in
423: * *temp_file. Should undoubtedly open the file once for update and use fseek()
424: * to move around in the file!
425: *
426: */
427:
428: if ( temp_file == NULL )
429: if ( (temp_file = tempnam(TEMPDIR, "picpac")) == NULL )
430: return;
431:
432: if ( (fp_pic = fopen(temp_file, "a")) != NULL ) {
433: fprintf(fp_pic, "%s\n", name);
434: fclose(fp_pic);
435: } /* End if */
436:
437: } /* End of addpicfile */
438:
439: /*****************************************************************************/
440:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.