source: trunk/third/tex/xdvi/gsftopk/gsftopk.c @ 12209

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