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