Back to index

tetex-bin  3.0
gsftopk.c
Go to the documentation of this file.
00001 /*========================================================================*\
00002 
00003 Copyright (c) 1993-2000  Paul Vojta
00004 
00005 Permission is hereby granted, free of charge, to any person obtaining a copy
00006 of this software and associated documentation files (the "Software"), to
00007 deal in the Software without restriction, including without limitation the
00008 rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
00009 sell copies of the Software, and to permit persons to whom the Software is
00010 furnished to do so, subject to the following conditions:
00011 
00012 The above copyright notice and this permission notice shall be included in
00013 all copies or substantial portions of the Software.
00014 
00015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00016 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00017 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
00018 PAUL VOJTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
00019 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00020 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00021 
00022 \*========================================================================*/
00023 
00024 #if !lint
00025 static char   copyright[] =
00026 "@(#) Copyright (c) 1993-1998 Paul Vojta.\n";
00027 #endif
00028 
00029 /*
00030  *     Reference for PK file format:
00031  *
00032  *     Tomas Rokicki, Packed (PK) font file format, TUGBoat 6 (1985) 115-120.
00033  */
00034 
00035 /*
00036  * Kpathsea version by Thomas Esser, John Interrante, Yves Arrouye, Karl Berry.
00037  */
00038 
00039 #include "version.h"
00040 
00041 #ifndef KPATHSEA
00042 
00043 #include "config.h"
00044 
00045 /* Some O/S dependent kludges.  */
00046 #if _AIX
00047 #define _ALL_SOURCE 1
00048 #endif
00049 
00050 #if __hpux
00051 #define _HPUX_SOURCE 1
00052 #endif
00053 
00054 #if STDC_HEADERS
00055 # include <stdlib.h>
00056 # include <string.h>
00057 #else
00058 # if !HAVE_STRCHR
00059 #  define strchr index
00060 #  define strrchr rindex
00061 # endif
00062 char *strchr(), *strrchr();
00063 # if !HAVE_MEMCPY
00064 #  define memcpy(d, s, n)   bcopy((s), (d), (n))
00065 #  define memmove(d, s, n)  bcopy((s), (d), (n))
00066 #  define memcmp(s1, s2, n) bcmp((s1), (s2), (n))
00067 # endif
00068 #endif
00069 
00070 #if HAVE_UNISTD_H
00071 #include <unistd.h>
00072 #endif
00073 
00074 #include <stdio.h>
00075 #include <ctype.h>
00076 #include <memory.h>
00077 #include <sys/types.h>
00078 #include <sys/stat.h>
00079 #include <setjmp.h>
00080 #include <signal.h>
00081 #include <fcntl.h>
00082 
00083 #include <errno.h>
00084 #ifndef errno
00085 extern int    errno;
00086 #endif
00087 
00088 #if HAVE_DIRENT_H
00089 # include <dirent.h>
00090 # define NAMLEN(dirent) strlen((dirent)->d_name)
00091 #else
00092 # define dirent direct
00093 # define NAMLEN(dirent) (dirent)->d_namlen
00094 # if HAVE_SYS_NDIR_H
00095 #  include <sys/ndir.h>
00096 # endif
00097 # if HAVE_SYS_DIR_H
00098 #  include <sys/dir.h>
00099 # endif
00100 # if HAVE_NDIR_H
00101 #  include <ndir.h>
00102 # endif
00103 #endif
00104 
00105 #if TIME_WITH_SYS_TIME
00106 # include <sys/time.h>
00107 # include <time.h>
00108 #else
00109 # if HAVE_SYS_TIME_H
00110 #  include <sys/time.h>
00111 # else
00112 #  include <time.h>
00113 # endif
00114 #endif
00115 
00116 #ifndef atof
00117 double atof();
00118 #endif
00119 char   *getenv();
00120 
00121 /* <sys/types.h> is already included.  */
00122 #if HAVE_SYS_WAIT_H
00123 #include <sys/wait.h>
00124 #endif
00125 
00126 #ifndef WIFSTOPPED
00127 #define       WIFSTOPPED(stat_val) (((stat_val) & 0377) == 0177)
00128 #endif
00129 
00130 #ifndef WIFSIGNALED
00131 #define       WIFSIGNALED(stat_val)       (((stat_val) & 0377) != 0)
00132 #endif
00133 
00134 #ifndef WTERMSIG
00135 #define       WTERMSIG(stat_val)   ((stat_val) & 0177)
00136 #endif
00137 
00138 #ifndef WEXITSTATUS
00139 #define WEXITSTATUS(stat_val)      ((unsigned)(stat_val) >> 8)
00140 #endif
00141 
00142 #ifndef SIGCHLD
00143 #define       SIGCHLD       SIGCLD
00144 #endif
00145 
00146 /* How to open a text file for reading:  */
00147 #ifndef FOPEN_R_MODE
00148 #define       FOPEN_R_MODE  "r"
00149 #endif
00150 
00151 /* How to open a binary file for reading:  */
00152 #ifndef FOPEN_RBIN_MODE
00153 #if DOS
00154 #define       FOPEN_RBIN_MODE "r+b"
00155 #elif VMS || VMCMS || OS2 || WIN32
00156 #define       FOPEN_RBIN_MODE      "rb"
00157 #else
00158 #define       FOPEN_RBIN_MODE      "r"
00159 #endif
00160 #endif /* undef FOPEN_RBIN_MODE */
00161 
00162 /* How to open a binary file for writing:  */
00163 #ifndef FOPEN_WBIN_MODE
00164 #if DOS
00165 #define       FOPEN_WBIN_MODE "w+b"
00166 #elif OS2 || WIN32
00167 #define       FOPEN_WBIN_MODE "wb"
00168 #elif VMCMS
00169 #define       FOPEN_WBIN_MODE "wb, lrecl=1024, recfm=f"
00170 #else
00171 #define       FOPEN_WBIN_MODE      "w"
00172 #endif
00173 #endif /* undef FOPEN_WBIN_MODE */
00174 
00175 
00176 /* These macros munge function declarations to make them work in both
00177    cases.  The P?H macros are used for declarations, the P?C for
00178    definitions.  Cf. <ansidecl.h> from the GNU C library.  P1H(void)
00179    also works for definitions of routines which take no args.  */
00180 
00181 #if __STDC__
00182 
00183 #define       AA(args) args /* For an arbitrary number; ARGS must be in parens.  */
00184 
00185 #define       P1H(p1) (p1)
00186 
00187 #define       P1C(t1,n1)(t1 n1)
00188 #define       P2C(t1,n1, t2,n2)(t1 n1, t2 n2)
00189 #define       P3C(t1,n1, t2,n2, t3,n3)(t1 n1, t2 n2, t3 n3)
00190 #define       P4C(t1,n1, t2,n2, t3,n3, t4,n4)(t1 n1, t2 n2, t3 n3, t4 n4)
00191 #define       P5C(t1,n1, t2,n2, t3,n3, t4,n4, t5,n5) \
00192   (t1 n1, t2 n2, t3 n3, t4 n4, t5 n5)
00193 #define       P6C(t1,n1, t2,n2, t3,n3, t4,n4, t5,n5, t6,n6) \
00194   (t1 n1, t2 n2, t3 n3, t4 n4, t5 n5, t6 n6)
00195 #define       P7C(t1,n1, t2,n2, t3,n3, t4,n4, t5,n5, t6,n6, t7,n7) \
00196   (t1 n1, t2 n2, t3 n3, t4 n4, t5 n5, t6 n6, t7 n7)
00197 
00198 #else /* not __STDC__ */
00199 
00200 #define       AA(args) ()
00201 
00202 #define       P1H(p1) ()
00203 
00204 #define       P1C(t1,n1) (n1) t1 n1;
00205 #define       P2C(t1,n1, t2,n2) (n1,n2) t1 n1; t2 n2;
00206 #define       P3C(t1,n1, t2,n2, t3,n3) (n1,n2,n3) t1 n1; t2 n2; t3 n3;
00207 #define       P4C(t1,n1, t2,n2, t3,n3, t4,n4) (n1,n2,n3,n4) \
00208   t1 n1; t2 n2; t3 n3; t4 n4;
00209 #define       P5C(t1,n1, t2,n2, t3,n3, t4,n4, t5,n5) (n1,n2,n3,n4,n5) \
00210   t1 n1; t2 n2; t3 n3; t4 n4; t5 n5;
00211 #define       P6C(t1,n1, t2,n2, t3,n3, t4,n4, t5,n5, t6,n6) (n1,n2,n3,n4,n5,n6) \
00212   t1 n1; t2 n2; t3 n3; t4 n4; t5 n5; t6 n6;
00213 #define       P7C(t1,n1, t2,n2, t3,n3, t4,n4, t5,n5, t6,n6, t7,n7) \
00214   (n1,n2,n3,n4,n5,n6,n7) \
00215   t1 n1; t2 n2; t3 n3; t4 n4; t5 n5; t6 n6; t7 n7;
00216 #define       const  /* nothing */
00217 
00218 #endif /* not __STDC__ */
00219 
00220 #else /* KPATHSEA */
00221 
00222 #include <kpathsea/config.h>
00223 #include <kpathsea/c-errno.h>
00224 #include <kpathsea/c-ctype.h>
00225 #include <kpathsea/c-fopen.h>
00226 #include <kpathsea/c-pathmx.h>
00227 #include <kpathsea/proginit.h>
00228 #include <kpathsea/tex-file.h>
00229 #include <kpathsea/tex-make.h>
00230 #include <kpathsea/variable.h>
00231 #include <c-auto.h>
00232 #include <signal.h>
00233 #include <fcntl.h>
00234 #include <setjmp.h>
00235 
00236 #if TIME_WITH_SYS_TIME
00237 # include <sys/time.h>
00238 # include <time.h>
00239 #else
00240 # if HAVE_SYS_TIME_H
00241 #  include <sys/time.h>
00242 # else
00243 #  include <time.h>
00244 # endif
00245 #endif
00246 
00247 #if !HAVE_STRCHR
00248 #define       strchr index
00249 #endif
00250 
00251 #if !HAVE_STRRCHR
00252 #define       strrchr       rindex
00253 #endif
00254 
00255 #if HAVE_POLL && !HAVE_POLL_H
00256 #undef HAVE_POLL
00257 #endif
00258 
00259 /* Add two new flags to kpathsea_debug for debugging gsftopk */
00260 #define       GSPK_DEBUG_BITMAP    (KPSE_LAST_DEBUG + 1)
00261 #define       GSPK_DEBUG_PK        (KPSE_LAST_DEBUG + 2)
00262 
00263 /* <sys/types.h> is already included:  <kpathsea/config.h>
00264      --> <kpathsea/c-std.h> --> <kpathsea/c-unistd.h>
00265      --> <kpathsea/systypes.h> --> <sys/types.h>.  */
00266 #if HAVE_SYS_WAIT_H
00267 # include <sys/wait.h>
00268 #endif
00269 
00270 #if WIN32
00271 
00272 #include <win32lib.h>
00273 #include <gs32lib.h>
00274 #include <gsdll.h>
00275 HANDLE hGsThread = NULL;
00276 HANDLE hGsDataIn = 0, hGsDataOut = 0; /* Events to synchronize threads */
00277 /* Arguments to gs dll */
00278 char *gs_argv[] = { "gswin32c.exe",              /* 0, */
00279                   "-dNOGC",               /* 1, */
00280                   "-dNODISPLAY",          /* 2, */
00281                   NULL,                   /* 3, substarg */
00282                   "-q",                   /* 4, */
00283                   "--",                   /* 5, */
00284                   NULL,                   /* 6, searchpath */
00285                   NULL,                   /* 7, PSname */
00286                   NULL,            /* 8, dlstring != NULL ? dlstring : "" */
00287                   NULL,                   /* 9, specinfo */
00288                   NULL,                   /* 10, dpistr */
00289                   NULL                    /* 11, NULL terminator */
00290   };
00291 int gs_argc = 11;
00292 
00293 char *buffer_stdin; /* This is the buffer from where data are taken. */
00294 
00295 #else /* not WIN32 */
00296 
00297 #ifndef WEXITSTATUS
00298 #define WEXITSTATUS(stat_val)      ((unsigned)(stat_val) >> 8)
00299 #endif
00300 
00301 #ifndef WIFSTOPPED
00302 #define       WIFSTOPPED(stat_val) (((stat_val) & 0377) == 0177)
00303 #endif
00304 
00305 #ifndef WIFSIGNALED
00306 #define       WIFSIGNALED(stat_val)       (((stat_val) & 0377) != 0)
00307 #endif
00308 
00309 #ifndef WTERMSIG
00310 #define       WTERMSIG(stat_val)   ((stat_val) & 0177)
00311 #endif
00312 
00313 #endif /* not WIN32 */
00314 
00315 #endif /* KPATHSEA */
00316 
00317 #if HAVE_POLL
00318 # include <poll.h>
00319 #else
00320 # if HAVE_SYS_SELECT_H
00321 #  include <sys/select.h>
00322 # else
00323 #  if HAVE_SELECT_H
00324 #   include <select.h>
00325 #  endif
00326 # endif
00327 #endif
00328 
00329 #if HAVE_VFORK_H
00330 #include <vfork.h>
00331 #endif
00332 
00333 #if _AMIGA
00334 #include <proto/dos.h>
00335 #include <dos/dostags.h>
00336 #endif
00337 
00338 #define       NUMBER(x)     (sizeof (x) / sizeof *(x))
00339 
00340 /* if POSIX O_NONBLOCK is not available, use O_NDELAY */
00341 #if !defined(O_NONBLOCK) && defined(O_NDELAY)
00342 #define       O_NONBLOCK    O_NDELAY
00343 #endif
00344 
00345 #ifndef S_ISDIR
00346 #if defined(S_IFMT) && defined(S_IFDIR)
00347 #define       S_ISDIR(m)    (((m) & S_IFMT) == S_IFDIR)
00348 #endif
00349 #endif
00350 
00351 #ifndef GS_PATH
00352 #define       GS_PATH       "gs"
00353 #endif
00354 
00355 #if __GNUC__
00356 #define       NORETURN      volatile
00357 #else
00358 #define       NORETURN      /* nothing */
00359 #endif
00360 
00361 #if STDC_HEADERS && __STDC__
00362 #define       NeedVarargsPrototypes       1
00363 #include <stdarg.h>
00364 #else /* no prototypes */
00365 #define       NeedVarargsPrototypes       0
00366 #include <varargs.h>
00367 #endif /* no prototypes */
00368 
00369 typedef       char   Boolean;
00370 #define       True   1
00371 #define       False  0
00372 
00373 #ifndef NeedWidePrototypes
00374 #if __STDC__
00375 #define       NeedWidePrototypes   1
00376 #else
00377 #define       NeedWidePrototypes   0
00378 #endif
00379 #endif /* NeedWidePrototypes */
00380 
00381 #if NeedWidePrototypes
00382 typedef       int           wide_bool;
00383 #else
00384 typedef       Boolean              wide_bool;
00385 #endif
00386 
00387 #ifndef MAXPATHLEN
00388 #define       MAXPATHLEN    256
00389 #endif
00390 
00391 #define       PK_PRE (char) 247
00392 #define       PK_ID  (char) 89
00393 #define       PK_SPC (char) 240
00394 #define       PK_POST       (char) 245
00395 #define       PK_NOP (char) 246
00396 
00397 #ifndef KPATHSEA
00398 char   progname[]    = "gsftopk ";
00399 #else
00400 char   progname[]    = "gsftopk(k) ";
00401 #endif
00402 
00403 char   version[]     = VERSION;
00404 
00405 /*
00406  *     Command line arguments
00407  */
00408 
00409 #define              OPT_DBG              0x101
00410 
00411 Boolean              test          = False;
00412 char          *fontname;
00413 int           fontlen;
00414 char          *mapline      = NULL;
00415 const char    *mapfile      = NULL;
00416 const char    *gspath              = GS_PATH;    /* gs interpreter path */
00417 Boolean              dosnames      = False;
00418 Boolean              quiet         = False;
00419 
00420 struct option {
00421        const char    *longname;
00422        short         shortname;
00423        Boolean              has_arg;
00424        void          *addr;
00425        int           value;
00426 };
00427 
00428 static const struct option  options[]     = {
00429               {"test",      't',   False, &test, True},
00430               {"mapline",   0,     True,  &mapline, 0},
00431               {"mapfile",   0,     True,  &mapfile, 0},
00432               {"interpreter",      'i',   True,  &gspath, 0},
00433               {"dosnames",  0,     False, &dosnames, True},
00434               {"quiet",     'q',   False, &quiet,       True},
00435 #ifdef KPATHSEA
00436               {"debug",     OPT_DBG,True, NULL,  0},
00437 #endif
00438               {"version",   'v',   False, NULL,  0},
00439               {"help",      'h',   False, NULL,  0}};
00440 
00441 FILE          *pk_file      = NULL;
00442 char          *xfilename;
00443 int           col           = 0;          /* current column number */
00444 const char    *specinfo     = "";
00445 pid_t         gs_pid        = 0;
00446 
00447 /*
00448  *     Config file options
00449  */
00450 
00451 #ifndef KPATHSEA                          /* 'H' option */
00452 const char    *config_file_header_path    = HEADERPATH;
00453 #else
00454 const char    *config_file_header_path    = NULL;
00455 #endif
00456 
00457 struct p_list {                                  /* list of 'p' options */
00458        struct p_list *next;
00459        const char    *value;
00460 };
00461 
00462        /* Initialize this list to "psfonts.map".  */
00463 
00464 struct p_list psfonts_map          = {NULL, "psfonts.map"};
00465 
00466 struct p_list *p_head                     = &psfonts_map;
00467 struct p_list **p_tail             = &psfonts_map.next;
00468 
00469 /*
00470  *     Reading from the pipe from ghostscript
00471  */
00472 
00473 Boolean              data_eof      = False;
00474 
00475 #if !_AMIGA
00476 
00477 #define              BUFSIZE              512
00478 
00479 typedef       unsigned char byte;
00480 
00481 int           data_fd;
00482 byte          buffer[BUFSIZE];
00483 byte          *data_out     = buffer;
00484 byte          *data_end     = buffer;
00485 
00486 #else /* _AMIGA */
00487 
00488 FILE          *data_file;
00489 
00490 /* This string will be used to open pipes in and out */
00491 char   tmpname[]     = "gsftopkXXXXXX";
00492 
00493 #endif /* _AMIGA */
00494 
00495 /*
00496  *     Information from the .tfm file.
00497  */
00498 
00499 int           tfm_lengths[12];
00500 #define       lh     tfm_lengths[1]
00501 #define       bc     tfm_lengths[2]
00502 #define       ec     tfm_lengths[3]
00503 #define       nw     tfm_lengths[4]
00504 
00505 long          checksum;
00506 long          design;
00507 byte          width_index[256];
00508 long          tfm_widths[256];
00509 
00510 /*
00511  *     Information on the bitmap currently being worked on.
00512  */
00513 
00514 byte          *bitmap;
00515 int           width;
00516 int           skip;
00517 int           height;
00518 int           hoff;
00519 int           voff;
00520 int           bytes_wide;
00521 unsigned int  bm_size;
00522 byte          *bitmap_end;
00523 int           pk_len;
00524 
00525 
00526 #if !_AMIGA
00527 
00528 /*
00529  *     Exit, and kill the child process, too.
00530  */
00531 
00532 NORETURN void
00533 exit_toto_too P1H(void)
00534 {
00535 #if !WIN32
00536        if (gs_pid != 0)
00537            kill(gs_pid, SIGKILL);
00538 #else
00539        if (hGsThread) {
00540          switch (WaitForSingleObject(hGsThread, 2000)) {
00541          case WAIT_OBJECT_0:
00542            CloseHandle(hGsThread);
00543            hGsThread = NULL;
00544            break;
00545          case WAIT_TIMEOUT:
00546            fprintf(stderr, "Timeout waiting for Gs thread.\n");
00547            break;
00548          case WAIT_FAILED:
00549            fprintf(stderr, "WaitForSingleObject failed on Gs thread (Error code %d).\n",
00550                   GetLastError());
00551            break;
00552          default:
00553            break;
00554          }
00555 
00556          if (hGsThread) {
00557            if (TerminateThread(hGsThread, 1) == 0) {
00558              fprintf(stderr, "... couldn't terminate gs thread\n");
00559            }
00560            CloseHandle(hGsThread);
00561            /* FIXME : is it right to call this ? */
00562            gs_dll_release();
00563          }      
00564        }
00565 
00566        if (hGsDataIn)
00567          CloseHandle(hGsDataIn);
00568        if (hGsDataOut)
00569          CloseHandle(hGsDataOut);
00570 
00571 #endif
00572        if (pk_file != NULL) {
00573            fclose(pk_file);
00574            if (unlink(xfilename) != 0) perror("unlink");
00575        }
00576 
00577        _exit(1);
00578 }
00579 
00580 #else /* _AMIGA */
00581 
00582 #define       exit_toto_too()      exit(1)
00583 
00584 #endif /* _AMIGA */
00585 
00586 /*
00587  *     Print error message and quit.
00588  */
00589 
00590 #if NeedVarargsPrototypes
00591 NORETURN void
00592 oops(const char *message, ...)
00593 #else
00594 /* VARARGS */
00595 NORETURN void
00596 oops(va_alist)
00597        va_dcl
00598 #endif
00599 {
00600 #if !NeedVarargsPrototypes
00601        const char *message;
00602 #endif
00603        va_list       args;
00604 
00605 #if NeedVarargsPrototypes
00606        va_start(args, message);
00607 #else
00608        va_start(args);
00609        message = va_arg(args, const char *);
00610 #endif
00611        if (col != 0) putchar('\n');
00612        vfprintf(stderr, message, args);
00613        va_end(args);
00614        putc('\n', stderr);
00615        exit_toto_too();
00616 }
00617 
00618 
00619 /*
00620  *     Same as oops, but with arguments.
00621  */
00622 #if NeedVarargsPrototypes
00623 NORETURN void
00624 opt_oops(const char *message, ...)
00625 #else
00626 /* VARARGS */
00627 NORETURN void
00628 opt_oops(va_alist)
00629        va_dcl
00630 #endif
00631 {
00632 #if !NeedVarargsPrototypes
00633        const char *message;
00634 #endif
00635        va_list       args;
00636 
00637 #if NeedVarargsPrototypes
00638        va_start(args, message);
00639 #else
00640        va_start(args);
00641        message = va_arg(args, const char *);
00642 #endif
00643        fputs("gsftopk: ", stderr);
00644        vfprintf(stderr, message, args);
00645        va_end(args);
00646        fputs("\nTry `gsftopk --help' for more information.\n", stderr);
00647        exit(1);
00648 }
00649 
00650 
00651 #ifndef KPATHSEA
00652 
00653 /*
00654  *     Either allocate storage or fail.
00655  */
00656 
00657 static void *
00658 xmalloc P1C(unsigned, size)
00659 {
00660        void *mem = (void *) malloc(size);
00661 
00662        if (mem == NULL)
00663            oops("gsftopk: Cannot allocate %u bytes.\n", size);
00664        return mem;
00665 }
00666 
00667 
00668 /*
00669  *     Either reallocate storage or fail.
00670  */
00671 
00672 static void *
00673 xrealloc P2C(char *, oldp, unsigned, size)
00674 {
00675        void   *mem;
00676 
00677        mem = oldp == NULL ? (void *) malloc(size)
00678            : (void *) realloc(oldp, size);
00679        if (mem == NULL)
00680            oops("gsftopk: Cannot reallocate %u bytes.\n", size);
00681        return mem;
00682 }
00683 
00684 #endif /* not KPATHSEA */
00685 
00686 
00687 /*
00688  *     Get a single white-space-delimited argument (or fail).
00689  */
00690 
00691 char *
00692 get_one_arg P1C(const char *, src)
00693 {
00694        char          *dest;
00695        const char    *p;
00696        unsigned int  len;
00697 
00698        len = strlen(src);
00699        p = memchr(src, ' ', len);
00700        if (p != NULL) len = p - src;
00701        p = memchr(src, '\t', len);
00702        if (p != NULL) len = p - src;
00703 
00704        dest = xmalloc(len + 1);
00705        memcpy(dest, src, len);
00706        dest[len] = '\0';
00707 
00708        return dest;
00709 }
00710 
00711 #if !_AMIGA
00712 
00713 /*
00714  *     Signal handlers.
00715  */
00716 
00717 static Boolean       got_sigchld   = False;
00718 
00719 #if WIN32
00720 
00721 BOOL WINAPI
00722 handle_sigterm(DWORD dwCtrlType)
00723 {
00724 
00725        /*
00726         *     Fix me:  There is a problem if a system() command is running.
00727         *     We should wait for the child process to be interrupted.
00728         *     Only way I can think of to do that : rewrite system() based on
00729         *     spawn() with parsing of the command line and set a global pid
00730         *     Next cwait(pid) in the HandlerRoutine.
00731         */
00732 
00733        switch (dwCtrlType) {
00734            case CTRL_C_EVENT:
00735            case CTRL_BREAK_EVENT:
00736               fprintf(stderr, "...exiting\n");
00737               exit_toto_too();
00738               return FALSE;
00739            default:
00740               fprintf(stderr, "... not exiting\n");
00741               return TRUE;
00742         }
00743 }
00744 
00745 #else /* not WIN32 */
00746 
00747 /* ARGSUSED */
00748 static RETSIGTYPE
00749 handle_sigchild P1C(int, signo)
00750 {
00751        got_sigchld = True;
00752 }
00753 
00754 /* ARGSUSED */
00755 static RETSIGTYPE
00756 handle_sigterm P1C(int, signo)
00757 {
00758        exit_toto_too();
00759 }
00760 
00761 #endif /* WIN32 */
00762 
00763 #define       gs_is_done    (gs_pid == 0)
00764 
00765 typedef       int           gsf_wait_t;
00766 
00767 #if WIN32
00768 
00769 /* This is the callback function for gs. It is mainly used to read and
00770   write  data on   gs   stdin/stdout. Data exchanges   happen  through
00771   buffers.  */
00772 int __cdecl
00773 gsdll_callback(int message, char *str, unsigned long count)
00774 {
00775   int n;
00776   static char **pin = &buffer_stdin; /* not yet allocated, so used a pointer on it. */
00777 
00778   switch (message) {
00779 
00780   case GSDLL_STDIN:
00781     /* Put count chars on gs stdin */
00782 #if DEBUG
00783     fprintf(stderr, "gs wants %d chars\n", count);
00784 #endif
00785     strncpy(str, *pin, count);
00786     *pin += count;
00787     return strlen(str);
00788 
00789   case GSDLL_STDOUT:
00790     /* Fill the buffer in, wait for gsftopk to ask for data. */
00791     WaitForSingleObject(hGsDataOut, INFINITE);
00792 #if DEBUG
00793     fprintf(stderr, "gs gives %d chars\n", count);
00794 #endif
00795     data_out = buffer;
00796 
00797     n = (count >= BUFSIZE ? BUFSIZE : count);
00798     memcpy(data_out, str, n);
00799     data_end = data_out + n;
00800     /* Tell data_fillbuf() that data are available */
00801     if (SetEvent(hGsDataIn) == FALSE)
00802       Win32Error("gsdll_callback/SetEvent");
00803     /* return the number of chars read */
00804     return n;
00805 
00806   case GSDLL_DEVICE:
00807 #if DEBUG
00808     fprintf(stdout,"Callback: DEVICE %p %s\n", str,
00809            count ? "open" : "close");
00810 #endif
00811     break;
00812 
00813   case GSDLL_SYNC:
00814 #if DEBUG
00815     fprintf(stdout,"Callback: SYNC %p\n", str);
00816 #endif
00817     break;
00818 
00819   case GSDLL_PAGE:
00820     fprintf(stdout,"Callback: PAGE %p\n", str);
00821     break;
00822 
00823   case GSDLL_SIZE:
00824 #if DEBUG
00825     fprintf(stdout,"Callback: SIZE %p width=%d height=%d\n", str,
00826            (int)(count & 0xffff), (int)((count>>16) & 0xffff) );
00827 #endif
00828     break;
00829 
00830   case GSDLL_POLL:
00831 #if 0
00832     fprintf(stderr, "GS: Poll sent (%d)!\n", 0);
00833 #endif
00834     return 0; /* no error ? */
00835   default:
00836     fprintf(stdout,"%s: gs callback: unknown message=%d\n",progname, message);
00837     break;
00838   }
00839   return 0;
00840 }
00841 
00842 /*
00843   This is the thread function that will load the gs dll and
00844   send it the data.
00845 */
00846 DWORD WINAPI Win32GsSendData(LPVOID lpParam)
00847 {
00848   int ret;
00849 
00850   gs_dll_initialize();
00851 
00852   ret = (*pgsdll_init)(gsdll_callback,
00853                      NULL,
00854                      gs_argc,
00855                      gs_argv);
00856 
00857   switch (ret) {
00858   case 0:
00859     /* Should not happen : gs should quit
00860        right after being initialized. */
00861     (*pgsdll_exit)();
00862     /* FIXME: this is working, but we could expect something cleaner ! */
00863     /*  GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0); */
00864     break;
00865   case GSDLL_INIT_QUIT:
00866     break;
00867   default:
00868     (*pgsdll_exit)();
00869     break;
00870   }
00871 #if DEBUG  
00872   fprintf(stderr, "%s: gsdll_init returned %d\n", progname, ret);
00873 #endif
00874   WaitForSingleObject(hGsDataOut, INFINITE);
00875   data_eof = True;
00876   data_end = data_out;
00877   /* Tell data_fillbuf() */
00878   SetEvent(hGsDataIn);
00879 
00880   gs_dll_release();
00881 
00882   return 0;
00883 }
00884 
00885 #else /* not WIN32 */
00886 
00887 static void
00888 wait_for_gs P1H(void)
00889 {
00890        gsf_wait_t    status;
00891 
00892 #if _AMIGA
00893 
00894        /* Do nothing */
00895 
00896 #else /* not _AMIGA */
00897 
00898        got_sigchld = False;
00899 
00900        for (;;) {
00901            if (wait(&status) != -1) break;
00902            /* if (errno == EINTR) continue; */
00903            if (errno != EINTR) {
00904               perror("wait");
00905               exit_toto_too();
00906            }
00907        }
00908 
00909        if (WIFSTOPPED(status))
00910            return;
00911 
00912        gs_pid = 0;
00913 
00914        if (WIFSIGNALED(status))
00915            oops("gs died due to signal %d\n", WTERMSIG(status));
00916 
00917        /* otherwise, it exited */
00918        if (WEXITSTATUS(status) != 0)
00919            oops("gs terminated abnormally with status %d\n",
00920              WEXITSTATUS(status));
00921 
00922 #endif /* not _AMIGA */
00923 
00924 }
00925 
00926 #endif /* not WIN32 */
00927 
00928 #endif /* not _AMIGA */
00929 
00930 /*
00931  *     Routines to read from the data file.
00932  */
00933 
00934 #if _AMIGA
00935 
00936 #define       data_getc()   getc(data_file)
00937 #define       data_ungetc(c)       ungetc(c, data_file)
00938 #define       data_read(p, l)      fread(p, 1, l, data_file)
00939 
00940 #else /* not _AMIGA */
00941 
00942 #if WIN32
00943 
00944 static void
00945 data_fillbuf P1H(void)
00946 {
00947   if (data_eof)
00948     return;
00949 
00950   /* wait until data are available. First tell gs it can fill the buffer in. */
00951   SetEvent(hGsDataOut);
00952   /* wait for the data. */
00953   switch (WaitForSingleObject(hGsDataIn, INFINITE)) {
00954   case WAIT_OBJECT_0:
00955     /* normal case */
00956     break;
00957   case WAIT_TIMEOUT:
00958     /* should not happen */
00959     fprintf(stderr, "Gs did not return on time from callback.\n");
00960     break;
00961   case WAIT_FAILED:
00962     break;
00963   default:
00964     fprintf(stderr, "WaitForSingleObject failed for unknown reason.\n");
00965   }
00966 }
00967 
00968 #else /* not WIN32 */
00969 
00970 #if HAVE_POLL
00971 #define       ISSET(a, b)          (poll_fd.revents & POLLIN != 0)
00972 #else
00973 #define       ISSET(a, b)          FD_ISSET(a, b)
00974 #endif
00975 
00976 static void
00977 data_fillbuf P1H(void)
00978 {
00979        int                  n;
00980 
00981 #if HAVE_POLL
00982        static struct pollfd poll_fd       = {0, POLLIN, 0};
00983 #else
00984        fd_set               read_fds;
00985        struct timeval              timeout;
00986 #endif
00987 
00988        if (data_eof)
00989            return;
00990 
00991        /* wait for readable data */
00992        if (!gs_is_done) {
00993            for (;;) {
00994               if (!got_sigchld) {
00995 #if HAVE_POLL
00996                   poll_fd.fd = data_fd;
00997                   poll_fd.revents = 0;
00998                   if (poll(&poll_fd, 1, 5000) == -1) {
00999                      if (errno != EINTR) {
01000                          perror("poll");
01001                          sleep(4);
01002                      }
01003                      continue;
01004                   }
01005 #else
01006                   FD_ZERO(&read_fds);
01007                   FD_SET(data_fd, &read_fds);
01008                   timeout.tv_sec = 5;
01009                   timeout.tv_usec = 0;
01010                   if (select(data_fd + 1, &read_fds, (fd_set *) NULL,
01011                     (fd_set *) NULL, &timeout) == -1) {
01012                      if (errno != EINTR) {
01013                          perror("select");
01014                          sleep(4);
01015                      }
01016                      continue;
01017                   }
01018 #endif
01019               }
01020               if (got_sigchld) {
01021                   wait_for_gs();
01022                   break;
01023               }
01024               if (ISSET(data_fd, &read_fds))
01025                   break;
01026            }
01027        }
01028 
01029        /* read the data */
01030        for (;;) {
01031            n = read(data_fd, (void *) (data_out = buffer), BUFSIZE);
01032            if (n >= 0)
01033               break;
01034            if (errno == EINTR)
01035               continue;
01036            if (gs_is_done && errno == EAGAIN) {
01037               n = 0;
01038               break;
01039            }
01040            perror("read from gs");
01041            sleep(4);
01042        }
01043 
01044        data_end = data_out + n;
01045        if (n == 0)
01046            data_eof = True;
01047 }
01048 
01049 #endif /* not WIN32 */
01050 
01051 static byte
01052 data_fgetc P1H(void)
01053 {
01054        if (data_out >= data_end)
01055            data_fillbuf();
01056 
01057        return data_eof ? EOF : *data_out++;
01058 }
01059 
01060 #define       data_getc()   (data_out < data_end ? *data_out++ : data_fgetc())
01061 
01062 static void
01063 data_ungetc P1C(byte, c)
01064 {
01065        if (data_out <= buffer)
01066            oops("Too many calls to data_ungetc()");
01067 
01068        *--data_out = c;
01069 }
01070 
01071 static int
01072 data_read P2C(byte *, buf, int, n)
01073 {
01074        byte   *buf1  = buf;
01075        byte   *buf_end = buf + n;
01076        int    n1;
01077 
01078        if (buf1 >= buf_end)
01079            return 0;
01080 
01081        while (!data_eof) {
01082            n1 = buf_end - buf1;
01083            if (n1 > data_end - data_out)
01084               n1 = data_end - data_out;
01085            memcpy(buf1, data_out, n1);
01086            buf1 += n1;
01087            data_out += n1;
01088            if (buf1 >= buf_end) break;
01089            data_fillbuf();
01090        }
01091 
01092        return buf1 - buf;
01093 }
01094 
01095 static void
01096 data_gets P2C(byte *, buf, int, n)
01097 {
01098        byte   *buf1  = buf;
01099        byte   *buf_end = buf + n - 1;
01100        int    n1;
01101        byte   *p1;
01102 
01103        if (n <= 0)
01104            return;
01105 
01106        for (;;) {
01107            if (data_eof)
01108               oops("Premature end of file");
01109            n1 = buf_end - buf1;
01110            if (n1 > data_end - data_out)
01111               n1 = data_end - data_out;
01112            p1 = (byte *) memchr((char *) data_out, '\n', n1);
01113            if (p1 != NULL)
01114               n1 = p1 + 1 - data_out;
01115            memcpy((char *) buf1, (char *) data_out, n1);
01116            buf1 += n1;
01117            data_out += n1;
01118            if (p1 != NULL || buf1 >= buf_end) break;
01119            data_fillbuf();
01120        }
01121 
01122        *buf1 = '\0';
01123 
01124        return;
01125 }
01126 
01127 #endif /* not _AMIGA */
01128 
01129 /*
01130  *     Here's the patch searching stuff.  First the typedefs and variables.
01131  */
01132 
01133 #ifndef KPATHSEA
01134 static char   searchpath[MAXPATHLEN + 1];
01135 #else
01136 static char   *searchpath;
01137 #endif
01138 
01139 #define       HUNKSIZE      (MAXPATHLEN + 2)
01140 
01141 struct spacenode {   /* used for storage of directory names */
01142        struct spacenode     *next;
01143        char                 *sp_end;      /* end of data for this chunk */
01144        char                 sp[HUNKSIZE];
01145 }
01146        firstnode;
01147 
01148 #ifndef KPATHSEA
01149 
01150 static jmp_buf              found_env;
01151 static FILE          *searchfile;
01152 static const char    *searchname;
01153 static int           searchnamelen;
01154 
01155 static const char *
01156 find_dbl_slash P2C(const char *, sp_bgn, const char *, sp_end)
01157 {
01158        const char    *p;
01159 
01160        for (;;) {
01161            p = memchr(sp_bgn, '/', sp_end - sp_bgn);
01162            if (p == NULL) return sp_end;
01163            if (p[1] == '/') return p;
01164            sp_bgn = p + 1;
01165        }
01166 }
01167 
01168 static void
01169 main_search_proc P7C(char *, matpos, const char *, sp_pos,
01170        const char *, sp_slash, const char *, sp_end,
01171        wide_bool, skip_subdirs, struct spacenode *, space, char *, spacenext)
01172 {
01173        char          *mp;
01174        struct stat   statbuf;
01175        DIR           *dir;
01176        struct dirent *entry;
01177        int           lenleft;
01178        int           len;
01179        struct spacenode *space1;
01180        char          *spacenext1;
01181 
01182        mp = matpos + (sp_slash - sp_pos);
01183        /* check length */
01184        if (mp + searchnamelen >= searchpath + sizeof(searchpath) - 2) return;
01185        memcpy(matpos, sp_pos, sp_slash - sp_pos);
01186        if (sp_slash == sp_end) {   /* try for a file */
01187            *mp = '/';
01188            strcpy(mp + (mp == searchpath || mp[-1] != '/'), searchname);
01189            searchfile = fopen(searchpath, "r");
01190            if (searchfile != NULL) longjmp(found_env, True);
01191        }
01192        else {/* try for a subdirectory */
01193            *mp = '\0';
01194            if (stat(searchpath, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) {
01195               *mp++ = '/';
01196               main_search_proc(mp, sp_slash + 2,
01197                   find_dbl_slash(sp_slash + 2, sp_end), sp_end,
01198                   statbuf.st_nlink <= 2, space, spacenext);
01199            }
01200        }
01201        if (skip_subdirs) return;
01202        *matpos = '\0';
01203        dir = opendir(searchpath);
01204        if (dir == NULL) return;
01205        lenleft = searchpath + sizeof(searchpath) - matpos;
01206        space1 = space;
01207        spacenext1 = spacenext;
01208        for (;;) {
01209            entry = readdir(dir);
01210            if (entry == NULL) break;
01211            len = NAMLEN(entry) + 1;
01212            if (len > lenleft) continue;   /* too long */
01213            strcpy(matpos, entry->d_name);
01214            if (*matpos == '.' && (matpos[1] == '\0' || (matpos[1] == '.'
01215                   && matpos[2] == '\0')))
01216               continue;            /* ignore . and .. */
01217            if (stat(searchpath, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
01218               continue;            /* if not a directory */
01219            if (statbuf.st_nlink > 2) ++len;
01220            if (spacenext1 + len > space1->sp + HUNKSIZE) {
01221               space1->sp_end = spacenext1;
01222               if (space1->next == NULL) {
01223                   space1->next = xmalloc(sizeof(struct spacenode));
01224                   space1->next->next = NULL;
01225               }
01226               space1 = space1->next;
01227               spacenext1 = space1->sp;
01228            }
01229            if (statbuf.st_nlink > 2) {
01230               *spacenext1++ = '/';
01231               --len;
01232            }
01233            memcpy(spacenext1, entry->d_name, len - 1);
01234            spacenext1[len - 1] = '\0';
01235            spacenext1 += len;
01236        }
01237        closedir(dir);
01238        for (;;) {
01239            space1->sp_end = spacenext1;
01240            if (spacenext == space->sp_end) {
01241               if (space == space1) break;
01242               space = space->next;
01243               spacenext = space->sp;
01244            }
01245            skip_subdirs = True;
01246            if (*spacenext == '/') {
01247               ++spacenext;
01248               skip_subdirs = False;
01249            }
01250            len = strlen(spacenext);
01251            memcpy(matpos, spacenext, len);
01252            matpos[len] = '/';
01253            main_search_proc(matpos + len + 1, sp_pos, sp_slash, sp_end,
01254               skip_subdirs, space1, spacenext1);
01255            spacenext += len + 1;
01256        }
01257 }
01258 
01259 static FILE *
01260 search P3C(const char *, path, const char *, path_var, const char *, name)
01261 {
01262        const char    *env_path     = NULL;
01263        FILE          *f;
01264 
01265        if (path_var != NULL) {
01266            if (*name == '/') {
01267               strcpy(searchpath, name);
01268               return fopen(searchpath, "r");
01269            }
01270            env_path = getenv(path_var);
01271        }
01272        if (env_path == NULL) {
01273            env_path = path;
01274            path = NULL;
01275        }
01276        searchname = name;
01277        searchnamelen = strlen(name);
01278        for (;;) {
01279            const char *p;
01280 
01281            p = strchr(env_path, ':');
01282            if (p == NULL) p = env_path + strlen(env_path);
01283            if (p == env_path) {
01284               if (path != NULL) {
01285                   f = search(path, (char *) NULL, name);
01286                   if (f != NULL) return f;
01287               }
01288            }
01289            else {
01290               if (setjmp(found_env))
01291                   return searchfile;
01292               main_search_proc(searchpath,
01293                   env_path, find_dbl_slash(env_path, p), p,
01294                   True, &firstnode, firstnode.sp);
01295            }
01296            if (*p == '\0') return NULL;
01297            env_path = p + 1;
01298        }
01299 }
01300 
01301 #endif /* not KPATHSEA */
01302 
01303 /*
01304  *     Reading configuration and map files.
01305  */
01306 
01307 char   *long_line           = NULL;       /* for reading config and map files */
01308 int    long_line_len        = 82;  /* allocated length of the above */
01309 
01310 Boolean
01311 fgets_long P1C(FILE *, f)
01312 {
01313        int    len;
01314 
01315        if (fgets(long_line, long_line_len, f) == NULL)
01316            return False;
01317 
01318        len = 0;
01319        for (;;) {
01320            len += strlen(long_line + len);
01321            if (len > 0 && long_line[len - 1] == '\n') {
01322               long_line[--len] = '\0';
01323               break;
01324            }
01325            if (len < long_line_len - 1)
01326               break;
01327            long_line_len += 80;
01328            long_line = xrealloc(long_line, long_line_len);
01329            fgets(long_line + len, long_line_len - len, f);
01330        }
01331 
01332        return True;
01333 }
01334 
01335 
01336 void
01337 #ifndef KPATHSEA
01338 getdefaults P1C(FILE *, f)
01339 #else
01340 getdefaults P1C(const char *, name)
01341 #endif
01342 {
01343 #ifdef KPATHSEA
01344        FILE          *f;
01345 #endif
01346        char          *p;
01347        char          c;
01348        struct p_list *p_node;
01349 
01350 #ifdef KPATHSEA
01351        p = kpse_find_file(name, kpse_dvips_config_format, false);
01352        if (p == NULL)
01353            return;
01354 
01355        f = fopen(p, FOPEN_R_MODE);
01356        if (f == NULL)
01357            return;
01358 #endif
01359 
01360        while (fgets_long(f)) {
01361            p = long_line;
01362            while (*p == ' ' || *p == '\t') ++p;
01363            c = *p;
01364            if (c == '\0')
01365               continue;
01366            do ++p;
01367            while (*p == ' ' || *p == '\t');
01368            switch (c) {
01369               case 'H':
01370                   config_file_header_path = get_one_arg(p);
01371                   break;
01372 
01373               case 'p':
01374                   if (*p == '+')
01375                      do ++p;
01376                      while (*p == ' ' || *p == '\t');
01377                   else
01378                      p_tail = &p_head;    /* discard old list */
01379 
01380                   p_node = xmalloc(sizeof *p_node);
01381                   p_node->value = get_one_arg(p);
01382                   *p_tail = p_node;
01383                   p_tail = &p_node->next;
01384                   break;
01385            }
01386        }
01387 
01388        fclose(f);
01389 }
01390 
01391 
01392 Boolean
01393 scan_map_file P1C(FILE *, f)
01394 {
01395        while (fgets_long(f))
01396            if (memcmp(long_line, fontname, fontlen) == 0
01397              && (long_line[fontlen] == '\0' || isspace(long_line[fontlen]))) {
01398               fclose(f);
01399               return True;
01400            }
01401 
01402        fclose(f);
01403        return False;
01404 }
01405 
01406 
01407 /*
01408  *     Add to dlstring
01409  */
01410 
01411 char          *dlstring     = NULL;
01412 unsigned int  dls_len              = 0;
01413 unsigned int  dls_max              = 0;
01414 
01415 void
01416 addtodls P1C(const char *, s)
01417 {
01418        int    len    = strlen(s);
01419 
01420        if (dls_len + len >= dls_max) {
01421            unsigned int newsize = dls_max + 80;
01422 
01423            if (newsize <= dls_len + len) newsize = dls_len + len + 1;
01424            dlstring = xrealloc(dlstring, dls_max = newsize);
01425        }
01426        strcpy(dlstring + dls_len, s);
01427        dls_len += len;
01428 }
01429 
01430 
01431 
01432 long
01433 getlong P1C(FILE *, f)
01434 {
01435        int    value;
01436 
01437        value = (int) ((byte) getc(f)) << 24;
01438        value |= (int) ((byte) getc(f)) << 16;
01439        value |= (int) ((byte) getc(f)) << 8;
01440        value |= (int) ((byte) getc(f));
01441        return value;
01442 }
01443 
01444 
01445 char   line[82];
01446 
01447 void
01448 expect P1C(const char *, waitingfor)
01449 {
01450        for (;;) {
01451 #if !_AMIGA
01452            data_gets((byte *) line, sizeof(line));
01453 #else
01454            if (fgets(line, sizeof(line), data_file) == NULL)
01455               oops("Premature end of file");
01456 #endif
01457            if (memcmp(line, waitingfor, strlen(waitingfor)) == 0) return;
01458            fputs("gs: ", stdout);
01459            for (;;) {
01460               fputs(line, stdout);
01461               if (*line == '\0' || line[strlen(line) - 1] == '\n') break;
01462 #if !_AMIGA
01463               data_gets((byte *) line, sizeof(line));
01464 #else
01465               if (fgets(line, sizeof(line), data_file) == NULL)
01466                   oops("Premature end of file");
01467 #endif
01468            }
01469        }
01470 }
01471 
01472 void
01473 whitespace P1H(void)
01474 {
01475        char   c;
01476 
01477        for (;;) {
01478            c = data_getc();
01479            if (c == '#')
01480               do c = data_getc(); while (!data_eof && c != '\n');
01481            else if (!isspace(c)) {
01482               data_ungetc(c);
01483               break;
01484            }
01485        }
01486 }
01487 
01488 int
01489 getint P1H(void)
01490 {
01491        char   c;
01492        int    i      = 0;
01493 
01494        do c = data_getc(); while (isspace(c));
01495        if (c < '0' || c > '9') oops("digit expected");
01496        do {
01497            i = i * 10 + (c - '0');
01498            c = data_getc();
01499        } while (c >= '0' && c <= '9');
01500        if (!data_eof) data_ungetc(c);
01501        return i;
01502 }
01503 
01504 static byte   masks[]       = {0, 1, 3, 7, 017, 037, 077, 0177, 0377};
01505 
01506 byte   flag;
01507 int    pk_dyn_f;
01508 int    pk_dyn_g;
01509 int    base;         /* cost of this character if pk_dyn_f = 0 */
01510 int    deltas[13];   /* cost of increasing pk_dyn_f from i to i+1 */
01511 
01512 /*
01513  *     Add up statistics for putting out the given shift count
01514  */
01515 
01516 static void
01517 tallyup P1C(int, n)
01518 {
01519        int    m;
01520 
01521        if (n > 208) {
01522            ++base;
01523            n -= 192;
01524            for (m = 0x100; m != 0 && m < n; m <<= 4) base += 2;
01525            if (m != 0 && (m = (m - n) / 15) < 13) deltas[m] += 2;
01526        }
01527        else if (n > 13) ++deltas[(208 - n) / 15];
01528        else --deltas[n - 1];
01529 }
01530 
01531 /*
01532  *     Routines for storing the shift counts
01533  */
01534 
01535 static Boolean       odd    = False;
01536 static byte   part;
01537 
01538 static void
01539 pk_put_nyb P1C(int, n)
01540 {
01541        if (odd) {
01542            *bitmap_end++ = (part << 4) | n;
01543            odd = False;
01544        }
01545        else {
01546            part = n;
01547            odd = True;
01548        }
01549 }
01550 
01551 static void
01552 pk_put_long P1C(int, n)
01553 {
01554        if (n >= 16) {
01555            pk_put_nyb(0);
01556            pk_put_long(n / 16);
01557        }
01558        pk_put_nyb(n % 16);
01559 }
01560 
01561 static void
01562 pk_put_count P1C(int, n)
01563 {
01564        if (n > pk_dyn_f) {
01565            if (n > pk_dyn_g)
01566               pk_put_long(n - pk_dyn_g + 15);
01567            else {
01568               pk_put_nyb(pk_dyn_f + (n - pk_dyn_f + 15) / 16);
01569               pk_put_nyb((n - pk_dyn_f - 1) % 16);
01570            }
01571        }
01572        else pk_put_nyb(n);
01573 }
01574 
01575 static void
01576 trim_bitmap P1H(void)
01577 {
01578        byte   *p;
01579        byte   mask;
01580 
01581        /* clear out garbage bits in bitmap */
01582        if (width % 8 != 0) {
01583            mask = ~masks[8 - width % 8];
01584            for (p = bitmap + bytes_wide - 1; p < bitmap_end; p += bytes_wide)
01585               *p &= mask;
01586        }
01587 
01588        /*
01589         *     Find the bounding box of the bitmap.
01590         */
01591 
01592        /* trim top */
01593        skip = 0;
01594        mask = 0;
01595        for (;;) {
01596            if (bitmap >= bitmap_end) {    /* if bitmap is empty */
01597               width = height = hoff = voff = 0;
01598               return;
01599            }
01600            p = bitmap + bytes_wide;
01601            while (p > bitmap) mask |= *--p;
01602            if (mask) break;
01603            ++skip;
01604            bitmap += bytes_wide;
01605        }
01606        height -= skip;
01607        voff -= skip;
01608 #if DEBUG
01609 #ifdef KPATHSEA
01610      if (KPSE_DEBUG_P (GSPK_DEBUG_PK))
01611 #endif
01612        if (skip < 2 || skip > 3)
01613            printf("Character has %d empty rows at top\n", skip);
01614 #endif /* DEBUG */
01615 
01616        /* trim bottom */
01617        skip = 0;
01618        mask = 0;
01619        for (;;) {
01620            p = bitmap_end - bytes_wide;
01621            while (p < bitmap_end) mask |= *p++;
01622            if (mask) break;
01623            ++skip;
01624            bitmap_end -= bytes_wide;
01625        }
01626        height -= skip;
01627 #if DEBUG
01628 #ifdef KPATHSEA
01629      if (KPSE_DEBUG_P (GSPK_DEBUG_PK))
01630 #endif
01631        if (skip < 2 || skip > 3)
01632            printf("Character has %d empty rows at bottom\n", skip);
01633 #endif /* DEBUG */
01634 
01635        /* trim right */
01636        skip = 0;
01637        --width;
01638        for (;;) {
01639            mask = 0;
01640            for (p = bitmap + width / 8; p < bitmap_end; p += bytes_wide)
01641               mask |= *p;
01642            if (mask & (0x80 >> (width % 8))) break;
01643            --width;
01644            ++skip;
01645        }
01646        ++width;
01647 #if DEBUG
01648 #ifdef KPATHSEA
01649      if (KPSE_DEBUG_P (GSPK_DEBUG_PK))
01650 #endif
01651        if (skip < 2 || skip > 3)
01652            printf("Character has %d empty columns at right\n", skip);
01653 #endif /* DEBUG */
01654 
01655        /* trim left */
01656        skip = 0;
01657        for (;;) {
01658            mask = 0;
01659            for (p = bitmap + skip / 8; p < bitmap_end; p += bytes_wide)
01660               mask |= *p;
01661            if (mask & (0x80 >> (skip % 8))) break;
01662            ++skip;
01663        }
01664        width -= skip;
01665        hoff -= skip;
01666 #if DEBUG
01667 #ifdef KPATHSEA
01668      if (KPSE_DEBUG_P (GSPK_DEBUG_PK))
01669 #endif
01670        if (skip < 2 || skip > 3)
01671            printf("Character has %d empty columns at left\n", skip);
01672 #endif /* DEBUG */
01673        bitmap += skip / 8;
01674        skip = skip % 8;
01675 }
01676 
01677 /*
01678  *     Pack the bitmap using the rll method.  (Return false if it's better
01679  *     to just pack the bits.)
01680  */
01681 
01682 static Boolean
01683 pk_rll_cvt P1H(void)
01684 {
01685        static int    *counts              = NULL;       /* area for saving bit counts */
01686        static int    maxcounts     = 0;   /* size of this area */
01687        unsigned int  ncounts;             /* max to allow this time */
01688        int    *nextcount;                 /* next count value */
01689        int    *counts_end;                /* pointer to end */
01690        byte   *rowptr;
01691        byte   *p;
01692        byte   mask;
01693        byte   *rowdup;                    /* last row checked for dup */
01694        byte   paint_switch;               /* 0 or 0xff */
01695        int    bits_left;                  /* bits left in row */
01696        int    cost;
01697        int    i;
01698 
01699        /*
01700         *     Allocate space for bit counts.
01701         */
01702 
01703        ncounts = (width * height + 3) / 4;
01704        if (ncounts > maxcounts) {
01705            if (counts != NULL) free(counts);
01706            counts = xmalloc((ncounts + 2) * sizeof(int));
01707            maxcounts = ncounts;
01708        }
01709        counts_end = counts + ncounts;
01710 
01711        /*
01712         *     Form bit counts and collect statistics
01713         */
01714        base = 0;
01715        bzero(deltas, sizeof(deltas));
01716        rowdup = NULL;       /* last row checked for duplicates */
01717        p = rowptr = bitmap;
01718        mask = 0x80 >> skip;
01719        flag = 0;
01720        paint_switch = 0;
01721        if (*p & mask) {
01722            flag = 8;
01723            paint_switch = 0xff;
01724        }
01725        bits_left = width;
01726        nextcount = counts;
01727        while (rowptr < bitmap_end) {      /* loop over shift counts */
01728            int shift_count = bits_left;
01729 
01730            for (;;) {
01731               if (bits_left == 0) {
01732                   if ((p = rowptr += bytes_wide) >= bitmap_end) break;
01733                   mask = 0x80 >> skip;
01734                   bits_left = width;
01735                   shift_count += width;
01736               }
01737               if (((*p ^ paint_switch) & mask) != 0) break;
01738               --bits_left;
01739               mask >>= 1;
01740               if (mask == 0) {
01741                   ++p;
01742                   while (*p == paint_switch && bits_left >= 8) {
01743                      ++p;
01744                      bits_left -= 8;
01745                   }
01746                   mask = 0x80;
01747               }
01748            }
01749            if (nextcount >= counts_end) return False;
01750            shift_count -= bits_left;
01751            *nextcount++ = shift_count;
01752            tallyup(shift_count);
01753            /* check for duplicate rows */
01754            if (rowptr != rowdup && bits_left != width) {
01755               byte   *p1    = rowptr;
01756               byte   *q     = rowptr + bytes_wide;
01757               int    repeat_count;
01758 
01759               while (q < bitmap_end && *p1 == *q) ++p1, ++q;
01760               repeat_count = (p1 - rowptr) / bytes_wide;
01761               if (repeat_count > 0) {
01762                   *nextcount++ = -repeat_count;
01763                   if (repeat_count == 1) --base;
01764                   else {
01765                      ++base;
01766                      tallyup(repeat_count);
01767                   }
01768                   rowptr += repeat_count * bytes_wide;
01769               }
01770               rowdup = rowptr;
01771            }
01772            paint_switch = ~paint_switch;
01773        }
01774 
01775 #if DEBUG
01776 #ifdef KPATHSEA
01777        if (KPSE_DEBUG_P (GSPK_DEBUG_BITMAP))
01778 #endif
01779        {
01780            /*
01781             * Dump the bitmap
01782             */
01783 
01784            for (p = bitmap; p < bitmap_end; p += bytes_wide) {
01785               byte *p1      = p;
01786               int j;
01787 
01788               mask = 0x80 >> skip;
01789               for (j = 0; j < width; ++j) {
01790                   putchar(*p1 & mask ? '@' : '.');
01791                   if ((mask >>= 1) == 0) mask = 0x80, ++p1;
01792               }
01793               putchar('\n');
01794            }
01795            putchar('\n');
01796        }
01797 #endif /* DEBUG */
01798 
01799        /*
01800         *     Determine the best pk_dyn_f
01801         */
01802 
01803        pk_dyn_f = 0;
01804        cost = base += 2 * (nextcount - counts);
01805        for (i = 1; i < 14; ++i) {
01806            base += deltas[i - 1];
01807            if (base < cost) {
01808               pk_dyn_f = i;
01809               cost = base;
01810            }
01811        }
01812        /* last chance to bail out */
01813        if (cost * 4 > width * height) return False;
01814 
01815        /*
01816         *     Pack the bit counts
01817         */
01818 
01819        pk_dyn_g = 208 - 15 * pk_dyn_f;
01820        flag |= pk_dyn_f << 4;
01821        bitmap_end = bitmap;
01822        *nextcount = 0;
01823        nextcount = counts;
01824        while (*nextcount != 0) {
01825            if (*nextcount > 0) pk_put_count(*nextcount);
01826            else
01827               if (*nextcount == -1) pk_put_nyb(15);
01828               else {
01829                   pk_put_nyb(14);
01830                   pk_put_count(-*nextcount);
01831               }
01832            ++nextcount;
01833        }
01834        if (odd) {
01835            pk_put_nyb(0);
01836            ++cost;
01837        }
01838        if (cost != 2 * (bitmap_end - bitmap))
01839            printf("Cost miscalculation:  expected %d, got %d\n", cost,
01840               2 * (bitmap_end - bitmap));
01841        pk_len = bitmap_end - bitmap;
01842        return True;
01843 }
01844 
01845 static void
01846 pk_bm_cvt P1H(void)
01847 {
01848        byte   *rowptr;
01849        byte   *p;
01850        int    blib1;        /* bits left in byte */
01851        int    bits_left;    /* bits left in row */
01852        byte   *q;
01853        int    blib2;
01854        byte   nextbyte;
01855 
01856        flag = 14 << 4;
01857        q = bitmap;
01858        blib2 = 8;
01859        nextbyte = 0;
01860        for (rowptr = bitmap; rowptr < bitmap_end; rowptr += bytes_wide) {
01861            p = rowptr;
01862            blib1 = 8 - skip;
01863            bits_left = width;
01864            if (blib2 != 8) {
01865               int    n;
01866 
01867               if (blib1 < blib2) {
01868                   nextbyte |= *p << (blib2 - blib1);
01869                   n = blib1;
01870               }
01871               else {
01872                   nextbyte |= *p >> (blib1 - blib2);
01873                   n = blib2;
01874               }
01875               blib2 -= n;
01876               if ((bits_left -= n) < 0) {
01877                   blib2 -= bits_left;
01878                   continue;
01879               }
01880               if ((blib1 -= n) == 0) {
01881                   blib1 = 8;
01882                   ++p;
01883                   if (blib2 > 0) {
01884                      nextbyte |= *p >> (8 - blib2);
01885                      blib1 -= blib2;
01886                      bits_left -= blib2;
01887                      if (bits_left < 0) {
01888                          blib2 = -bits_left;
01889                          continue;
01890                      }
01891                   }
01892               }
01893               *q++ = nextbyte;
01894            }
01895            /* fill up whole (destination) bytes */
01896            while (bits_left >= 8) {
01897               nextbyte = *p++ << (8 - blib1);
01898               *q++ = nextbyte | (*p >> blib1);
01899               bits_left -= 8;
01900            }
01901            /* now do the remainder */
01902            nextbyte = *p << (8 - blib1);
01903            if (bits_left > blib1) nextbyte |= p[1] >> blib1;
01904            blib2 = 8 - bits_left;
01905        }
01906        if (blib2 != 8) *q++ = nextbyte;
01907        pk_len = q - bitmap;
01908 }
01909 
01910 static void
01911 putshort P1C(short, w)
01912 {
01913        putc(w >> 8, pk_file);
01914        putc(w, pk_file);
01915 }
01916 
01917 static void
01918 putmed P1C(long, w)
01919 {
01920        putc(w >> 16, pk_file);
01921        putc(w >> 8, pk_file);
01922        putc(w, pk_file);
01923 }
01924 
01925 static void
01926 putlong P1C(long, w)
01927 {
01928        putc(w >> 24, pk_file);
01929        putc(w >> 16, pk_file);
01930        putc(w >> 8, pk_file);
01931        putc(w, pk_file);
01932 }
01933 
01934 static void
01935 putglyph P1C(int, cc)
01936 {
01937        static Boolean       have_first_line = False;
01938        static int    llx, lly, urx, ury;
01939        static float  char_width;
01940        static byte   *area1 = NULL;
01941        static unsigned int size1 = 0;
01942        static int    i;
01943        long   dm;
01944        long   tfm_wid;
01945        byte   *p;
01946 
01947        if (!quiet) {
01948            int wid;
01949            static const char *s = "";
01950 
01951            wid = (cc >= 100) + (cc >= 10) + 4;
01952            if (col + wid > 80) {
01953               s = "\n";
01954               col = 0;
01955            }
01956            printf("%s[%d", s, cc);
01957            fflush(stdout);
01958            col += wid;
01959            s = " ";
01960        }
01961        if (!have_first_line) {
01962            expect("#^");
01963            if (sscanf(line, "#^ %d %d %d %d %d %f\n", &i,
01964                   &llx, &lly, &urx, &ury, &char_width) != 6)
01965               oops("Cannot scanf first line");
01966        }
01967        if (i < cc) oops("Character %d received, %d expected", i, cc);
01968        if (i > cc) {
01969            fprintf(stderr, "Character %d is missing.\n", cc);
01970            have_first_line = True;
01971            return;
01972        }
01973        have_first_line = False;
01974        hoff = -llx + 2;
01975        voff = ury + 2 - 1;
01976        expect("P4\n");
01977        whitespace();
01978        width = getint();
01979        whitespace();
01980        height = getint();
01981        (void) data_getc();
01982        if (width != urx - llx + 4 || height != ury - lly + 4)
01983            oops("Dimensions do not match:  %d %d %d %d %d %d",
01984               llx, lly, urx, ury, width, height);
01985        bytes_wide = (width + 7) / 8;
01986        bm_size = bytes_wide * height;
01987        if (size1 < bm_size) {
01988            if (area1 != NULL) free(area1);
01989            area1 = xmalloc(bm_size);
01990            size1 = bm_size;
01991        }
01992        for (p = area1 + (height - 1) * bytes_wide; p >= area1; p -= bytes_wide)
01993            if (data_read(p, bytes_wide) != bytes_wide)
01994               oops("Cannot read bitmap of size %u", bm_size);
01995        bitmap = area1;
01996        bitmap_end = bitmap + bm_size;
01997        trim_bitmap();
01998        if (height == 0 || !pk_rll_cvt()) pk_bm_cvt();
01999        tfm_wid = tfm_widths[width_index[cc]];
02000        dm = (long) (char_width + 0.5) - (char_width < -0.5);
02001        if (pk_len + 8 < 4 * 256 && tfm_wid < (1<<24) &&
02002               dm >= 0 && dm < 256 && width < 256 && height < 256 &&
02003               hoff >= -128 && hoff < 128 && voff >= -128 && voff < 128) {
02004            putc(flag | ((pk_len + 8) >> 8), pk_file);
02005            putc(pk_len + 8, pk_file);
02006            putc(cc, pk_file);
02007            putmed(tfm_wid);
02008            putc(dm, pk_file);
02009            putc(width, pk_file);
02010            putc(height, pk_file);
02011            putc(hoff, pk_file);
02012            putc(voff, pk_file);
02013        } else
02014        if (pk_len + 13 < 3 * 65536L && tfm_wid < (1<<24) &&
02015               dm >= 0 && dm < 65536L && width < 65536L && height < 65536L &&
02016               hoff >= -65536L && hoff < 65536L &&
02017               voff >= -65536L && voff < 65536L) {
02018            putc(flag | 4 | ((pk_len + 13) >> 16), pk_file);
02019            putshort(pk_len + 13);
02020            putc(cc, pk_file);
02021            putmed(tfm_wid);
02022            putshort(dm);
02023            putshort(width);
02024            putshort(height);
02025            putshort(hoff);
02026            putshort(voff);
02027        }
02028        else {
02029            putc(flag | 7, pk_file);
02030            putlong(pk_len + 28);
02031            putlong(cc);
02032            putlong(tfm_wid);
02033            putlong((long) (char_width * 65536.0 + 0.5) - (char_width < -0.5));
02034            putlong(0);
02035            putlong(width);
02036            putlong(height);
02037            putlong(hoff);
02038            putlong(voff);
02039        }
02040        fwrite(bitmap, 1, pk_len, pk_file);
02041        if (!quiet) {
02042            putchar(']');
02043            fflush(stdout);
02044        }
02045 }
02046 
02047 static void
02048 putspecl P2C(const char *, str1, const char *, str2)
02049 {
02050        int    len1   = strlen(str1);
02051        int    len2   = 0;
02052 
02053        if (str2 != NULL) len2 = strlen(str2);
02054        if (len1 + len2 > 255) return;
02055        putc(PK_SPC, pk_file);
02056        putc(len1 + len2, pk_file);
02057        fwrite(str1, 1, len1, pk_file);
02058        if (len2 != 0) fwrite(str2, 1, len2, pk_file);
02059 }
02060 
02061 int
02062 main P2C(int, argc, char **, argv)
02063 {
02064        FILE          *config_file;
02065        FILE          *render_ps;
02066        FILE          *tfm_file;
02067        char          **argp;
02068        float         dpi;
02069        const char    *dvipsrc;
02070        char          *p;
02071        char          *PSname              = NULL;
02072        char          *specinf      = NULL;
02073        char          *specp        = NULL;       /* NULL pacifies lint */
02074        char          charlist[10*2 + 90*3 + 156*4 + 1];
02075        char          designstr[20];
02076        char          dpistr[20];
02077 #if HAVE_SIGACTION
02078        struct sigaction sigact;
02079 #endif
02080 #if _AMIGA
02081        char          fngs[50];
02082        char          fngsf[50];
02083        char          tfm_path[256];
02084        BPTR          in, out;
02085 #else
02086        char          *substarg;
02087 #endif
02088 #if WIN32
02089        DWORD idGsThread;
02090 #else /* not WIN32 */
02091 #if !_AMIGA
02092        int           std_out[2];
02093 #endif
02094        int           std_in[2];
02095 #endif /* not WIN32 */
02096        int           cc;
02097        int           ppp;
02098        int           i;
02099 
02100        argp = argv;
02101        while (++argp < argv + argc && (*argp)[0] == '-') {
02102            const struct option *opt_ptr;
02103            const struct option *opt;
02104            char *arg = *argp + 1;
02105 
02106            if (*arg == '\0') --arg;       /* this will flag an error later */
02107            if (*arg != '-') {             /* if short argument */
02108               opt = options;
02109               for (;;) {
02110                   if (*arg == opt->shortname)
02111                      break;
02112                   if (++opt >= options + NUMBER(options))
02113                      opt_oops("invalid option -- %c", *arg);
02114               }
02115               if (opt->has_arg) {
02116                   ++arg;
02117                   if (*arg == '\0') {
02118                      if (++argp >= argv + argc)
02119                          opt_oops("option requires an argument -- %c",
02120                            arg[-1]);
02121                      arg = *argp;
02122                   }
02123               }
02124               else {
02125                   if (arg[1] != '\0')
02126                      opt_oops("invalid number of bytes in option `%s'",
02127                        arg - 1);
02128               }
02129            }
02130            else {                  /* long argument */
02131               int    len;
02132               char   *arg1;
02133 
02134               ++arg;
02135               if (*arg == '\0') {  /* if -- */
02136                   ++argp;
02137                   break;
02138               }
02139               len = strlen(arg);
02140               arg1 = memchr(arg, '=', len);
02141               if (arg1 != NULL) {
02142                   len = arg1 - arg;
02143                   ++arg1;
02144               }
02145               opt = NULL;
02146               for (opt_ptr = options; opt_ptr < options + NUMBER(options);
02147                 ++opt_ptr)
02148                   if (memcmp(arg, opt_ptr->longname, len) == 0) {
02149                      if (opt != NULL)
02150                          opt_oops("option `%s' is ambiguous.", arg - 2);
02151                      opt = opt_ptr;
02152                   }
02153               if (opt == NULL)
02154                   opt_oops("unrecognized option `%s'", arg - 2);
02155               if (opt->has_arg) {
02156                   if (arg1 == NULL) {
02157                      if (++argp >= argv + argc)
02158                          opt_oops("option `--%s' requires an argument.",
02159                            opt->longname);
02160                      arg1 = *argp;
02161                   }
02162               }
02163               else {
02164                   if (arg1 != NULL)
02165                      opt_oops("option `--%s' doesn't allow an argument.",
02166                        opt->longname);
02167               }
02168               arg = arg1;
02169            }         /* end long argument */
02170 
02171            if (opt->addr != NULL)
02172               if (opt->has_arg)
02173                   *((char **) opt->addr) = arg;
02174               else
02175                   *((Boolean *) opt->addr) = opt->value;
02176 
02177            switch (opt->shortname) {
02178 #ifdef KPATHSEA
02179            case OPT_DBG:
02180               kpathsea_debug |= atoi(arg);
02181               break;
02182 #endif
02183            case 'h':
02184 #ifndef KPATHSEA
02185               puts("\
02186 Usage:  gsftopk [OPTION] FONT DPI\n\
02187 Translate the PostScript Type 1 font FONT to PK bitmap format at DPI dpi.\n\
02188 \n\
02189   -t, --test         check for presence of font in .map file.\n\
02190   --mapline=LINE     use LINE as the line from the .map file.\n\
02191   --mapfile=FILE     use FILE as a .map file; default psfonts.map.\n\
02192   -i GS, --interpreter=GS  use GS as Ghostscript interpreter.\n\
02193   --dosnames         short pk filename (cmr10.pk instead of cmr10.600pk).\n\
02194   -q, --quiet        don't print progress information to standard output.\n\
02195   -h, --help         print this message and exit.\n\
02196   -v, --version             print version number and exit.\n");
02197 #else
02198               puts("\
02199 Usage:  gsftopk [OPTION] FONT DPI\n\
02200 Translate the PostScript Type 1 font FONT to PK bitmap format at DPI dpi.\n\
02201 \n\
02202   -t, --test         check for presence of font in .map file.\n\
02203   --mapline=LINE     use LINE as the line from the .map file.\n\
02204   --mapfile=FILE     use FILE as a .map file; default psfonts.map.\n\
02205   -i GS, --interpreter=GS  use GS as Ghostscript interpreter.\n\
02206   --dosnames         short pk filename (cmr10.pk instead of cmr10.600pk).\n\
02207   -q, --quiet        don't print progress information to standard output.\n\
02208   --debug=NUM        set debugging flags.\n\
02209   -h, --help         print this message and exit.\n\
02210   -v, --version             print version number and exit.\n");
02211 #endif
02212               return 0;
02213            case 'v':
02214 #ifndef KPATHSEA
02215               printf("gsftopk %s\n", version);
02216 #else
02217               {
02218                   extern KPSEDLL char *kpathsea_version_string;
02219 
02220                   printf("gsftopk(k) %s\n", version);
02221                   puts(kpathsea_version_string);
02222                   puts("Copyright (C) 1993-1998 Paul Vojta.\n\
02223 There is NO warranty.  You may redistribute this software\n\
02224 under the terms of the GNU General Public License\n\
02225 and the standard X consortium copyright notice.\n\
02226 For more information about these matters, see the files\n\
02227 named COPYING and gsftopk.c.\n\
02228 Author of gsftopk: Paul Vojta.");
02229               }
02230 #endif
02231               return 0;
02232            }
02233        }
02234 
02235        if (mapfile != NULL && mapline != NULL)
02236            opt_oops("cannot specify both `--mapline' and `--mapfile'");
02237 
02238        if (argp >= argv + argc)
02239            opt_oops(test ? "must provide a font name"
02240              : "must provide a font name and resolution");
02241 
02242        fontname = *argp++;
02243        fontlen = strlen(fontname);
02244 
02245        if (argp >= argv + argc) {
02246            if (!test)
02247               opt_oops("must provide rendering resolution");
02248            dpi = 0.0;
02249        }
02250        else {
02251            dpi = atof(*argp++);
02252            if (dpi <= 0.0)
02253               opt_oops("DPI argument `%s' must be a positive number", *argp);
02254        }
02255 
02256        if (argp < argv + argc)
02257            opt_oops("no more than two arguments are allowed");
02258 
02259 #ifdef KPATHSEA
02260        kpse_set_progname(argv[0]);
02261        kpse_init_prog("GSFTOPK", (int) (dpi + 0.5), NULL, "cmr10");
02262        if (!test)
02263            xputenv_int("KPATHSEA_DPI", (int) (dpi + 0.5));
02264 #endif
02265 
02266 #if _AMIGA
02267        /* [CL] 21-Jun-97
02268           This is quite silly but it really helps things when determining the
02269           font supplier and family.
02270        */
02271        putenv("GSFTOPKTFM=");
02272 #endif
02273 
02274        /*
02275         * Read the dvips-style config file(s).
02276         */
02277 
02278        long_line = xmalloc(long_line_len);       /* initialize fgets_long */
02279 
02280 #ifndef KPATHSEA
02281        config_file = search(CONFIGPATH, "TEXCONFIG", "config.ps");
02282        if (config_file != NULL)
02283            getdefaults(config_file);
02284 
02285        dvipsrc = getenv("DVIPSRC");
02286        if (dvipsrc == NULL) {
02287            dvipsrc = getenv("HOME");
02288            if (dvipsrc != NULL) {
02289               i = strlen(dvipsrc);
02290               p = xmalloc(i + 10);
02291               memcpy(p, dvipsrc, i);
02292               memcpy(p + i, "/.dvipsrc", 10);
02293            }
02294        }
02295        if (dvipsrc != NULL) {
02296            config_file = fopen(dvipsrc, "r");
02297            if (config_file != NULL)
02298               getdefaults(config_file);
02299        }
02300 
02301        config_file = search(CONFIGPATH, "TEXCONFIG", "config.gsftopk");
02302        if (config_file != NULL)
02303            getdefaults(config_file);
02304 #else
02305        getdefaults("config.ps");
02306 
02307        dvipsrc = kpse_var_value("DVIPSRC");
02308        getdefaults(dvipsrc != NULL ? dvipsrc : "$HOME/.dvipsrc");
02309 
02310        getdefaults("config.gsftopk");
02311 
02312        /* Set HEADERPATH from config file.  */
02313 
02314        if (config_file_header_path != NULL)
02315            kpse_format_info[kpse_tex_ps_header_format].client_path
02316              = config_file_header_path;
02317 #endif
02318 
02319        /*
02320         * Get the map line.
02321         */
02322 
02323        if (mapline != NULL) {
02324            if (memcmp(mapline, fontname, fontlen) != 0
02325              || (mapline[fontlen] != '\0' && !isspace(mapline[fontlen])))
02326               oops("font name does not match --mapline argument");
02327        }
02328        else {
02329            Boolean font_found;
02330 
02331            if (mapfile != NULL) {
02332 #ifndef KPATHSEA
02333               config_file = search(CONFIGPATH, "TEXCONFIG",
02334                                  mapfile);
02335 #else
02336               config_file = kpse_open_file(mapfile,
02337                                         kpse_fontmap_format);
02338 #endif
02339 
02340               if (config_file == NULL) {
02341                   perror(mapfile);
02342                   exit(1);
02343               }
02344               font_found = scan_map_file(config_file);
02345            }
02346            else {
02347               struct p_list *p_node;
02348 
02349               font_found = False;
02350               *p_tail = NULL;
02351               for (p_node = p_head; p_node != NULL; p_node = p_node->next) {
02352 #ifndef KPATHSEA
02353                   config_file = search(CONFIGPATH, "TEXCONFIG",
02354                     p_node->value);
02355 #else
02356                   config_file = kpse_open_file(p_node->value,
02357                     kpse_fontmap_format);
02358 #endif
02359                   if (config_file != NULL)
02360                      if (scan_map_file(config_file)) {
02361                          font_found = True;
02362                          break;
02363                      }
02364               }
02365            }
02366 
02367            if (!font_found)
02368               if (test)
02369                   exit(1);
02370               else
02371                   oops("Cannot find font %s in map file(s).", fontname);
02372 
02373            mapline = long_line;
02374        }
02375 
02376        if (test)
02377            exit(0);
02378 
02379        if (!quiet) {
02380            printf("%sversion %s", progname, version);
02381            fflush(stdout);
02382            col = 1;  /* any nonzero value will do */
02383        }
02384 
02385        /*
02386         * Parse the line from the map file.
02387         */
02388        for (p = mapline + fontlen; *p != '\0'; ++p) {
02389            if (isspace(*p)) continue;
02390            if (*p == '<') {
02391               char   *q;
02392               char   endc;
02393               char   c;
02394               FILE   *f;
02395 
02396               ++p;
02397               /* There may be two '<'s in front of the filename. */
02398               if (*p == '<') ++p;
02399               /* ... and maybe a '[' */
02400               if (*p == '[') ++p;
02401               q = p;
02402               while (*p != '\0' && !isspace(*p)) ++p;
02403               endc = *p;
02404               *p = '\0';
02405 #ifdef KPATHSEA
02406               searchpath = kpse_find_file(q, kpse_tex_ps_header_format,true);
02407 #ifdef WIN32
02408               /* Be safe for Ghostscript's sake */
02409               dostounix_filename(searchpath);
02410 #endif /* WIN32 */
02411               f = searchpath ? fopen(searchpath, FOPEN_R_MODE) : NULL;
02412 #else
02413               f = search(config_file_header_path, "DVIPSHEADERS", q);
02414 #endif
02415               if (f == NULL) oops("Cannot find font file %s", q);
02416               /* search() also sets searchpath */
02417               addtodls(" (");
02418               addtodls(searchpath);
02419               c = getc(f);
02420               addtodls(c == '\0' ? ") ttload"
02421                 : c == '\200' ? ") brun"
02422                 : ") run");
02423               fclose(f);
02424               if (endc == '\0') break;
02425               continue;
02426            }
02427            else if (*p == '"') {
02428               char   *q;
02429 
02430               if (specinf != NULL)
02431                   *specp++ = ' ';
02432               else
02433                   specinf = specp = xmalloc(strlen(p));
02434               ++p;
02435               q = strchr(p, '"');
02436               if (q == NULL) q = p + strlen(p);
02437               memcpy(specp, p, q - p);
02438               specp += q - p;
02439               p = q;
02440               if (*p == '\0') break;
02441               else continue;
02442            }
02443            else {
02444               PSname = p;
02445               while (*p != '\0' && !isspace(*p)) ++p;
02446               if (*p == '\0') break;
02447            }
02448            *p = '\0';
02449        }
02450 
02451 #if OLD_DVIPS
02452        /* Parse lines like `Symbol-Slanted "/Symbol .167 SlantFont"'. */
02453        if (*(p = specinf) == '/') {
02454            PSname = ++p;
02455            while (*p && !isspace(*p)) ++p;
02456            if (*p) *p++ = '\0';
02457            specinf = p;
02458        }
02459 #endif /* OLD_DVIPS */
02460 
02461        if (specinf != NULL) {
02462            *specp = '\0';
02463            specinfo = specinf;
02464        }
02465 
02466        if (PSname == NULL)
02467            PSname = fontname;
02468 
02469        /*
02470         *     Start up Ghostscript.
02471         */
02472 
02473 #ifdef KPATHSEA
02474        searchpath = kpse_find_file("render.ps", kpse_tex_ps_header_format,
02475                                 true);
02476        render_ps = searchpath ? fopen (searchpath, FOPEN_R_MODE) : NULL;
02477 #else
02478        render_ps = search(config_file_header_path, "DVIPSHEADERS",
02479            "render.ps");
02480 #endif
02481        if (render_ps == NULL)
02482            oops("Cannot find PS driver file \"render.ps\".");
02483        fclose(render_ps);
02484 
02485 #if !_AMIGA
02486        substarg = xmalloc(strlen(PSname) + 13);
02487        sprintf(substarg, "-sSUBSTFONT=%s", PSname);
02488 #endif
02489 
02490        sprintf(dpistr, "%f", dpi);
02491 
02492 #if _AMIGA
02493 
02494        mktemp(tmpname);
02495 
02496        sprintf(fngs, "fifo:%s/rweK", tmpname);
02497        sprintf(fngsf, "fifo:%s/rweKm", tmpname);
02498 
02499        std_in[1] = open(fngsf, O_WRONLY|O_TRUNC|O_CREAT, 511);
02500 
02501        if (std_in[1] == -1) {
02502            perror("pipe");
02503            return 1;
02504        }
02505 
02506        in = Open(fngs, MODE_OLDFILE);
02507        out = Open(fngs, MODE_NEWFILE);
02508 
02509        if (in && out) {
02510            int error;
02511            char *cmd;
02512            char formatstr[] = "%s -dNODISPLAY -dNOGC -sSUBSTFONT=\"%s\" -q -- \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"";
02513            unsigned int len;
02514 
02515            len = sizeof formatstr + strlen(gspath) + strlen(searchpath)
02516              + 2 * strlen(PSname) + (dlstring != NULL ? strlen(dlstring) : 0)
02517              + strlen(specinfo) + strlen(dpistr);
02518 
02519            cmd = xmalloc(len);
02520 
02521            sprintf(cmd, formatstr, PSname, gspath, searchpath, PSname,
02522              dlstring != NULL ? dlstring : "", specinfo, dpistr);
02523 
02524            error = SystemTags(cmd, SYS_Input, in,
02525                                SYS_Output, out,
02526                                SYS_Asynch, TRUE,
02527                                /* NP_StackSize, 50000, */
02528                                TAG_DONE, TAG_DONE);
02529            free(cmd);
02530 
02531            if (error == -1) {
02532               Close(in);
02533               Close(out);
02534               PrintFault(error, "System(gs)");
02535               exit(1);
02536            }
02537        }
02538        else {
02539            perror("pipes");
02540            if (in) Close(in);
02541            if (out) Close(out);
02542            exit(1);
02543        }
02544 
02545 #elif WIN32
02546 
02547        /* (later) */
02548 
02549 #else /* neither _AMIGA nor WIN32 */
02550 
02551        if (pipe(std_in) != 0 || pipe(std_out) != 0) {
02552            perror("pipe");
02553            return 1;
02554        }
02555 
02556        /* Catch the signal for death of the child process. */
02557 
02558 #if HAVE_SIGACTION
02559        sigact.sa_handler = handle_sigchild;
02560        (void) sigemptyset(&sigact.sa_mask);
02561        sigact.sa_flags = SA_NOCLDSTOP;
02562        (void) sigaction(SIGCHLD, &sigact, (struct sigaction *) NULL);
02563 #else
02564        (void) signal(SIGCHLD, handle_sigchild);
02565 #endif
02566 
02567        /*
02568         * Also catch various termination signals, so that we can kill the
02569         * gs process before terminating.
02570         */
02571 
02572        (void) signal(SIGHUP, handle_sigterm);
02573        (void) signal(SIGINT, handle_sigterm);
02574        (void) signal(SIGQUIT, handle_sigterm);
02575        (void) signal(SIGTERM, handle_sigterm);
02576 
02577        fflush(stderr);             /* to avoid double flushing */
02578        gs_pid = vfork();
02579        if (gs_pid == 0) {
02580            close(std_in[1]);
02581            dup2(std_in[0], 0);
02582            close(std_in[0]);
02583            close(std_out[0]);
02584            dup2(std_out[1], 1);
02585            close(std_out[1]);
02586            execlp(gspath, "gs", "-dNODISPLAY", "-dNOGC", substarg, "-q", "--",
02587               /* render.ps */ searchpath,
02588               PSname,
02589               dlstring != NULL ? dlstring : "", specinfo, dpistr, NULL);
02590            if (col != 0) {
02591               putc('\n', stderr);
02592               col = 0;
02593            }
02594            perror(gspath);
02595            exit(1);
02596        }
02597        if (gs_pid == -1) {
02598            perror("fork");
02599            exit(1);
02600        }
02601 
02602 #endif /* neither _AMIGA nor WIN32 */
02603 
02604        /*
02605         *     Open and read the tfm file.  If this takes a while, at least
02606         *     it can overlap with the startup of Ghostscript.
02607         */
02608 
02609        xfilename = xmalloc(fontlen + 10);
02610        strcpy(xfilename, fontname);
02611 #ifdef KPATHSEA
02612 #if _AMIGA
02613        strcpy(tfm_path, kpse_find_file(xfilename, kpse_tfm_format, true));
02614        tfm_file = fopen(tfm_path, "r");
02615 #else
02616        tfm_file = kpse_open_file(xfilename, kpse_tfm_format);
02617 #endif /* _AMIGA */
02618 #else /* not KPATHSEA */
02619        strcpy(xfilename + fontlen, ".tfm");
02620        tfm_file = search(TFMPATH, "TEXFONTS", xfilename);
02621 #endif /* not KPATHSEA */
02622        if (tfm_file == NULL) oops("Cannot find tfm file.");
02623 
02624        for (i = 0; i < 12; ++i) {
02625            int j;
02626 
02627            j = (int) ((byte) getc(tfm_file)) << 8;
02628            tfm_lengths[i] = j | (int) ((byte) getc(tfm_file));
02629        }
02630        checksum = getlong(tfm_file);
02631        design = getlong(tfm_file);
02632        fseek(tfm_file, 4 * (lh + 6), 0);
02633        p = charlist;
02634        for (cc = bc; cc <= ec; ++cc) {
02635            width_index[cc] = (byte) getc(tfm_file);
02636            if (width_index[cc] != 0) {
02637               sprintf(p, "%d ", cc);
02638               p += strlen(p);
02639            }
02640            (void) getc(tfm_file);
02641            (void) getc(tfm_file);
02642            (void) getc(tfm_file);
02643        }
02644        for (i = 0; i < nw; ++i) tfm_widths[i] = getlong(tfm_file);
02645        fclose(tfm_file);
02646        p[-1] = '\n';
02647 
02648        sprintf(designstr, "%f\n", (float) design / (1 << 20));
02649 
02650 #if !WIN32
02651 
02652        /* write the design size and character list to the file */
02653        write(std_in[1], designstr, strlen(designstr));
02654        write(std_in[1], charlist, p - charlist);
02655 
02656        close(std_in[1]);
02657 
02658 #else /* WIN32 */
02659 
02660        if (gs_locate() == NULL) {
02661          fprintf(stderr, "\nCan't locate Ghostscript ! Exiting ...\n");
02662          return EXIT_FAILURE;
02663        }
02664 
02665        SetConsoleCtrlHandler(handle_sigterm, TRUE);
02666 
02667        hGsDataIn = CreateEvent(NULL, FALSE, FALSE, "gsDataIn");
02668        hGsDataOut = CreateEvent(NULL, FALSE, FALSE, "gsDataOut");
02669 
02670        gs_argv[3] = substarg;
02671        gs_argv[6] = searchpath;
02672        gs_argv[7] = PSname;
02673        gs_argv[8] = dlstring != NULL ? dlstring : "";
02674        gs_argv[9] = specinfo;
02675        gs_argv[10] = dpistr;
02676 
02677        buffer_stdin = concat(designstr, charlist);
02678 
02679        if ((hGsThread = CreateThread(NULL,            /* security attributes */
02680                                   0,               /* default stack size */
02681                                   Win32GsSendData, /* start address of thread */
02682                                   0,               /* parameter */
02683                                   0,               /* creation flags */
02684                                   &idGsThread      /* thread id */
02685                                   )) == NULL)
02686          Win32Error("CreateThread");
02687 
02688 #endif /* WIN32 */
02689 
02690 /*
02691  *     Read the output from Ghostscript.
02692  */
02693 
02694 #if _AMIGA
02695 
02696        if ((data_file = fopen(fngsf, "r")) == NULL) {
02697            perror("GS_out");
02698            exit(1);
02699        }
02700 
02701 #elif WIN32
02702 
02703        /* Nothing */
02704 
02705 #else /* neither _AMIGA nor WIN32 */
02706 
02707        data_fd = std_out[0];
02708 
02709        /* Set data_fd for non-blocking I/O */
02710        if (fcntl(data_fd, F_SETFL, fcntl(data_fd, F_GETFL, 0) | O_NONBLOCK)
02711          == -1)
02712            perror("fcntl");
02713 
02714 #endif /* neither _AMIGA nor WIN32 */
02715 
02716 /*
02717  *     Create pk file and write preamble.
02718  */
02719 
02720        if (dosnames)
02721            strcpy(xfilename + fontlen, ".pk");
02722        else
02723            sprintf(xfilename + fontlen, ".%dpk", (int) (dpi + 0.5));
02724 
02725        if ((pk_file = fopen(xfilename, FOPEN_WBIN_MODE)) == NULL) {
02726            perror(xfilename);
02727            exit_toto_too();
02728        }
02729        putc(PK_PRE, pk_file);
02730        putc(PK_ID, pk_file);
02731        expect("V");  /* get GS version */
02732        i = strlen(line) - 2;
02733        if (i < 0 || i > 10) i = 0;
02734        line[1] = '/';
02735        if (!quiet) {
02736            if (i > 0) fwrite(line + 1, 1, i, stdout);
02737            putchar('\n');
02738            col = 0;
02739        }
02740        putc(sizeof(progname) + sizeof(version) + i - 2, pk_file);
02741        fwrite(progname, 1, sizeof(progname) - 1, pk_file);
02742        fwrite(version, 1, sizeof(version) - 1, pk_file);
02743        if (i >= 0) {
02744            fwrite(line + 1, 1, i, pk_file);
02745        }
02746        putlong(design);
02747        putlong(checksum);
02748        ppp = dpi / 72.27 * 65536.0 + 0.5;
02749        putlong(ppp); /* hppp */
02750        putlong(ppp); /* vppp */
02751 
02752 /*
02753  *     Write the actual characters.
02754  */
02755 
02756        for (cc = bc; cc <= ec; ++cc)
02757            if (width_index[cc] != 0)
02758               putglyph(cc);
02759 
02760 #if _AMIGA
02761 
02762        fclose(data_file);
02763 
02764 #elif WIN32
02765 
02766        /* Release data buffer, enable thread to terminate */
02767        SetEvent(hGsDataOut);
02768 
02769 #ifdef DEBUG
02770        fprintf(stderr, "Waiting for thread ... \n");
02771 #endif
02772        if (hGsThread) {
02773          switch (WaitForSingleObject(hGsThread, 2000)) {
02774          case WAIT_OBJECT_0:
02775            CloseHandle(hGsThread);
02776            hGsThread = NULL;
02777            break;
02778          case WAIT_TIMEOUT:
02779            fprintf(stderr, "Timeout waiting for Gs thread.\n");
02780            break;
02781          case WAIT_FAILED:
02782            fprintf(stderr, "WaitForSingleObject failed on Gs thread (Error code %d).\n",
02783                   GetLastError());
02784            break;
02785          default:
02786            break;
02787          }
02788        }
02789 
02790        if (hGsThread) {
02791          if (TerminateThread(hGsThread, 1) == 0) {
02792            fprintf(stderr, "... couldn't terminate gs thread\n");
02793          }
02794          CloseHandle(hGsThread);
02795          /* FIXME : is it right to call this ? */
02796          gs_dll_release();
02797        }
02798        if (hGsDataIn)
02799          CloseHandle(hGsDataIn);
02800        if (hGsDataOut)
02801          CloseHandle(hGsDataOut);
02802 
02803 #else /* neither _AMIGA nor WIN32 */
02804 
02805        close(data_fd);
02806        if (!gs_is_done)
02807            wait_for_gs();
02808 
02809 #endif /* neither _AMIGA nor WIN32 */
02810 
02811 /*
02812  *     Write out identifying specials:
02813  *            jobname=(font)
02814  *            mag=1
02815  *            mode=modeless
02816  *            pixels_per_inch=(dpi)
02817  */
02818 
02819        putspecl("jobname=", fontname);
02820        putspecl("mag=1", NULL);
02821        putspecl("mode=modeless", NULL);
02822        sprintf(dpistr, "%d", (int) dpi);
02823        putspecl("pixels_per_inch=", dpistr);
02824 
02825 /*
02826  *     Postamble
02827  */
02828 
02829        putc(PK_POST, pk_file);
02830        while (ftell(pk_file) % 4 != 0) putc(PK_NOP, pk_file);
02831        fclose(pk_file);
02832        if (!quiet) putchar('\n');
02833        col = 0;
02834 
02835 #if _AMIGA
02836        /* [CL] 21-Jun-97
02837           The same silly thing to indicate the path of the tfm file
02838        */
02839        {
02840            char tmpstr[80];
02841 
02842            sprintf(tmpstr, "GSFTOPKTFM=%s", tfm_path);
02843            putenv(tmpstr);
02844        }
02845 #endif
02846 
02847        return 0;
02848 }