1 | /* t1asm |
---|
2 | * |
---|
3 | * This program `assembles' Adobe Type-1 font programs in pseudo-PostScript |
---|
4 | * form into either PFB or PFA format. The human readable/editable input is |
---|
5 | * charstring- and eexec-encrypted as specified in the `Adobe Type 1 Font |
---|
6 | * Format' version 1.1 (the `black book'). There is a companion program, |
---|
7 | * t1disasm, which `disassembles' PFB and PFA files into a pseudo-PostScript |
---|
8 | * file. |
---|
9 | * |
---|
10 | * Copyright (c) 1992 by I. Lee Hetherington, all rights reserved. |
---|
11 | * |
---|
12 | * Permission is hereby granted to use, modify, and distribute this program |
---|
13 | * for any purpose provided this copyright notice and the one below remain |
---|
14 | * intact. |
---|
15 | * |
---|
16 | * I. Lee Hetherington (ilh@lcs.mit.edu) |
---|
17 | * |
---|
18 | * Revision 1.2 92/05/22 11:54:45 ilh |
---|
19 | * Fixed bug where integers larger than 32000 could not be encoded in |
---|
20 | * charstrings. Now integer range is correct for four-byte |
---|
21 | * twos-complement integers: -(1<<31) <= i <= (1<<31)-1. Bug detected by |
---|
22 | * Piet Tutelaers (rcpt@urc.tue.nl). |
---|
23 | * |
---|
24 | * Revision 1.1 92/05/22 11:48:46 ilh |
---|
25 | * initial version |
---|
26 | * |
---|
27 | * Ported to Microsoft C/C++ Compiler and MS-DOS operating system by |
---|
28 | * Kai-Uwe Herbing (herbing@netmbx.netmbx.de) on June 12, 1992. Code |
---|
29 | * specific to the MS-DOS version is encapsulated with #ifdef _MSDOS |
---|
30 | * ... #endif, where _MSDOS is an identifier, which is automatically |
---|
31 | * defined, if you compile with the Microsoft C/C++ Compiler. |
---|
32 | * |
---|
33 | */ |
---|
34 | |
---|
35 | #ifndef lint |
---|
36 | static char copyright[] = |
---|
37 | "@(#) Copyright (c) 1992 by I. Lee Hetherington, all rights reserved."; |
---|
38 | #ifdef _MSDOS |
---|
39 | static char portnotice[] = |
---|
40 | "@(#) Ported to MS-DOS by Kai-Uwe Herbing (herbing@netmbx.netmbx.de)."; |
---|
41 | #endif |
---|
42 | #endif |
---|
43 | |
---|
44 | /* Note: this is ANSI C. */ |
---|
45 | |
---|
46 | #ifdef _MSDOS |
---|
47 | #include <fcntl.h> |
---|
48 | #include <getopt.h> |
---|
49 | #include <io.h> |
---|
50 | #endif |
---|
51 | #include <stdio.h> |
---|
52 | #include <stdlib.h> |
---|
53 | #include <string.h> |
---|
54 | #include <ctype.h> |
---|
55 | #include <limits.h> |
---|
56 | |
---|
57 | #ifdef WINDOWS |
---|
58 | # ifdef STANDALONE |
---|
59 | # define WINDOWS_FUNCTIONS |
---|
60 | # include "windows.h" |
---|
61 | # endif |
---|
62 | #endif |
---|
63 | |
---|
64 | /* int32 must be at least 32-bit and uint16 must be at least 16-bit */ |
---|
65 | #if INT_MAX >= 0x7FFFFFFFUL |
---|
66 | typedef int int32; |
---|
67 | #else |
---|
68 | typedef long int32; |
---|
69 | #endif |
---|
70 | #if USHRT_MAX >= 0xFFFFUL |
---|
71 | typedef unsigned short uint16; |
---|
72 | #else |
---|
73 | typedef unsigned int uint16; |
---|
74 | #endif |
---|
75 | |
---|
76 | #define LINESIZE 256 |
---|
77 | |
---|
78 | #define MAXBLOCKLEN ((1L<<17)-6) |
---|
79 | #define MINBLOCKLEN ((1L<<8)-6) |
---|
80 | |
---|
81 | #define MARKER 128 |
---|
82 | #define ASCII 1 |
---|
83 | #define BINARY 2 |
---|
84 | #define DONE 3 |
---|
85 | |
---|
86 | typedef unsigned char byte; |
---|
87 | |
---|
88 | /* must be visible from outside */ |
---|
89 | FILE *ifp; |
---|
90 | FILE *ofp; |
---|
91 | |
---|
92 | /* flags */ |
---|
93 | static int pfb = 0; |
---|
94 | static int active = 0; |
---|
95 | static int start_charstring = 0; |
---|
96 | static int in_eexec = 0; |
---|
97 | |
---|
98 | static char line[LINESIZE]; |
---|
99 | |
---|
100 | /* lenIV and charstring start command */ |
---|
101 | static int lenIV = 4; |
---|
102 | static char cs_start[10]; |
---|
103 | |
---|
104 | /* for charstring buffering */ |
---|
105 | static byte charstring_buf[65535]; |
---|
106 | static byte *charstring_bp; |
---|
107 | |
---|
108 | /* for PFB block buffering */ |
---|
109 | static byte blockbuf[MAXBLOCKLEN]; |
---|
110 | static int32 blocklen = MAXBLOCKLEN; |
---|
111 | static int32 blockpos = -1; |
---|
112 | static int blocktyp = ASCII; |
---|
113 | |
---|
114 | /* decryption stuff */ |
---|
115 | static uint16 er, cr; |
---|
116 | static uint16 c1 = 52845, c2 = 22719; |
---|
117 | |
---|
118 | /* table of charstring commands */ |
---|
119 | static struct command { |
---|
120 | char *name; |
---|
121 | int one, two; |
---|
122 | } command_table[] = { |
---|
123 | { "callothersubr", 12, 16 }, |
---|
124 | { "callsubr", 10, -1 }, |
---|
125 | { "closepath", 9, -1 }, |
---|
126 | { "div", 12, 12 }, |
---|
127 | { "dotsection", 12, 0 }, |
---|
128 | { "endchar", 14, -1 }, |
---|
129 | { "hlineto", 6, -1 }, |
---|
130 | { "hmoveto", 22, -1 }, |
---|
131 | { "hsbw", 13, -1 }, |
---|
132 | { "hstem", 1, -1 }, |
---|
133 | { "hstem3", 12, 2 }, |
---|
134 | { "hvcurveto", 31, -1 }, |
---|
135 | { "pop", 12, 17 }, |
---|
136 | { "return", 11, -1 }, |
---|
137 | { "rlineto", 5, -1 }, |
---|
138 | { "rmoveto", 21, -1 }, |
---|
139 | { "rrcurveto", 8, -1 }, |
---|
140 | { "sbw", 12, 7 }, |
---|
141 | { "seac", 12, 6 }, |
---|
142 | { "setcurrentpoint", 12, 33 }, |
---|
143 | { "vhcurveto", 30, -1 }, |
---|
144 | { "vlineto", 7, -1 }, |
---|
145 | { "vmoveto", 4, -1 }, |
---|
146 | { "vstem", 3, -1 }, |
---|
147 | { "vstem3", 12, 1 }, |
---|
148 | }; /* alphabetical */ |
---|
149 | |
---|
150 | /* Two separate encryption functions because eexec and charstring encryption |
---|
151 | must proceed in parallel. */ |
---|
152 | |
---|
153 | static byte eencrypt(byte plain) |
---|
154 | { |
---|
155 | byte cipher; |
---|
156 | |
---|
157 | cipher = (byte) (plain ^ (er >> 8)); |
---|
158 | er = (uint16) ((cipher + er) * c1 + c2); |
---|
159 | return cipher; |
---|
160 | } |
---|
161 | |
---|
162 | static byte cencrypt(byte plain) |
---|
163 | { |
---|
164 | byte cipher; |
---|
165 | |
---|
166 | cipher = (byte) (plain ^ (cr >> 8)); |
---|
167 | cr = (uint16) ((cipher + cr) * c1 + c2); |
---|
168 | return cipher; |
---|
169 | } |
---|
170 | |
---|
171 | /* This function flushes a buffered PFB block. */ |
---|
172 | |
---|
173 | static void output_block() |
---|
174 | { |
---|
175 | int32 i; |
---|
176 | |
---|
177 | /* output four-byte block length */ |
---|
178 | fputc((int) (blockpos & 0xff), ofp); |
---|
179 | fputc((int) ((blockpos >> 8) & 0xff), ofp); |
---|
180 | fputc((int) ((blockpos >> 16) & 0xff), ofp); |
---|
181 | fputc((int) ((blockpos >> 24) & 0xff), ofp); |
---|
182 | |
---|
183 | /* output block data */ |
---|
184 | for (i = 0; i < blockpos; i++) |
---|
185 | fputc(blockbuf[i], ofp); |
---|
186 | |
---|
187 | /* mark block buffer empty and uninitialized */ |
---|
188 | blockpos = -1; |
---|
189 | } |
---|
190 | |
---|
191 | /* This function outputs a single byte. If output is in PFB format then output |
---|
192 | is buffered through blockbuf[]. If output is in PFA format, then output |
---|
193 | will be hexadecimal if in_eexec is set, ASCII otherwise. */ |
---|
194 | |
---|
195 | static void output_byte(byte b) |
---|
196 | { |
---|
197 | static char *hexchar = "0123456789ABCDEF"; |
---|
198 | static int hexcol = 0; |
---|
199 | |
---|
200 | if (pfb) { |
---|
201 | /* PFB */ |
---|
202 | if (blockpos < 0) { |
---|
203 | fputc(MARKER, ofp); |
---|
204 | fputc(blocktyp, ofp); |
---|
205 | blockpos = 0; |
---|
206 | } |
---|
207 | blockbuf[blockpos++] = b; |
---|
208 | if (blockpos == blocklen) |
---|
209 | output_block(); |
---|
210 | } else { |
---|
211 | /* PFA */ |
---|
212 | if (in_eexec) { |
---|
213 | /* trim hexadecimal lines to 64 columns */ |
---|
214 | if (hexcol >= 64) { |
---|
215 | fputc('\n', ofp); |
---|
216 | hexcol = 0; |
---|
217 | } |
---|
218 | fputc(hexchar[(b >> 4) & 0xf], ofp); |
---|
219 | fputc(hexchar[b & 0xf], ofp); |
---|
220 | hexcol += 2; |
---|
221 | } else { |
---|
222 | fputc(b, ofp); |
---|
223 | } |
---|
224 | } |
---|
225 | } |
---|
226 | |
---|
227 | /* This function outputs a byte through possible eexec encryption. */ |
---|
228 | |
---|
229 | static void eexec_byte(byte b) |
---|
230 | { |
---|
231 | if (in_eexec) |
---|
232 | output_byte(eencrypt(b)); |
---|
233 | else |
---|
234 | output_byte(b); |
---|
235 | } |
---|
236 | |
---|
237 | /* This function outputs a null-terminated string through possible eexec |
---|
238 | encryption. */ |
---|
239 | |
---|
240 | static void eexec_string(char *string) |
---|
241 | { |
---|
242 | while (*string) |
---|
243 | eexec_byte((byte) *string++); |
---|
244 | } |
---|
245 | |
---|
246 | /* This function gets ready for the eexec-encrypted data. If output is in |
---|
247 | PFB format then flush current ASCII block and get ready for binary block. |
---|
248 | We start encryption with four random (zero) bytes. */ |
---|
249 | |
---|
250 | static void eexec_start() |
---|
251 | { |
---|
252 | eexec_string(line); |
---|
253 | if (pfb) { |
---|
254 | output_block(); |
---|
255 | blocktyp = BINARY; |
---|
256 | } |
---|
257 | |
---|
258 | in_eexec = 1; |
---|
259 | er = 55665; |
---|
260 | eexec_byte(0); |
---|
261 | eexec_byte(0); |
---|
262 | eexec_byte(0); |
---|
263 | eexec_byte(0); |
---|
264 | } |
---|
265 | |
---|
266 | /* This function wraps-up the eexec-encrypted data. |
---|
267 | If output is in PFB format then this entails flushing binary block and |
---|
268 | starting an ASCII block. */ |
---|
269 | |
---|
270 | static void eexec_end() |
---|
271 | { |
---|
272 | int i, j; |
---|
273 | |
---|
274 | if (pfb) { |
---|
275 | output_block(); |
---|
276 | blocktyp = ASCII; |
---|
277 | } else { |
---|
278 | fputc('\n', ofp); |
---|
279 | } |
---|
280 | in_eexec = 0; |
---|
281 | for (i = 0; i < 8; i++) { |
---|
282 | for (j = 0; j < 64; j++) |
---|
283 | eexec_byte('0'); |
---|
284 | eexec_byte('\n'); |
---|
285 | } |
---|
286 | #if 0 |
---|
287 | eexec_string("cleartomark\n"); |
---|
288 | #endif |
---|
289 | } |
---|
290 | |
---|
291 | /* This function writes ASCII trailer. |
---|
292 | If output is in PFB format then this entails flushing binary block and |
---|
293 | starting an ASCII block. */ |
---|
294 | |
---|
295 | static void file_end() |
---|
296 | { |
---|
297 | if (pfb) { |
---|
298 | output_block(); |
---|
299 | fputc(MARKER, ofp); |
---|
300 | fputc(DONE, ofp); |
---|
301 | } |
---|
302 | } |
---|
303 | /* This function returns an input line of characters. A line is terminated by |
---|
304 | length (including terminating null) greater than LINESIZE, a newline \n, or |
---|
305 | when active (looking for charstrings) by '{'. When terminated by a newline |
---|
306 | the newline is put into line[]. When terminated by '{', the '{' is not put |
---|
307 | into line[], and the flag start_charstring is set to 1. */ |
---|
308 | |
---|
309 | static void t1asm_getline() |
---|
310 | { |
---|
311 | int c; |
---|
312 | char *p = line; |
---|
313 | int comment = 0; |
---|
314 | |
---|
315 | start_charstring = 0; |
---|
316 | while (p < line + LINESIZE) { |
---|
317 | c = fgetc(ifp); |
---|
318 | if (c == EOF) |
---|
319 | break; |
---|
320 | if (c == '%') |
---|
321 | comment = 1; |
---|
322 | if (active && !comment && c == '{') { |
---|
323 | start_charstring = 1; |
---|
324 | break; |
---|
325 | } |
---|
326 | *p++ = (char) c; |
---|
327 | if (c == '\n') |
---|
328 | break; |
---|
329 | } |
---|
330 | *p = '\0'; |
---|
331 | } |
---|
332 | |
---|
333 | /* This function is used by the binary search, bsearch(), for command names in |
---|
334 | the command table. */ |
---|
335 | |
---|
336 | static int command_compare(const void *key, const void *item) |
---|
337 | { |
---|
338 | return strcmp((char *) key, ((struct command *) item)->name); |
---|
339 | } |
---|
340 | |
---|
341 | /* This function returns 1 if the string is an integer and 0 otherwise. */ |
---|
342 | |
---|
343 | static int is_integer(char *string) |
---|
344 | { |
---|
345 | if (isdigit(string[0]) || string[0] == '-' || string[0] == '+') { |
---|
346 | while (*++string && isdigit(*string)) |
---|
347 | ; /* deliberately empty */ |
---|
348 | if (!*string) |
---|
349 | return 1; |
---|
350 | } |
---|
351 | return 0; |
---|
352 | } |
---|
353 | |
---|
354 | /* This function initializes charstring encryption. Note that this is called |
---|
355 | at the beginning of every charstring. */ |
---|
356 | |
---|
357 | static void charstring_start() |
---|
358 | { |
---|
359 | int i; |
---|
360 | |
---|
361 | charstring_bp = charstring_buf; |
---|
362 | cr = 4330; |
---|
363 | for (i = 0; i < lenIV; i++) |
---|
364 | *charstring_bp++ = cencrypt((byte) 0); |
---|
365 | } |
---|
366 | |
---|
367 | /* This function encrypts and buffers a single byte of charstring data. */ |
---|
368 | |
---|
369 | static void charstring_byte(int v) |
---|
370 | { |
---|
371 | byte b = (byte) (v & 0xff); |
---|
372 | |
---|
373 | if (charstring_bp - charstring_buf > sizeof(charstring_buf)) { |
---|
374 | fprintf(stderr, "error: charstring_buf full (%d bytes)\n", |
---|
375 | sizeof(charstring_buf)); |
---|
376 | exit(1); |
---|
377 | } |
---|
378 | *charstring_bp++ = cencrypt(b); |
---|
379 | } |
---|
380 | |
---|
381 | /* This function outputs buffered, encrypted charstring data through possible |
---|
382 | eexec encryption. */ |
---|
383 | |
---|
384 | static void charstring_end() |
---|
385 | { |
---|
386 | byte *bp; |
---|
387 | |
---|
388 | sprintf(line, "%d ", charstring_bp - charstring_buf); |
---|
389 | eexec_string(line); |
---|
390 | sprintf(line, "%s ", cs_start); |
---|
391 | eexec_string(line); |
---|
392 | for (bp = charstring_buf; bp < charstring_bp; bp++) |
---|
393 | eexec_byte(*bp); |
---|
394 | } |
---|
395 | |
---|
396 | /* This function generates the charstring representation of an integer. */ |
---|
397 | |
---|
398 | static void charstring_int(int num) |
---|
399 | { |
---|
400 | int x; |
---|
401 | |
---|
402 | if (num >= -107 && num <= 107) { |
---|
403 | charstring_byte(num + 139); |
---|
404 | } else if (num >= 108 && num <= 1131) { |
---|
405 | x = num - 108; |
---|
406 | charstring_byte(x / 256 + 247); |
---|
407 | charstring_byte(x % 256); |
---|
408 | } else if (num >= -1131 && num <= -108) { |
---|
409 | x = abs(num) - 108; |
---|
410 | charstring_byte(x / 256 + 251); |
---|
411 | charstring_byte(x % 256); |
---|
412 | } else if (num >= (-2147483647-1) && num <= 2147483647) { |
---|
413 | charstring_byte(255); |
---|
414 | charstring_byte(num >> 24); |
---|
415 | charstring_byte(num >> 16); |
---|
416 | charstring_byte(num >> 8); |
---|
417 | charstring_byte(num); |
---|
418 | } else { |
---|
419 | fprintf(stderr, |
---|
420 | "error: cannot format the integer %d, too large\n", num); |
---|
421 | exit(1); |
---|
422 | } |
---|
423 | } |
---|
424 | |
---|
425 | /* This function parses an entire charstring into integers and commands, |
---|
426 | outputting bytes through the charstring buffer. */ |
---|
427 | |
---|
428 | static void parse_charstring() |
---|
429 | { |
---|
430 | struct command *cp; |
---|
431 | |
---|
432 | charstring_start(); |
---|
433 | while (fscanf(ifp, "%s", line) == 1) { |
---|
434 | if (line[0] == '%') { |
---|
435 | /* eat comment to end of line */ |
---|
436 | while (fgetc(ifp) != '\n' && !feof(ifp)) |
---|
437 | ; /* deliberately empty */ |
---|
438 | continue; |
---|
439 | } |
---|
440 | if (line[0] == '}') |
---|
441 | break; |
---|
442 | if (is_integer(line)) { |
---|
443 | charstring_int(atoi(line)); |
---|
444 | } else { |
---|
445 | cp = (struct command *) |
---|
446 | bsearch((void *) line, (void *) command_table, |
---|
447 | sizeof(command_table) / sizeof(struct command), |
---|
448 | sizeof(struct command), |
---|
449 | command_compare); |
---|
450 | if (cp) { |
---|
451 | charstring_byte(cp->one); |
---|
452 | if (cp->two >= 0) |
---|
453 | charstring_byte(cp->two); |
---|
454 | } else { |
---|
455 | fprintf(stderr, "error: cannot use `%s' in charstring\n",line); |
---|
456 | exit(1); |
---|
457 | } |
---|
458 | } |
---|
459 | } |
---|
460 | charstring_end(); |
---|
461 | } |
---|
462 | |
---|
463 | static void usage() |
---|
464 | { |
---|
465 | fprintf(stderr, |
---|
466 | "usage: t1asm [-b] [-l block-length] [input [output]]\n"); |
---|
467 | fprintf(stderr, |
---|
468 | "\n-b means output in PFB format, otherwise PFA format.\n"); |
---|
469 | fprintf(stderr, |
---|
470 | "The block length applies to the length of blocks in the\n"); |
---|
471 | fprintf(stderr, |
---|
472 | "PFB output file; the default is to use the largest possible.\n"); |
---|
473 | exit(1); |
---|
474 | } |
---|
475 | |
---|
476 | static void print_banner() |
---|
477 | { |
---|
478 | static char rcs_revision[] = ""; /* removed RCS */ |
---|
479 | static char revision[20]; |
---|
480 | |
---|
481 | if (sscanf(rcs_revision, "$Revision: %19s", revision) != 1) |
---|
482 | revision[0] = '\0'; |
---|
483 | fprintf(stderr, "This is t1asm %s.\n", revision); |
---|
484 | } |
---|
485 | |
---|
486 | #ifdef STANDALONE |
---|
487 | int main(int argc, char **argv) |
---|
488 | { |
---|
489 | char *p, *q, *r; |
---|
490 | int c; |
---|
491 | |
---|
492 | extern char *optarg; |
---|
493 | extern int optind; |
---|
494 | |
---|
495 | ifp = stdin; |
---|
496 | ofp = stdout; |
---|
497 | |
---|
498 | print_banner(); |
---|
499 | |
---|
500 | /* interpret command line arguments using getopt */ |
---|
501 | while ((c = getopt(argc, argv, "bl:")) != -1) |
---|
502 | switch (c) { |
---|
503 | case 'b': |
---|
504 | pfb = 1; |
---|
505 | break; |
---|
506 | case 'l': |
---|
507 | blocklen = atoi(optarg); |
---|
508 | if (blocklen < MINBLOCKLEN) { |
---|
509 | blocklen = MINBLOCKLEN; |
---|
510 | fprintf(stderr, |
---|
511 | "warning: using minimum block length of %d\n", |
---|
512 | blocklen); |
---|
513 | } else if (blocklen > MAXBLOCKLEN) { |
---|
514 | blocklen = MAXBLOCKLEN; |
---|
515 | fprintf(stderr, |
---|
516 | "warning: using maximum block length of %d\n", |
---|
517 | blocklen); |
---|
518 | } |
---|
519 | break; |
---|
520 | default: |
---|
521 | usage(); |
---|
522 | break; |
---|
523 | } |
---|
524 | if (argc - optind > 2) |
---|
525 | usage(); |
---|
526 | |
---|
527 | /* possibly open input & output files */ |
---|
528 | if (argc - optind >= 1) { |
---|
529 | ifp = fopen(argv[optind], "r"); |
---|
530 | if (!ifp) { |
---|
531 | fprintf(stderr, "error: cannot open %s for reading\n", argv[1]); |
---|
532 | exit(1); |
---|
533 | } |
---|
534 | } |
---|
535 | if (argc - optind >= 2) { |
---|
536 | ofp = fopen(argv[optind + 1], "w"); |
---|
537 | if (!ofp) { |
---|
538 | fprintf(stderr, "error: cannot open %s for writing\n", argv[2]); |
---|
539 | exit(1); |
---|
540 | } |
---|
541 | } |
---|
542 | |
---|
543 | #else |
---|
544 | int runt1asm(int pfbflag) |
---|
545 | { |
---|
546 | char *p, *q, *r; |
---|
547 | |
---|
548 | pfb = pfbflag; |
---|
549 | #endif |
---|
550 | |
---|
551 | #ifdef _MSDOS |
---|
552 | /* If we are processing a PFB (binary) output */ |
---|
553 | /* file, we must set its file mode to binary. */ |
---|
554 | if (pfb) |
---|
555 | _setmode(_fileno(ofp), _O_BINARY); |
---|
556 | #endif |
---|
557 | |
---|
558 | /* Finally, we loop until no more input. Some special things to look for |
---|
559 | are the `currentfile eexec' line, the beginning of the `/Subrs' |
---|
560 | definition, the definition of `/lenIV', and the definition of the |
---|
561 | charstring start command which has `...string currentfile...' in it. */ |
---|
562 | |
---|
563 | while (!feof(ifp) && !ferror(ifp)) { |
---|
564 | t1asm_getline(); |
---|
565 | if (strcmp(line, "currentfile eexec\n") == 0) { |
---|
566 | eexec_start(); |
---|
567 | continue; |
---|
568 | } else if (strstr(line, "/Subrs") && isspace(line[6])) { |
---|
569 | active = 1; |
---|
570 | } else if ((p = strstr(line, "/lenIV"))) { |
---|
571 | sscanf(p, "%*s %d", &lenIV); |
---|
572 | } else if ((p = strstr(line, "string currentfile"))) { |
---|
573 | /* locate the name of the charstring start command */ |
---|
574 | *p = '\0'; /* damage line[] */ |
---|
575 | q = strrchr(line, '/'); |
---|
576 | if (q) { |
---|
577 | r = cs_start; |
---|
578 | ++q; |
---|
579 | while (!isspace(*q) && *q != '{') |
---|
580 | *r++ = *q++; |
---|
581 | *r = '\0'; |
---|
582 | } |
---|
583 | *p = 's'; /* repair line[] */ |
---|
584 | } |
---|
585 | /* output line data */ |
---|
586 | eexec_string(line); |
---|
587 | if ((p = strstr(line, "currentfile closefile"))) { |
---|
588 | eexec_end(); |
---|
589 | } |
---|
590 | if (start_charstring) { |
---|
591 | if (!cs_start[0]) { |
---|
592 | fprintf(stderr, "error: couldn't find charstring start command\n"); |
---|
593 | exit(1); |
---|
594 | } |
---|
595 | parse_charstring(); |
---|
596 | } |
---|
597 | } |
---|
598 | file_end(); |
---|
599 | |
---|
600 | fclose(ifp); |
---|
601 | fclose(ofp); |
---|
602 | |
---|
603 | return 0; |
---|
604 | } |
---|