1 /*========================================================================*\
2
3 Copyright (c) 1993-2000 Paul Vojta
4
5 Permission is hereby granted, free of charge, to any person obtaining a copy
6 of this software and associated documentation files (the "Software"), to
7 deal in the Software without restriction, including without limitation the
8 rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 sell copies of the Software, and to permit persons to whom the Software is
10 furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 PAUL VOJTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 \*========================================================================*/
23
24 #if !lint
25 static char copyright[] =
26 "@(#) Copyright (c) 1993-1998 Paul Vojta.\n";
27 #endif
28
29 /*
30 * Reference for PK file format:
31 *
32 * Tomas Rokicki, Packed (PK) font file format, TUGBoat 6 (1985) 115-120.
33 */
34
35 /*
36 * Kpathsea version by Thomas Esser, John Interrante, Yves Arrouye, Karl Berry.
37 */
38
39 #include "version.h"
40
41 #ifndef KPATHSEA
42
43 #include "config.h"
44
45 /* Some O/S dependent kludges. */
46 #if _AIX
47 #define _ALL_SOURCE 1
48 #endif
49
50 #if __hpux
51 #define _HPUX_SOURCE 1
52 #endif
53
54 #if STDC_HEADERS
55 # include <stdlib.h>
56 # include <string.h>
57 #else
58 # if !HAVE_STRCHR
59 # define strchr index
60 # define strrchr rindex
61 # endif
62 char *strchr(), *strrchr();
63 # if !HAVE_MEMCPY
64 # define memcpy(d, s, n) bcopy((s), (d), (n))
65 # define memmove(d, s, n) bcopy((s), (d), (n))
66 # define memcmp(s1, s2, n) bcmp((s1), (s2), (n))
67 # endif
68 #endif
69
70 #if HAVE_UNISTD_H
71 #include <unistd.h>
72 #endif
73
74 #include <stdio.h>
75 #include <ctype.h>
76 #include <memory.h>
77 #include <sys/types.h>
78 #include <sys/stat.h>
79 #include <setjmp.h>
80 #include <signal.h>
81 #include <fcntl.h>
82
83 #include <errno.h>
84 #ifndef errno
85 extern int errno;
86 #endif
87
88 #if HAVE_DIRENT_H
89 # include <dirent.h>
90 # define NAMLEN(dirent) strlen((dirent)->d_name)
91 #else
92 # define dirent direct
93 # define NAMLEN(dirent) (dirent)->d_namlen
94 # if HAVE_SYS_NDIR_H
95 # include <sys/ndir.h>
96 # endif
97 # if HAVE_SYS_DIR_H
98 # include <sys/dir.h>
99 # endif
100 # if HAVE_NDIR_H
101 # include <ndir.h>
102 # endif
103 #endif
104
105 #if TIME_WITH_SYS_TIME
106 # include <sys/time.h>
107 # include <time.h>
108 #else
109 # if HAVE_SYS_TIME_H
110 # include <sys/time.h>
111 # else
112 # include <time.h>
113 # endif
114 #endif
115
116 #ifndef atof
117 double atof();
118 #endif
119 char *getenv();
120
121 /* <sys/types.h> is already included. */
122 #if HAVE_SYS_WAIT_H
123 #include <sys/wait.h>
124 #endif
125
126 #ifndef WIFSTOPPED
127 #define WIFSTOPPED(stat_val) (((stat_val) & 0377) == 0177)
128 #endif
129
130 #ifndef WIFSIGNALED
131 #define WIFSIGNALED(stat_val) (((stat_val) & 0377) != 0)
132 #endif
133
134 #ifndef WTERMSIG
135 #define WTERMSIG(stat_val) ((stat_val) & 0177)
136 #endif
137
138 #ifndef WEXITSTATUS
139 #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
140 #endif
141
142 #ifndef SIGCHLD
143 #define SIGCHLD SIGCLD
144 #endif
145
146 /* How to open a text file for reading: */
147 #ifndef FOPEN_R_MODE
148 #define FOPEN_R_MODE "r"
149 #endif
150
151 /* How to open a binary file for reading: */
152 #ifndef FOPEN_RBIN_MODE
153 #if DOS
154 #define FOPEN_RBIN_MODE "r+b"
155 #elif VMS || VMCMS || OS2 || WIN32
156 #define FOPEN_RBIN_MODE "rb"
157 #else
158 #define FOPEN_RBIN_MODE "r"
159 #endif
160 #endif /* undef FOPEN_RBIN_MODE */
161
162 /* How to open a binary file for writing: */
163 #ifndef FOPEN_WBIN_MODE
164 #if DOS
165 #define FOPEN_WBIN_MODE "w+b"
166 #elif OS2 || WIN32
167 #define FOPEN_WBIN_MODE "wb"
168 #elif VMCMS
169 #define FOPEN_WBIN_MODE "wb, lrecl=1024, recfm=f"
170 #else
171 #define FOPEN_WBIN_MODE "w"
172 #endif
173 #endif /* undef FOPEN_WBIN_MODE */
174
175 #else /* KPATHSEA */
176
177 #include <kpathsea/config.h>
178 #include <kpathsea/c-errno.h>
179 #include <kpathsea/c-ctype.h>
180 #include <kpathsea/c-fopen.h>
181 #include <kpathsea/c-pathmx.h>
182 #include <kpathsea/proginit.h>
183 #include <kpathsea/tex-file.h>
184 #include <kpathsea/tex-make.h>
185 #include <kpathsea/variable.h>
186 #include <kpathsea/version.h>
187 #include <c-auto.h>
188 #include <signal.h>
189 #include <fcntl.h>
190 #include <setjmp.h>
191
192 #if TIME_WITH_SYS_TIME
193 # include <sys/time.h>
194 # include <time.h>
195 #else
196 # if HAVE_SYS_TIME_H
197 # include <sys/time.h>
198 # else
199 # include <time.h>
200 # endif
201 #endif
202
203 #if !HAVE_STRCHR
204 #define strchr index
205 #endif
206
207 #if !HAVE_STRRCHR
208 #define strrchr rindex
209 #endif
210
211 #if HAVE_POLL && !HAVE_POLL_H
212 #undef HAVE_POLL
213 #endif
214
215 /* Add two new flags to kpathsea_debug for debugging gsftopk */
216 #define GSPK_DEBUG_BITMAP (KPSE_LAST_DEBUG + 1)
217 #define GSPK_DEBUG_PK (KPSE_LAST_DEBUG + 2)
218
219 /* <sys/types.h> is already included: <kpathsea/config.h>
220 --> <kpathsea/c-std.h> --> <kpathsea/c-unistd.h>
221 --> <kpathsea/systypes.h> --> <sys/types.h>. */
222 #if HAVE_SYS_WAIT_H
223 # include <sys/wait.h>
224 #endif
225
226 #if WIN32
227
228 /* code from Akira Kakuto */
229
230 /* message values for callback */
231 #define GSDLL_STDIN 1
232 #define GSDLL_STDOUT 2
233 #define GSDLL_DEVICE 3
234 #define GSDLL_SYNC 4
235 #define GSDLL_PAGE 5
236 #define GSDLL_SIZE 6
237 #define GSDLL_POLL 7
238 /* return values from gsdll_init() */
239 #define GSDLL_INIT_IN_USE 100
240 #define GSDLL_INIT_QUIT 101
241
242 #include <windows.h>
243
244 HINSTANCE hgsdll = NULL;
245 PROC pgsdll_init = NULL;
246 PROC pgsdll_exit = NULL;
247 PROC pgsdll_revision = NULL;
248
249 #if 0 /* unused */
250 static long revision_n = 0;
251 static char product_str[128];
252 static char copyright_str[128];
253 static long revdate_n;
254 #endif /* 0, unused */
255
Win32Error(const char * s)256 static void Win32Error(const char *s)
257 {
258 fprintf(stderr, "%s\n", s);
259 exit(EXIT_FAILURE);
260 }
261
262 #ifdef _WIN64
263 #define GSDLLNAME "gsdll64.dll"
264 #else
265 #define GSDLLNAME "gsdll32.dll"
266 #endif
267
gs_locate(void)268 static HINSTANCE gs_locate(void)
269 {
270 hgsdll = GetModuleHandle(GSDLLNAME);
271 if(hgsdll == NULL) {
272 hgsdll = LoadLibrary(GSDLLNAME);
273 }
274 return hgsdll;
275 }
276
gs_dll_release(void)277 static void gs_dll_release(void)
278 {
279 FreeLibrary(hgsdll);
280 }
281
gs_dll_initialize(void)282 static void gs_dll_initialize(void)
283 {
284 pgsdll_init = GetProcAddress(hgsdll, "gsdll_init");
285 pgsdll_exit = GetProcAddress(hgsdll, "gsdll_exit");
286 pgsdll_revision = GetProcAddress(hgsdll, "gsdll_revision");
287 if(pgsdll_init == NULL || pgsdll_exit == NULL ||
288 pgsdll_revision == NULL) {
289 fprintf(stderr, "Failed to get proc addresses in GSDLL32.\n");
290 gs_dll_release();
291 exit(100);
292 }
293 }
294
295 /* end of code from Akira Kakuto */
296
297 HANDLE hGsThread = NULL;
298 HANDLE hGsDataIn = 0, hGsDataOut = 0; /* Events to synchronize threads */
299 /* Arguments to gs dll */
300 const
301 char *gs_argv[] = { "rungs.exe", /* 0, dummy */
302 "-dNOGC", /* 1, */
303 "-dNODISPLAY", /* 2, */
304 NULL, /* 3, substarg */
305 "-q", /* 4, */
306 "--", /* 5, */
307 NULL, /* 6, searchpath */
308 NULL, /* 7, PSname */
309 NULL, /* 8, dlstring != NULL ? dlstring : "" */
310 NULL, /* 9, specinfo */
311 NULL, /* 10, dpistr */
312 NULL /* 11, NULL terminator */
313 };
314 int gs_argc = 11;
315
316 char *buffer_stdin; /* This is the buffer from where data are taken. */
317
318 #else /* not WIN32 */
319
320 #ifndef WEXITSTATUS
321 #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
322 #endif
323
324 #ifndef WIFSTOPPED
325 #define WIFSTOPPED(stat_val) (((stat_val) & 0377) == 0177)
326 #endif
327
328 #ifndef WIFSIGNALED
329 #define WIFSIGNALED(stat_val) (((stat_val) & 0377) != 0)
330 #endif
331
332 #ifndef WTERMSIG
333 #define WTERMSIG(stat_val) ((stat_val) & 0177)
334 #endif
335
336 #endif /* not WIN32 */
337
338 #endif /* KPATHSEA */
339
340 #if HAVE_POLL
341 # include <poll.h>
342 #else
343 # if HAVE_SYS_SELECT_H
344 # include <sys/select.h>
345 # else
346 # if HAVE_SELECT_H
347 # include <select.h>
348 # endif
349 # endif
350 #endif
351
352 #if HAVE_VFORK_H
353 #include <vfork.h>
354 #endif
355
356 #if _AMIGA
357 #include <proto/dos.h>
358 #include <dos/dostags.h>
359 #endif
360
361 #define NUMBER(x) (sizeof (x) / sizeof *(x))
362
363 /* if POSIX O_NONBLOCK is not available, use O_NDELAY */
364 #if !defined(O_NONBLOCK) && defined(O_NDELAY)
365 #define O_NONBLOCK O_NDELAY
366 #endif
367
368 #ifndef S_ISDIR
369 #if defined(S_IFMT) && defined(S_IFDIR)
370 #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
371 #endif
372 #endif
373
374 #ifndef GS_PATH
375 #define GS_PATH "gs"
376 #endif
377
378 #include <stdarg.h>
379
380 typedef char Boolean;
381 #define True 1
382 #define False 0
383
384 typedef int wide_bool;
385
386 #ifndef MAXPATHLEN
387 #define MAXPATHLEN 256
388 #endif
389
390 #define PK_PRE (char) 247
391 #define PK_ID (char) 89
392 #define PK_SPC (char) 240
393 #define PK_POST (char) 245
394 #define PK_NOP (char) 246
395
396 #ifndef KPATHSEA
397 char progname[] = "gsftopk ";
398 #else
399 char progname[] = "gsftopk(k) ";
400 #endif
401
402 char version[] = VERSION;
403
404 /*
405 * Command line arguments
406 */
407
408 #define OPT_DBG 0x101
409
410 Boolean test = False;
411 char *fontname;
412 int fontlen;
413 char *mapline = NULL;
414 char *mapfile = NULL;
415 char gspath[] = GS_PATH; /* gs interpreter path */
416 Boolean dosnames = False;
417 Boolean quiet = False;
418
419 struct option {
420 const char *longname;
421 short shortname;
422 Boolean has_arg;
423 void *addr;
424 int value;
425 };
426
427 static const struct option options[] = {
428 {"test", 't', False, &test, True},
429 {"mapline", 0, True, &mapline, 0},
430 {"mapfile", 0, True, &mapfile, 0},
431 {"interpreter", 'i', True, &gspath, 0},
432 {"dosnames", 0, False, &dosnames, True},
433 {"quiet", 'q', False, &quiet, True},
434 #if defined(KPATHSEA) && defined (KPSE_DEBUG)
435 {"debug", OPT_DBG,True, NULL, 0},
436 #endif
437 {"version", 'v', False, NULL, 0},
438 {"help", 'h', False, NULL, 0}};
439
440 FILE *pk_file = NULL;
441 char *xfilename;
442 int col = 0; /* current column number */
443 const char *specinfo = "";
444 pid_t gs_pid = 0;
445
446 /*
447 * Config file options
448 */
449
450 #ifndef KPATHSEA /* 'H' option */
451 const char *config_file_header_path = HEADERPATH;
452 #else
453 const char *config_file_header_path = NULL;
454 #endif
455
456 struct p_list { /* list of 'p' options */
457 struct p_list *next;
458 const char *value;
459 };
460
461 /* Initialize this list to "psfonts.map". */
462
463 struct p_list psfonts_map = {NULL, "psfonts.map"};
464
465 struct p_list *p_head = &psfonts_map;
466 struct p_list **p_tail = &psfonts_map.next;
467
468 /*
469 * Reading from the pipe from ghostscript
470 */
471
472 Boolean data_eof = False;
473
474 #if !_AMIGA
475
476 #define BUFSIZE 512
477
478 typedef unsigned char byte;
479
480 int data_fd;
481 byte buffer[BUFSIZE];
482 byte *data_out = buffer;
483 byte *data_end = buffer;
484
485 #else /* _AMIGA */
486
487 FILE *data_file;
488
489 /* This string will be used to open pipes in and out */
490 char tmpname[] = "gsftopkXXXXXX";
491
492 #endif /* _AMIGA */
493
494 /*
495 * Information from the .tfm file.
496 */
497
498 int tfm_lengths[12];
499 #define lh tfm_lengths[1]
500 #define bc tfm_lengths[2]
501 #define ec tfm_lengths[3]
502 #define nw tfm_lengths[4]
503
504 long checksum;
505 long design;
506 byte width_index[256];
507 long tfm_widths[256];
508
509 /*
510 * Information on the bitmap currently being worked on.
511 */
512
513 byte *bitmap;
514 int width;
515 int skip;
516 int height;
517 int hoff;
518 int voff;
519 int bytes_wide;
520 unsigned int bm_size;
521 byte *bitmap_end;
522 int pk_len;
523
524
525 #if !_AMIGA
526
527 /*
528 * Exit, and kill the child process, too.
529 */
530
531 static void
exit_toto_too(void)532 exit_toto_too(void)
533 {
534 #if !WIN32
535 if (gs_pid != 0)
536 kill(gs_pid, SIGKILL);
537 #else
538 if (hGsThread) {
539 switch (WaitForSingleObject(hGsThread, 2000)) {
540 case WAIT_OBJECT_0:
541 CloseHandle(hGsThread);
542 hGsThread = NULL;
543 break;
544 case WAIT_TIMEOUT:
545 fprintf(stderr, "Timeout waiting for Gs thread.\n");
546 break;
547 case WAIT_FAILED:
548 fprintf(stderr, "WaitForSingleObject failed on Gs thread (Error code %d).\n",
549 (int)GetLastError());
550 break;
551 default:
552 break;
553 }
554
555 if (hGsThread) {
556 if (TerminateThread(hGsThread, 1) == 0) {
557 fprintf(stderr, "... couldn't terminate gs thread\n");
558 }
559 CloseHandle(hGsThread);
560 /* FIXME : is it right to call this ? */
561 gs_dll_release();
562 }
563 }
564
565 if (hGsDataIn)
566 CloseHandle(hGsDataIn);
567 if (hGsDataOut)
568 CloseHandle(hGsDataOut);
569
570 #endif
571 if (pk_file != NULL) {
572 fclose(pk_file);
573 if (unlink(xfilename) != 0) perror("unlink");
574 }
575
576 _exit(1);
577 }
578
579 #else /* _AMIGA */
580
581 #define exit_toto_too() exit(1)
582
583 #endif /* _AMIGA */
584
585 /*
586 * Print error message and quit.
587 */
588
589 static void
oops(const char * message,...)590 oops(const char *message, ...)
591 {
592 va_list args;
593
594 va_start(args, message);
595 if (col != 0) putchar('\n');
596 vfprintf(stderr, message, args);
597 va_end(args);
598 putc('\n', stderr);
599 exit_toto_too();
600 }
601
602
603 /*
604 * Same as oops, but with arguments.
605 */
606 static void
opt_oops(const char * message,...)607 opt_oops(const char *message, ...)
608 {
609 va_list args;
610
611 va_start(args, message);
612 fputs("gsftopk: ", stderr);
613 vfprintf(stderr, message, args);
614 va_end(args);
615 fputs("\nTry `gsftopk --help' for more information.\n", stderr);
616 exit(1);
617 }
618
619
620 #ifndef KPATHSEA
621
622 /*
623 * Either allocate storage or fail.
624 */
625
626 static void *
xmalloc(unsigned size)627 xmalloc(unsigned size)
628 {
629 void *mem = (void *) malloc(size);
630
631 if (mem == NULL)
632 oops("gsftopk: Cannot allocate %u bytes.\n", size);
633 return mem;
634 }
635
636
637 /*
638 * Either reallocate storage or fail.
639 */
640
641 static void *
xrealloc(char * oldp,unsigned size)642 xrealloc(char *oldp, unsigned size)
643 {
644 void *mem;
645
646 mem = oldp == NULL ? (void *) malloc(size)
647 : (void *) realloc(oldp, size);
648 if (mem == NULL)
649 oops("gsftopk: Cannot reallocate %u bytes.\n", size);
650 return mem;
651 }
652
653 #endif /* not KPATHSEA */
654
655
656 /*
657 * Get a single white-space-delimited argument (or fail).
658 */
659
660 static char *
get_one_arg(const char * src)661 get_one_arg(const char *src)
662 {
663 char *dest;
664 const char *p;
665 unsigned int len;
666
667 len = strlen(src);
668 p = memchr(src, ' ', len);
669 if (p != NULL) len = p - src;
670 p = memchr(src, '\t', len);
671 if (p != NULL) len = p - src;
672
673 dest = xmalloc(len + 1);
674 memcpy(dest, src, len);
675 dest[len] = '\0';
676
677 return dest;
678 }
679
680 #if !_AMIGA
681
682 /*
683 * Signal handlers.
684 */
685
686 #if WIN32
687
688 static BOOL WINAPI
handle_sigterm(DWORD dwCtrlType)689 handle_sigterm(DWORD dwCtrlType)
690 {
691
692 /*
693 * Fix me: There is a problem if a system() command is running.
694 * We should wait for the child process to be interrupted.
695 * Only way I can think of to do that : rewrite system() based on
696 * spawn() with parsing of the command line and set a global pid
697 * Next cwait(pid) in the HandlerRoutine.
698 */
699
700 switch (dwCtrlType) {
701 case CTRL_C_EVENT:
702 case CTRL_BREAK_EVENT:
703 fprintf(stderr, "...exiting\n");
704 if (hGsThread) {
705 if (TerminateThread(hGsThread, 1) == 0) {
706 fprintf(stderr, "... couldn't terminate gs thread\n");
707 }
708 }
709 exit_toto_too();
710 return FALSE;
711 default:
712 fprintf(stderr, "... not exiting\n");
713 return TRUE;
714 }
715 }
716
717 #else /* not WIN32 */
718
719 static Boolean got_sigchld = False;
720
721 /* ARGSUSED */
722 static RETSIGTYPE
handle_sigchild(int signo)723 handle_sigchild(int signo)
724 {
725 got_sigchld = True;
726 }
727
728 /* ARGSUSED */
729 static RETSIGTYPE
handle_sigterm(int signo)730 handle_sigterm(int signo)
731 {
732 exit_toto_too();
733 }
734
735 #endif /* WIN32 */
736
737 #define gs_is_done (gs_pid == 0)
738
739 typedef int gsf_wait_t;
740
741 #if WIN32
742
743 /* This is the callback function for gs. It is mainly used to read and
744 write data on gs stdin/stdout. Data exchanges happen through
745 buffers. */
746 static int __cdecl
gsdll_callback(int message,char * str,unsigned long count)747 gsdll_callback(int message, char *str, unsigned long count)
748 {
749 int n;
750 static char **pin = &buffer_stdin; /* not yet allocated, so used a pointer on it. */
751
752 switch (message) {
753
754 case GSDLL_STDIN:
755 /* Put count chars on gs stdin */
756 #if DEBUG
757 fprintf(stderr, "gs wants %d chars\n", count);
758 #endif
759 strncpy(str, *pin, count);
760 *pin += count;
761 return strlen(str);
762
763 case GSDLL_STDOUT:
764 /* Fill the buffer in, wait for gsftopk to ask for data. */
765 WaitForSingleObject(hGsDataOut, INFINITE);
766 #if DEBUG
767 fprintf(stderr, "gs gives %d chars\n", count);
768 #endif
769 data_out = buffer;
770
771 if (str == (char *)NULL || count == 0) {
772 data_eof = True;
773 data_end = data_out;
774 /* Tell data_fillbuf() */
775 SetEvent(hGsDataIn);
776 return 0;
777 }
778 n = (count >= BUFSIZE ? BUFSIZE : count);
779 memcpy(data_out, str, n);
780 data_end = data_out + n;
781 /* Tell data_fillbuf() that data are available */
782 if (SetEvent(hGsDataIn) == FALSE)
783 Win32Error("gsdll_callback/SetEvent");
784 /* return the number of chars read */
785 return n;
786
787 case GSDLL_DEVICE:
788 #if DEBUG
789 fprintf(stdout,"Callback: DEVICE %p %s\n", str,
790 count ? "open" : "close");
791 #endif
792 break;
793
794 case GSDLL_SYNC:
795 #if DEBUG
796 fprintf(stdout,"Callback: SYNC %p\n", str);
797 #endif
798 break;
799
800 case GSDLL_PAGE:
801 fprintf(stdout,"Callback: PAGE %p\n", str);
802 break;
803
804 case GSDLL_SIZE:
805 #if DEBUG
806 fprintf(stdout,"Callback: SIZE %p width=%d height=%d\n", str,
807 (int)(count & 0xffff), (int)((count>>16) & 0xffff) );
808 #endif
809 break;
810
811 case GSDLL_POLL:
812 return 0; /* no error ? */
813 default:
814 fprintf(stdout,"%s: gs callback: unknown message=%d\n",progname, message);
815 break;
816 }
817 return 0;
818 }
819
820 /*
821 This is the thread function that will load the gs dll and
822 send it the data.
823 */
Win32GsSendData(LPVOID lpParam)824 static DWORD WINAPI Win32GsSendData(LPVOID lpParam)
825 {
826 int ret;
827
828 if (gs_locate() == NULL) {
829 fprintf(stderr, "Can't locate Ghostscript ! Exiting ...\n");
830 return EXIT_FAILURE;
831 }
832
833 gs_dll_initialize();
834
835 ret = (*pgsdll_init)(gsdll_callback,
836 NULL,
837 gs_argc,
838 gs_argv);
839
840 if (ret == 0) {
841 /* Should not happen : gs should quit
842 right after being initialized. */
843 (*pgsdll_exit)();
844 /* FIXME: this is working, but we could expect something cleaner ! */
845 /* GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0); */
846 return EXIT_FAILURE;
847 }
848
849 if (ret == GSDLL_INIT_QUIT) {
850 gs_dll_release();
851 return 0;
852 }
853
854 if (ret == GSDLL_INIT_IN_USE) {
855 fprintf(stderr, "gsdll_init returned %d\n", ret);
856 gs_dll_release();
857 return EXIT_FAILURE;
858 }
859
860 (*pgsdll_exit)();
861
862 #if DEBUG
863 fprintf(stderr, "%s: gsdll_init returned %d\n", progname, ret);
864 #endif
865
866 WaitForSingleObject(hGsDataOut, INFINITE);
867 data_eof = True;
868 data_end = data_out;
869 /* Tell data_fillbuf() */
870 SetEvent(hGsDataIn);
871
872 gs_dll_release();
873
874 return 0;
875 }
876
877 #else /* not WIN32 */
878
879 static void
wait_for_gs(void)880 wait_for_gs(void)
881 {
882 gsf_wait_t status;
883
884 #if _AMIGA
885
886 /* Do nothing */
887
888 #else /* not _AMIGA */
889
890 got_sigchld = False;
891
892 for (;;) {
893 if (wait(&status) != -1) break;
894 /* if (errno == EINTR) continue; */
895 if (errno != EINTR) {
896 perror("wait");
897 exit_toto_too();
898 }
899 }
900
901 if (WIFSTOPPED(status))
902 return;
903
904 gs_pid = 0;
905
906 if (WIFSIGNALED(status))
907 oops("gs died due to signal %d\n", WTERMSIG(status));
908
909 /* otherwise, it exited */
910 if (WEXITSTATUS(status) != 0)
911 oops("gs terminated abnormally with status %d\n",
912 WEXITSTATUS(status));
913
914 #endif /* not _AMIGA */
915
916 }
917
918 #endif /* not WIN32 */
919
920 #endif /* not _AMIGA */
921
922 /*
923 * Routines to read from the data file.
924 */
925
926 #if _AMIGA
927
928 #define data_getc() getc(data_file)
929 #define data_ungetc(c) ungetc(c, data_file)
930 #define data_read(p, l) fread(p, 1, l, data_file)
931
932 #else /* not _AMIGA */
933
934 #if WIN32
935
936 static void
data_fillbuf(void)937 data_fillbuf(void)
938 {
939 if (data_eof)
940 return;
941
942 /* wait until data are available. First tell gs it can fill the buffer in. */
943 SetEvent(hGsDataOut);
944 /* wait for the data. */
945 switch (WaitForSingleObject(hGsDataIn, INFINITE)) {
946 case WAIT_OBJECT_0:
947 /* normal case */
948 break;
949 case WAIT_TIMEOUT:
950 /* should not happen */
951 fprintf(stderr, "Gs did not return on time from callback.\n");
952 break;
953 case WAIT_FAILED:
954 break;
955 default:
956 fprintf(stderr, "WaitForSingleObject failed for unknown reason.\n");
957 }
958 }
959
960 #else /* not WIN32 */
961
962 #if HAVE_POLL
963 #define ISSET(a, b) ((poll_fd.revents & POLLIN) != 0)
964 #else
965 #define ISSET(a, b) FD_ISSET(a, b)
966 #endif
967
968 static void
data_fillbuf(void)969 data_fillbuf(void)
970 {
971 int n;
972
973 #if HAVE_POLL
974 static struct pollfd poll_fd = {0, POLLIN, 0};
975 #else
976 fd_set read_fds;
977 struct timeval timeout;
978 #endif
979
980 if (data_eof)
981 return;
982
983 /* wait for readable data */
984 if (!gs_is_done) {
985 for (;;) {
986 if (!got_sigchld) {
987 #if HAVE_POLL
988 poll_fd.fd = data_fd;
989 poll_fd.revents = 0;
990 if (poll(&poll_fd, 1, 5000) == -1) {
991 if (errno != EINTR) {
992 perror("poll");
993 sleep(4);
994 }
995 continue;
996 }
997 #else
998 FD_ZERO(&read_fds);
999 FD_SET(data_fd, &read_fds);
1000 timeout.tv_sec = 5;
1001 timeout.tv_usec = 0;
1002 if (select(data_fd + 1, &read_fds, (fd_set *) NULL,
1003 (fd_set *) NULL, &timeout) == -1) {
1004 if (errno != EINTR) {
1005 perror("select");
1006 sleep(4);
1007 }
1008 continue;
1009 }
1010 #endif
1011 }
1012 if (got_sigchld) {
1013 wait_for_gs();
1014 break;
1015 }
1016 if (ISSET(data_fd, &read_fds))
1017 break;
1018 }
1019 }
1020
1021 /* read the data */
1022 for (;;) {
1023 n = read(data_fd, (void *) (data_out = buffer), BUFSIZE);
1024 if (n >= 0)
1025 break;
1026 if (errno == EINTR)
1027 continue;
1028 if (gs_is_done && errno == EAGAIN) {
1029 n = 0;
1030 break;
1031 }
1032 perror("read from gs");
1033 sleep(4);
1034 }
1035
1036 data_end = data_out + n;
1037 if (n == 0)
1038 data_eof = True;
1039 }
1040
1041 #endif /* not WIN32 */
1042
1043 static byte
data_fgetc(void)1044 data_fgetc(void)
1045 {
1046 if (data_out >= data_end)
1047 data_fillbuf();
1048
1049 return data_eof ? EOF : *data_out++;
1050 }
1051
1052 #define data_getc() (data_out < data_end ? *data_out++ : data_fgetc())
1053
1054 static void
data_ungetc(byte c)1055 data_ungetc(byte c)
1056 {
1057 if (data_out <= buffer)
1058 oops("Too many calls to data_ungetc()");
1059
1060 *--data_out = c;
1061 }
1062
1063 static int
data_read(byte * buf,int n)1064 data_read(byte *buf, int n)
1065 {
1066 byte *buf1 = buf;
1067 byte *buf_end = buf + n;
1068 int n1;
1069
1070 if (buf1 >= buf_end)
1071 return 0;
1072
1073 while (!data_eof) {
1074 n1 = buf_end - buf1;
1075 if (n1 > data_end - data_out)
1076 n1 = data_end - data_out;
1077 memcpy(buf1, data_out, n1);
1078 buf1 += n1;
1079 data_out += n1;
1080 if (buf1 >= buf_end) break;
1081 data_fillbuf();
1082 }
1083
1084 return buf1 - buf;
1085 }
1086
1087 static void
data_gets(byte * buf,int n)1088 data_gets(byte *buf, int n)
1089 {
1090 byte *buf1 = buf;
1091 byte *buf_end = buf + n - 1;
1092 int n1;
1093 byte *p1;
1094
1095 if (n <= 0)
1096 return;
1097
1098 for (;;) {
1099 if (data_eof)
1100 oops("Premature end of file");
1101 n1 = buf_end - buf1;
1102 if (n1 > data_end - data_out)
1103 n1 = data_end - data_out;
1104 p1 = (byte *) memchr((char *) data_out, '\n', n1);
1105 if (p1 != NULL)
1106 n1 = p1 + 1 - data_out;
1107 memcpy((char *) buf1, (char *) data_out, n1);
1108 buf1 += n1;
1109 data_out += n1;
1110 if (p1 != NULL || buf1 >= buf_end) break;
1111 data_fillbuf();
1112 }
1113
1114 *buf1 = '\0';
1115
1116 return;
1117 }
1118
1119 #endif /* not _AMIGA */
1120
1121 /*
1122 * Here's the patch searching stuff. First the typedefs and variables.
1123 */
1124
1125 #ifndef KPATHSEA
1126 static char searchpath[MAXPATHLEN + 1];
1127 #else
1128 static char *searchpath;
1129 #endif
1130
1131 #define HUNKSIZE (MAXPATHLEN + 2)
1132
1133 struct spacenode { /* used for storage of directory names */
1134 struct spacenode *next;
1135 char *sp_end; /* end of data for this chunk */
1136 char sp[HUNKSIZE];
1137 }
1138 firstnode;
1139
1140 #ifndef KPATHSEA
1141
1142 static jmp_buf found_env;
1143 static FILE *searchfile;
1144 static const char *searchname;
1145 static int searchnamelen;
1146
1147 static const char *
find_dbl_slash(const char * sp_bgn,const char * sp_end)1148 find_dbl_slash(const char *sp_bgn, const char *sp_end)
1149 {
1150 const char *p;
1151
1152 for (;;) {
1153 p = memchr(sp_bgn, '/', sp_end - sp_bgn);
1154 if (p == NULL) return sp_end;
1155 if (p[1] == '/') return p;
1156 sp_bgn = p + 1;
1157 }
1158 }
1159
1160 static void
main_search_proc(char * matpos,const char * sp_pos,const char * sp_slash,const char * sp_end,wide_bool skip_subdirs,struct spacenode * space,char * spacenext)1161 main_search_proc(char *matpos, const char *sp_pos,
1162 const char *sp_slash, const char *sp_end,
1163 wide_bool skip_subdirs, struct spacenode *space, char *spacenext)
1164 {
1165 char *mp;
1166 struct stat statbuf;
1167 DIR *dir;
1168 struct dirent *entry;
1169 int lenleft;
1170 int len;
1171 struct spacenode *space1;
1172 char *spacenext1;
1173
1174 mp = matpos + (sp_slash - sp_pos);
1175 /* check length */
1176 if (mp + searchnamelen >= searchpath + sizeof(searchpath) - 2) return;
1177 memcpy(matpos, sp_pos, sp_slash - sp_pos);
1178 if (sp_slash == sp_end) { /* try for a file */
1179 *mp = '/';
1180 strcpy(mp + (mp == searchpath || mp[-1] != '/'), searchname);
1181 searchfile = fopen(searchpath, "r");
1182 if (searchfile != NULL) longjmp(found_env, True);
1183 }
1184 else {/* try for a subdirectory */
1185 *mp = '\0';
1186 if (stat(searchpath, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) {
1187 *mp++ = '/';
1188 main_search_proc(mp, sp_slash + 2,
1189 find_dbl_slash(sp_slash + 2, sp_end), sp_end,
1190 statbuf.st_nlink <= 2, space, spacenext);
1191 }
1192 }
1193 if (skip_subdirs) return;
1194 *matpos = '\0';
1195 dir = opendir(searchpath);
1196 if (dir == NULL) return;
1197 lenleft = searchpath + sizeof(searchpath) - matpos;
1198 space1 = space;
1199 spacenext1 = spacenext;
1200 for (;;) {
1201 entry = readdir(dir);
1202 if (entry == NULL) break;
1203 len = NAMLEN(entry) + 1;
1204 if (len > lenleft) continue; /* too long */
1205 strcpy(matpos, entry->d_name);
1206 if (*matpos == '.' && (matpos[1] == '\0' || (matpos[1] == '.'
1207 && matpos[2] == '\0')))
1208 continue; /* ignore . and .. */
1209 if (stat(searchpath, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
1210 continue; /* if not a directory */
1211 if (statbuf.st_nlink > 2) ++len;
1212 if (spacenext1 + len > space1->sp + HUNKSIZE) {
1213 space1->sp_end = spacenext1;
1214 if (space1->next == NULL) {
1215 space1->next = xmalloc(sizeof(struct spacenode));
1216 space1->next->next = NULL;
1217 }
1218 space1 = space1->next;
1219 spacenext1 = space1->sp;
1220 }
1221 if (statbuf.st_nlink > 2) {
1222 *spacenext1++ = '/';
1223 --len;
1224 }
1225 memcpy(spacenext1, entry->d_name, len - 1);
1226 spacenext1[len - 1] = '\0';
1227 spacenext1 += len;
1228 }
1229 closedir(dir);
1230 for (;;) {
1231 space1->sp_end = spacenext1;
1232 if (spacenext == space->sp_end) {
1233 if (space == space1) break;
1234 space = space->next;
1235 spacenext = space->sp;
1236 }
1237 skip_subdirs = True;
1238 if (*spacenext == '/') {
1239 ++spacenext;
1240 skip_subdirs = False;
1241 }
1242 len = strlen(spacenext);
1243 memcpy(matpos, spacenext, len);
1244 matpos[len] = '/';
1245 main_search_proc(matpos + len + 1, sp_pos, sp_slash, sp_end,
1246 skip_subdirs, space1, spacenext1);
1247 spacenext += len + 1;
1248 }
1249 }
1250
1251 static FILE *
search(const char * path,const char * path_var,const char * name)1252 search(const char *path, const char *path_var, const char *name)
1253 {
1254 const char *env_path = NULL;
1255 FILE *f;
1256
1257 if (path_var != NULL) {
1258 if (*name == '/') {
1259 strcpy(searchpath, name);
1260 return fopen(searchpath, "r");
1261 }
1262 env_path = getenv(path_var);
1263 }
1264 if (env_path == NULL) {
1265 env_path = path;
1266 path = NULL;
1267 }
1268 searchname = name;
1269 searchnamelen = strlen(name);
1270 for (;;) {
1271 const char *p;
1272
1273 p = strchr(env_path, ':');
1274 if (p == NULL) p = env_path + strlen(env_path);
1275 if (p == env_path) {
1276 if (path != NULL) {
1277 f = search(path, (char *) NULL, name);
1278 if (f != NULL) return f;
1279 }
1280 }
1281 else {
1282 if (setjmp(found_env))
1283 return searchfile;
1284 main_search_proc(searchpath,
1285 env_path, find_dbl_slash(env_path, p), p,
1286 True, &firstnode, firstnode.sp);
1287 }
1288 if (*p == '\0') return NULL;
1289 env_path = p + 1;
1290 }
1291 }
1292
1293 #endif /* not KPATHSEA */
1294
1295 /*
1296 * Reading configuration and map files.
1297 */
1298
1299 char *long_line = NULL; /* for reading config and map files */
1300 int long_line_len = 82; /* allocated length of the above */
1301
1302 static Boolean
fgets_long(FILE * f)1303 fgets_long(FILE *f)
1304 {
1305 int len;
1306
1307 if (fgets(long_line, long_line_len, f) == NULL)
1308 return False;
1309
1310 len = 0;
1311 for (;;) {
1312 len += strlen(long_line + len);
1313 if (len > 0 && long_line[len - 1] == '\n') {
1314 long_line[--len] = '\0';
1315 break;
1316 }
1317 if (len < long_line_len - 1)
1318 break;
1319 long_line_len += 80;
1320 long_line = xrealloc(long_line, long_line_len);
1321 fgets(long_line + len, long_line_len - len, f);
1322 }
1323
1324 return True;
1325 }
1326
1327
1328 static void
1329 #ifndef KPATHSEA
getdefaults(FILE * f)1330 getdefaults(FILE *f)
1331 #else
1332 getdefaults(const char *name)
1333 #endif
1334 {
1335 #ifdef KPATHSEA
1336 FILE *f;
1337 #endif
1338 char *p;
1339 char c;
1340 struct p_list *p_node;
1341
1342 #ifdef KPATHSEA
1343 p = kpse_find_file(name, kpse_dvips_config_format, false);
1344 if (p == NULL)
1345 return;
1346
1347 f = fopen(p, FOPEN_R_MODE);
1348 if (f == NULL)
1349 return;
1350 #endif
1351
1352 while (fgets_long(f)) {
1353 p = long_line;
1354 while (*p == ' ' || *p == '\t') ++p;
1355 c = *p;
1356 if (c == '\0')
1357 continue;
1358 do ++p;
1359 while (*p == ' ' || *p == '\t');
1360 switch (c) {
1361 case 'H':
1362 config_file_header_path = get_one_arg(p);
1363 break;
1364
1365 case 'p':
1366 if (*p == '+')
1367 do ++p;
1368 while (*p == ' ' || *p == '\t');
1369 else
1370 p_tail = &p_head; /* discard old list */
1371
1372 p_node = xmalloc(sizeof *p_node);
1373 p_node->value = get_one_arg(p);
1374 *p_tail = p_node;
1375 p_tail = &p_node->next;
1376 break;
1377 }
1378 }
1379
1380 fclose(f);
1381 }
1382
1383
1384 static Boolean
scan_map_file(FILE * f)1385 scan_map_file(FILE *f)
1386 {
1387 while (fgets_long(f))
1388 if (memcmp(long_line, fontname, fontlen) == 0
1389 && (long_line[fontlen] == '\0' || isspace((unsigned char)long_line[fontlen]))) {
1390 fclose(f);
1391 return True;
1392 }
1393
1394 fclose(f);
1395 return False;
1396 }
1397
1398
1399 /*
1400 * Add to dlstring
1401 */
1402
1403 char *dlstring = NULL;
1404 unsigned int dls_len = 0;
1405 unsigned int dls_max = 0;
1406
1407 static void
addtodls(const char * s)1408 addtodls(const char *s)
1409 {
1410 int len = strlen(s);
1411
1412 if (dls_len + len >= dls_max) {
1413 unsigned int newsize = dls_max + 80;
1414
1415 if (newsize <= dls_len + len) newsize = dls_len + len + 1;
1416 dlstring = xrealloc(dlstring, dls_max = newsize);
1417 }
1418 strcpy(dlstring + dls_len, s);
1419 dls_len += len;
1420 }
1421
1422
1423
1424 static long
getlong(FILE * f)1425 getlong(FILE *f)
1426 {
1427 int value;
1428
1429 value = (int) ((byte) getc(f)) << 24;
1430 value |= (int) ((byte) getc(f)) << 16;
1431 value |= (int) ((byte) getc(f)) << 8;
1432 value |= (int) ((byte) getc(f));
1433 return value;
1434 }
1435
1436
1437 char line[82];
1438
1439 static void
expect(const char * waitingfor)1440 expect(const char *waitingfor)
1441 {
1442 for (;;) {
1443 #if !_AMIGA
1444 data_gets((byte *) line, sizeof(line));
1445 #else
1446 if (fgets(line, sizeof(line), data_file) == NULL)
1447 oops("Premature end of file");
1448 #endif
1449 if (memcmp(line, waitingfor, strlen(waitingfor)) == 0) return;
1450 fputs("gs: ", stdout);
1451 for (;;) {
1452 fputs(line, stdout);
1453 if (*line == '\0' || line[strlen(line) - 1] == '\n') break;
1454 #if !_AMIGA
1455 data_gets((byte *) line, sizeof(line));
1456 #else
1457 if (fgets(line, sizeof(line), data_file) == NULL)
1458 oops("Premature end of file");
1459 #endif
1460 }
1461 }
1462 }
1463
1464 static void
whitespace(void)1465 whitespace(void)
1466 {
1467 char c;
1468
1469 for (;;) {
1470 c = data_getc();
1471 if (c == '#')
1472 do c = data_getc(); while (!data_eof && c != '\n');
1473 else if (!isspace((unsigned char)c)) {
1474 data_ungetc(c);
1475 break;
1476 }
1477 }
1478 }
1479
1480 static int
getint(void)1481 getint(void)
1482 {
1483 char c;
1484 int i = 0;
1485
1486 do c = data_getc(); while (isspace((unsigned char)c));
1487 if (c < '0' || c > '9') oops("digit expected");
1488 do {
1489 i = i * 10 + (c - '0');
1490 c = data_getc();
1491 } while (c >= '0' && c <= '9');
1492 if (!data_eof) data_ungetc(c);
1493 return i;
1494 }
1495
1496 static byte masks[] = {0, 1, 3, 7, 017, 037, 077, 0177, 0377};
1497
1498 byte flag;
1499 int pk_dyn_f;
1500 int pk_dyn_g;
1501 int base; /* cost of this character if pk_dyn_f = 0 */
1502 int deltas[13]; /* cost of increasing pk_dyn_f from i to i+1 */
1503
1504 /*
1505 * Add up statistics for putting out the given shift count
1506 */
1507
1508 static void
tallyup(int n)1509 tallyup(int n)
1510 {
1511 int m;
1512
1513 if (n > 208) {
1514 ++base;
1515 n -= 192;
1516 for (m = 0x100; m != 0 && m < n; m <<= 4) base += 2;
1517 if (m != 0 && (m = (m - n) / 15) < 13) deltas[m] += 2;
1518 }
1519 else if (n > 13) ++deltas[(208 - n) / 15];
1520 else --deltas[n - 1];
1521 }
1522
1523 /*
1524 * Routines for storing the shift counts
1525 */
1526
1527 static Boolean odd = False;
1528 static byte part;
1529
1530 static void
pk_put_nyb(int n)1531 pk_put_nyb(int n)
1532 {
1533 if (odd) {
1534 *bitmap_end++ = (part << 4) | n;
1535 odd = False;
1536 }
1537 else {
1538 part = n;
1539 odd = True;
1540 }
1541 }
1542
1543 static void
pk_put_long(int n)1544 pk_put_long(int n)
1545 {
1546 if (n >= 16) {
1547 pk_put_nyb(0);
1548 pk_put_long(n / 16);
1549 }
1550 pk_put_nyb(n % 16);
1551 }
1552
1553 static void
pk_put_count(int n)1554 pk_put_count(int n)
1555 {
1556 if (n > pk_dyn_f) {
1557 if (n > pk_dyn_g)
1558 pk_put_long(n - pk_dyn_g + 15);
1559 else {
1560 pk_put_nyb(pk_dyn_f + (n - pk_dyn_f + 15) / 16);
1561 pk_put_nyb((n - pk_dyn_f - 1) % 16);
1562 }
1563 }
1564 else pk_put_nyb(n);
1565 }
1566
1567 static void
trim_bitmap(void)1568 trim_bitmap(void)
1569 {
1570 byte *p;
1571 byte mask;
1572
1573 /* clear out garbage bits in bitmap */
1574 if (width % 8 != 0) {
1575 mask = ~masks[8 - width % 8];
1576 for (p = bitmap + bytes_wide - 1; p < bitmap_end; p += bytes_wide)
1577 *p &= mask;
1578 }
1579
1580 /*
1581 * Find the bounding box of the bitmap.
1582 */
1583
1584 /* trim top */
1585 skip = 0;
1586 mask = 0;
1587 for (;;) {
1588 if (bitmap >= bitmap_end) { /* if bitmap is empty */
1589 width = height = hoff = voff = 0;
1590 return;
1591 }
1592 p = bitmap + bytes_wide;
1593 while (p > bitmap) mask |= *--p;
1594 if (mask) break;
1595 ++skip;
1596 bitmap += bytes_wide;
1597 }
1598 height -= skip;
1599 voff -= skip;
1600 #if DEBUG
1601 #if defined(KPATHSEA) && defined (KPSE_DEBUG)
1602 if (KPSE_DEBUG_P (GSPK_DEBUG_PK))
1603 #endif
1604 if (skip < 2 || skip > 3)
1605 printf("Character has %d empty rows at top\n", skip);
1606 #endif /* DEBUG */
1607
1608 /* trim bottom */
1609 skip = 0;
1610 mask = 0;
1611 for (;;) {
1612 p = bitmap_end - bytes_wide;
1613 while (p < bitmap_end) mask |= *p++;
1614 if (mask) break;
1615 ++skip;
1616 bitmap_end -= bytes_wide;
1617 }
1618 height -= skip;
1619 #if DEBUG
1620 #if defined(KPATHSEA) && defined (KPSE_DEBUG)
1621 if (KPSE_DEBUG_P (GSPK_DEBUG_PK))
1622 #endif
1623 if (skip < 2 || skip > 3)
1624 printf("Character has %d empty rows at bottom\n", skip);
1625 #endif /* DEBUG */
1626
1627 /* trim right */
1628 skip = 0;
1629 --width;
1630 for (;;) {
1631 mask = 0;
1632 for (p = bitmap + width / 8; p < bitmap_end; p += bytes_wide)
1633 mask |= *p;
1634 if (mask & (0x80 >> (width % 8))) break;
1635 --width;
1636 ++skip;
1637 }
1638 ++width;
1639 #if DEBUG
1640 #if defined(KPATHSEA) && defined (KPSE_DEBUG)
1641 if (KPSE_DEBUG_P (GSPK_DEBUG_PK))
1642 #endif
1643 if (skip < 2 || skip > 3)
1644 printf("Character has %d empty columns at right\n", skip);
1645 #endif /* DEBUG */
1646
1647 /* trim left */
1648 skip = 0;
1649 for (;;) {
1650 mask = 0;
1651 for (p = bitmap + skip / 8; p < bitmap_end; p += bytes_wide)
1652 mask |= *p;
1653 if (mask & (0x80 >> (skip % 8))) break;
1654 ++skip;
1655 }
1656 width -= skip;
1657 hoff -= skip;
1658 #if DEBUG
1659 #if defined(KPATHSEA) && defined (KPSE_DEBUG)
1660 if (KPSE_DEBUG_P (GSPK_DEBUG_PK))
1661 #endif
1662 if (skip < 2 || skip > 3)
1663 printf("Character has %d empty columns at left\n", skip);
1664 #endif /* DEBUG */
1665 bitmap += skip / 8;
1666 skip = skip % 8;
1667 }
1668
1669 /*
1670 * Pack the bitmap using the rll method. (Return false if it's better
1671 * to just pack the bits.)
1672 */
1673
1674 static Boolean
pk_rll_cvt(void)1675 pk_rll_cvt(void)
1676 {
1677 static int *counts = NULL; /* area for saving bit counts */
1678 static int maxcounts = 0; /* size of this area */
1679 unsigned int ncounts; /* max to allow this time */
1680 int *nextcount; /* next count value */
1681 int *counts_end; /* pointer to end */
1682 byte *rowptr;
1683 byte *p;
1684 byte mask;
1685 byte *rowdup; /* last row checked for dup */
1686 byte paint_switch; /* 0 or 0xff */
1687 int bits_left; /* bits left in row */
1688 int cost;
1689 int i;
1690
1691 /*
1692 * Allocate space for bit counts.
1693 */
1694
1695 ncounts = (width * height + 3) / 4;
1696 if (ncounts > maxcounts) {
1697 if (counts != NULL) free(counts);
1698 counts = xmalloc((ncounts + 2) * sizeof(int));
1699 maxcounts = ncounts;
1700 }
1701 counts_end = counts + ncounts;
1702
1703 /*
1704 * Form bit counts and collect statistics
1705 */
1706 base = 0;
1707 memset(deltas, 0, sizeof(deltas));
1708 rowdup = NULL; /* last row checked for duplicates */
1709 p = rowptr = bitmap;
1710 mask = 0x80 >> skip;
1711 flag = 0;
1712 paint_switch = 0;
1713 if (*p & mask) {
1714 flag = 8;
1715 paint_switch = 0xff;
1716 }
1717 bits_left = width;
1718 nextcount = counts;
1719 while (rowptr < bitmap_end) { /* loop over shift counts */
1720 int shift_count = bits_left;
1721
1722 for (;;) {
1723 if (bits_left == 0) {
1724 if ((p = rowptr += bytes_wide) >= bitmap_end) break;
1725 mask = 0x80 >> skip;
1726 bits_left = width;
1727 shift_count += width;
1728 }
1729 if (((*p ^ paint_switch) & mask) != 0) break;
1730 --bits_left;
1731 mask >>= 1;
1732 if (mask == 0) {
1733 ++p;
1734 while (*p == paint_switch && bits_left >= 8) {
1735 ++p;
1736 bits_left -= 8;
1737 }
1738 mask = 0x80;
1739 }
1740 }
1741 if (nextcount >= counts_end) return False;
1742 shift_count -= bits_left;
1743 *nextcount++ = shift_count;
1744 tallyup(shift_count);
1745 /* check for duplicate rows */
1746 if (rowptr != rowdup && bits_left != width) {
1747 byte *p1 = rowptr;
1748 byte *q = rowptr + bytes_wide;
1749 int repeat_count;
1750
1751 while (q < bitmap_end && *p1 == *q) ++p1, ++q;
1752 repeat_count = (p1 - rowptr) / bytes_wide;
1753 if (repeat_count > 0) {
1754 *nextcount++ = -repeat_count;
1755 if (repeat_count == 1) --base;
1756 else {
1757 ++base;
1758 tallyup(repeat_count);
1759 }
1760 rowptr += repeat_count * bytes_wide;
1761 }
1762 rowdup = rowptr;
1763 }
1764 paint_switch = ~paint_switch;
1765 }
1766
1767 #if DEBUG
1768 #if defined(KPATHSEA) && defined (KPSE_DEBUG)
1769 if (KPSE_DEBUG_P (GSPK_DEBUG_BITMAP))
1770 #endif
1771 {
1772 /*
1773 * Dump the bitmap
1774 */
1775
1776 for (p = bitmap; p < bitmap_end; p += bytes_wide) {
1777 byte *p1 = p;
1778 int j;
1779
1780 mask = 0x80 >> skip;
1781 for (j = 0; j < width; ++j) {
1782 putchar(*p1 & mask ? '@' : '.');
1783 if ((mask >>= 1) == 0) mask = 0x80, ++p1;
1784 }
1785 putchar('\n');
1786 }
1787 putchar('\n');
1788 }
1789 #endif /* DEBUG */
1790
1791 /*
1792 * Determine the best pk_dyn_f
1793 */
1794
1795 pk_dyn_f = 0;
1796 cost = base += 2 * (nextcount - counts);
1797 for (i = 1; i < 14; ++i) {
1798 base += deltas[i - 1];
1799 if (base < cost) {
1800 pk_dyn_f = i;
1801 cost = base;
1802 }
1803 }
1804 /* last chance to bail out */
1805 if (cost * 4 > width * height) return False;
1806
1807 /*
1808 * Pack the bit counts
1809 */
1810
1811 pk_dyn_g = 208 - 15 * pk_dyn_f;
1812 flag |= pk_dyn_f << 4;
1813 bitmap_end = bitmap;
1814 *nextcount = 0;
1815 nextcount = counts;
1816 while (*nextcount != 0) {
1817 if (*nextcount > 0) pk_put_count(*nextcount);
1818 else
1819 if (*nextcount == -1) pk_put_nyb(15);
1820 else {
1821 pk_put_nyb(14);
1822 pk_put_count(-*nextcount);
1823 }
1824 ++nextcount;
1825 }
1826 if (odd) {
1827 pk_put_nyb(0);
1828 ++cost;
1829 }
1830 if (cost != 2 * (bitmap_end - bitmap))
1831 printf("Cost miscalculation: expected %d, got %ld\n", cost,
1832 2 * (long) (bitmap_end - bitmap));
1833 pk_len = bitmap_end - bitmap;
1834 return True;
1835 }
1836
1837 static void
pk_bm_cvt(void)1838 pk_bm_cvt(void)
1839 {
1840 byte *rowptr;
1841 byte *p;
1842 int blib1; /* bits left in byte */
1843 int bits_left; /* bits left in row */
1844 byte *q;
1845 int blib2;
1846 byte nextbyte;
1847
1848 flag = 14 << 4;
1849 q = bitmap;
1850 blib2 = 8;
1851 nextbyte = 0;
1852 for (rowptr = bitmap; rowptr < bitmap_end; rowptr += bytes_wide) {
1853 p = rowptr;
1854 blib1 = 8 - skip;
1855 bits_left = width;
1856 if (blib2 != 8) {
1857 int n;
1858
1859 if (blib1 < blib2) {
1860 nextbyte |= *p << (blib2 - blib1);
1861 n = blib1;
1862 }
1863 else {
1864 nextbyte |= *p >> (blib1 - blib2);
1865 n = blib2;
1866 }
1867 blib2 -= n;
1868 if ((bits_left -= n) < 0) {
1869 blib2 -= bits_left;
1870 continue;
1871 }
1872 if ((blib1 -= n) == 0) {
1873 blib1 = 8;
1874 ++p;
1875 if (blib2 > 0) {
1876 nextbyte |= *p >> (8 - blib2);
1877 blib1 -= blib2;
1878 bits_left -= blib2;
1879 if (bits_left < 0) {
1880 blib2 = -bits_left;
1881 continue;
1882 }
1883 }
1884 }
1885 *q++ = nextbyte;
1886 }
1887 /* fill up whole (destination) bytes */
1888 while (bits_left >= 8) {
1889 nextbyte = *p++ << (8 - blib1);
1890 *q++ = nextbyte | (*p >> blib1);
1891 bits_left -= 8;
1892 }
1893 /* now do the remainder */
1894 nextbyte = *p << (8 - blib1);
1895 if (bits_left > blib1) nextbyte |= p[1] >> blib1;
1896 blib2 = 8 - bits_left;
1897 }
1898 if (blib2 != 8) *q++ = nextbyte;
1899 pk_len = q - bitmap;
1900 }
1901
1902 static void
putshort(int w)1903 putshort(int w)
1904 {
1905 putc(w >> 8, pk_file);
1906 putc(w, pk_file);
1907 }
1908
1909 static void
putmed(long w)1910 putmed(long w)
1911 {
1912 putc(w >> 16, pk_file);
1913 putc(w >> 8, pk_file);
1914 putc(w, pk_file);
1915 }
1916
1917 static void
putlong(long w)1918 putlong(long w)
1919 {
1920 putc(w >> 24, pk_file);
1921 putc(w >> 16, pk_file);
1922 putc(w >> 8, pk_file);
1923 putc(w, pk_file);
1924 }
1925
1926 static void
putglyph(int cc)1927 putglyph(int cc)
1928 {
1929 static Boolean have_first_line = False;
1930 static int llx, lly, urx, ury;
1931 static float char_width;
1932 static byte *area1 = NULL;
1933 static unsigned int size1 = 0;
1934 static int i;
1935 long dm;
1936 long tfm_wid;
1937 byte *p;
1938
1939 if (!quiet) {
1940 int wid;
1941 static const char *s = "";
1942
1943 wid = (cc >= 100) + (cc >= 10) + 4;
1944 if (col + wid > 80) {
1945 s = "\n";
1946 col = 0;
1947 }
1948 printf("%s[%d", s, cc);
1949 fflush(stdout);
1950 col += wid;
1951 s = " ";
1952 }
1953 if (!have_first_line) {
1954 expect("#^");
1955 if (sscanf(line, "#^ %d %d %d %d %d %f\n", &i,
1956 &llx, &lly, &urx, &ury, &char_width) != 6)
1957 oops("Cannot scanf first line");
1958 }
1959 if (i < cc) oops("Character %d received, %d expected", i, cc);
1960 if (i > cc) {
1961 fprintf(stderr, "Character %d is missing.\n", cc);
1962 have_first_line = True;
1963 return;
1964 }
1965 have_first_line = False;
1966 hoff = -llx + 2;
1967 voff = ury + 2 - 1;
1968 expect("P4\n");
1969 whitespace();
1970 width = getint();
1971 whitespace();
1972 height = getint();
1973 (void) data_getc();
1974 if (width != urx - llx + 4 || height != ury - lly + 4)
1975 oops("Dimensions do not match: %d %d %d %d %d %d",
1976 llx, lly, urx, ury, width, height);
1977 bytes_wide = (width + 7) / 8;
1978 bm_size = bytes_wide * height;
1979 if (size1 < bm_size) {
1980 if (area1 != NULL) free(area1);
1981 area1 = xmalloc(bm_size);
1982 size1 = bm_size;
1983 }
1984 for (p = area1 + (height - 1) * bytes_wide; p >= area1; p -= bytes_wide)
1985 if (data_read(p, bytes_wide) != bytes_wide)
1986 oops("Cannot read bitmap of size %u", bm_size);
1987 bitmap = area1;
1988 bitmap_end = bitmap + bm_size;
1989 trim_bitmap();
1990 if (height == 0 || !pk_rll_cvt()) pk_bm_cvt();
1991 tfm_wid = tfm_widths[width_index[cc]];
1992 dm = (long) (char_width + 0.5) - (char_width < -0.5);
1993 if (pk_len + 8 < 4 * 256 && tfm_wid < (1<<24) &&
1994 dm >= 0 && dm < 256 && width < 256 && height < 256 &&
1995 hoff >= -128 && hoff < 128 && voff >= -128 && voff < 128) {
1996 putc(flag | ((pk_len + 8) >> 8), pk_file);
1997 putc(pk_len + 8, pk_file);
1998 putc(cc, pk_file);
1999 putmed(tfm_wid);
2000 putc(dm, pk_file);
2001 putc(width, pk_file);
2002 putc(height, pk_file);
2003 putc(hoff, pk_file);
2004 putc(voff, pk_file);
2005 } else
2006 if (pk_len + 13 < 3 * 65536L && tfm_wid < (1<<24) &&
2007 dm >= 0 && dm < 65536L && width < 65536L && height < 65536L &&
2008 hoff >= -65536L && hoff < 65536L &&
2009 voff >= -65536L && voff < 65536L) {
2010 putc(flag | 4 | ((pk_len + 13) >> 16), pk_file);
2011 putshort(pk_len + 13);
2012 putc(cc, pk_file);
2013 putmed(tfm_wid);
2014 putshort(dm);
2015 putshort(width);
2016 putshort(height);
2017 putshort(hoff);
2018 putshort(voff);
2019 }
2020 else {
2021 putc(flag | 7, pk_file);
2022 putlong(pk_len + 28);
2023 putlong(cc);
2024 putlong(tfm_wid);
2025 putlong((long) (char_width * 65536.0 + 0.5) - (char_width < -0.5));
2026 putlong(0);
2027 putlong(width);
2028 putlong(height);
2029 putlong(hoff);
2030 putlong(voff);
2031 }
2032 fwrite(bitmap, 1, pk_len, pk_file);
2033 if (!quiet) {
2034 putchar(']');
2035 fflush(stdout);
2036 }
2037 }
2038
2039 static void
putspecl(const char * str1,const char * str2)2040 putspecl(const char *str1, const char *str2)
2041 {
2042 int len1 = strlen(str1);
2043 int len2 = 0;
2044
2045 if (str2 != NULL) len2 = strlen(str2);
2046 if (len1 + len2 > 255) return;
2047 putc(PK_SPC, pk_file);
2048 putc(len1 + len2, pk_file);
2049 fwrite(str1, 1, len1, pk_file);
2050 if (len2 != 0) fwrite(str2, 1, len2, pk_file);
2051 }
2052
2053 int
main(int argc,char ** argv)2054 main(int argc, char **argv)
2055 {
2056 FILE *config_file;
2057 FILE *render_ps;
2058 FILE *tfm_file;
2059 char **argp;
2060 float dpi;
2061 const char *dvipsrc;
2062 char *p;
2063 char *PSname = NULL;
2064 char *specinf = NULL;
2065 char *specp = NULL; /* NULL pacifies lint */
2066 char charlist[10*2 + 90*3 + 156*4 + 1];
2067 char designstr[20];
2068 char dpistr[20];
2069 #if HAVE_SIGACTION
2070 struct sigaction sigact;
2071 #endif
2072 #if _AMIGA
2073 char fngs[50];
2074 char fngsf[50];
2075 char tfm_path[256];
2076 BPTR in, out;
2077 #else
2078 char *substarg;
2079 #endif
2080 #if WIN32
2081 DWORD idGsThread;
2082 SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
2083 #else /* not WIN32 */
2084 #if !_AMIGA
2085 int std_out[2];
2086 #endif
2087 int std_in[2];
2088 #endif /* not WIN32 */
2089 int cc;
2090 int ppp;
2091 int i;
2092
2093 argp = argv;
2094 while (++argp < argv + argc && (*argp)[0] == '-') {
2095 const struct option *opt_ptr;
2096 const struct option *opt;
2097 char *arg = *argp + 1;
2098
2099 if (*arg == '\0') --arg; /* this will flag an error later */
2100 if (*arg != '-') { /* if short argument */
2101 opt = options;
2102 for (;;) {
2103 if (*arg == opt->shortname)
2104 break;
2105 if (++opt >= options + NUMBER(options))
2106 opt_oops("invalid option -- %c", *arg);
2107 }
2108 if (opt->has_arg) {
2109 ++arg;
2110 if (*arg == '\0') {
2111 if (++argp >= argv + argc)
2112 opt_oops("option requires an argument -- %c",
2113 arg[-1]);
2114 arg = *argp;
2115 }
2116 }
2117 else {
2118 if (arg[1] != '\0')
2119 opt_oops("invalid number of bytes in option `%s'",
2120 arg - 1);
2121 }
2122 }
2123 else { /* long argument */
2124 int len;
2125 char *arg1;
2126
2127 ++arg;
2128 if (*arg == '\0') { /* if -- */
2129 ++argp;
2130 break;
2131 }
2132 len = strlen(arg);
2133 arg1 = memchr(arg, '=', len);
2134 if (arg1 != NULL) {
2135 len = arg1 - arg;
2136 ++arg1;
2137 }
2138 opt = NULL;
2139 for (opt_ptr = options; opt_ptr < options + NUMBER(options);
2140 ++opt_ptr)
2141 if (memcmp(arg, opt_ptr->longname, len) == 0) {
2142 if (opt != NULL)
2143 opt_oops("option `%s' is ambiguous.", arg - 2);
2144 opt = opt_ptr;
2145 }
2146 if (opt == NULL)
2147 opt_oops("unrecognized option `%s'", arg - 2);
2148 if (opt->has_arg) {
2149 if (arg1 == NULL) {
2150 if (++argp >= argv + argc)
2151 opt_oops("option `--%s' requires an argument.",
2152 opt->longname);
2153 arg1 = *argp;
2154 }
2155 }
2156 else {
2157 if (arg1 != NULL)
2158 opt_oops("option `--%s' doesn't allow an argument.",
2159 opt->longname);
2160 }
2161 arg = arg1;
2162 } /* end long argument */
2163
2164 if (opt->addr != NULL) {
2165 if (opt->has_arg)
2166 *((char **) opt->addr) = arg;
2167 else
2168 *((Boolean *) opt->addr) = opt->value;
2169 }
2170
2171 switch (opt->shortname) {
2172 #if defined(KPATHSEA) && defined (KPSE_DEBUG)
2173 case OPT_DBG:
2174 kpathsea_debug |= atoi(arg);
2175 break;
2176 #endif
2177 case 'h':
2178 #ifndef KPATHSEA
2179 puts("\
2180 Usage: gsftopk [OPTION] FONT DPI\n\
2181 Translate the PostScript Type 1 font FONT to PK bitmap format at DPI dpi.\n\
2182 \n\
2183 -t, --test check for presence of font in .map file.\n\
2184 --mapline=LINE use LINE as the line from the .map file.\n\
2185 --mapfile=FILE use FILE as a .map file; default psfonts.map.\n\
2186 -i GS, --interpreter=GS use GS as Ghostscript interpreter.\n\
2187 --dosnames short pk filename (cmr10.pk instead of cmr10.600pk).\n\
2188 -q, --quiet don't print progress information to standard output.\n\
2189 -h, --help print this message and exit.\n\
2190 -v, --version print version number and exit.\n");
2191 #else
2192 puts("\
2193 Usage: gsftopk [OPTION] FONT DPI\n\
2194 Translate the PostScript Type 1 font FONT to PK bitmap format at DPI dpi.\n\
2195 \n\
2196 -t, --test check for presence of font in .map file.\n\
2197 --mapline=LINE use LINE as the line from the .map file.\n\
2198 --mapfile=FILE use FILE as a .map file; default psfonts.map.\n\
2199 -i GS, --interpreter=GS use GS as Ghostscript interpreter.\n\
2200 --dosnames short pk filename (cmr10.pk instead of cmr10.600pk).\n\
2201 -q, --quiet don't print progress information to standard output.\n\
2202 --debug=NUM set debugging flags.\n\
2203 -h, --help print this message and exit.\n\
2204 -v, --version print version number and exit.\n");
2205 #endif
2206 return 0;
2207 case 'v':
2208 #ifndef KPATHSEA
2209 printf("gsftopk %s\n", version);
2210 #else
2211 {
2212 printf("gsftopk(k) %s\n", version);
2213 puts(kpathsea_version_string);
2214 puts("Copyright (C) 1993-1998 Paul Vojta.\n\
2215 There is NO warranty. You may redistribute this software\n\
2216 under the terms of the GNU General Public License\n\
2217 and the standard X consortium copyright notice.\n\
2218 For more information about these matters, see the files\n\
2219 named COPYING and gsftopk.c.\n\
2220 Author of gsftopk: Paul Vojta.");
2221 }
2222 #endif
2223 return 0;
2224 }
2225 }
2226
2227 if (mapfile != NULL && mapline != NULL)
2228 opt_oops("cannot specify both `--mapline' and `--mapfile'");
2229
2230 if (argp >= argv + argc)
2231 opt_oops(test ? "must provide a font name"
2232 : "must provide a font name and resolution");
2233
2234 fontname = *argp++;
2235 fontlen = strlen(fontname);
2236
2237 if (argp >= argv + argc) {
2238 if (!test)
2239 opt_oops("must provide rendering resolution");
2240 dpi = 0.0;
2241 }
2242 else {
2243 dpi = atof(*argp++);
2244 if (dpi <= 0.0)
2245 opt_oops("DPI argument `%s' must be a positive number", *argp);
2246 }
2247
2248 if (argp < argv + argc)
2249 opt_oops("no more than two arguments are allowed");
2250
2251 #ifdef KPATHSEA
2252 #ifdef WIN32
2253 setmode(fileno(stdout), _O_BINARY);
2254 #endif
2255 kpse_set_program_name(argv[0], "gsftopk");
2256 kpse_init_prog("GSFTOPK", (int) (dpi + 0.5), NULL, "cmr10");
2257 if (!test)
2258 xputenv_int("KPATHSEA_DPI", (int) (dpi + 0.5));
2259
2260 #if defined(WIN32)
2261 /* TeXLive uses its own Ghostscript */
2262 texlive_gs_init();
2263 #endif
2264
2265 #endif
2266
2267 #if _AMIGA
2268 /* [CL] 21-Jun-97
2269 This is quite silly but it really helps things when determining the
2270 font supplier and family.
2271 */
2272 putenv("GSFTOPKTFM=");
2273 #endif
2274
2275 /*
2276 * Read the dvips-style config file(s).
2277 */
2278
2279 long_line = xmalloc(long_line_len); /* initialize fgets_long */
2280
2281 #ifndef KPATHSEA
2282 config_file = search(CONFIGPATH, "TEXCONFIG", "config.ps");
2283 if (config_file != NULL)
2284 getdefaults(config_file);
2285
2286 dvipsrc = getenv("DVIPSRC");
2287 if (dvipsrc == NULL) {
2288 dvipsrc = getenv("HOME");
2289 if (dvipsrc != NULL) {
2290 i = strlen(dvipsrc);
2291 p = xmalloc(i + 10);
2292 memcpy(p, dvipsrc, i);
2293 memcpy(p + i, "/.dvipsrc", 10);
2294 }
2295 }
2296 if (dvipsrc != NULL) {
2297 config_file = fopen(dvipsrc, "r");
2298 if (config_file != NULL)
2299 getdefaults(config_file);
2300 }
2301
2302 config_file = search(CONFIGPATH, "TEXCONFIG", "config.gsftopk");
2303 if (config_file != NULL)
2304 getdefaults(config_file);
2305 #else
2306 getdefaults("config.ps");
2307
2308 dvipsrc = kpse_var_value("DVIPSRC");
2309 getdefaults(dvipsrc != NULL ? dvipsrc : "$HOME/.dvipsrc");
2310
2311 getdefaults("config.gsftopk");
2312
2313 /* Set HEADERPATH from config file. */
2314
2315 if (config_file_header_path != NULL)
2316 kpse_format_info[kpse_tex_ps_header_format].client_path
2317 = config_file_header_path;
2318 #endif
2319
2320 /*
2321 * Get the map line.
2322 */
2323
2324 if (mapline != NULL) {
2325 if (memcmp(mapline, fontname, fontlen) != 0
2326 || (mapline[fontlen] != '\0' && !isspace((unsigned char)mapline[fontlen])))
2327 oops("font name does not match --mapline argument");
2328 }
2329 else {
2330 Boolean font_found;
2331
2332 if (mapfile != NULL) {
2333 #ifndef KPATHSEA
2334 config_file = search(CONFIGPATH, "TEXCONFIG",
2335 mapfile);
2336 #else
2337 config_file = kpse_open_file(mapfile,
2338 kpse_fontmap_format);
2339 #endif
2340
2341 if (config_file == NULL) {
2342 perror(mapfile);
2343 exit(1);
2344 }
2345 font_found = scan_map_file(config_file);
2346 }
2347 else {
2348 struct p_list *p_node;
2349
2350 font_found = False;
2351 *p_tail = NULL;
2352 for (p_node = p_head; p_node != NULL; p_node = p_node->next) {
2353 #ifndef KPATHSEA
2354 config_file = search(CONFIGPATH, "TEXCONFIG",
2355 p_node->value);
2356 #else
2357 config_file = kpse_open_file(p_node->value,
2358 kpse_fontmap_format);
2359 #endif
2360 if (config_file != NULL)
2361 if (scan_map_file(config_file)) {
2362 font_found = True;
2363 break;
2364 }
2365 }
2366 }
2367
2368 if (!font_found) {
2369 if (test)
2370 exit(1);
2371 else
2372 oops("Cannot find font %s in map file(s).", fontname);
2373 }
2374
2375 mapline = long_line;
2376 }
2377
2378 if (test)
2379 exit(0);
2380
2381 if (!quiet) {
2382 printf("%sversion %s", progname, version);
2383 fflush(stdout);
2384 col = 1; /* any nonzero value will do */
2385 }
2386
2387 /*
2388 * Parse the line from the map file.
2389 */
2390 for (p = mapline + fontlen; *p != '\0'; ++p) {
2391 if (isspace((unsigned char)*p)) continue;
2392 if (*p == '<') {
2393 char *q;
2394 char endc;
2395 char c;
2396 FILE *f;
2397
2398 ++p;
2399 /* There may be two '<'s in front of the filename. */
2400 if (*p == '<') ++p;
2401 /* ... and maybe a '[' */
2402 if (*p == '[') ++p;
2403 q = p;
2404 while (*p != '\0' && !isspace((unsigned char)*p)) ++p;
2405 endc = *p;
2406 *p = '\0';
2407 #ifdef KPATHSEA
2408 searchpath = kpse_find_file(q, kpse_tex_ps_header_format,true);
2409 f = searchpath ? fopen(searchpath, FOPEN_R_MODE) : NULL;
2410 #else
2411 f = search(config_file_header_path, "DVIPSHEADERS", q);
2412 #endif
2413 if (f == NULL) oops("Cannot find font file %s", q);
2414 /* search() also sets searchpath */
2415 addtodls(" (");
2416 addtodls(searchpath);
2417 c = getc(f);
2418 addtodls(c == '\0' ? ") ttload"
2419 : c == '\200' ? ") brun"
2420 : ") run");
2421 fclose(f);
2422 if (endc == '\0') break;
2423 continue;
2424 }
2425 else if (*p == '"') {
2426 char *q;
2427
2428 if (specinf != NULL)
2429 *specp++ = ' ';
2430 else
2431 specinf = specp = xmalloc(strlen(p));
2432 ++p;
2433 q = strchr(p, '"');
2434 if (q == NULL) q = p + strlen(p);
2435 memcpy(specp, p, q - p);
2436 specp += q - p;
2437 p = q;
2438 if (*p == '\0') break;
2439 else continue;
2440 }
2441 else {
2442 PSname = p;
2443 while (*p != '\0' && !isspace((unsigned char)*p)) ++p;
2444 if (*p == '\0') break;
2445 }
2446 *p = '\0';
2447 }
2448
2449 #if OLD_DVIPS
2450 /* Parse lines like `Symbol-Slanted "/Symbol .167 SlantFont"'. */
2451 if (*(p = specinf) == '/') {
2452 PSname = ++p;
2453 while (*p && !isspace(*p)) ++p;
2454 if (*p) *p++ = '\0';
2455 specinf = p;
2456 }
2457 #endif /* OLD_DVIPS */
2458
2459 if (specinf != NULL) {
2460 *specp = '\0';
2461 specinfo = specinf;
2462 }
2463
2464 if (PSname == NULL)
2465 PSname = fontname;
2466
2467 /*
2468 * Start up Ghostscript.
2469 */
2470
2471 #ifdef KPATHSEA
2472 searchpath = kpse_find_file("render.ps", kpse_tex_ps_header_format,
2473 true);
2474 render_ps = searchpath ? fopen (searchpath, FOPEN_R_MODE) : NULL;
2475 #else
2476 render_ps = search(config_file_header_path, "DVIPSHEADERS",
2477 "render.ps");
2478 #endif
2479 if (render_ps == NULL)
2480 oops("Cannot find PS driver file \"render.ps\".");
2481 fclose(render_ps);
2482
2483 #if !_AMIGA
2484 substarg = xmalloc(strlen(PSname) + 13);
2485 sprintf(substarg, "-sSUBSTFONT=%s", PSname);
2486 #endif
2487
2488 sprintf(dpistr, "%f", dpi);
2489
2490 #if _AMIGA
2491
2492 mktemp(tmpname);
2493
2494 sprintf(fngs, "fifo:%s/rweK", tmpname);
2495 sprintf(fngsf, "fifo:%s/rweKm", tmpname);
2496
2497 std_in[1] = open(fngsf, O_WRONLY|O_TRUNC|O_CREAT, 511);
2498
2499 if (std_in[1] == -1) {
2500 perror("pipe");
2501 return 1;
2502 }
2503
2504 in = Open(fngs, MODE_OLDFILE);
2505 out = Open(fngs, MODE_NEWFILE);
2506
2507 if (in && out) {
2508 int error;
2509 char *cmd;
2510 char formatstr[] = "%s -dNODISPLAY -dNOGC -sSUBSTFONT=\"%s\" -q -- \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"";
2511 unsigned int len;
2512
2513 len = sizeof formatstr + strlen(gspath) + strlen(searchpath)
2514 + 2 * strlen(PSname) + (dlstring != NULL ? strlen(dlstring) : 0)
2515 + strlen(specinfo) + strlen(dpistr);
2516
2517 cmd = xmalloc(len);
2518
2519 sprintf(cmd, formatstr, PSname, gspath, searchpath, PSname,
2520 dlstring != NULL ? dlstring : "", specinfo, dpistr);
2521
2522 error = SystemTags(cmd, SYS_Input, in,
2523 SYS_Output, out,
2524 SYS_Asynch, TRUE,
2525 /* NP_StackSize, 50000, */
2526 TAG_DONE, TAG_DONE);
2527 free(cmd);
2528
2529 if (error == -1) {
2530 Close(in);
2531 Close(out);
2532 PrintFault(error, "System(gs)");
2533 exit(1);
2534 }
2535 }
2536 else {
2537 perror("pipes");
2538 if (in) Close(in);
2539 if (out) Close(out);
2540 exit(1);
2541 }
2542
2543 #elif WIN32
2544
2545 /* (later) */
2546
2547 #else /* neither _AMIGA nor WIN32 */
2548
2549 if (pipe(std_in) != 0 || pipe(std_out) != 0) {
2550 perror("pipe");
2551 return 1;
2552 }
2553
2554 /* Catch the signal for death of the child process. */
2555
2556 #if HAVE_SIGACTION
2557 sigact.sa_handler = handle_sigchild;
2558 (void) sigemptyset(&sigact.sa_mask);
2559 sigact.sa_flags = SA_NOCLDSTOP;
2560 (void) sigaction(SIGCHLD, &sigact, (struct sigaction *) NULL);
2561 #else
2562 (void) signal(SIGCHLD, handle_sigchild);
2563 #endif
2564
2565 /*
2566 * Also catch various termination signals, so that we can kill the
2567 * gs process before terminating.
2568 */
2569
2570 (void) signal(SIGHUP, handle_sigterm);
2571 (void) signal(SIGINT, handle_sigterm);
2572 (void) signal(SIGQUIT, handle_sigterm);
2573 (void) signal(SIGTERM, handle_sigterm);
2574
2575 fflush(stderr); /* to avoid double flushing */
2576 gs_pid = vfork();
2577 if (gs_pid == 0) {
2578 close(std_in[1]);
2579 dup2(std_in[0], 0);
2580 close(std_in[0]);
2581 close(std_out[0]);
2582 dup2(std_out[1], 1);
2583 close(std_out[1]);
2584 execlp(gspath, "gs", "-dNODISPLAY", "-dNOGC", substarg, "-q", "--",
2585 /* render.ps */ searchpath,
2586 PSname,
2587 dlstring != NULL ? dlstring : "", specinfo, dpistr, NULL);
2588 if (col != 0) {
2589 putc('\n', stderr);
2590 col = 0;
2591 }
2592 perror(gspath);
2593 exit(1);
2594 }
2595 if (gs_pid == -1) {
2596 perror("fork");
2597 exit(1);
2598 }
2599
2600 #endif /* neither _AMIGA nor WIN32 */
2601
2602 /*
2603 * Open and read the tfm file. If this takes a while, at least
2604 * it can overlap with the startup of Ghostscript.
2605 */
2606
2607 xfilename = xmalloc(fontlen + 10);
2608 strcpy(xfilename, fontname);
2609 #ifdef KPATHSEA
2610 #if _AMIGA
2611 strcpy(tfm_path, kpse_find_file(xfilename, kpse_tfm_format, true));
2612 tfm_file = fopen(tfm_path, "r");
2613 #else
2614 tfm_file = kpse_open_file(xfilename, kpse_tfm_format);
2615 #endif /* _AMIGA */
2616 #else /* not KPATHSEA */
2617 strcpy(xfilename + fontlen, ".tfm");
2618 tfm_file = search(TFMPATH, "TEXFONTS", xfilename);
2619 #endif /* not KPATHSEA */
2620 if (tfm_file == NULL) oops("Cannot find tfm file.");
2621
2622 for (i = 0; i < 12; ++i) {
2623 int j;
2624
2625 j = (int) ((byte) getc(tfm_file)) << 8;
2626 tfm_lengths[i] = j | (int) ((byte) getc(tfm_file));
2627 }
2628 checksum = getlong(tfm_file);
2629 design = getlong(tfm_file);
2630 fseek(tfm_file, 4 * (lh + 6), 0);
2631 p = charlist;
2632 for (cc = bc; cc <= ec; ++cc) {
2633 width_index[cc] = (byte) getc(tfm_file);
2634 if (width_index[cc] != 0) {
2635 sprintf(p, "%d ", cc);
2636 p += strlen(p);
2637 }
2638 (void) getc(tfm_file);
2639 (void) getc(tfm_file);
2640 (void) getc(tfm_file);
2641 }
2642 for (i = 0; i < nw; ++i) tfm_widths[i] = getlong(tfm_file);
2643 fclose(tfm_file);
2644 p[-1] = '\n';
2645
2646 sprintf(designstr, "%f\n", (float) design / (1 << 20));
2647
2648 #if !WIN32
2649
2650 /* write the design size and character list to the file */
2651 write(std_in[1], designstr, strlen(designstr));
2652 write(std_in[1], charlist, p - charlist);
2653
2654 close(std_in[1]);
2655
2656 #else /* WIN32 */
2657 SetConsoleCtrlHandler(handle_sigterm, TRUE);
2658
2659 hGsDataIn = CreateEvent(&sa, FALSE, FALSE, "gsDataIn");
2660 hGsDataOut = CreateEvent(&sa, FALSE, FALSE, "gsDataOut");
2661
2662 gs_argv[3] = substarg;
2663 gs_argv[6] = searchpath;
2664 gs_argv[7] = PSname;
2665 gs_argv[8] = dlstring != NULL ? dlstring : "";
2666 gs_argv[9] = specinfo;
2667 gs_argv[10] = dpistr;
2668
2669 buffer_stdin = concat(designstr, charlist);
2670
2671 if ((hGsThread = CreateThread(&sa, /* security attributes */
2672 0, /* default stack size */
2673 Win32GsSendData, /* start address of thread */
2674 0, /* parameter */
2675 0, /* creation flags */
2676 &idGsThread /* thread id */
2677 )) == NULL)
2678 Win32Error("CreateThread");
2679
2680 #endif /* WIN32 */
2681
2682 /*
2683 * Read the output from Ghostscript.
2684 */
2685
2686 #if _AMIGA
2687
2688 if ((data_file = fopen(fngsf, "r")) == NULL) {
2689 perror("GS_out");
2690 exit(1);
2691 }
2692
2693 #elif WIN32
2694
2695 /* Nothing */
2696
2697 #else /* neither _AMIGA nor WIN32 */
2698
2699 data_fd = std_out[0];
2700
2701 /* Set data_fd for non-blocking I/O */
2702 if (fcntl(data_fd, F_SETFL, fcntl(data_fd, F_GETFL, 0) | O_NONBLOCK)
2703 == -1)
2704 perror("fcntl");
2705
2706 #endif /* neither _AMIGA nor WIN32 */
2707
2708 /*
2709 * Create pk file and write preamble.
2710 */
2711
2712 if (dosnames)
2713 strcpy(xfilename + fontlen, ".pk");
2714 else
2715 sprintf(xfilename + fontlen, ".%dpk", (int) (dpi + 0.5));
2716
2717 if ((pk_file = fopen(xfilename, FOPEN_WBIN_MODE)) == NULL) {
2718 perror(xfilename);
2719 exit_toto_too();
2720 }
2721 putc(PK_PRE, pk_file);
2722 putc(PK_ID, pk_file);
2723 expect("V"); /* get GS version */
2724 i = strlen(line) - 2;
2725 if (i < 0 || i > 10) i = 0;
2726 line[1] = '/';
2727 if (!quiet) {
2728 if (i > 0) fwrite(line + 1, 1, i, stdout);
2729 putchar('\n');
2730 col = 0;
2731 }
2732 putc(sizeof(progname) + sizeof(version) + i - 2, pk_file);
2733 fwrite(progname, 1, sizeof(progname) - 1, pk_file);
2734 fwrite(version, 1, sizeof(version) - 1, pk_file);
2735 if (i >= 0) {
2736 fwrite(line + 1, 1, i, pk_file);
2737 }
2738 putlong(design);
2739 putlong(checksum);
2740 ppp = dpi / 72.27 * 65536.0 + 0.5;
2741 putlong(ppp); /* hppp */
2742 putlong(ppp); /* vppp */
2743
2744 /*
2745 * Write the actual characters.
2746 */
2747
2748 for (cc = bc; cc <= ec; ++cc)
2749 if (width_index[cc] != 0)
2750 putglyph(cc);
2751
2752 #if _AMIGA
2753
2754 fclose(data_file);
2755
2756 #elif WIN32
2757
2758 /* Release data buffer, enable thread to terminate */
2759 SetEvent(hGsDataOut);
2760
2761 #ifdef DEBUG
2762 fprintf(stderr, "Waiting for thread ... \n");
2763 #endif
2764 if (hGsThread) {
2765 switch (WaitForSingleObject(hGsThread, 2000)) {
2766 case WAIT_OBJECT_0:
2767 CloseHandle(hGsThread);
2768 hGsThread = NULL;
2769 break;
2770 case WAIT_TIMEOUT:
2771 fprintf(stderr, "Timeout waiting for Gs thread.\n");
2772 break;
2773 case WAIT_FAILED:
2774 fprintf(stderr, "WaitForSingleObject failed on Gs thread (Error code %d).\n",
2775 (int)GetLastError());
2776 break;
2777 default:
2778 break;
2779 }
2780 }
2781
2782 if (hGsThread) {
2783 if (TerminateThread(hGsThread, 1) == 0) {
2784 fprintf(stderr, "... couldn't terminate gs thread\n");
2785 }
2786 CloseHandle(hGsThread);
2787 /* FIXME : is it right to call this ? */
2788 gs_dll_release();
2789 }
2790 if (hGsDataIn)
2791 CloseHandle(hGsDataIn);
2792 if (hGsDataOut)
2793 CloseHandle(hGsDataOut);
2794
2795 #else /* neither _AMIGA nor WIN32 */
2796
2797 close(data_fd);
2798 if (!gs_is_done)
2799 wait_for_gs();
2800
2801 #endif /* neither _AMIGA nor WIN32 */
2802
2803 /*
2804 * Write out identifying specials:
2805 * jobname=(font)
2806 * mag=1
2807 * mode=modeless
2808 * pixels_per_inch=(dpi)
2809 */
2810
2811 putspecl("jobname=", fontname);
2812 putspecl("mag=1", NULL);
2813 putspecl("mode=modeless", NULL);
2814 sprintf(dpistr, "%d", (int) dpi);
2815 putspecl("pixels_per_inch=", dpistr);
2816
2817 /*
2818 * Postamble
2819 */
2820
2821 putc(PK_POST, pk_file);
2822 while (ftell(pk_file) % 4 != 0) putc(PK_NOP, pk_file);
2823 fclose(pk_file);
2824 if (!quiet) putchar('\n');
2825 col = 0;
2826
2827 #if _AMIGA
2828 /* [CL] 21-Jun-97
2829 The same silly thing to indicate the path of the tfm file
2830 */
2831 {
2832 char tmpstr[80];
2833
2834 sprintf(tmpstr, "GSFTOPKTFM=%s", tfm_path);
2835 putenv(tmpstr);
2836 }
2837 #endif
2838
2839 return 0;
2840 }
2841