]> git.kernelconcepts.de Git - gbdfed.git/blob - hbf.c
Fixup several compile faults due to changes in recent distributions,
[gbdfed.git] / hbf.c
1 /*
2  * Copyright 1993,1994,1995,2005 by Ross Paterson
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *  1. Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  *  3. The name of the author may not be used to endorse or promote
14  *     products derived from this software without specific prior written
15  *     permission.
16  *
17  *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  *  DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
21  *  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23  *  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25  *  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  *  POSSIBILITY OF SUCH DAMAGE.
28  *
29  *
30  * Ross Paterson <ross@soi.city.ac.uk>
31  * 17 October 1995
32  *
33  * The following people have supplied bug fixes:
34  *
35  *   Simon Chow     <khsc@synoptics.com>
36  *   Fung Fung Lee  <lee@simd.stanford.edu>
37  *   Man-Chi Pong   <mcpong@cs.ust.hk>
38  *   Steven Simpson <simpson@math.psu.edu>
39  *   Charles Wang   <charles.wang@infores.com>
40  *   Werner Lemberg <wl@gnu.org>
41  *
42  * Ross no longer maintains this code.  Please send bug reports to
43  * Werner Lemberg <wl@gnu.org>.
44  *
45  */
46
47 /*
48  * Two C interfaces to HBF files.
49  *
50  * The multiple interfaces make this code rather messy; I intend
51  * to clean it up as experience is gained on what is really needed.
52  *
53  * There are also two modes of operation:
54  * - the default is to read each bitmap from its file as demanded
55  * - if IN_MEMORY is defined, the whole bitmap file is held in memory.
56  *   In this case, if running under Unix, the bitmap files may be gzipped
57  *   (but the filename used in the HBF file should be the name of the
58  *   file before it was gzipped).
59  */
60 #include <stddef.h>
61 #include <stdlib.h>
62 #include <stdio.h>
63 #include <ctype.h>
64 #include <string.h>
65 #include "hbf.h"
66
67 #ifdef __MSDOS__
68 #define msdos
69 #endif
70
71 /*
72  * if the linker complains about an unresolved identifier '_strdup',
73  * uncomment the following definition.
74  */
75 /* #define NO_STRDUP */
76
77 #ifdef  __STDC__
78 #       define  _(x)    x
79 #else
80 #       define  _(x)    ()
81 #endif
82
83 #define reg     register
84
85 typedef int     bool;
86 #define TRUE    1
87 #define FALSE   0
88
89 #define Bit(n)  (1<<(7 - (n)))
90
91 /*
92  * Messy file system issues
93  */
94
95 #ifdef unix
96 #define PATH_DELIMITER ':'
97 #define RelativeFileName(fn)    ((fn)[0] != '/')
98 #define LocalFileName(fn)       (strchr(fn, '/') == NULL)
99 #endif /* unix */
100 #ifdef msdos
101 #define PATH_DELIMITER ';'
102 #define HasDrive(fn)    (isalpha((fn)[0]) && (fn)[1] == ':')
103 #ifdef __EMX__
104 #define RelativeFileName(fn)    (! HasDrive(fn) && \
105                                 !((fn)[0] == '\\' || (fn)[0] == '/'))
106 #define LocalFileName(fn)       (! HasDrive(fn) && \
107                                 strchr(fn, '\\') == NULL && \
108                                 strchr(fn, '/') == NULL)
109 #else
110 #define RelativeFileName(fn)    (! HasDrive(fn) && (fn)[0] != '\\')
111 #define LocalFileName(fn)       (! HasDrive(fn) && strchr(fn, '\\') == NULL)
112 #endif /* __EMX__ */
113 #define READ_BINARY     "rb"
114 #endif /* msdos */
115 #ifdef vms
116 #define PATH_DELIMITER ','
117 #define RelativeFileName(fn)    (strchr(fn, ':') == NULL && ((fn)[0] != '[' || (fn)[1] == '.' || (fn)[1] == '-'))
118 #define LocalFileName(fn)       (strchr(fn, ':') == NULL && strchr(fn, ']') == NULL)
119 #endif
120
121 #ifndef RelativeFileName
122 #define RelativeFileName(fn)    FALSE
123 #endif
124
125 #ifndef LocalFileName
126 #define LocalFileName(fn)       FALSE
127 #endif
128
129 #ifndef READ_BINARY
130 #define READ_BINARY     "r"
131 #endif
132
133 #define MAX_FILENAME    1024
134
135 /*
136  *      Internal structures
137  */
138
139 typedef unsigned char   byte;
140
141 #define PROPERTY        struct _PROPERTY
142 #define BM_FILE         struct _BM_FILE
143 #define B2_RANGE        struct _B2_RANGE
144 #define CODE_RANGE      struct _CODE_RANGE
145
146 PROPERTY {
147         char            *prop_name;
148         char            *prop_value;
149         PROPERTY        *prop_next;
150 };
151
152 BM_FILE {
153         char    *bmf_name;
154 #ifdef IN_MEMORY
155         byte    *bmf_contents;
156 #else
157         FILE    *bmf_file;
158 #endif
159         long    bmf_size;
160         BM_FILE *bmf_next;
161 };
162
163 B2_RANGE {
164         byte            b2r_start;
165         byte            b2r_finish;
166         B2_RANGE        *b2r_next;
167 };
168
169 typedef unsigned short  CHAR;
170 typedef unsigned int    CHAR_INDEX;     /* character index in file */
171 #define BAD_CHAR_INDEX  0xffff
172
173 CODE_RANGE {
174         CHAR            code_start;
175         CHAR            code_finish;
176         BM_FILE         *code_bm_file;
177         long            code_offset;
178         CHAR_INDEX      code_pos;
179         bool            code_transposed;
180         bool            code_inverted;
181         CODE_RANGE      *code_next;
182 };
183
184 /*
185  *      Extended internal version of HBF
186  */
187
188 typedef struct {
189         /* fields corresponding to the definition */
190         HBF             public;
191         /* plus internal stuff */
192         char            *filename;
193         byte            *bitmap_buffer;
194         unsigned int    b2_size;        /* number of legal byte-2's */
195         PROPERTY        *property;
196         B2_RANGE        *byte_2_range;
197         CODE_RANGE      *code_range;
198         BM_FILE         *bm_file;
199 } HBF_STRUCT;
200
201 #define FirstByte(code)         ((code)>>8)
202 #define SecondByte(code)        ((code)&0xff)
203 #define MakeCode(byte1,byte2)   (((byte1)<<8)|(byte2))
204
205 /* size of a bitmap in the file (may be affected by transposition) */
206 #define FileBitmapSize(hbfFile,cp) \
207                 ((cp)->code_transposed ? \
208                         (hbfBitmapBBox(hbfFile)->hbf_height + 7)/8 * \
209                                 hbfBitmapBBox(hbfFile)->hbf_width : \
210                         HBF_BitmapSize(hbfFile))
211
212 #define NEW(type)       ((type *)malloc((unsigned)(sizeof(type))))
213
214 #define QUOTE '"'
215
216 #define MAXLINE 1024
217
218 #ifdef WIN32
219 #define strdup(x)       _strdup(x)
220 #else
221         extern  char    *strdup _((const char *s));
222 #endif
223
224 static  void    add_b2r _((B2_RANGE **last_b2r, int start, int finish));
225 static  bool    add_code_range _((HBF_STRUCT *hbf, const char *line));
226 static  void    add_property _((HBF_STRUCT *hbf, const char *lp));
227 static  CHAR_INDEX      b2_pos _((HBF_STRUCT *hbf, HBF_CHAR code));
228 static  int     b2_size _((B2_RANGE *b2r));
229 static  void    clear_bbox _((HBF_BBOX *bbox));
230 static  void    clear_record _((HBF_STRUCT *hbf));
231 static  char    *concat _((const char *dir, int dirlen, const char *stem));
232 static  char    *expand_filename _((const char *name, const char *filename));
233 static  const   byte *get_bitmap
234                 _((HBF_STRUCT *hbf, HBF_CHAR code, byte *buffer));
235 static  byte    *local_buffer _((HBF_STRUCT *hbf));
236 static  void    invert _((byte *buffer, unsigned length));
237 #ifdef IN_MEMORY
238 static  bool    read_bitmap_file _((BM_FILE *bmf, FILE *f));
239 static  bool    copy_transposed
240                 _((HBF *hbf, byte *bitmap, const byte *source));
241 #else
242 static  bool    get_transposed _((HBF *hbf, FILE *f, byte *bitmap));
243 #endif
244 static  bool    match _((const char *lp, const char *sp));
245 static  bool    parse_file _((FILE *f, HBF_STRUCT *hbf));
246 static  FILE    *path_open
247                 _((const char *path, const char *filename, char **fullp));
248 static  bool    real_open _((const char *filename, HBF_STRUCT *hbf));
249
250 /* Error reporting */
251
252 int     hbfDebug;       /* set this for error reporting */
253
254 #ifdef  __STDC__
255 #include <stdarg.h>
256
257 static void
258 eprintf(const char *fmt, ...)
259 {
260         if (hbfDebug) {
261                 va_list args;
262
263                 (void)fprintf(stderr, "HBF: ");
264                 va_start(args, fmt);
265                 (void)vfprintf(stderr, fmt, args);
266                 va_end(args);
267                 (void)fprintf(stderr, "\n");
268         }
269 }
270 #else /* ! __STDC__ */
271 /* poor man's variable-length argument list */
272 static void
273 eprintf(fmt, x1, x2, x3, x4, x5, x6, x7, x8, x9)
274         const   char    *fmt;
275         int     x1, x2, x3, x4, x5, x6, x7, x8, x9;
276 {
277         if (hbfDebug) {
278                 (void)fprintf(stderr, "HBF: ");
279                 (void)fprintf(stderr, fmt, x1, x2, x3, x4, x5, x6, x7, x8, x9);
280                 (void)fprintf(stderr, "\n");
281         }
282 }
283 #endif /* __STDC__ */
284
285 static void
286 clear_bbox(bbox)
287         HBF_BBOX *bbox;
288 {
289         bbox->hbf_width = bbox->hbf_height = 0;
290         bbox->hbf_xDisplacement = bbox->hbf_yDisplacement = 0;
291 }
292
293 static void
294 clear_record(hbf)
295         HBF_STRUCT *hbf;
296 {
297         clear_bbox(&(hbf->public.hbf_bitmap_bbox));
298         clear_bbox(&(hbf->public.hbf_font_bbox));
299         hbf->property = NULL;
300         hbf->filename = NULL;
301         hbf->bitmap_buffer = NULL;
302         hbf->byte_2_range = NULL;
303         hbf->code_range = NULL;
304         hbf->bm_file = NULL;
305 }
306
307 /*
308  *      Byte-2 ranges
309  */
310
311 static void
312 add_b2r(last_b2r, start, finish)
313 reg     B2_RANGE **last_b2r;
314         int     start;
315         int     finish;
316 {
317 reg     B2_RANGE *b2r;
318
319         b2r = NEW(B2_RANGE);
320         while (*last_b2r != NULL && (*last_b2r)->b2r_start < start)
321                 last_b2r = &((*last_b2r)->b2r_next);
322         b2r->b2r_next = *last_b2r;
323         b2r->b2r_start = start;
324         b2r->b2r_finish = finish;
325         *last_b2r = b2r;
326 }
327
328 static CHAR_INDEX
329 b2_pos(hbf, code)
330         HBF_STRUCT      *hbf;
331         HBF_CHAR        code;
332 {
333 reg     B2_RANGE *b2r;
334 reg     unsigned c;
335 reg     CHAR_INDEX      pos;
336
337         c = SecondByte(code);
338         pos = 0;
339         for (b2r = hbf->byte_2_range; b2r != NULL; b2r = b2r->b2r_next)
340                 if (b2r->b2r_start <= c && c <= b2r->b2r_finish)
341                         return pos + c - b2r->b2r_start;
342                 else
343                         pos += b2r->b2r_finish - b2r->b2r_start + 1;
344         return BAD_CHAR_INDEX;
345 }
346
347 static int
348 b2_size(b2r)
349 reg     B2_RANGE *b2r;
350 {
351 reg     int     size;
352
353         size = 0;
354         for ( ; b2r != NULL; b2r = b2r->b2r_next)
355                 size += b2r->b2r_finish - b2r->b2r_start + 1;
356         return size;
357 }
358
359 /* map a position to a character code */
360 static long
361 code_of(hbf, pos)
362         HBF_STRUCT      *hbf;
363         long            pos;
364 {
365         long    code;
366         int     residue;
367 reg     B2_RANGE *b2r;
368
369         code = pos / hbf->b2_size * 256;
370         residue = pos % hbf->b2_size;
371         for (b2r = hbf->byte_2_range; b2r != NULL; b2r = b2r->b2r_next)
372                 if (b2r->b2r_start + residue <= b2r->b2r_finish)
373                         return code + b2r->b2r_start + residue;
374                 else
375                         residue -= b2r->b2r_finish - b2r->b2r_start + 1;
376         /* should never get here */
377         return 0L;
378 }
379
380 /*
381  *      String stuff
382  */
383
384 static bool
385 match(lp, sp)
386 reg     const   char    *lp;
387 reg     const   char    *sp;
388 {
389         while (*lp == *sp && *sp != '\0') {
390                 lp++;
391                 sp++;
392         }
393         return (*lp == '\0' || isspace(*lp)) && *sp == '\0';
394 }
395
396 #ifdef NO_STRDUP
397 char *
398 strdup(s)
399         const   char    *s;
400 {
401         char    *new_s;
402
403         new_s = malloc((unsigned)strlen(s) + 1);
404         strcpy(new_s, s);
405         return new_s;
406 }
407 #endif
408
409 /*
410  *      Properties
411  */
412
413 static void
414 add_property(hbf, lp)
415 reg     HBF_STRUCT      *hbf;
416 reg     const char      *lp;
417 {
418 reg     PROPERTY        *prop;
419         char    tmp[MAXLINE];
420 reg     char    *tp;
421
422         prop = NEW(PROPERTY);
423
424         tp = tmp;
425         while (*lp != '\0' && ! isspace(*lp))
426                 *tp++ = *lp++;
427         *tp = '\0';
428         prop->prop_name = strdup(tmp);
429
430         while (*lp != '\0' && isspace(*lp))
431                 lp++;
432
433         tp = tmp;
434         if (*lp == QUOTE) {
435                 lp++;
436                 while (*lp != '\0' && ! (*lp == QUOTE && *++lp != QUOTE))
437                         *tp++ = *lp++;
438         }
439         else
440                 for (;;) {
441                         while (*lp != '\0' && ! isspace(*lp))
442                                 *tp++ = *lp++;
443                         while (*lp != '\0' && isspace(*lp))
444                                 lp++;
445                         if (*lp == '\0')
446                                 break;
447                         *tp++ = ' ';
448                 }
449         *tp = '\0';
450         prop->prop_value = strdup(tmp);
451
452         prop->prop_next = hbf->property;
453         hbf->property = prop;
454 }
455
456 const char *
457 hbfProperty(hbfFile, propName)
458         HBF             *hbfFile;
459         const   char    *propName;
460 {
461 reg     HBF_STRUCT      *hbf;
462 reg     PROPERTY        *prop;
463
464         hbf = (HBF_STRUCT *)hbfFile;
465         for (prop = hbf->property; prop != NULL; prop = prop->prop_next)
466                 if (strcmp(prop->prop_name, propName) == 0)
467                         return prop->prop_value;
468         return NULL;
469 }
470
471 /*
472  *      Compatability routines
473  */
474
475 const char *
476 HBF_GetProperty(handle, propertyName)
477         HBF             *handle;
478         const   char    *propertyName;
479 {
480         return hbfProperty(handle, propertyName);
481 }
482
483 int
484 HBF_GetFontBoundingBox(handle, width, height, xDisplacement, yDisplacement)
485         HBF_Handle      handle;
486         unsigned int    *width;
487         unsigned int    *height;
488         int             *xDisplacement;
489         int             *yDisplacement;
490 {
491         if (width != NULL)
492                 *width = hbfFontBBox(handle)->hbf_width;
493         if (height != NULL)
494                 *height = hbfFontBBox(handle)->hbf_height;
495         if (xDisplacement != NULL)
496                 *xDisplacement = hbfFontBBox(handle)->hbf_xDisplacement;
497         if (yDisplacement != NULL)
498                 *yDisplacement = hbfFontBBox(handle)->hbf_yDisplacement;
499         return 0;
500 }
501
502 int
503 HBF_GetBitmapBoundingBox(handle, width, height, xDisplacement, yDisplacement)
504         HBF_Handle      handle;
505         unsigned int    *width;
506         unsigned int    *height;
507         int             *xDisplacement;
508         int             *yDisplacement;
509 {
510         if (width != NULL)
511                 *width = hbfBitmapBBox(handle)->hbf_width;
512         if (height != NULL)
513                 *height = hbfBitmapBBox(handle)->hbf_height;
514         if (xDisplacement != NULL)
515                 *xDisplacement = hbfBitmapBBox(handle)->hbf_xDisplacement;
516         if (yDisplacement != NULL)
517                 *yDisplacement = hbfBitmapBBox(handle)->hbf_yDisplacement;
518         return 0;
519 }
520
521 /*
522  * Prepend a directory to a relative filename.
523  */
524 static char *
525 concat(dir, dirlen, stem)
526         const   char    *dir;   /* not necessarily null-terminated */
527         int     dirlen;         /* number of significant chars in dir */
528         const   char    *stem;  /* relative filename */
529 {
530         char    *fullname;
531
532         if (dirlen == 0)        /* null: current directory */
533                 return strdup(stem);
534 #ifdef unix
535         fullname = malloc(dirlen + strlen(stem) + 2);
536         (void)sprintf(fullname, "%.*s/%s", dirlen, dir, stem);
537 #else
538 #ifdef msdos
539         fullname = malloc(dirlen + strlen(stem) + 2);
540         (void)sprintf(fullname, "%.*s\\%s", dirlen, dir, stem);
541 #else
542 #ifdef vms
543         if (dir[dirlen-1] == ']' && stem[0] == '[' && stem[1] == '-') {
544                 dirlen--;
545                 stem++;
546                 fullname = malloc(dirlen + strlen(stem) + 2);
547                 (void)sprintf(fullname, "%.*s.%s", dirlen, dir, stem);
548         }
549         else {
550                 if (dir[dirlen-1] == ']' && stem[0] == '[' && stem[1] == '.') {
551                         dirlen--;
552                         stem++;
553                 }
554                 fullname = malloc(dirlen + strlen(stem) + 1);
555                 (void)sprintf(fullname, "%.*s%s", dirlen, dir, stem);
556         }
557 #else
558         fullname = strdup(stem);
559 #endif /* vms */
560 #endif /* msdos */
561 #endif /* unix */
562         return fullname;
563 }
564
565 /*
566  *      Bitmap files
567  *
568  *      If the host operating system has a heirarchical file system and
569  *      the bitmap file name is relative, it is relative to the directory
570  *      containing the HBF file.
571  */
572 static char *
573 expand_filename(name, hbf_name)
574         const   char    *name;
575         const   char    *hbf_name;
576 {
577 #ifdef unix
578 reg     char    *s;
579 reg     int     size;
580
581         size = name[0] != '/' && (s = strrchr(hbf_name, '/')) != NULL ?
582                 s - hbf_name + 1 : 0;
583         s = malloc((unsigned)size + strlen(name) + 1);
584         (void)sprintf(s, "%.*s%s", size, hbf_name, name);
585         return s;
586 #else
587 #ifdef msdos
588 reg     char    *s;
589 reg     int     size;
590
591 #ifdef __EMX__
592         s = (unsigned char *)hbf_name + strlen((unsigned char *)hbf_name) - 1;
593         for(;;) {
594                 if (*s == '\\' || *s == '/')
595                         break;
596                 if (s == hbf_name) {
597                         s = NULL;
598                         break;
599                 }
600                 s--;
601         }
602         
603         size = HasDrive(name) ? 0 :
604                 (name[0] == '\\' || name[0] == '/') ?
605                         (HasDrive(hbf_name) ? 2 : 0) :
606                 s != NULL ? s - hbf_name + 1 : 0;
607 #else
608         size = HasDrive(name) ? 0 :
609                 name[0] == '\\' ? (HasDrive(hbf_name) ? 2 : 0) :
610                 (s = strrchr(hbf_name, '\\')) != NULL ?
611                         s - hbf_name + 1 : 0;
612 #endif /* __EMX__ */
613         s = malloc((unsigned)size + strlen(name) + 1);
614         (void)sprintf(s, "%.*s%s", size, hbf_name, name);
615         return s;
616 #else
617 #ifdef vms
618 reg     char    *s;
619 reg     const   char    *copyto;
620 reg     int     size;
621
622         if ((s = strchr(hbf_name, ']')) != NULL && RelativeFileName(name))
623                 return concat(hbf_name, (s - hbf_name) + 1, name);
624
625         copyto = hbf_name;
626         if ((s = strstr(copyto, "::")) != NULL && strstr(name, "::") == NULL)
627                 copyto = s+2;
628         if ((s = strchr(copyto, ':')) != NULL && strchr(name, ':') == NULL)
629                 copyto = s+1;
630         size = copyto - hbf_name;
631         s = malloc((unsigned)size + strlen(name) + 1);
632         (void)sprintf(s, "%.*s%s", size, hbf_name, name);
633         return s;
634 #else
635         return strdup(name);
636 #endif /* vms */
637 #endif /* msdos */
638 #endif /* unix */
639 }
640
641 static BM_FILE *
642 find_file(hbf, filename)
643         HBF_STRUCT *hbf;
644         const char *filename;
645 {
646         BM_FILE **fp;
647 reg     BM_FILE *file;
648         FILE    *f;
649         char    *bmfname;
650 #ifdef IN_MEMORY
651 #ifdef unix
652         bool    from_pipe;
653 #endif
654 #endif
655
656         for (fp = &(hbf->bm_file); *fp != NULL; fp = &((*fp)->bmf_next)) {
657                 bmfname = strrchr((*fp)->bmf_name, '/');
658                 bmfname = (bmfname) ? bmfname + 1 : (*fp)->bmf_name;
659                 if (strcmp(bmfname, filename) == 0)
660                         return *fp;
661         }
662
663         file = NEW(BM_FILE);
664         if (file == NULL) {
665                 eprintf("out of memory");
666                 return NULL;
667         }
668         file->bmf_name = expand_filename(filename, hbf->filename);
669         if (file->bmf_name == NULL) {
670                 free((char *)file);
671                 return NULL;
672         }
673         f = fopen(file->bmf_name, READ_BINARY);
674 #ifdef IN_MEMORY
675 #ifdef unix
676         from_pipe = FALSE;
677         if (f == NULL) {
678                 char    tmp[400];
679
680                 sprintf(tmp, "%s.gz", file->bmf_name);
681                 if ((f = fopen(tmp, "r")) != NULL) {
682                         fclose(f);
683                         sprintf(tmp, "gzcat %s.gz", file->bmf_name);
684                         if ((f = popen(tmp, "r")) != NULL)
685                                 from_pipe = TRUE;
686                 }
687         }
688 #endif /* unix */
689 #endif /* IN_MEMORY */
690         if (f == NULL) {
691                 eprintf("can't open bitmap file '%s'", file->bmf_name);
692                 free(file->bmf_name);
693                 free((char *)file);
694                 return NULL;
695         }
696 #ifdef IN_MEMORY
697         if (! read_bitmap_file(file, f)) {
698                 free(file->bmf_name);
699                 free((char *)file);
700                 return NULL;
701         }
702 #ifdef unix
703         if (from_pipe)
704                 pclose(f);
705         else
706                 fclose(f);
707 #else /* ! unix */
708         fclose(f);
709 #endif /* ! unix */
710 #else /* ! IN_MEMORY */
711         file->bmf_file = f;
712         fseek(f, 0L, 2);
713         file->bmf_size = ftell(f);
714 #endif /* ! IN_MEMORY */
715         file->bmf_next = NULL;
716         *fp = file;
717         return file;
718 }
719
720 #ifdef IN_MEMORY
721 #define GRAIN_SIZE      512
722
723 static bool
724 read_bitmap_file(bmf, f)
725         BM_FILE *bmf;
726         FILE    *f;
727 {
728         byte    *contents, *cp;
729         long    size;
730         int     c;
731
732         size = 0;
733         cp = contents = (byte *)malloc((unsigned)GRAIN_SIZE);
734         if (contents == NULL) {
735                 eprintf("not enough space for bitmap file");
736                 return NULL;
737         }
738         while ((c = getc(f)) != EOF) {
739                 if (size%GRAIN_SIZE == 0) {
740                         contents = (byte *)realloc((char *)contents,
741                                         (unsigned)(size + GRAIN_SIZE));
742                         if (contents == NULL) {
743                                 eprintf("not enough space for bitmap file");
744                                 return NULL;
745                         }
746                         cp = contents + size;
747                 }
748                 *cp++ = c;
749                 size++;
750         }
751         bmf->bmf_size = size;
752         bmf->bmf_contents = (byte *)realloc((char *)contents, (unsigned)size);
753         return TRUE;
754 }
755 #endif /* IN_MEMORY */
756
757 /*
758  *      Code ranges
759  */
760
761 /* check that a code range fits within its bitmap file */
762 static bool
763 too_short(hbf, cp)
764         HBF_STRUCT      *hbf;
765         CODE_RANGE      *cp;
766 {
767         int     bm_size;
768         long    offset, end_offset;
769         BM_FILE *bmf;
770         long    start, finish;
771
772         bm_size = FileBitmapSize(&(hbf->public), cp);
773         offset = cp->code_offset;
774         start = cp->code_start;
775         finish = cp->code_finish;
776         end_offset = offset + bm_size *
777                         (hbf->b2_size*(long)FirstByte(finish) +
778                                 b2_pos(hbf, finish) - cp->code_pos + 1);
779         bmf = cp->code_bm_file;
780         if (end_offset <= bmf->bmf_size)
781                 return FALSE;
782         /* bitmap file is too short: produce a specific error message */
783         if (offset > bmf->bmf_size)
784                 eprintf("bitmap file '%s' is shorter than offset 0x%04lx",
785                         bmf->bmf_name, offset);
786         else if (offset + bm_size > bmf->bmf_size)
787                 eprintf("bitmap file '%s' too short: no room for any bitmaps at offset 0x%04lx",
788                         bmf->bmf_name, offset);
789         else
790                 eprintf("bitmap file '%s' is too short - code range appears to be 0x%04lx-0x%04lx",
791                         bmf->bmf_name,
792                         start,
793                         code_of(hbf, cp->code_pos +
794                                         (bmf->bmf_size - offset)/bm_size) - 1);
795         return TRUE;
796 }
797
798 static const char *
799 skip_word(n, s)
800         int     n;
801         const   char    *s;
802 {
803         for ( ; n > 0; n--) {
804                 while (*s != '\0' && ! isspace(*s))
805                         s++;
806                 while (*s != '\0' && isspace(*s))
807                         s++;
808         }
809         return s;
810 }
811
812 /* optional keywords at the end of a CODE_RANGE line */
813 static void
814 parse_keywords(cp, s)
815         CODE_RANGE *cp;
816         const   char    *s;
817 {
818         for (s = skip_word(4, s) ; *s != '\0'; s = skip_word(1, s)) {
819                 switch (*s) {
820                 case 's': case 'S': case 't': case 'T':
821                         /* keyword "sideways" or "transposed" */
822                         cp->code_transposed = TRUE;
823                         break;
824                 case 'i': case 'I':
825                         /* keyword "inverted" */
826                         cp->code_inverted = TRUE;
827                 }
828         }
829 }
830
831 static bool
832 add_code_range(hbf, line)
833         HBF_STRUCT      *hbf;
834         const char      *line;
835 {
836         CODE_RANGE *cp;
837         CODE_RANGE **cpp;
838         long    start, finish;
839         long    offset;
840         char    filename[MAXLINE];
841         BM_FILE *bmf;
842         CHAR_INDEX b2pos;
843
844         if (sscanf(line, "HBF_CODE_RANGE %li-%li %s %li",
845                            &start, &finish, filename, &offset) != 4) {
846                 eprintf("syntax error in HBF_CODE_RANGE");
847                 return FALSE;
848         }
849         /* code ranges are checked in real_open() */
850         if ((bmf = find_file(hbf, filename)) == NULL)
851                 return FALSE;
852         if ((cp = NEW(CODE_RANGE)) == NULL) {
853                 eprintf("out of memory");
854                 return FALSE;
855         }
856
857         cp->code_start = (CHAR)start;
858         cp->code_finish = (CHAR)finish;
859         cp->code_bm_file = bmf;
860         cp->code_offset = offset;
861         cp->code_transposed = cp->code_inverted = FALSE;
862         parse_keywords(cp, line);
863         /* insert it in order */
864         for (cpp = &hbf->code_range;
865              *cpp != NULL && (*cpp)->code_finish < start;
866              cpp = &((*cpp)->code_next))
867                 ;
868         if (*cpp != NULL && (*cpp)->code_start <= finish) {
869                 eprintf("code ranges overlap");
870                 return FALSE;
871         }
872         cp->code_next = *cpp;
873         *cpp = cp;
874
875         /* set code_pos, and check range */
876         if (start > finish) {
877                 eprintf("illegal code range 0x%04lx-0x%04lx", start, finish);
878                 return FALSE;
879         }
880         if ((b2pos = b2_pos(hbf, start)) == BAD_CHAR_INDEX) {
881                 eprintf("illegal start code 0x%04lx", start);
882                 return FALSE;
883         }
884         cp->code_pos = hbf->b2_size*(long)FirstByte(start) + b2pos;
885         if ((b2pos = b2_pos(hbf, finish)) == BAD_CHAR_INDEX) {
886                 eprintf("illegal finish code 0x%04lx", finish);
887                 return FALSE;
888         }
889         /* check that the bitmap file has enough bitmaps */
890         return ! too_short(hbf, cp);
891 }
892
893 /*
894  *      Reading and parsing of an HBF file
895  */
896
897 /* get line, truncating to len, and trimming trailing spaces */
898 static bool
899 get_line(buf, len, f)
900         char    *buf;
901         int     len;
902         FILE    *f;
903 {
904         int     c;
905         char    *bp;
906
907         bp = buf;
908         for (;;) {
909                 if ((c = getc(f)) == EOF) {
910                         eprintf("unexpected end of file");
911                         return FALSE;
912                 }
913                 if (c == '\n' || c == '\r') {
914                         /* trim trailing space */
915                         while (bp > buf && isspace(*(bp-1)))
916                                 bp--;
917                         *bp = '\0';
918                         return TRUE;
919                 }
920                 if (len > 0) {
921                         *bp++ = c;
922                         len--;
923                 }
924         }
925 }
926
927 /* get next non-COMMENT line */
928 static bool
929 get_text_line(buf, len, f)
930         char    *buf;
931         int     len;
932         FILE    *f;
933 {
934         while (get_line(buf, len, f))
935                 if (*buf != '\0' && ! match(buf, "COMMENT"))
936                         return TRUE;
937         return FALSE;
938 }
939
940 static bool
941 get_property(line, keyword, hbf)
942         const   char    *line;
943         const   char    *keyword;
944         HBF_STRUCT      *hbf;
945 {
946         if (! match(line, keyword)) {
947                 eprintf("%s expected", keyword);
948                 return FALSE;
949         }
950         add_property(hbf, line);
951         return TRUE;
952 }
953
954 static bool
955 get_bbox(line, keyword, bbox)
956         const   char    *line;
957         const   char    *keyword;
958         HBF_BBOX        *bbox;
959 {
960         int     w, h, xd, yd;
961
962         if (! match(line, keyword) ||
963             sscanf(line + strlen(keyword), "%i %i %i %i",
964                         &w, &h, &xd, &yd) != 4) {
965                 eprintf("%s expected", keyword);
966                 return FALSE;
967         }
968         if (w <= 0 || h <= 0) {
969                 eprintf("illegal %s dimensions %dx%d", keyword, w, h);
970                 return FALSE;
971         }
972         bbox->hbf_width = w;
973         bbox->hbf_height = h;
974         bbox->hbf_xDisplacement = xd;
975         bbox->hbf_yDisplacement = yd;
976         return TRUE;
977 }
978
979 /*
980  *  HBFHeaderFile ::=
981  *      'HBF_START_FONT'                version                 EOLN
982  *      'HBF_CODE_SCHEME'               word ...                EOLN
983  *      'FONT'                          fontName                EOLN
984  *      'SIZE'                          ptsize xres yres        EOLN
985  *      'HBF_BITMAP_BOUNDING_BOX'       w h xd yd               EOLN
986  *      'FONTBOUNDINGBOX'               w h xd yd               EOLN
987  *      X11R5FontPropertySection
988  *      'CHARS'                         n                       EOLN
989  *      HBFByte2RangeSection
990  *      HBFCodeRangeSection
991  *      'HBF_END_FONT'                  EOLN .
992  *
993  * This implementation allows extra lines before HBF_END_FONT.
994  * Anything after HBF_END_FONT is ignored.
995  */
996
997 static bool
998 parse_file(f, hbf)
999         FILE    *f;
1000 reg     HBF_STRUCT *hbf;
1001 {
1002         char    line[MAXLINE];
1003         int     start, finish;
1004
1005         if (! get_text_line(line, MAXLINE, f) ||
1006             ! get_property(line, "HBF_START_FONT", hbf))
1007                 return FALSE;
1008
1009         if (! get_text_line(line, MAXLINE, f) ||
1010             ! get_property(line, "HBF_CODE_SCHEME", hbf))
1011                 return FALSE;
1012
1013         if (! get_text_line(line, MAXLINE, f) ||
1014             ! get_property(line, "FONT", hbf))
1015                 return FALSE;
1016
1017         if (! get_text_line(line, MAXLINE, f) ||
1018             ! get_property(line, "SIZE", hbf))
1019                 return FALSE;
1020
1021         if (! get_text_line(line, MAXLINE, f) ||
1022             ! get_bbox(line, "HBF_BITMAP_BOUNDING_BOX",
1023                         &(hbf->public.hbf_bitmap_bbox)))
1024                 return FALSE;
1025
1026         if (! get_text_line(line, MAXLINE, f) ||
1027             ! get_bbox(line, "FONTBOUNDINGBOX", &(hbf->public.hbf_font_bbox)))
1028                 return FALSE;
1029
1030         if (! get_text_line(line, MAXLINE, f))
1031                 return FALSE;
1032         if (match(line, "STARTPROPERTIES")) {
1033                 for (;;) {
1034                         if (! get_text_line(line, MAXLINE, f))
1035                                 return FALSE;
1036                         if (match(line, "ENDPROPERTIES"))
1037                                 break;
1038                         add_property(hbf, line);
1039                 }
1040                 if (! get_text_line(line, MAXLINE, f))
1041                         return FALSE;
1042         }
1043
1044         if (match(line, "CHARS"))
1045                 if (! get_text_line(line, MAXLINE, f))
1046                         return FALSE;
1047
1048         if (match(line, "HBF_START_BYTE_2_RANGES")) {
1049                 for (;;) {
1050                         if (! get_text_line(line, MAXLINE, f))
1051                                 return FALSE;
1052                         if (match(line, "HBF_END_BYTE_2_RANGES"))
1053                                 break;
1054                         if (sscanf(line, "HBF_BYTE_2_RANGE %i-%i",
1055                                         &start, &finish) != 2) {
1056                                 eprintf("HBF_BYTE_2_RANGE expected");
1057                                 return FALSE;
1058                         }
1059                         add_b2r(&(hbf->byte_2_range), start, finish);
1060                 }
1061                 if (! get_text_line(line, MAXLINE, f))
1062                         return FALSE;
1063         }
1064         else
1065                 add_b2r(&(hbf->byte_2_range), 0, 0xff);
1066         hbf->b2_size = b2_size(hbf->byte_2_range);
1067
1068         if (! match(line, "HBF_START_CODE_RANGES")) {
1069                 eprintf("HBF_START_CODE_RANGES expected");
1070                 return FALSE;
1071         }
1072         for (;;) {
1073                 if (! get_text_line(line, MAXLINE, f))
1074                         return FALSE;
1075                 if (match(line, "HBF_END_CODE_RANGES"))
1076                         break;
1077                 if (! add_code_range(hbf, line))
1078                         return FALSE;
1079         }
1080
1081         for (;;) {
1082                 if (! get_text_line(line, MAXLINE, f))
1083                         return FALSE;
1084                 if (match(line, "HBF_END_FONT"))
1085                         break;
1086                 /* treat extra lines as properties (for private extensions) */
1087                 add_property(hbf, line);
1088         }
1089
1090         return TRUE;
1091 }
1092
1093 static FILE *
1094 path_open(path, filename, fullp)
1095         const   char    *path;
1096         const   char    *filename;
1097         char    **fullp;
1098 {
1099         if (LocalFileName(filename) && path != NULL) {
1100 #ifdef PATH_DELIMITER
1101                 int     len;
1102                 char    *fullname;
1103                 FILE    *f;
1104                 const   char    *p_next;
1105
1106                 len = strlen(filename);
1107                 for (;;) {
1108                         p_next = strchr(path, PATH_DELIMITER);
1109                         if (p_next == NULL)
1110                                 p_next = path + strlen(path);
1111                         fullname = concat(path, p_next - path, filename);
1112                         if ((f = fopen(fullname, "r")) != NULL) {
1113                                 *fullp = fullname;
1114                                 return f;
1115                         }
1116                         free(fullname);
1117                         if (*p_next == '\0')
1118                                 break;
1119                         path = p_next + 1;
1120                 }
1121 #endif
1122                 return NULL;
1123         }
1124         else {
1125                 *fullp = strdup(filename);
1126                 return fopen(*fullp, "r");
1127         }
1128 }
1129
1130 static bool
1131 real_open(filename, hbf)
1132         const   char    *filename;
1133 reg     HBF_STRUCT *hbf;
1134 {
1135         FILE    *f;
1136
1137         f = path_open(getenv("HBFPATH"), filename, &(hbf->filename));
1138         if (f == NULL) {
1139                 eprintf("can't read file '%s'", filename);
1140                 return FALSE;
1141         }
1142         if (! parse_file(f, hbf)) {
1143                 fclose(f);
1144                 return FALSE;
1145         }
1146         fclose(f);
1147         return TRUE;
1148 }
1149
1150 HBF *
1151 hbfOpen(filename)
1152         const   char    *filename;
1153 {
1154 reg     HBF_STRUCT *hbf;
1155
1156         if ((hbf = NEW(HBF_STRUCT)) == NULL) {
1157                 eprintf("can't allocate HBF structure");
1158                 return NULL;
1159         }
1160         clear_record(hbf);
1161         if (real_open(filename, hbf))
1162                 return &(hbf->public);
1163         hbfClose(&(hbf->public));
1164         return NULL;
1165 }
1166
1167 int
1168 HBF_OpenFont(filename, ptrHandleStorage)
1169         const   char    *filename;
1170         HBF     **ptrHandleStorage;
1171 {
1172         return (*ptrHandleStorage = hbfOpen(filename)) == NULL ? -1 : 0;
1173 }
1174
1175 /*
1176  *      Close files, free everything associated with the HBF.
1177  */
1178
1179 int
1180 HBF_CloseFont(hbfFile)
1181         HBF     *hbfFile;
1182 {
1183 reg     HBF_STRUCT      *hbf;
1184         PROPERTY        *prop_ptr, *prop_next;
1185         B2_RANGE        *b2r_ptr, *b2r_next;
1186         CODE_RANGE      *code_ptr, *code_next;
1187         BM_FILE         *bmf_ptr, *bmf_next;
1188         int             status;
1189
1190         status = 0;
1191         hbf = (HBF_STRUCT *)hbfFile;
1192
1193         if (hbf->filename != NULL)
1194                 free(hbf->filename);
1195         if (hbf->bitmap_buffer != NULL)
1196                 free(hbf->bitmap_buffer);
1197
1198         for (prop_ptr = hbf->property;
1199              prop_ptr != NULL;
1200              prop_ptr = prop_next) {
1201                 prop_next = prop_ptr->prop_next;
1202                 free(prop_ptr->prop_name);
1203                 free(prop_ptr->prop_value);
1204                 free((char *)prop_ptr);
1205         }
1206
1207         for (b2r_ptr = hbf->byte_2_range;
1208              b2r_ptr != NULL;
1209              b2r_ptr = b2r_next) {
1210                 b2r_next = b2r_ptr->b2r_next;
1211                 free((char *)b2r_ptr);
1212         }
1213
1214         for (code_ptr = hbf->code_range;
1215              code_ptr != NULL;
1216              code_ptr = code_next) {
1217                 code_next = code_ptr->code_next;
1218                 free((char *)code_ptr);
1219         }
1220
1221         for (bmf_ptr = hbf->bm_file;
1222              bmf_ptr != NULL;
1223              bmf_ptr = bmf_next) {
1224                 bmf_next = bmf_ptr->bmf_next;
1225 #ifdef IN_MEMORY
1226                 free((char *)(bmf_ptr->bmf_contents));
1227 #else
1228                 if (bmf_ptr->bmf_file != NULL &&
1229                     fclose(bmf_ptr->bmf_file) < 0)
1230                         status = -1;
1231 #endif
1232                 free(bmf_ptr->bmf_name);
1233                 free((char *)bmf_ptr);
1234         }
1235
1236         free((char *)hbf);
1237
1238         return status;
1239 }
1240
1241 void
1242 hbfClose(hbfFile)
1243         HBF     *hbfFile;
1244 {
1245         (void)HBF_CloseFont(hbfFile);
1246 }
1247
1248 /*
1249  *      Fetch a bitmap
1250  */
1251
1252 const byte *
1253 hbfGetBitmap(hbf, code)
1254         HBF             *hbf;
1255         HBF_CHAR        code;
1256 {
1257         return get_bitmap((HBF_STRUCT *)hbf, code, (byte *)NULL);
1258 }
1259
1260 int
1261 HBF_GetBitmap(hbf, code, buffer)
1262         HBF             *hbf;
1263         HBF_CHAR        code;
1264         byte            *buffer;
1265 {
1266         return get_bitmap((HBF_STRUCT *)hbf, code, buffer) == NULL ? -1 : 0;
1267 }
1268
1269 /*
1270  * Internal function to fetch a bitmap.
1271  * If buffer is non-null, it must be used.
1272  */
1273 static const byte *
1274 get_bitmap(hbf, code, buffer)
1275 reg     HBF_STRUCT      *hbf;
1276         HBF_CHAR        code;
1277         byte            *buffer;
1278 {
1279         CHAR_INDEX      pos, b2pos;
1280 reg     CODE_RANGE      *cp;
1281         BM_FILE         *bmf;
1282         int             bm_size;
1283         long            offset;
1284
1285         if ((b2pos = b2_pos(hbf, code)) == BAD_CHAR_INDEX)
1286                 return NULL;
1287         pos = hbf->b2_size*FirstByte(code) + b2pos;
1288         for (cp = hbf->code_range; cp != NULL; cp = cp->code_next)
1289                 if (cp->code_start <= code && code <= cp->code_finish) {
1290                         bmf = cp->code_bm_file;
1291                         bm_size = FileBitmapSize(&(hbf->public), cp);
1292                         offset = cp->code_offset +
1293                                    (long)(pos - cp->code_pos) * bm_size;
1294 #ifdef IN_MEMORY
1295                         if (buffer == NULL &&
1296                             ! cp->code_transposed && ! cp->code_inverted)
1297                                 return bmf->bmf_contents + offset;
1298 #endif /* IN_MEMORY */
1299                         if (buffer == NULL &&
1300                             ((buffer = local_buffer(hbf)) == NULL))
1301                                 return NULL;
1302 #ifdef IN_MEMORY
1303                         if (cp->code_transposed)
1304                                 copy_transposed(&(hbf->public),
1305                                                 buffer,
1306                                                 bmf->bmf_contents + offset);
1307                         else
1308                                 memcpy((char *)buffer,
1309                                        (char *)(bmf->bmf_contents + offset),
1310                                        bm_size);
1311 #else /* ! IN_MEMORY */
1312                         if (fseek(bmf->bmf_file, offset, 0) != 0) {
1313                                 eprintf("seek error on code 0x%04x", code);
1314                                 return NULL;
1315                         }
1316                         if (cp->code_transposed ?
1317                             ! get_transposed(&(hbf->public), bmf->bmf_file,
1318                                                 buffer) :
1319                             fread((char *)buffer,
1320                                         bm_size, 1, bmf->bmf_file) != 1) {
1321                                 eprintf("read error on code 0x%04x", code);
1322                                 return NULL;
1323                         }
1324 #endif /* IN_MEMORY */
1325                         if (cp->code_inverted)
1326                                 invert(buffer, HBF_BitmapSize(&(hbf->public)));
1327                         return buffer;
1328                 }
1329         eprintf("code 0x%04x out of range", code);
1330         return NULL;
1331 }
1332
1333 static byte *
1334 local_buffer(hbf)
1335         HBF_STRUCT      *hbf;
1336 {
1337         if (hbf->bitmap_buffer == NULL &&
1338             (hbf->bitmap_buffer = (byte *)malloc(HBF_BitmapSize(&(hbf->public)))) == NULL) {
1339                 eprintf("out of memory");
1340                 return NULL;
1341         }
1342         return hbf->bitmap_buffer;
1343 }
1344
1345 static void
1346 invert(buffer, length)
1347         byte    *buffer;
1348         unsigned int    length;
1349 {
1350         for ( ; length > 0; length--)
1351                 *buffer++ ^= 0xff;
1352 }
1353
1354 #ifdef IN_MEMORY
1355 static bool
1356 copy_transposed(hbf, bitmap, source)
1357         HBF     *hbf;
1358 reg     byte    *bitmap;
1359 reg     const   byte    *source;
1360 {
1361 reg     byte    *pos;
1362 reg     byte    *bm_end;
1363         int     x;
1364         int     width;
1365 reg     int     row_size;
1366 reg     int     c;
1367 reg     int     imask, omask;
1368
1369         width = hbfBitmapBBox(hbf)->hbf_width;
1370         row_size = HBF_RowSize(hbf);
1371         bm_end = bitmap + HBF_BitmapSize(hbf);
1372         (void)memset((char *)bitmap, '\0', HBF_BitmapSize(hbf));
1373         for (x = 0; x < width; x++) {
1374                 pos = bitmap + x/8;
1375                 omask = Bit(x%8);
1376                 /* y = 0 */
1377                 for (;;) {
1378                         c = *source++;
1379                         for (imask = Bit(0); imask != 0; imask >>= 1) {
1380                                 /*
1381                                  * At this point,
1382                                  *
1383                                  *      imask == Bit(y%8)
1384                                  *      pos == bitmap + y*row_size + x/8
1385                                  *
1386                                  * We examine bit y of row x of the input,
1387                                  * setting bit x of row y of the output if
1388                                  * required, by applying omask to *pos.
1389                                  */
1390                                 if ((c & imask) != 0)
1391                                         *pos |= omask;
1392                                 /* if (++y > height) goto end_column */
1393                                 pos += row_size;
1394                                 if (pos >= bm_end)
1395                                         goto end_column;
1396                         }
1397                 }
1398 end_column:
1399                 ;
1400         }
1401         return TRUE;
1402 }
1403 #else /* ! IN_MEMORY */
1404 static bool
1405 get_transposed(hbf, f, bitmap)
1406         HBF     *hbf;
1407         FILE    *f;
1408 reg     byte    *bitmap;
1409 {
1410 reg     byte    *pos;
1411 reg     byte    *bm_end;
1412         int     x;
1413         int     width;
1414 reg     int     row_size;
1415 reg     int     c;
1416 reg     int     imask, omask;
1417
1418         width = hbfBitmapBBox(hbf)->hbf_width;
1419         row_size = HBF_RowSize(hbf);
1420         bm_end = bitmap + HBF_BitmapSize(hbf);
1421         (void)memset((char *)bitmap, '\0', HBF_BitmapSize(hbf));
1422         for (x = 0; x < width; x++) {
1423                 pos = bitmap + x/8;
1424                 omask = Bit(x%8);
1425                 /* y = 0 */
1426                 for (;;) {
1427                         if ((c = getc(f)) == EOF)
1428                                 return FALSE;
1429                         for (imask = Bit(0); imask != 0; imask >>= 1) {
1430                                 /*
1431                                  * At this point,
1432                                  *
1433                                  *      imask == Bit(y%8)
1434                                  *      pos == bitmap + y*row_size + x/8
1435                                  *
1436                                  * We examine bit y of row x of the input,
1437                                  * setting bit x of row y of the output if
1438                                  * required, by applying omask to *pos.
1439                                  */
1440                                 if ((c & imask) != 0)
1441                                         *pos |= omask;
1442                                 /* if (++y > height) goto end_column */
1443                                 pos += row_size;
1444                                 if (pos >= bm_end)
1445                                         goto end_column;
1446                         }
1447                 }
1448 end_column:
1449                 ;
1450         }
1451         return TRUE;
1452 }
1453 #endif /* ! IN_MEMORY */
1454
1455 /*
1456  * Call function on each valid code in ascending order.
1457  */
1458 void
1459 hbfForEach(hbfFile, func, data)
1460 reg     HBF     *hbfFile;
1461 reg     void    (*func)_((HBF *sameHbfFile, HBF_CHAR code, void *data));
1462 reg     void    *data;
1463 {
1464         HBF_STRUCT      *hbf;
1465         CODE_RANGE      *cp;
1466 reg     B2_RANGE        *b2r;
1467 reg     unsigned        byte1, byte2;
1468 reg     unsigned        finish;
1469
1470         hbf = (HBF_STRUCT *)hbfFile;
1471         for (cp = hbf->code_range; cp != NULL; cp = cp->code_next) {
1472                 byte1 = FirstByte(cp->code_start);
1473                 byte2 = SecondByte(cp->code_start);
1474                 while (MakeCode(byte1, byte2) <= cp->code_finish) {
1475                         for (b2r = hbf->byte_2_range;
1476                              b2r != NULL;
1477                              b2r = b2r->b2r_next) {
1478                                 if (byte2 < b2r->b2r_start)
1479                                         byte2 = b2r->b2r_start;
1480                                 finish = b2r->b2r_finish;
1481                                 if (byte1 == FirstByte(cp->code_finish) &&
1482                                     finish > SecondByte(cp->code_finish))
1483                                         finish = SecondByte(cp->code_finish);
1484                                 while (byte2 <= finish) {
1485                                         (*func)(hbfFile,
1486                                                 MakeCode(byte1, byte2), data);
1487                                         byte2++;
1488                                 }
1489                         }
1490                         byte1++;
1491                         byte2 = 0;
1492                 }
1493         }
1494 }
1495
1496 const char *
1497 hbfFileName(hbf)
1498         HBF     *hbf;
1499 {
1500         return ((HBF_STRUCT *)hbf)->filename;
1501 }
1502
1503 long
1504 hbfChars(hbfFile)
1505         HBF     *hbfFile;
1506 {
1507         HBF_STRUCT      *hbf;
1508         CODE_RANGE      *cp;
1509         long            num_chars;
1510
1511         hbf = (HBF_STRUCT *)hbfFile;
1512         num_chars = 0;
1513         for (cp = hbf->code_range; cp != NULL; cp = cp->code_next)
1514                 num_chars +=
1515                         hbf->b2_size*FirstByte(cp->code_finish) +
1516                         b2_pos(hbf, cp->code_finish) -
1517                         (hbf->b2_size*FirstByte(cp->code_start) +
1518                         b2_pos(hbf, cp->code_start)) + 1;
1519         return num_chars;
1520 }
1521
1522 /*
1523  *      Functions also implemented as macros
1524  */
1525
1526 #ifdef hbfBitmapBBox
1527 #undef hbfBitmapBBox
1528 #endif
1529
1530 HBF_BBOX *
1531 hbfBitmapBBox(hbf)
1532         HBF     *hbf;
1533 {
1534         return &(hbf->hbf_bitmap_bbox);
1535 }
1536
1537 #ifdef hbfFontBBox
1538 #undef hbfFontBBox
1539 #endif
1540
1541 HBF_BBOX *
1542 hbfFontBBox(hbf)
1543         HBF     *hbf;
1544 {
1545         return &(hbf->hbf_font_bbox);
1546 }
1547
1548 const void *
1549 hbfGetByte2Range(hbfFile, b2r_pointer, startp, finishp)
1550         HBF             *hbfFile;
1551         const void      *b2r_pointer;
1552         byte            *startp;
1553         byte            *finishp;
1554 {
1555         HBF_STRUCT      *hbf;
1556         B2_RANGE        *b2r;
1557
1558         hbf = (HBF_STRUCT *)hbfFile;
1559         if (b2r_pointer == NULL)
1560                 b2r = hbf->byte_2_range;
1561         else
1562                 b2r = ((B2_RANGE *)b2r_pointer)->b2r_next;
1563         if(b2r == NULL)
1564                 return NULL;
1565         *startp = b2r->b2r_start;
1566         *finishp = b2r->b2r_finish;
1567         return (void *)b2r;
1568 }
1569
1570 const void *
1571 hbfGetCodeRange(hbfFile, code_pointer, startp, finishp)
1572         HBF             *hbfFile;
1573         const void      *code_pointer;
1574         HBF_CHAR        *startp;
1575         HBF_CHAR        *finishp;
1576 {
1577         HBF_STRUCT      *hbf;
1578         CODE_RANGE      *cp;
1579
1580         hbf = (HBF_STRUCT *)hbfFile;
1581         if (code_pointer == NULL)
1582                 cp = hbf->code_range;
1583         else
1584                 cp = ((CODE_RANGE *)code_pointer)->code_next;
1585         if(cp == NULL)
1586                 return NULL;
1587         *startp = cp->code_start;
1588         *finishp = cp->code_finish;
1589         return (void *)cp;
1590 }