1 | /* |
---|
2 | * Copyright (c) 1997 Paul Vojta. |
---|
3 | * |
---|
4 | * Redistribution and use in source and binary forms, with or without |
---|
5 | * modification, are permitted provided that the following conditions |
---|
6 | * are met: |
---|
7 | * 1. Redistributions of source code must retain the above copyright |
---|
8 | * notice, this list of conditions and the following disclaimer. |
---|
9 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
10 | * notice, this list of conditions and the following disclaimer in the |
---|
11 | * documentation and/or other materials provided with the distribution. |
---|
12 | * |
---|
13 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
---|
14 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
16 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
---|
17 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
18 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
---|
19 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
---|
20 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
---|
21 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
---|
22 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
---|
23 | * SUCH DAMAGE. |
---|
24 | */ |
---|
25 | |
---|
26 | #ifndef lint |
---|
27 | static char copyright[] = |
---|
28 | "@(#) Copyright (c) 1997 Paul Vojta.\n"; |
---|
29 | #endif |
---|
30 | |
---|
31 | /* |
---|
32 | * Modified by Yves Arrouye to support the kpathsea library v2.6, based on |
---|
33 | * previous work from Thomas Essen. |
---|
34 | */ |
---|
35 | |
---|
36 | #ifndef KPATHSEA |
---|
37 | #include "config.h" |
---|
38 | #else |
---|
39 | #include "c-auto.h" |
---|
40 | #endif |
---|
41 | #include <errno.h> |
---|
42 | #include <ctype.h> |
---|
43 | #include <memory.h> |
---|
44 | #include <sys/types.h> |
---|
45 | #if 0 |
---|
46 | #include <sys/wait.h> |
---|
47 | #endif |
---|
48 | #include <sys/stat.h> |
---|
49 | #include <setjmp.h> |
---|
50 | |
---|
51 | #ifdef KPATHSEA |
---|
52 | #include <kpathsea/c-std.h> |
---|
53 | #include <kpathsea/tex-file.h> |
---|
54 | #endif |
---|
55 | |
---|
56 | #ifdef POSIX_DIRENT |
---|
57 | #include <dirent.h> |
---|
58 | typedef struct dirent struct_dirent; |
---|
59 | #else /* !POSIX */ |
---|
60 | #include <sys/dir.h> |
---|
61 | typedef struct direct struct_dirent; |
---|
62 | #endif |
---|
63 | |
---|
64 | #ifndef S_ISDIR |
---|
65 | #if defined(S_IFMT) && defined(S_IFDIR) |
---|
66 | #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) |
---|
67 | #endif |
---|
68 | #endif |
---|
69 | |
---|
70 | #ifndef GS |
---|
71 | #define GS "gs" |
---|
72 | #endif |
---|
73 | |
---|
74 | #ifndef atof |
---|
75 | double atof(); |
---|
76 | #endif |
---|
77 | char *getenv(); |
---|
78 | |
---|
79 | #ifdef __GNUC__ |
---|
80 | #define NORETURN volatile |
---|
81 | #else |
---|
82 | #define NORETURN /* nothing */ |
---|
83 | #endif |
---|
84 | |
---|
85 | #ifdef I_STDARG |
---|
86 | #define NeedVarargsPrototypes 1 |
---|
87 | #include <stdarg.h> |
---|
88 | #else |
---|
89 | #define NeedVarargsPrototypes 0 |
---|
90 | #include <varargs.h> |
---|
91 | #endif |
---|
92 | |
---|
93 | typedef char Boolean; |
---|
94 | #define True 1 |
---|
95 | #define False 0 |
---|
96 | |
---|
97 | #ifndef MAXPATHLEN |
---|
98 | #define MAXPATHLEN 256 |
---|
99 | #endif |
---|
100 | |
---|
101 | #define PK_PRE (char) 247 |
---|
102 | #define PK_ID (char) 89 |
---|
103 | #define PK_SPC (char) 240 |
---|
104 | #define PK_POST (char) 245 |
---|
105 | #define PK_NOP (char) 246 |
---|
106 | |
---|
107 | char ident[] = "gsftopk version 1.12"; |
---|
108 | |
---|
109 | typedef unsigned char byte; |
---|
110 | |
---|
111 | FILE *data_file; |
---|
112 | FILE *pk_file; |
---|
113 | Boolean quiet = False; |
---|
114 | int col = 0; /* current column number */ |
---|
115 | |
---|
116 | /* |
---|
117 | * Information from the .tfm file. |
---|
118 | */ |
---|
119 | |
---|
120 | int tfm_lengths[12]; |
---|
121 | #define lh tfm_lengths[1] |
---|
122 | #define bc tfm_lengths[2] |
---|
123 | #define ec tfm_lengths[3] |
---|
124 | #define nw tfm_lengths[4] |
---|
125 | |
---|
126 | long checksum; |
---|
127 | long design; |
---|
128 | byte width_index[256]; |
---|
129 | long tfm_widths[256]; |
---|
130 | |
---|
131 | /* |
---|
132 | * Information on the bitmap currently being worked on. |
---|
133 | */ |
---|
134 | |
---|
135 | byte *bitmap; |
---|
136 | int width; |
---|
137 | int skip; |
---|
138 | int height; |
---|
139 | int hoff; |
---|
140 | int voff; |
---|
141 | int bytes_wide; |
---|
142 | unsigned int bm_size; |
---|
143 | byte *bitmap_end; |
---|
144 | int pk_len; |
---|
145 | |
---|
146 | /* |
---|
147 | * Print error message and quit. |
---|
148 | */ |
---|
149 | |
---|
150 | #if NeedVarargsPrototypes |
---|
151 | NORETURN void |
---|
152 | oops(const char *message, ...) |
---|
153 | #else |
---|
154 | /* VARARGS */ |
---|
155 | NORETURN void |
---|
156 | oops(va_alist) |
---|
157 | va_dcl |
---|
158 | #endif |
---|
159 | { |
---|
160 | #if !NeedVarargsPrototypes |
---|
161 | const char *message; |
---|
162 | #endif |
---|
163 | va_list args; |
---|
164 | |
---|
165 | #if NeedVarargsPrototypes |
---|
166 | va_start(args, message); |
---|
167 | #else |
---|
168 | va_start(args); |
---|
169 | message = va_arg(args, const char *); |
---|
170 | #endif |
---|
171 | vfprintf(stderr, message, args); |
---|
172 | va_end(args); |
---|
173 | putc('\n', stderr); |
---|
174 | exit(1); |
---|
175 | } |
---|
176 | |
---|
177 | /* |
---|
178 | * Either allocate storage or fail with explanation. |
---|
179 | */ |
---|
180 | |
---|
181 | char * |
---|
182 | xmalloc(size, why) |
---|
183 | unsigned size; |
---|
184 | const char *why; |
---|
185 | { |
---|
186 | char *mem = (char *) malloc(size); |
---|
187 | |
---|
188 | if (mem == NULL) |
---|
189 | oops("Cannot allocate %u bytes for %s.\n", size, why); |
---|
190 | return mem; |
---|
191 | } |
---|
192 | |
---|
193 | /* |
---|
194 | * Either reallocate storage or fail with explanation. |
---|
195 | */ |
---|
196 | |
---|
197 | char * |
---|
198 | xrealloc(oldp, size, why) |
---|
199 | char *oldp; |
---|
200 | unsigned size; |
---|
201 | const char *why; |
---|
202 | { |
---|
203 | char *mem; |
---|
204 | |
---|
205 | mem = oldp == NULL ? (char *) malloc(size) |
---|
206 | : (char *) realloc(oldp, size); |
---|
207 | if (mem == NULL) |
---|
208 | oops("Cannot reallocate %u bytes for %s.\n", size, why); |
---|
209 | return mem; |
---|
210 | } |
---|
211 | |
---|
212 | /* |
---|
213 | * Here's the patch searching stuff. First the typedefs and variables. |
---|
214 | */ |
---|
215 | |
---|
216 | static char searchpath[MAXPATHLEN + 1]; |
---|
217 | |
---|
218 | #define HUNKSIZE (MAXPATHLEN + 2) |
---|
219 | |
---|
220 | struct spacenode { /* used for storage of directory names */ |
---|
221 | struct spacenode *next; |
---|
222 | char *sp_end; /* end of data for this chunk */ |
---|
223 | char sp[HUNKSIZE]; |
---|
224 | } |
---|
225 | firstnode; |
---|
226 | |
---|
227 | static jmp_buf found_env; |
---|
228 | static FILE *searchfile; |
---|
229 | static char *searchname; |
---|
230 | static int searchnamelen; |
---|
231 | |
---|
232 | #ifdef KPATHSEA |
---|
233 | |
---|
234 | static char* kstrcpy(char* a, const char* b) { |
---|
235 | if (b == (const char*) 0) { |
---|
236 | *a = 0; |
---|
237 | } else { |
---|
238 | char* z = a; |
---|
239 | |
---|
240 | while (*z++ = *b++); |
---|
241 | } |
---|
242 | |
---|
243 | return a; |
---|
244 | } |
---|
245 | |
---|
246 | #else /* ! KPATHSEA */ |
---|
247 | |
---|
248 | static char * |
---|
249 | find_dbl_slash(char *sp_bgn, char *sp_end) |
---|
250 | { |
---|
251 | char *p; |
---|
252 | |
---|
253 | for (;;) { |
---|
254 | p = memchr(sp_bgn, '/', sp_end - sp_bgn); |
---|
255 | if (p == NULL) return sp_end; |
---|
256 | if (p[1] == '/') return p; |
---|
257 | sp_bgn = p + 1; |
---|
258 | } |
---|
259 | } |
---|
260 | |
---|
261 | static void |
---|
262 | main_search_proc(char *matpos, char *sp_pos, char *sp_slash, char *sp_end, |
---|
263 | Boolean skip_subdirs, struct spacenode *space, char *spacenext) |
---|
264 | { |
---|
265 | char *mp; |
---|
266 | struct stat statbuf; |
---|
267 | DIR *dir; |
---|
268 | struct_dirent *entry; |
---|
269 | int lenleft; |
---|
270 | int len; |
---|
271 | struct spacenode *space1; |
---|
272 | char *spacenext1; |
---|
273 | |
---|
274 | mp = matpos + (sp_slash - sp_pos); |
---|
275 | /* check length */ |
---|
276 | if (mp + searchnamelen >= searchpath + sizeof(searchpath) - 2) return; |
---|
277 | memcpy(matpos, sp_pos, sp_slash - sp_pos); |
---|
278 | if (sp_slash == sp_end) { /* try for a file */ |
---|
279 | *mp = '/'; |
---|
280 | strcpy(mp + (mp == searchpath || mp[-1] != '/'), searchname); |
---|
281 | searchfile = fopen(searchpath, "r"); |
---|
282 | if (searchfile != NULL) longjmp(found_env, True); |
---|
283 | } |
---|
284 | else {/* try for a subdirectory */ |
---|
285 | *mp = '\0'; |
---|
286 | if (stat(searchpath, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) { |
---|
287 | *mp++ = '/'; |
---|
288 | main_search_proc(mp, sp_slash + 2, |
---|
289 | find_dbl_slash(sp_slash + 2, sp_end), sp_end, |
---|
290 | statbuf.st_nlink <= 2, space, spacenext); |
---|
291 | } |
---|
292 | } |
---|
293 | if (skip_subdirs) return; |
---|
294 | *matpos = '\0'; |
---|
295 | dir = opendir(searchpath); |
---|
296 | if (dir == NULL) return; |
---|
297 | lenleft = searchpath + sizeof(searchpath) - matpos; |
---|
298 | space1 = space; |
---|
299 | spacenext1 = spacenext; |
---|
300 | for (;;) { |
---|
301 | entry = readdir(dir); |
---|
302 | if (entry == NULL) break; |
---|
303 | len = strlen(entry->d_name) + 1; |
---|
304 | if (len > lenleft) continue; /* too long */ |
---|
305 | strcpy(matpos, entry->d_name); |
---|
306 | if (*matpos == '.' && (matpos[1] == '\0' || (matpos[1] == '.' |
---|
307 | && matpos[2] == '\0'))) |
---|
308 | continue; /* ignore . and .. */ |
---|
309 | if (stat(searchpath, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) |
---|
310 | continue; /* if not a directory */ |
---|
311 | if (statbuf.st_nlink > 2) ++len; |
---|
312 | if (spacenext1 + len > space1->sp + HUNKSIZE) { |
---|
313 | space1->sp_end = spacenext1; |
---|
314 | if (space1->next == NULL) { |
---|
315 | space1->next = |
---|
316 | (struct spacenode *) xmalloc(sizeof(struct spacenode), |
---|
317 | "space for directory names"); |
---|
318 | space1->next->next = NULL; |
---|
319 | } |
---|
320 | space1 = space1->next; |
---|
321 | spacenext1 = space1->sp; |
---|
322 | } |
---|
323 | if (statbuf.st_nlink > 2) { |
---|
324 | *spacenext1++ = '/'; |
---|
325 | --len; |
---|
326 | } |
---|
327 | memcpy(spacenext1, entry->d_name, len); |
---|
328 | spacenext1 += len; |
---|
329 | } |
---|
330 | closedir(dir); |
---|
331 | for (;;) { |
---|
332 | space1->sp_end = spacenext1; |
---|
333 | if (spacenext == space->sp_end) { |
---|
334 | if (space == space1) break; |
---|
335 | space = space->next; |
---|
336 | spacenext = space->sp; |
---|
337 | } |
---|
338 | skip_subdirs = True; |
---|
339 | if (*spacenext == '/') { |
---|
340 | ++spacenext; |
---|
341 | skip_subdirs = False; |
---|
342 | } |
---|
343 | len = strlen(spacenext); |
---|
344 | memcpy(matpos, spacenext, len); |
---|
345 | matpos[len] = '/'; |
---|
346 | main_search_proc(matpos + len + 1, sp_pos, sp_slash, sp_end, |
---|
347 | skip_subdirs, space1, spacenext1); |
---|
348 | spacenext += len + 1; |
---|
349 | } |
---|
350 | } |
---|
351 | |
---|
352 | static FILE * |
---|
353 | search(char *path, char *path_var, char *name) |
---|
354 | { |
---|
355 | char *env_path = NULL; |
---|
356 | FILE *f; |
---|
357 | |
---|
358 | if (path_var != NULL) { |
---|
359 | if (*name == '/') { |
---|
360 | strcpy(searchpath, name); |
---|
361 | return fopen(searchpath, "r"); |
---|
362 | } |
---|
363 | env_path = getenv(path_var); |
---|
364 | } |
---|
365 | if (env_path == NULL) { |
---|
366 | env_path = path; |
---|
367 | path = NULL; |
---|
368 | } |
---|
369 | searchname = name; |
---|
370 | searchnamelen = strlen(name); |
---|
371 | for (;;) { |
---|
372 | char *p; |
---|
373 | |
---|
374 | p = strchr(env_path, ':'); |
---|
375 | if (p == NULL) p = env_path + strlen(env_path); |
---|
376 | if (p == env_path) { |
---|
377 | if (path != NULL) { |
---|
378 | f = search(path, NULL, name); |
---|
379 | if (f != NULL) return f; |
---|
380 | } |
---|
381 | } |
---|
382 | else { |
---|
383 | if (setjmp(found_env)) |
---|
384 | return searchfile; |
---|
385 | main_search_proc(searchpath, |
---|
386 | env_path, find_dbl_slash(env_path, p), p, |
---|
387 | True, &firstnode, firstnode.sp); |
---|
388 | } |
---|
389 | if (*p == '\0') return NULL; |
---|
390 | env_path = p + 1; |
---|
391 | } |
---|
392 | } |
---|
393 | |
---|
394 | #endif /* ! KPATHSEA */ |
---|
395 | |
---|
396 | /* |
---|
397 | * Add to dlstring |
---|
398 | */ |
---|
399 | |
---|
400 | char *dlstring = NULL; |
---|
401 | unsigned int dls_len = 0; |
---|
402 | unsigned int dls_max = 0; |
---|
403 | |
---|
404 | void |
---|
405 | addtodls(char *s) |
---|
406 | { |
---|
407 | int len = strlen(s); |
---|
408 | |
---|
409 | if (dls_len + len >= dls_max) { |
---|
410 | unsigned int newsize = dls_max + 80; |
---|
411 | |
---|
412 | if (newsize <= dls_len + len) newsize = dls_len + len + 1; |
---|
413 | dlstring = xrealloc(dlstring, dls_max = newsize, "download string"); |
---|
414 | } |
---|
415 | strcpy(dlstring + dls_len, s); |
---|
416 | dls_len += len; |
---|
417 | } |
---|
418 | |
---|
419 | |
---|
420 | |
---|
421 | long |
---|
422 | getlong(FILE *f) |
---|
423 | { |
---|
424 | int value; |
---|
425 | |
---|
426 | value = (int) ((byte) getc(f)) << 24; |
---|
427 | value |= (int) ((byte) getc(f)) << 16; |
---|
428 | value |= (int) ((byte) getc(f)) << 8; |
---|
429 | value |= (int) ((byte) getc(f)); |
---|
430 | return value; |
---|
431 | } |
---|
432 | |
---|
433 | |
---|
434 | char line[82]; |
---|
435 | |
---|
436 | void |
---|
437 | expect(char *waitingfor) |
---|
438 | { |
---|
439 | for (;;) { |
---|
440 | if (fgets(line, sizeof(line), data_file) == NULL) |
---|
441 | oops("Premature end of file"); |
---|
442 | if (memcmp(line, waitingfor, strlen(waitingfor)) == 0) return; |
---|
443 | fputs("gs: ", stdout); |
---|
444 | for (;;) { |
---|
445 | fputs(line, stdout); |
---|
446 | if (*line == '\0' || line[strlen(line) - 1] == '\n') break; |
---|
447 | if (fgets(line, sizeof(line), data_file) == NULL) |
---|
448 | oops("Premature end of file"); |
---|
449 | } |
---|
450 | } |
---|
451 | } |
---|
452 | |
---|
453 | void |
---|
454 | whitespace(void) |
---|
455 | { |
---|
456 | char c; |
---|
457 | |
---|
458 | for (;;) { |
---|
459 | c = getc(data_file); |
---|
460 | if (c == '#') |
---|
461 | do c = getc(data_file); while (!feof(data_file) && c != '\n'); |
---|
462 | else if (!isspace(c)) { |
---|
463 | ungetc(c, data_file); |
---|
464 | break; |
---|
465 | } |
---|
466 | } |
---|
467 | } |
---|
468 | |
---|
469 | int |
---|
470 | getint(void) |
---|
471 | { |
---|
472 | char c; |
---|
473 | int i = 0; |
---|
474 | |
---|
475 | do c = getc(data_file); while (isspace(c)); |
---|
476 | if (c < '0' || c > '9') oops("digit expected"); |
---|
477 | do { |
---|
478 | i = i * 10 + (c - '0'); |
---|
479 | c = getc(data_file); |
---|
480 | } while (c >= '0' && c <= '9'); |
---|
481 | if (!feof(data_file)) ungetc(c, data_file); |
---|
482 | return i; |
---|
483 | } |
---|
484 | |
---|
485 | static byte masks[] = {0, 1, 3, 7, 017, 037, 077, 0177, 0377}; |
---|
486 | |
---|
487 | byte flag; |
---|
488 | int pk_dyn_f; |
---|
489 | int pk_dyn_g; |
---|
490 | int base; /* cost of this character if pk_dyn_f = 0 */ |
---|
491 | int deltas[13]; /* cost of increasing pk_dyn_f from i to i+1 */ |
---|
492 | |
---|
493 | /* |
---|
494 | * Add up statistics for putting out the given shift count |
---|
495 | */ |
---|
496 | |
---|
497 | static void |
---|
498 | tallyup(int n) |
---|
499 | { |
---|
500 | int m; |
---|
501 | |
---|
502 | if (n > 208) { |
---|
503 | ++base; |
---|
504 | n -= 192; |
---|
505 | for (m = 0x100; m != 0 && m < n; m <<= 4) base += 2; |
---|
506 | if (m != 0 && (m = (m - n) / 15) < 13) deltas[m] += 2; |
---|
507 | } |
---|
508 | else if (n > 13) ++deltas[(208 - n) / 15]; |
---|
509 | else --deltas[n - 1]; |
---|
510 | } |
---|
511 | |
---|
512 | /* |
---|
513 | * Routines for storing the shift counts |
---|
514 | */ |
---|
515 | |
---|
516 | static Boolean odd = False; |
---|
517 | static byte part; |
---|
518 | |
---|
519 | static void |
---|
520 | pk_put_nyb(int n) |
---|
521 | { |
---|
522 | if (odd) { |
---|
523 | *bitmap_end++ = (part << 4) | n; |
---|
524 | odd = False; |
---|
525 | } |
---|
526 | else { |
---|
527 | part = n; |
---|
528 | odd = True; |
---|
529 | } |
---|
530 | } |
---|
531 | |
---|
532 | static void |
---|
533 | pk_put_long(int n) |
---|
534 | { |
---|
535 | if (n >= 16) { |
---|
536 | pk_put_nyb(0); |
---|
537 | pk_put_long(n / 16); |
---|
538 | } |
---|
539 | pk_put_nyb(n % 16); |
---|
540 | } |
---|
541 | |
---|
542 | static void |
---|
543 | pk_put_count(int n) |
---|
544 | { |
---|
545 | if (n > pk_dyn_f) { |
---|
546 | if (n > pk_dyn_g) |
---|
547 | pk_put_long(n - pk_dyn_g + 15); |
---|
548 | else { |
---|
549 | pk_put_nyb(pk_dyn_f + (n - pk_dyn_f + 15) / 16); |
---|
550 | pk_put_nyb((n - pk_dyn_f - 1) % 16); |
---|
551 | } |
---|
552 | } |
---|
553 | else pk_put_nyb(n); |
---|
554 | } |
---|
555 | |
---|
556 | static void |
---|
557 | trim_bitmap(void) |
---|
558 | { |
---|
559 | byte *p; |
---|
560 | byte mask; |
---|
561 | |
---|
562 | /* clear out garbage bits in bitmap */ |
---|
563 | if (width % 8 != 0) { |
---|
564 | mask = ~masks[8 - width % 8]; |
---|
565 | for (p = bitmap + bytes_wide - 1; p < bitmap_end; p += bytes_wide) |
---|
566 | *p &= mask; |
---|
567 | } |
---|
568 | |
---|
569 | /* |
---|
570 | * Find the bounding box of the bitmap. |
---|
571 | */ |
---|
572 | |
---|
573 | /* trim top */ |
---|
574 | skip = 0; |
---|
575 | mask = 0; |
---|
576 | for (;;) { |
---|
577 | if (bitmap >= bitmap_end) { /* if bitmap is empty */ |
---|
578 | width = height = hoff = voff = 0; |
---|
579 | return; |
---|
580 | } |
---|
581 | p = bitmap + bytes_wide; |
---|
582 | while (p > bitmap) mask |= *--p; |
---|
583 | if (mask) break; |
---|
584 | ++skip; |
---|
585 | bitmap += bytes_wide; |
---|
586 | } |
---|
587 | height -= skip; |
---|
588 | voff -= skip; |
---|
589 | #ifdef DEBUG |
---|
590 | if (skip < 2 || skip > 3) |
---|
591 | printf("Character has %d empty rows at top\n", skip); |
---|
592 | #endif |
---|
593 | |
---|
594 | /* trim bottom */ |
---|
595 | skip = 0; |
---|
596 | mask = 0; |
---|
597 | for (;;) { |
---|
598 | p = bitmap_end - bytes_wide; |
---|
599 | while (p < bitmap_end) mask |= *p++; |
---|
600 | if (mask) break; |
---|
601 | ++skip; |
---|
602 | bitmap_end -= bytes_wide; |
---|
603 | } |
---|
604 | height -= skip; |
---|
605 | #ifdef DEBUG |
---|
606 | if (skip < 2 || skip > 3) |
---|
607 | printf("Character has %d empty rows at bottom\n", skip); |
---|
608 | #endif |
---|
609 | |
---|
610 | /* trim right */ |
---|
611 | skip = 0; |
---|
612 | --width; |
---|
613 | for (;;) { |
---|
614 | mask = 0; |
---|
615 | for (p = bitmap + width / 8; p < bitmap_end; p += bytes_wide) |
---|
616 | mask |= *p; |
---|
617 | if (mask & (0x80 >> (width % 8))) break; |
---|
618 | --width; |
---|
619 | ++skip; |
---|
620 | } |
---|
621 | ++width; |
---|
622 | #ifdef DEBUG |
---|
623 | if (skip < 2 || skip > 3) |
---|
624 | printf("Character has %d empty columns at right\n", skip); |
---|
625 | #endif |
---|
626 | |
---|
627 | /* trim left */ |
---|
628 | skip = 0; |
---|
629 | for (;;) { |
---|
630 | mask = 0; |
---|
631 | for (p = bitmap + skip / 8; p < bitmap_end; p += bytes_wide) |
---|
632 | mask |= *p; |
---|
633 | if (mask & (0x80 >> (skip % 8))) break; |
---|
634 | ++skip; |
---|
635 | } |
---|
636 | width -= skip; |
---|
637 | hoff -= skip; |
---|
638 | #ifdef DEBUG |
---|
639 | if (skip < 2 || skip > 3) |
---|
640 | printf("Character has %d empty columns at left\n", skip); |
---|
641 | #endif |
---|
642 | bitmap += skip / 8; |
---|
643 | skip = skip % 8; |
---|
644 | } |
---|
645 | |
---|
646 | /* |
---|
647 | * Pack the bitmap using the rll method. (Return false if it's better |
---|
648 | * to just pack the bits.) |
---|
649 | */ |
---|
650 | |
---|
651 | static Boolean |
---|
652 | pk_rll_cvt(void) |
---|
653 | { |
---|
654 | static int *counts = NULL; /* area for saving bit counts */ |
---|
655 | static int maxcounts = 0; /* size of this area */ |
---|
656 | unsigned int ncounts; /* max to allow this time */ |
---|
657 | int *nextcount; /* next count value */ |
---|
658 | int *counts_end; /* pointer to end */ |
---|
659 | byte *rowptr; |
---|
660 | byte *p; |
---|
661 | byte mask; |
---|
662 | byte *rowdup; /* last row checked for dup */ |
---|
663 | byte paint_switch; /* 0 or 0xff */ |
---|
664 | int bits_left; /* bits left in row */ |
---|
665 | int cost; |
---|
666 | int i; |
---|
667 | |
---|
668 | /* |
---|
669 | * Allocate space for bit counts. |
---|
670 | */ |
---|
671 | |
---|
672 | ncounts = (width * height + 3) / 4; |
---|
673 | if (ncounts > maxcounts) { |
---|
674 | if (counts != NULL) free(counts); |
---|
675 | counts = (int *) xmalloc((ncounts + 2) * sizeof(int), |
---|
676 | "array for bit counts"); |
---|
677 | maxcounts = ncounts; |
---|
678 | } |
---|
679 | counts_end = counts + ncounts; |
---|
680 | |
---|
681 | /* |
---|
682 | * Form bit counts and collect statistics |
---|
683 | */ |
---|
684 | base = 0; |
---|
685 | bzero(deltas, sizeof(deltas)); |
---|
686 | rowdup = NULL; /* last row checked for duplicates */ |
---|
687 | p = rowptr = bitmap; |
---|
688 | mask = 0x80 >> skip; |
---|
689 | flag = 0; |
---|
690 | paint_switch = 0; |
---|
691 | if (*p & mask) { |
---|
692 | flag = 8; |
---|
693 | paint_switch = 0xff; |
---|
694 | } |
---|
695 | bits_left = width; |
---|
696 | nextcount = counts; |
---|
697 | while (rowptr < bitmap_end) { /* loop over shift counts */ |
---|
698 | int shift_count = bits_left; |
---|
699 | |
---|
700 | for (;;) { |
---|
701 | if (bits_left == 0) { |
---|
702 | if ((p = rowptr += bytes_wide) >= bitmap_end) break; |
---|
703 | mask = 0x80 >> skip; |
---|
704 | bits_left = width; |
---|
705 | shift_count += width; |
---|
706 | } |
---|
707 | if (((*p ^ paint_switch) & mask) != 0) break; |
---|
708 | --bits_left; |
---|
709 | mask >>= 1; |
---|
710 | if (mask == 0) { |
---|
711 | ++p; |
---|
712 | while (*p == paint_switch && bits_left >= 8) { |
---|
713 | ++p; |
---|
714 | bits_left -= 8; |
---|
715 | } |
---|
716 | mask = 0x80; |
---|
717 | } |
---|
718 | } |
---|
719 | if (nextcount >= counts_end) return False; |
---|
720 | shift_count -= bits_left; |
---|
721 | *nextcount++ = shift_count; |
---|
722 | tallyup(shift_count); |
---|
723 | /* check for duplicate rows */ |
---|
724 | if (rowptr != rowdup && bits_left != width) { |
---|
725 | byte *p1 = rowptr; |
---|
726 | byte *q = rowptr + bytes_wide; |
---|
727 | int repeat_count; |
---|
728 | |
---|
729 | while (q < bitmap_end && *p1 == *q) ++p1, ++q; |
---|
730 | repeat_count = (p1 - rowptr) / bytes_wide; |
---|
731 | if (repeat_count > 0) { |
---|
732 | *nextcount++ = -repeat_count; |
---|
733 | if (repeat_count == 1) --base; |
---|
734 | else { |
---|
735 | ++base; |
---|
736 | tallyup(repeat_count); |
---|
737 | } |
---|
738 | rowptr += repeat_count * bytes_wide; |
---|
739 | } |
---|
740 | rowdup = rowptr; |
---|
741 | } |
---|
742 | paint_switch = ~paint_switch; |
---|
743 | } |
---|
744 | |
---|
745 | #ifdef DEBUG |
---|
746 | /* |
---|
747 | * Dump the bitmap |
---|
748 | */ |
---|
749 | |
---|
750 | for (p = bitmap; p < bitmap_end; p += bytes_wide) { |
---|
751 | byte *p1 = p; |
---|
752 | int j; |
---|
753 | |
---|
754 | mask = 0x80 >> skip; |
---|
755 | for (j = 0; j < width; ++j) { |
---|
756 | putchar(*p1 & mask ? '@' : '.'); |
---|
757 | if ((mask >>= 1) == 0) mask = 0x80, ++p1; |
---|
758 | } |
---|
759 | putchar('\n'); |
---|
760 | } |
---|
761 | putchar('\n'); |
---|
762 | #endif |
---|
763 | |
---|
764 | /* |
---|
765 | * Determine the best pk_dyn_f |
---|
766 | */ |
---|
767 | |
---|
768 | pk_dyn_f = 0; |
---|
769 | cost = base += 2 * (nextcount - counts); |
---|
770 | for (i = 1; i < 14; ++i) { |
---|
771 | base += deltas[i - 1]; |
---|
772 | if (base < cost) { |
---|
773 | pk_dyn_f = i; |
---|
774 | cost = base; |
---|
775 | } |
---|
776 | } |
---|
777 | /* last chance to bail out */ |
---|
778 | if (cost * 4 > width * height) return False; |
---|
779 | |
---|
780 | /* |
---|
781 | * Pack the bit counts |
---|
782 | */ |
---|
783 | |
---|
784 | pk_dyn_g = 208 - 15 * pk_dyn_f; |
---|
785 | flag |= pk_dyn_f << 4; |
---|
786 | bitmap_end = bitmap; |
---|
787 | *nextcount = 0; |
---|
788 | nextcount = counts; |
---|
789 | while (*nextcount != 0) { |
---|
790 | if (*nextcount > 0) pk_put_count(*nextcount); |
---|
791 | else |
---|
792 | if (*nextcount == -1) pk_put_nyb(15); |
---|
793 | else { |
---|
794 | pk_put_nyb(14); |
---|
795 | pk_put_count(-*nextcount); |
---|
796 | } |
---|
797 | ++nextcount; |
---|
798 | } |
---|
799 | if (odd) { |
---|
800 | pk_put_nyb(0); |
---|
801 | ++cost; |
---|
802 | } |
---|
803 | if (cost != 2 * (bitmap_end - bitmap)) |
---|
804 | printf("Cost miscalculation: expected %d, got %d\n", cost, |
---|
805 | 2 * (bitmap_end - bitmap)); |
---|
806 | pk_len = bitmap_end - bitmap; |
---|
807 | return True; |
---|
808 | } |
---|
809 | |
---|
810 | static void |
---|
811 | pk_bm_cvt(void) |
---|
812 | { |
---|
813 | byte *rowptr; |
---|
814 | byte *p; |
---|
815 | int blib1; /* bits left in byte */ |
---|
816 | int bits_left; /* bits left in row */ |
---|
817 | byte *q; |
---|
818 | int blib2; |
---|
819 | byte nextbyte; |
---|
820 | |
---|
821 | flag = 14 << 4; |
---|
822 | q = bitmap; |
---|
823 | blib2 = 8; |
---|
824 | nextbyte = 0; |
---|
825 | for (rowptr = bitmap; rowptr < bitmap_end; rowptr += bytes_wide) { |
---|
826 | p = rowptr; |
---|
827 | blib1 = 8 - skip; |
---|
828 | bits_left = width; |
---|
829 | if (blib2 != 8) { |
---|
830 | int n; |
---|
831 | |
---|
832 | if (blib1 < blib2) { |
---|
833 | nextbyte |= *p << (blib2 - blib1); |
---|
834 | n = blib1; |
---|
835 | } |
---|
836 | else { |
---|
837 | nextbyte |= *p >> (blib1 - blib2); |
---|
838 | n = blib2; |
---|
839 | } |
---|
840 | blib2 -= n; |
---|
841 | if ((bits_left -= n) < 0) { |
---|
842 | blib2 -= bits_left; |
---|
843 | continue; |
---|
844 | } |
---|
845 | if ((blib1 -= n) == 0) { |
---|
846 | blib1 = 8; |
---|
847 | ++p; |
---|
848 | if (blib2 > 0) { |
---|
849 | nextbyte |= *p >> (8 - blib2); |
---|
850 | blib1 -= blib2; |
---|
851 | bits_left -= blib2; |
---|
852 | if (bits_left < 0) { |
---|
853 | blib2 = -bits_left; |
---|
854 | continue; |
---|
855 | } |
---|
856 | } |
---|
857 | } |
---|
858 | *q++ = nextbyte; |
---|
859 | } |
---|
860 | /* fill up whole (destination) bytes */ |
---|
861 | while (bits_left >= 8) { |
---|
862 | nextbyte = *p++ << (8 - blib1); |
---|
863 | *q++ = nextbyte | (*p >> blib1); |
---|
864 | bits_left -= 8; |
---|
865 | } |
---|
866 | /* now do the remainder */ |
---|
867 | nextbyte = *p << (8 - blib1); |
---|
868 | if (bits_left > blib1) nextbyte |= p[1] >> blib1; |
---|
869 | blib2 = 8 - bits_left; |
---|
870 | } |
---|
871 | if (blib2 != 8) *q++ = nextbyte; |
---|
872 | pk_len = q - bitmap; |
---|
873 | } |
---|
874 | |
---|
875 | static void |
---|
876 | putshort(short w) |
---|
877 | { |
---|
878 | putc(w >> 8, pk_file); |
---|
879 | putc(w, pk_file); |
---|
880 | } |
---|
881 | |
---|
882 | static void |
---|
883 | putmed(long w) |
---|
884 | { |
---|
885 | putc(w >> 16, pk_file); |
---|
886 | putc(w >> 8, pk_file); |
---|
887 | putc(w, pk_file); |
---|
888 | } |
---|
889 | |
---|
890 | static void |
---|
891 | putlong(long w) |
---|
892 | { |
---|
893 | putc(w >> 24, pk_file); |
---|
894 | putc(w >> 16, pk_file); |
---|
895 | putc(w >> 8, pk_file); |
---|
896 | putc(w, pk_file); |
---|
897 | } |
---|
898 | |
---|
899 | static void |
---|
900 | putglyph(int cc) |
---|
901 | { |
---|
902 | static Boolean have_first_line = False; |
---|
903 | static int llx, lly, urx, ury; |
---|
904 | static float char_width; |
---|
905 | static byte *area1 = NULL; |
---|
906 | static unsigned int size1 = 0; |
---|
907 | static int i; |
---|
908 | long dm; |
---|
909 | long tfm_wid; |
---|
910 | byte *p; |
---|
911 | |
---|
912 | if (!quiet) { |
---|
913 | int wid; |
---|
914 | static char *s = ""; |
---|
915 | |
---|
916 | wid = (cc >= 100) + (cc >= 10) + 4; |
---|
917 | if (col + wid > 80) { |
---|
918 | s = "\n"; |
---|
919 | col = 0; |
---|
920 | } |
---|
921 | printf("%s[%d", s, cc); |
---|
922 | fflush(stdout); |
---|
923 | col += wid; |
---|
924 | s = " "; |
---|
925 | } |
---|
926 | if (!have_first_line) { |
---|
927 | expect("#^"); |
---|
928 | if (sscanf(line, "#^ %d %d %d %d %d %f\n", &i, |
---|
929 | &llx, &lly, &urx, &ury, &char_width) != 6) |
---|
930 | oops("Cannot scanf first line"); |
---|
931 | } |
---|
932 | if (i < cc) oops("Character %d received, %d expected", i, cc); |
---|
933 | if (i > cc) { |
---|
934 | fprintf(stderr, "Character %d is missing.\n", cc); |
---|
935 | have_first_line = True; |
---|
936 | return; |
---|
937 | } |
---|
938 | have_first_line = False; |
---|
939 | hoff = -llx + 2; |
---|
940 | voff = ury + 2 - 1; |
---|
941 | expect("P4\n"); |
---|
942 | whitespace(); |
---|
943 | width = getint(); |
---|
944 | whitespace(); |
---|
945 | height = getint(); |
---|
946 | (void) getc(data_file); |
---|
947 | if (width != urx - llx + 4 || height != ury - lly + 4) |
---|
948 | oops("Dimensions do not match: %d %d %d %d %d %d", |
---|
949 | llx, lly, urx, ury, width, height); |
---|
950 | bytes_wide = (width + 7) / 8; |
---|
951 | bm_size = bytes_wide * height; |
---|
952 | if (size1 < bm_size) { |
---|
953 | if (area1 != NULL) free(area1); |
---|
954 | area1 = (byte *) xmalloc(bm_size, "original bitmap"); |
---|
955 | size1 = bm_size; |
---|
956 | } |
---|
957 | for (p = area1 + (height - 1) * bytes_wide; p >= area1; p -= bytes_wide) |
---|
958 | if (fread(p, 1, bytes_wide, data_file) != bytes_wide) |
---|
959 | oops("Cannot read bitmap of size %u", bm_size); |
---|
960 | bitmap = area1; |
---|
961 | bitmap_end = bitmap + bm_size; |
---|
962 | trim_bitmap(); |
---|
963 | if (height == 0 || !pk_rll_cvt()) pk_bm_cvt(); |
---|
964 | tfm_wid = tfm_widths[width_index[cc]]; |
---|
965 | dm = (long) (char_width + 0.5) - (char_width < -0.5); |
---|
966 | if (pk_len + 8 < 4 * 256 && tfm_wid < (1<<24) && |
---|
967 | dm >= 0 && dm < 256 && width < 256 && height < 256 && |
---|
968 | hoff >= -128 && hoff < 128 && voff >= -128 && voff < 128) { |
---|
969 | putc(flag | ((pk_len + 8) >> 8), pk_file); |
---|
970 | putc(pk_len + 8, pk_file); |
---|
971 | putc(cc, pk_file); |
---|
972 | putmed(tfm_wid); |
---|
973 | putc(dm, pk_file); |
---|
974 | putc(width, pk_file); |
---|
975 | putc(height, pk_file); |
---|
976 | putc(hoff, pk_file); |
---|
977 | putc(voff, pk_file); |
---|
978 | } else |
---|
979 | if (pk_len + 13 < 3 * 65536L && tfm_wid < (1<<24) && |
---|
980 | dm >= 0 && dm < 65536L && width < 65536L && height < 65536L && |
---|
981 | hoff >= -65536L && hoff < 65536L && |
---|
982 | voff >= -65536L && voff < 65536L) { |
---|
983 | putc(flag | 4 | ((pk_len + 13) >> 16), pk_file); |
---|
984 | putshort(pk_len + 13); |
---|
985 | putc(cc, pk_file); |
---|
986 | putmed(tfm_wid); |
---|
987 | putshort(dm); |
---|
988 | putshort(width); |
---|
989 | putshort(height); |
---|
990 | putshort(hoff); |
---|
991 | putshort(voff); |
---|
992 | } |
---|
993 | else { |
---|
994 | putc(flag | 7, pk_file); |
---|
995 | putlong(pk_len + 28); |
---|
996 | putlong(cc); |
---|
997 | putlong(tfm_wid); |
---|
998 | putlong((long) (char_width * 65536.0 + 0.5) - (char_width < -0.5)); |
---|
999 | putlong(0); |
---|
1000 | putlong(width); |
---|
1001 | putlong(height); |
---|
1002 | putlong(hoff); |
---|
1003 | putlong(voff); |
---|
1004 | } |
---|
1005 | fwrite(bitmap, 1, pk_len, pk_file); |
---|
1006 | if (!quiet) { |
---|
1007 | putchar(']'); |
---|
1008 | fflush(stdout); |
---|
1009 | } |
---|
1010 | } |
---|
1011 | |
---|
1012 | static void |
---|
1013 | putspecl(const char *str1, const char *str2) |
---|
1014 | { |
---|
1015 | int len1 = strlen(str1); |
---|
1016 | int len2 = 0; |
---|
1017 | |
---|
1018 | if (str2 != NULL) len2 = strlen(str2); |
---|
1019 | if (len1 + len2 > 255) return; |
---|
1020 | putc(PK_SPC, pk_file); |
---|
1021 | putc(len1 + len2, pk_file); |
---|
1022 | fwrite(str1, 1, len1, pk_file); |
---|
1023 | if (len2 != 0) fwrite(str2, 1, len2, pk_file); |
---|
1024 | } |
---|
1025 | |
---|
1026 | int |
---|
1027 | main(int argc, char **argv) |
---|
1028 | { |
---|
1029 | FILE *config_file; |
---|
1030 | FILE *tfm_file; |
---|
1031 | float dpi; |
---|
1032 | char *fontname; |
---|
1033 | int fontlen; |
---|
1034 | char *configline; |
---|
1035 | unsigned int cflinelen; |
---|
1036 | char *p; |
---|
1037 | char *PSname = NULL; |
---|
1038 | char *specinfo = ""; |
---|
1039 | char *xfilename; |
---|
1040 | char charlist[10*2 + 90*3 + 156*4 + 1]; |
---|
1041 | char designstr[20]; |
---|
1042 | char dpistr[20]; |
---|
1043 | int pid; |
---|
1044 | int std_in[2]; |
---|
1045 | int std_out[2]; |
---|
1046 | int status; |
---|
1047 | int cc; |
---|
1048 | int ppp; |
---|
1049 | int i; |
---|
1050 | |
---|
1051 | if (argc > 1 && strcmp(argv[1], "-q") == 0) { |
---|
1052 | ++argv; |
---|
1053 | --argc; |
---|
1054 | quiet = True; |
---|
1055 | } |
---|
1056 | |
---|
1057 | if (argc != 3 || (dpi = atof(argv[2])) <= 0.0) { |
---|
1058 | fputs("Usage: gsftopk [-q] <font> <dpi>\n", stderr); |
---|
1059 | exit(1); |
---|
1060 | } |
---|
1061 | |
---|
1062 | #ifdef KPATHSEA |
---|
1063 | kpse_set_progname(argv[0]); |
---|
1064 | kpse_init_prog(uppercasify(argv[0]), 300, "cx", false, "cmr10"); |
---|
1065 | xputenv_int("KPATHSEA_DPI", 300); |
---|
1066 | #endif |
---|
1067 | |
---|
1068 | fontname = argv[1]; |
---|
1069 | fontlen = strlen(fontname); |
---|
1070 | |
---|
1071 | if (!quiet) puts(ident); |
---|
1072 | |
---|
1073 | #ifdef KPATHSEA |
---|
1074 | config_file = fopen(kpse_find_file("psfonts.map", |
---|
1075 | kpse_dvips_config_format, false), "r"); |
---|
1076 | #else |
---|
1077 | config_file = search(CONFIGPATH, "TEXCONFIG", "psfonts.map"); |
---|
1078 | #endif |
---|
1079 | if (config_file == NULL) oops("Cannot find file psfonts.map."); |
---|
1080 | |
---|
1081 | configline = (char *) xmalloc(cflinelen = 80, "Config file line"); |
---|
1082 | do { |
---|
1083 | int len = 0; |
---|
1084 | |
---|
1085 | if (fgets(configline, cflinelen, config_file) == NULL) |
---|
1086 | oops("Cannot find font %s in config file.", fontname); |
---|
1087 | for (;;) { |
---|
1088 | i = strlen(configline + len); |
---|
1089 | |
---|
1090 | len += i; |
---|
1091 | if (len > 0 && configline[len - 1] == '\n') { |
---|
1092 | configline[--len] = '\0'; |
---|
1093 | break; |
---|
1094 | } |
---|
1095 | if (len < cflinelen - 1) break; |
---|
1096 | configline = xrealloc(configline, cflinelen += 80, |
---|
1097 | "config file line"); |
---|
1098 | fgets(configline + len, cflinelen - len, config_file); |
---|
1099 | } |
---|
1100 | } |
---|
1101 | while (memcmp(configline, fontname, fontlen) != 0 |
---|
1102 | || (configline[fontlen] != '\0' && !isspace(configline[fontlen]))); |
---|
1103 | fclose(config_file); |
---|
1104 | |
---|
1105 | /* |
---|
1106 | * Parse the line from the config file. |
---|
1107 | */ |
---|
1108 | for (p = configline + fontlen; *p != '\0'; ++p) { |
---|
1109 | if (isspace(*p)) continue; |
---|
1110 | if (*p == '<') { |
---|
1111 | char *q = ++p; |
---|
1112 | char endc; |
---|
1113 | FILE *f; |
---|
1114 | |
---|
1115 | addtodls(" ("); |
---|
1116 | while (*p != '\0' && !isspace(*p)) ++p; |
---|
1117 | endc = *p; |
---|
1118 | *p = '\0'; |
---|
1119 | #ifdef KPATHSEA |
---|
1120 | f = fopen(kstrcpy(searchpath, kpse_find_file(q, |
---|
1121 | kpse_dvips_header_format, true)), "r"); |
---|
1122 | #else |
---|
1123 | f = search(HEADERPATH, "DVIPSHEADERS", q); |
---|
1124 | #endif |
---|
1125 | if (f == NULL) oops("Cannot find font file %s", q); |
---|
1126 | /* search() also sets searchpath */ |
---|
1127 | addtodls(searchpath); |
---|
1128 | addtodls((char) getc(f) == '\200' ? ") brun" : ") run"); |
---|
1129 | fclose(f); |
---|
1130 | if (endc == '\0') break; |
---|
1131 | continue; |
---|
1132 | } |
---|
1133 | else if (*p == '"') { |
---|
1134 | char *q; |
---|
1135 | |
---|
1136 | specinfo = ++p; |
---|
1137 | q = strchr(p, '"'); |
---|
1138 | if (q == NULL) break; |
---|
1139 | p = q; |
---|
1140 | } |
---|
1141 | else { |
---|
1142 | PSname = p; |
---|
1143 | while (*p != '\0' && !isspace(*p)) ++p; |
---|
1144 | if (*p == '\0') break; |
---|
1145 | } |
---|
1146 | *p = '\0'; |
---|
1147 | } |
---|
1148 | |
---|
1149 | #ifdef OLD_DVIPS |
---|
1150 | /* Parse lines like `Symbol-Slanted "/Symbol .167 SlantFont"'. */ |
---|
1151 | if (*(p = specinfo) == '/') { |
---|
1152 | PSname = ++p; |
---|
1153 | while (*p && !isspace(*p)) ++p; |
---|
1154 | if (*p) *p++ = '\0'; |
---|
1155 | specinfo = p; |
---|
1156 | } |
---|
1157 | #endif /* OLD_DVIPS */ |
---|
1158 | |
---|
1159 | /* |
---|
1160 | * Start up GhostScript. |
---|
1161 | */ |
---|
1162 | |
---|
1163 | #ifdef KPATHSEA |
---|
1164 | tfm_file = fopen(kstrcpy(searchpath, kpse_find_file("render.ps", |
---|
1165 | kpse_dvips_header_format, true)), "r"); |
---|
1166 | #else |
---|
1167 | tfm_file = search(HEADERPATH, "DVIPSHEADERS", "render.ps"); |
---|
1168 | #endif |
---|
1169 | if (tfm_file == NULL) |
---|
1170 | oops("Cannot find PS driver file \"render.ps\"."); |
---|
1171 | fclose(tfm_file); |
---|
1172 | |
---|
1173 | sprintf(dpistr, "%f", dpi); |
---|
1174 | |
---|
1175 | if (pipe(std_in) != 0 || pipe(std_out) != 0) { |
---|
1176 | perror("pipe"); |
---|
1177 | return 1; |
---|
1178 | } |
---|
1179 | |
---|
1180 | fflush(stderr); /* to avoid double flushing */ |
---|
1181 | pid = vfork(); |
---|
1182 | if (pid == 0) { |
---|
1183 | close(std_in[1]); |
---|
1184 | dup2(std_in[0], 0); |
---|
1185 | close(std_in[0]); |
---|
1186 | close(std_out[0]); |
---|
1187 | dup2(std_out[1], 1); |
---|
1188 | close(std_out[1]); |
---|
1189 | execlp(GS, "gs", "-dNODISPLAY", "-dNOGC", "-q", "--", |
---|
1190 | /* render.ps */ searchpath, |
---|
1191 | PSname != NULL ? PSname : fontname, |
---|
1192 | dlstring != NULL ? dlstring : "", specinfo, dpistr, NULL); |
---|
1193 | perror("gs"); |
---|
1194 | exit(1); |
---|
1195 | } |
---|
1196 | if (pid == -1) { |
---|
1197 | perror("fork"); |
---|
1198 | exit(1); |
---|
1199 | } |
---|
1200 | |
---|
1201 | /* |
---|
1202 | * Open and read the tfm file. If this takes a while, at least |
---|
1203 | * it can overlap with the startup of GhostScript. |
---|
1204 | */ |
---|
1205 | |
---|
1206 | xfilename = xmalloc(fontlen + 10, "name of tfm/pk file"); |
---|
1207 | strcpy(xfilename, fontname); |
---|
1208 | #ifdef KPATHSEA |
---|
1209 | tfm_file = fopen(kpse_find_file(xfilename, kpse_tfm_format, true), "r"); |
---|
1210 | #else |
---|
1211 | strcpy(xfilename + fontlen, ".tfm"); |
---|
1212 | tfm_file = search(TEXFONTS_DEFAULT, "TEXFONTS", xfilename); |
---|
1213 | #endif |
---|
1214 | if (tfm_file == NULL) oops("Cannot find tfm file."); |
---|
1215 | for (i = 0; i < 12; ++i) { |
---|
1216 | int j; |
---|
1217 | |
---|
1218 | j = (int) ((byte) getc(tfm_file)) << 8; |
---|
1219 | tfm_lengths[i] = j | (int) ((byte) getc(tfm_file)); |
---|
1220 | } |
---|
1221 | checksum = getlong(tfm_file); |
---|
1222 | design = getlong(tfm_file); |
---|
1223 | fseek(tfm_file, 4 * (lh + 6), 0); |
---|
1224 | p = charlist; |
---|
1225 | for (cc = bc; cc <= ec; ++cc) { |
---|
1226 | width_index[cc] = (byte) getc(tfm_file); |
---|
1227 | if (width_index[cc] != 0) { |
---|
1228 | sprintf(p, "%d ", cc); |
---|
1229 | p += strlen(p); |
---|
1230 | } |
---|
1231 | (void) getc(tfm_file); |
---|
1232 | (void) getc(tfm_file); |
---|
1233 | (void) getc(tfm_file); |
---|
1234 | } |
---|
1235 | for (i = 0; i < nw; ++i) tfm_widths[i] = getlong(tfm_file); |
---|
1236 | fclose(tfm_file); |
---|
1237 | p[-1] = '\n'; |
---|
1238 | |
---|
1239 | /* write the design size and character list to the file */ |
---|
1240 | sprintf(designstr, "%f\n", (float) design / (1 << 20)); |
---|
1241 | write(std_in[1], designstr, strlen(designstr)); |
---|
1242 | write(std_in[1], charlist, p - charlist); |
---|
1243 | close(std_in[1]); |
---|
1244 | |
---|
1245 | /* |
---|
1246 | * Read the output from GhostScript. |
---|
1247 | */ |
---|
1248 | |
---|
1249 | if ((data_file = fdopen(std_out[0], "r")) == NULL) { |
---|
1250 | perror("GS_out"); |
---|
1251 | exit(1); |
---|
1252 | } |
---|
1253 | |
---|
1254 | /* |
---|
1255 | * Create pk file and write preamble. |
---|
1256 | */ |
---|
1257 | |
---|
1258 | fflush(stdout); |
---|
1259 | sprintf(xfilename + fontlen, ".%dpk", (int) (dpi + 0.5)); |
---|
1260 | if ((pk_file = fopen(xfilename, "w")) == NULL) { |
---|
1261 | perror(xfilename); |
---|
1262 | exit(1); |
---|
1263 | } |
---|
1264 | putc(PK_PRE, pk_file); |
---|
1265 | putc(PK_ID, pk_file); |
---|
1266 | i = strlen(ident); |
---|
1267 | putc(i, pk_file); |
---|
1268 | fwrite(ident, 1, i, pk_file); |
---|
1269 | putlong(design); |
---|
1270 | putlong(checksum); |
---|
1271 | ppp = dpi / 72.27 * 65536.0 + 0.5; |
---|
1272 | putlong(ppp); /* hppp */ |
---|
1273 | putlong(ppp); /* vppp */ |
---|
1274 | |
---|
1275 | /* |
---|
1276 | * Write the actual characters. |
---|
1277 | */ |
---|
1278 | |
---|
1279 | for (cc = bc; cc <= ec; ++cc) |
---|
1280 | if (width_index[cc] != 0) |
---|
1281 | putglyph(cc); |
---|
1282 | fclose(data_file); |
---|
1283 | |
---|
1284 | if (wait(&status) == -1) { |
---|
1285 | perror("wait"); |
---|
1286 | exit(1); |
---|
1287 | } |
---|
1288 | if (status != 0) |
---|
1289 | if (status & 0377) |
---|
1290 | oops("Call to gs stopped by signal %d", status & 0177); |
---|
1291 | else oops("Call to gs returned nonzero status %d", status >> 8); |
---|
1292 | |
---|
1293 | /* |
---|
1294 | * Write out identifying specials: |
---|
1295 | * jobname=(font) |
---|
1296 | * mag=1 |
---|
1297 | * mode=(gsftopk)Unknown |
---|
1298 | * pixels_per_inch=(dpi) |
---|
1299 | */ |
---|
1300 | |
---|
1301 | putspecl("jobname=", fontname); |
---|
1302 | putspecl("mag=1", NULL); |
---|
1303 | putspecl("mode=(gsftopk)Unknown", NULL); |
---|
1304 | sprintf(dpistr, "%d", (int) dpi); |
---|
1305 | putspecl("pixels_per_inch=", dpistr); |
---|
1306 | |
---|
1307 | /* |
---|
1308 | * Postamble |
---|
1309 | */ |
---|
1310 | |
---|
1311 | putc(PK_POST, pk_file); |
---|
1312 | while (ftell(pk_file) % 4 != 0) putc(PK_NOP, pk_file); |
---|
1313 | fclose(pk_file); |
---|
1314 | if (!quiet) putchar('\n'); |
---|
1315 | return 0; |
---|
1316 | } |
---|