]> git.karo-electronics.de Git - gbdfed.git/blob - bdf.c
Fixup several compile faults due to changes in recent distributions,
[gbdfed.git] / bdf.c
1 /*
2  * Copyright 2008 Department of Mathematical Sciences, New Mexico State University
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * DEPARTMENT OF MATHEMATICAL SCIENCES OR NEW MEXICO STATE UNIVERSITY BE
18  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
19  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 #include "bdfP.h"
23
24 #ifdef HAVE_HBF
25 #include "hbf.h"
26 #endif
27
28 #undef MAX
29 #define MAX(h, i) ((h) > (i) ? (h) : (i))
30
31 #undef MIN
32 #define MIN(l, o) ((l) < (o) ? (l) : (o))
33
34 /**************************************************************************
35  *
36  * Masks used for checking different bits per pixel cases.
37  *
38  **************************************************************************/
39
40 unsigned char bdf_onebpp[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
41 unsigned char bdf_twobpp[] = { 0xc0, 0x30, 0x0c, 0x03 };
42 unsigned char bdf_fourbpp[] = { 0xf0, 0x0f };
43 unsigned char bdf_eightbpp[] = { 0xff };
44
45 /**************************************************************************
46  *
47  * Default BDF font options.
48  *
49  **************************************************************************/
50
51 static bdf_options_t _bdf_opts = {
52 #ifdef HAVE_FREETYPE
53     FT_LOAD_DEFAULT,     /* OTF flags - hinting on.        */
54 #else
55     0,                   /* OTF flags                      */
56 #endif /* HAVE_FREETYPE */
57     1,                   /* Correct metrics.               */
58     1,                   /* Preserve unencoded glyphs.     */
59     1,                   /* Preserve comments.             */
60     1,                   /* Pad character-cells.           */
61     BDF_PROPORTIONAL,    /* Default spacing.               */
62     12,                  /* Default point size.            */
63     0,                   /* Default horizontal resolution. */
64     0,                   /* Default vertical resolution.   */
65     1,                   /* Bits per pixel.                */
66     BDF_UNIX_EOL,        /* Line separator.                */
67     BDF_PSF_ALL,         /* PSF font export options.       */
68     0,                   /* An X cursor font.              */
69 };
70
71 /**************************************************************************
72  *
73  * Builtin BDF font properties.
74  *
75  **************************************************************************/
76
77 /*
78  * List of most properties that might appear in a font.  Doesn't include the
79  * AXIS_* properties in X11R6 polymorphic fonts.
80  */
81 static bdf_property_t _bdf_properties[] = {
82     {"ADD_STYLE_NAME",          BDF_ATOM,     1},
83     {"AVERAGE_WIDTH",           BDF_INTEGER,  1},
84     {"AVG_CAPITAL_WIDTH",       BDF_INTEGER,  1},
85     {"AVG_LOWERCASE_WIDTH",     BDF_INTEGER,  1},
86     {"CAP_HEIGHT",              BDF_INTEGER,  1},
87     {"CHARSET_COLLECTIONS",     BDF_ATOM,     1},
88     {"CHARSET_ENCODING",        BDF_ATOM,     1},
89     {"CHARSET_REGISTRY",        BDF_ATOM,     1},
90     {"COMMENT",                 BDF_ATOM,     1},
91     {"COPYRIGHT",               BDF_ATOM,     1},
92     {"DEFAULT_CHAR",            BDF_CARDINAL, 1},
93     {"DESTINATION",             BDF_CARDINAL, 1},
94     {"DEVICE_FONT_NAME",        BDF_ATOM,     1},
95     {"END_SPACE",               BDF_INTEGER,  1},
96     {"FACE_NAME",               BDF_ATOM,     1},
97     {"FAMILY_NAME",             BDF_ATOM,     1},
98     {"FIGURE_WIDTH",            BDF_INTEGER,  1},
99     {"FONT",                    BDF_ATOM,     1},
100     {"FONTNAME_REGISTRY",       BDF_ATOM,     1},
101     {"FONT_ASCENT",             BDF_INTEGER,  1},
102     {"FONT_DESCENT",            BDF_INTEGER,  1},
103     {"FOUNDRY",                 BDF_ATOM,     1},
104     {"FULL_NAME",               BDF_ATOM,     1},
105     {"ITALIC_ANGLE",            BDF_INTEGER,  1},
106     {"MAX_SPACE",               BDF_INTEGER,  1},
107     {"MIN_SPACE",               BDF_INTEGER,  1},
108     {"NORM_SPACE",              BDF_INTEGER,  1},
109     {"NOTICE",                  BDF_ATOM,     1},
110     {"PIXEL_SIZE",              BDF_INTEGER,  1},
111     {"POINT_SIZE",              BDF_INTEGER,  1},
112     {"QUAD_WIDTH",              BDF_INTEGER,  1},
113     {"RAW_ASCENT",              BDF_INTEGER,  1},
114     {"RAW_AVERAGE_WIDTH",       BDF_INTEGER,  1},
115     {"RAW_AVG_CAPITAL_WIDTH",   BDF_INTEGER,  1},
116     {"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER,  1},
117     {"RAW_CAP_HEIGHT",          BDF_INTEGER,  1},
118     {"RAW_DESCENT",             BDF_INTEGER,  1},
119     {"RAW_END_SPACE",           BDF_INTEGER,  1},
120     {"RAW_FIGURE_WIDTH",        BDF_INTEGER,  1},
121     {"RAW_MAX_SPACE",           BDF_INTEGER,  1},
122     {"RAW_MIN_SPACE",           BDF_INTEGER,  1},
123     {"RAW_NORM_SPACE",          BDF_INTEGER,  1},
124     {"RAW_PIXEL_SIZE",          BDF_INTEGER,  1},
125     {"RAW_POINT_SIZE",          BDF_INTEGER,  1},
126     {"RAW_PIXELSIZE",           BDF_INTEGER,  1},
127     {"RAW_POINTSIZE",           BDF_INTEGER,  1},
128     {"RAW_QUAD_WIDTH",          BDF_INTEGER,  1},
129     {"RAW_SMALL_CAP_SIZE",      BDF_INTEGER,  1},
130     {"RAW_STRIKEOUT_ASCENT",    BDF_INTEGER,  1},
131     {"RAW_STRIKEOUT_DESCENT",   BDF_INTEGER,  1},
132     {"RAW_SUBSCRIPT_SIZE",      BDF_INTEGER,  1},
133     {"RAW_SUBSCRIPT_X",         BDF_INTEGER,  1},
134     {"RAW_SUBSCRIPT_Y",         BDF_INTEGER,  1},
135     {"RAW_SUPERSCRIPT_SIZE",    BDF_INTEGER,  1},
136     {"RAW_SUPERSCRIPT_X",       BDF_INTEGER,  1},
137     {"RAW_SUPERSCRIPT_Y",       BDF_INTEGER,  1},
138     {"RAW_UNDERLINE_POSITION",  BDF_INTEGER,  1},
139     {"RAW_UNDERLINE_THICKNESS", BDF_INTEGER,  1},
140     {"RAW_X_HEIGHT",            BDF_INTEGER,  1},
141     {"RELATIVE_SETWIDTH",       BDF_CARDINAL, 1},
142     {"RELATIVE_WEIGHT",         BDF_CARDINAL, 1},
143     {"RESOLUTION",              BDF_INTEGER,  1},
144     {"RESOLUTION_X",            BDF_CARDINAL, 1},
145     {"RESOLUTION_Y",            BDF_CARDINAL, 1},
146     {"SETWIDTH_NAME",           BDF_ATOM,     1},
147     {"SLANT",                   BDF_ATOM,     1},
148     {"SMALL_CAP_SIZE",          BDF_INTEGER,  1},
149     {"SPACING",                 BDF_ATOM,     1},
150     {"STRIKEOUT_ASCENT",        BDF_INTEGER,  1},
151     {"STRIKEOUT_DESCENT",       BDF_INTEGER,  1},
152     {"SUBSCRIPT_SIZE",          BDF_INTEGER,  1},
153     {"SUBSCRIPT_X",             BDF_INTEGER,  1},
154     {"SUBSCRIPT_Y",             BDF_INTEGER,  1},
155     {"SUPERSCRIPT_SIZE",        BDF_INTEGER,  1},
156     {"SUPERSCRIPT_X",           BDF_INTEGER,  1},
157     {"SUPERSCRIPT_Y",           BDF_INTEGER,  1},
158     {"UNDERLINE_POSITION",      BDF_INTEGER,  1},
159     {"UNDERLINE_THICKNESS",     BDF_INTEGER,  1},
160     {"WEIGHT",                  BDF_CARDINAL, 1},
161     {"WEIGHT_NAME",             BDF_ATOM,     1},
162     {"X_HEIGHT",                BDF_INTEGER,  1},
163     {"_MULE_BASELINE_OFFSET",   BDF_INTEGER,  1},
164     {"_MULE_RELATIVE_COMPOSE",  BDF_INTEGER,  1},
165     /*
166      * Throw this in to make it clear.
167      */
168     {"_XMBDFED_INFO",           BDF_ATOM,     1},
169 };
170
171 static unsigned int _num_bdf_properties =
172 sizeof(_bdf_properties) / sizeof(_bdf_properties[0]);
173
174 /*
175  * User defined properties.
176  */
177 static bdf_property_t *user_props;
178 static unsigned int nuser_props = 0;
179
180 /**************************************************************************
181  *
182  * Hash table utilities for the properties.
183  *
184  **************************************************************************/
185
186 #define INITIAL_HT_SIZE 241
187
188 typedef struct {
189     char *key;
190     void *data;
191 } _hashnode, *hashnode;
192
193 typedef struct {
194     int limit;
195     int size;
196     int used;
197     hashnode *table;
198 } hashtable;
199
200 typedef void (*hash_free_func)(hashnode node);
201
202 static hashnode *
203 hash_bucket(char *key, hashtable *ht)
204 {
205     char *kp = key;
206     unsigned int res = 0;
207     hashnode *bp = ht->table, *ndp;
208
209     /*
210      * Mocklisp hash function.
211      */
212     while (*kp)
213       res = (res << 5) - res + *kp++;
214
215     ndp = bp + (res % ht->size);
216     while (*ndp) {
217         kp = (*ndp)->key;
218         if (kp[0] == key[0] && strcmp(kp, key) == 0)
219           break;
220         ndp--;
221         if (ndp < bp)
222           ndp = bp + (ht->size - 1);
223     }
224     return ndp;
225 }
226
227 static void
228 hash_rehash(hashtable *ht)
229 {
230     hashnode *obp = ht->table, *bp, *nbp;
231     int i, sz = ht->size;
232
233     ht->size <<= 1;
234     ht->limit = ht->size / 3;
235     ht->table = (hashnode *) malloc(sizeof(hashnode) * ht->size);
236     (void) memset((char *) ht->table, 0, sizeof(hashnode) * ht->size);
237
238     for (i = 0, bp = obp; i < sz; i++, bp++) {
239         if (*bp) {
240             nbp = hash_bucket((*bp)->key, ht);
241             *nbp = *bp;
242         }
243     }
244     free((char *) obp);
245 }
246
247 static void
248 hash_init(hashtable *ht)
249 {
250     int sz = INITIAL_HT_SIZE;
251
252     ht->size = sz;
253     ht->limit = sz / 3;
254     ht->used = 0;
255     ht->table = (hashnode *) malloc(sizeof(hashnode) * sz);
256     (void) memset((char *) ht->table, 0, sizeof(hashnode) * sz);
257 }
258
259 static void
260 hash_free(hashtable *ht)
261 {
262     int i, sz = ht->size;
263     hashnode *bp = ht->table;
264
265     for (i = 0; i < sz; i++, bp++) {
266         if (*bp)
267           free((char *) *bp);
268     }
269     if (sz > 0)
270       free((char *) ht->table);
271 }
272
273 static void
274 hash_insert(char *key, void *data, hashtable *ht)
275 {
276     hashnode nn, *bp = hash_bucket(key, ht);
277
278     nn = *bp;
279     if (!nn) {
280         *bp = nn = (hashnode) malloc(sizeof(_hashnode));
281         nn->key = key;
282         nn->data = data;
283
284         if (ht->used >= ht->limit)
285           hash_rehash(ht);
286         ht->used++;
287     } else
288       nn->data = data;
289 }
290
291 static hashnode
292 hash_lookup(char *key, hashtable *ht)
293 {
294     hashnode *np = hash_bucket(key, ht);
295     return *np;
296 }
297
298 static void
299 hash_delete(char *name, hashtable *ht)
300 {
301     hashnode *hp;
302
303     hp = hash_bucket(name, ht);
304     if (*hp) {
305         free((char *) *hp);
306         *hp = 0;
307     }
308 }
309
310 /*
311  * The builtin property table.
312  */
313 static hashtable proptbl;
314
315 /**************************************************************************
316  *
317  * Utility types and functions.
318  *
319  **************************************************************************/
320
321 /*
322  * Function type for parsing lines of a BDF font.
323  */
324 typedef int (*_bdf_line_func_t)(
325     char *line,
326     unsigned int linelen,
327     unsigned int lineno,
328     void *call_data,
329     void *client_data
330 );
331
332 /*
333  * List structure for splitting lines into fields.
334  */
335 typedef struct {
336     char **field;
337     unsigned int size;
338     unsigned int used;
339     char *bfield;
340     unsigned int bsize;
341     unsigned int bused;
342 } _bdf_list_t;
343
344 /*
345  * Structure used while loading BDF fonts.
346  */
347 typedef struct {
348     unsigned int flags;
349     unsigned int cnt;
350     unsigned int row;
351     unsigned int bpr;
352     short minlb;
353     short maxlb;
354     short maxrb;
355     short maxas;
356     short maxds;
357     short rbearing;
358     char *glyph_name;
359     int glyph_enc;
360     bdf_font_t *font;
361     bdf_options_t *opts;
362     void *client_data;
363     bdf_callback_t callback;
364     bdf_callback_struct_t cb;
365     unsigned int have[2048];
366     _bdf_list_t list;
367 } _bdf_parse_t;
368
369 #define setsbit(m, cc) (m[(cc) >> 3] |= (1 << ((cc) & 7)))
370 #define sbitset(m, cc) (m[(cc) >> 3] & (1 << ((cc) & 7)))
371
372 /*
373  * An empty string for empty fields.
374  */
375 static char empty[1] = { 0 };
376
377 /*
378  * Assume the line is NULL terminated and that the `list' parameter was
379  * initialized the first time it was used.
380  */
381 static void
382 _bdf_split(char *separators, char *line, unsigned int linelen,
383            _bdf_list_t *list)
384 {
385     int mult, final_empty;
386     char *sp, *ep, *end;
387     unsigned char seps[32];
388
389     /*
390      * Initialize the list.
391      */
392     list->used = list->bused = 0;
393
394     /*
395      * If the line is empty, then simply return.
396      */
397     if (linelen == 0 || line[0] == 0)
398       return;
399
400     /*
401      * If the `separators' parameter is NULL or empty, split the list into
402      * individual bytes.
403      */
404     if (separators == 0 || *separators == 0) {
405         if (linelen > list->bsize) {
406             if (list->bsize)
407               list->bfield = (char *) malloc(linelen);
408             else
409               list->bfield = (char *) realloc(list->bfield, linelen);
410             list->bsize = linelen;
411         }
412         list->bused = linelen;
413         (void) memcpy(list->bfield, line, linelen);
414         return;
415     }
416
417     /*
418      * Prepare the separator bitmap.
419      */
420     (void) memset((char *) seps, 0, 32);
421
422     /*
423      * If the very last character of the separator string is a plus, then set
424      * the `mult' flag to indicate that multiple separators should be
425      * collapsed into one.
426      */
427     for (mult = 0, sp = separators; sp && *sp; sp++) {
428         if (*sp == '+' && *(sp + 1) == 0)
429           mult = 1;
430         else
431           setsbit(seps, *sp);
432     }
433
434     /*
435      * Break the line up into fields.
436      */
437     for (final_empty = 0, sp = ep = line, end = sp + linelen;
438          sp < end && *sp;) {
439         /*
440          * Collect everything that is not a separator.
441          */
442         for (; *ep && !sbitset(seps, *ep); ep++) ;
443
444         /*
445          * Resize the list if necessary.
446          */
447         if (list->used == list->size) {
448             if (list->size == 0)
449               list->field = (char **) malloc(sizeof(char *) * 5);
450             else
451               list->field = (char **)
452                   realloc((char *) list->field,
453                           sizeof(char *) * (list->size + 5));
454
455             list->size += 5;
456         }
457
458         /*
459          * Assign the field appropriately.
460          */
461         list->field[list->used++] = (ep > sp) ? sp : empty;
462
463         sp = ep;
464         if (mult) {
465             /*
466              * If multiple separators should be collapsed, do it now by
467              * setting all the separator characters to 0.
468              */
469             for (; *ep && sbitset(seps, *ep); ep++)
470               *ep = 0;
471         } else if (*ep != 0)
472           /*
473            * Don't collapse multiple separators by making them 0, so just
474            * make the one encountered 0.
475            */
476           *ep++ = 0;
477         final_empty = (ep > sp && *ep == 0);
478         sp = ep;
479     }
480
481     /*
482      * Finally, NULL terminate the list.
483      */
484     if (list->used + final_empty + 1 >= list->size) {
485         if (list->used == list->size) {
486             if (list->size == 0)
487               list->field = (char **) malloc(sizeof(char *) * 5);
488             else
489               list->field = (char **)
490                   realloc((char *) list->field,
491                           sizeof(char *) * (list->size + 5));
492             list->size += 5;
493         }
494     }
495     if (final_empty)
496       list->field[list->used++] = empty;
497
498     if (list->used == list->size) {
499         if (list->size == 0)
500           list->field = (char **) malloc(sizeof(char *) * 5);
501         else
502           list->field = (char **)
503               realloc((char *) list->field,
504                       sizeof(char *) * (list->size + 5));
505         list->size += 5;
506     }
507     list->field[list->used] = 0;
508 }
509
510 static void
511 _bdf_shift(unsigned int n, _bdf_list_t *list)
512 {
513     unsigned int i, u;
514
515     if (list == 0 || list->used == 0 || n == 0)
516       return;
517
518     if (n >= list->used) {
519         list->used = 0;
520         return;
521     }
522     for (u = n, i = 0; u < list->used; i++, u++)
523       list->field[i] = list->field[u];
524     list->used -= n;
525 }
526
527 static char *
528 _bdf_join(int c, unsigned int *len, _bdf_list_t *list)
529 {
530     unsigned int i, j;
531     char *fp, *dp;
532
533     if (list == 0 || list->used == 0)
534       return 0;
535
536     *len = 0;
537
538     dp = list->field[0];
539     for (i = j = 0; i < list->used; i++) {
540         fp = list->field[i];
541         while (*fp)
542           dp[j++] = *fp++;
543         if (i + 1 < list->used)
544           dp[j++] = c;
545     }
546     dp[j] = 0;
547
548     *len = j;
549     return dp;
550 }
551
552 /*
553  * High speed file reader that passes each line to a callback.
554  */
555 static int
556 _bdf_readlines(int fd, _bdf_line_func_t callback, void *client_data,
557                unsigned int *lno)
558 {
559     _bdf_line_func_t cb;
560     unsigned int lineno;
561     int n, res, done, refill, bytes, hold;
562     char *ls, *le, *pp, *pe, *hp;
563     char buf[65536];
564
565     if (callback == 0)
566       return -1;
567
568     cb = callback;
569     lineno = 1;
570     buf[0] = 0;
571     res = done = 0;
572     pp = ls = le = buf;
573     bytes = 65536;
574     while (!done && (n = read(fd, pp, bytes)) > 0) {
575         /*
576          * Determine the new end of the buffer pages.
577          */
578         pe = pp + n;
579
580         for (refill = 0; done == 0 && refill == 0; ) {
581             while (le < pe && *le != '\n' && *le != '\r')
582               le++;
583
584             if (le == pe) {
585                 /*
586                  * Hit the end of the last page in the buffer.  Need to find
587                  * out how many pages to shift and how many pages need to be
588                  * read in.  Adjust the line start and end pointers down to
589                  * point to the right places in the pages.
590                  */
591                 pp = buf + (((ls - buf) >> 13) << 13);
592                 n = pp - buf;
593                 ls -= n;
594                 le -= n;
595                 n = pe - pp;
596                 memmove(buf, pp, n);
597 #if 0
598                 memcpy(buf, pp, n);
599 #endif
600                 pp = buf + n;
601                 bytes = 65536 - n;
602                 refill = 1;
603             } else {
604                 /*
605                  * Temporarily NULL terminate the line.
606                  */
607                 hp = le;
608                 hold = *le;
609                 *le = 0;
610
611                 if (callback && *ls != '#' && *ls != 0x1a && le > ls &&
612                     (res = (*cb)(ls, le - ls, lineno, (void *) &cb,
613                                  client_data)) != 0)
614                   done = 1;
615                 else {
616                     ls = ++le;
617                     /*
618                      * Handle the case of DOS crlf sequences.
619                      */
620                     if (le < pe && hold == '\n' && *le =='\r')
621                       ls = ++le;
622                 }
623
624                 /*
625                  * Increment the line number.
626                  */
627                 lineno++;
628
629                 /*
630                  * Restore the character at the end of the line.
631                  */
632                 *hp = hold;
633             }
634         }
635     }
636     *lno = lineno;
637     return res;
638 }
639
640 unsigned char *
641 _bdf_strdup(unsigned char *s, unsigned int len)
642 {
643     unsigned char *ns;
644
645     if (s == 0 || len == 0)
646       return 0;
647
648     ns = (unsigned char *) malloc(len);
649     (void) memcpy((char *) ns, (char *) s, len);
650     return ns;
651 }
652
653 void
654 _bdf_memmove(char *dest, char *src, unsigned int bytes)
655 {
656     int i, j;
657
658     i = (int) bytes;
659     j = i & 7;
660     i = (i + 7) >> 3;
661
662     /*
663      * Do a memmove using Ye Olde Duff's Device for efficiency.
664      */
665     if (src < dest) {
666         src += bytes;
667         dest += bytes;
668
669         switch (j) {
670           case 0: do {
671               *--dest = *--src;
672             case 7: *--dest = *--src;
673             case 6: *--dest = *--src;
674             case 5: *--dest = *--src;
675             case 4: *--dest = *--src;
676             case 3: *--dest = *--src;
677             case 2: *--dest = *--src;
678             case 1: *--dest = *--src;
679           } while (--i > 0);
680         }
681     } else if (src > dest) {
682         switch (j) {
683           case 0: do {
684               *dest++ = *src++;
685             case 7: *dest++ = *src++;
686             case 6: *dest++ = *src++;
687             case 5: *dest++ = *src++;
688             case 4: *dest++ = *src++;
689             case 3: *dest++ = *src++;
690             case 2: *dest++ = *src++;
691             case 1: *dest++ = *src++;
692           } while (--i > 0);
693         }
694     }
695 }
696
697 static unsigned char a2i[128] = {
698     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
699     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
700     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
701     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
702     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
703     0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
704     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
705     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
706     0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
707     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
708     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
709 };
710
711 static unsigned char odigits[32] = {
712     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
713     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
714     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
715     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
716 };
717
718 static unsigned char ddigits[32] = {
719     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
720     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
721     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
722     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
723 };
724
725 static unsigned char hdigits[32] = {
726     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
727     0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
728     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
729     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
730 };
731
732 #define isdigok(m, d) (m[(d) >> 3] & (1 << ((d) & 7)))
733
734 /*
735  * Routine to convert an ASCII string into an unsigned int integer.
736  */
737 unsigned int
738 _bdf_atoul(char *s, char **end, int base)
739 {
740     unsigned int v;
741     unsigned char *dmap;
742
743     if (s == 0 || *s == 0)
744       return 0;
745
746     /*
747      * Make sure the radix is something recognizable.  Default to 10.
748      */
749     switch (base) {
750       case 8: dmap = odigits; break;
751       case 16: dmap = hdigits; break;
752       default: base = 10; dmap = ddigits; break;
753     }
754
755     /*
756      * Check for the special hex prefixes of 0[xX] or [Uu][+-].
757      */
758     if ((*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X')) ||
759         ((*s == 'U' || *s == 'u') && (*(s + 1) == '+' || *(s + 1) == '-'))) {
760         base = 16;
761         dmap = hdigits;
762         s += 2;
763     }
764
765     for (v = 0; isdigok(dmap, *s); s++)
766       v = (v * base) + a2i[(int) *s];
767
768     if (end != 0)
769       *end = s;
770
771     return v;
772 }
773
774 /*
775  * Routine to convert an ASCII string into an signed int integer.
776  */
777 int
778 _bdf_atol(char *s, char **end, int base)
779 {
780     int v, neg;
781     unsigned char *dmap;
782
783     if (s == 0 || *s == 0)
784       return 0;
785
786     /*
787      * Make sure the radix is something recognizable.  Default to 10.
788      */
789     switch (base) {
790       case 8: dmap = odigits; break;
791       case 16: dmap = hdigits; break;
792       default: base = 10; dmap = ddigits; break;
793     }
794
795     /*
796      * Check for a minus sign.
797      */
798     neg = 0;
799     if (*s == '-') {
800         s++;
801         neg = 1;
802     }
803
804     /*
805      * Check for the special hex prefix.
806      */
807     if ((*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X')) ||
808         ((*s == 'U' || *s == 'u') && (*(s + 1) == '+' || *(s + 1) == '-'))) {
809         base = 16;
810         dmap = hdigits;
811         s += 2;
812     }
813
814     for (v = 0; isdigok(dmap, *s); s++)
815       v = (v * base) + a2i[(int) *s];
816
817     if (end != 0)
818       *end = s;
819
820     return (!neg) ? v : -v;
821 }
822
823 /*
824  * Routine to convert an ASCII string into an signed short integer.
825  */
826 short
827 _bdf_atos(char *s, char **end, int base)
828 {
829     short v, neg;
830     unsigned char *dmap;
831
832     if (s == 0 || *s == 0)
833       return 0;
834
835     /*
836      * Make sure the radix is something recognizable.  Default to 10.
837      */
838     switch (base) {
839       case 8: dmap = odigits; break;
840       case 16: dmap = hdigits; break;
841       default: base = 10; dmap = ddigits; break;
842     }
843
844     /*
845      * Check for a minus.
846      */
847     neg = 0;
848     if (*s == '-') {
849         s++;
850         neg = 1;
851     }
852
853     /*
854      * Check for the special hex prefix.
855      */
856     if (*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X')) {
857         base = 16;
858         dmap = hdigits;
859         s += 2;
860     }
861
862     for (v = 0; isdigok(dmap, *s); s++)
863       v = (v * base) + a2i[(int) *s];
864
865     if (end != 0)
866       *end = s;
867
868     return (!neg) ? v : -v;
869 }
870
871 /*
872  * Routine to compare two glyphs by encoding so they can be sorted.
873  */
874 static int
875 by_encoding(const void *a, const void *b)
876 {
877     bdf_glyph_t *c1, *c2;
878
879     c1 = (bdf_glyph_t *) a;
880     c2 = (bdf_glyph_t *) b;
881     if (c1->encoding < c2->encoding)
882       return -1;
883     else if (c1->encoding > c2->encoding)
884       return 1;
885     return 0;
886 }
887
888 /**************************************************************************
889  *
890  * BDF font file parsing flags and functions.
891  *
892  **************************************************************************/
893
894 /*
895  * Parse flags.
896  */
897 #define _BDF_START     0x0001
898 #define _BDF_FONT_NAME 0x0002
899 #define _BDF_SIZE      0x0004
900 #define _BDF_FONT_BBX  0x0008
901 #define _BDF_PROPS     0x0010
902 #define _BDF_GLYPHS    0x0020
903 #define _BDF_GLYPH     0x0040
904 #define _BDF_ENCODING  0x0080
905 #define _BDF_SWIDTH    0x0100
906 #define _BDF_DWIDTH    0x0200
907 #define _BDF_BBX       0x0400
908 #define _BDF_BITMAP    0x0800
909
910 #define _BDF_SWIDTH_ADJ 0x1000
911
912 #define _BDF_GLYPH_BITS (_BDF_GLYPH|_BDF_ENCODING|_BDF_SWIDTH|\
913                          _BDF_DWIDTH|_BDF_BBX|_BDF_BITMAP)
914
915 #define _BDF_GLYPH_WIDTH_CHECK 0x40000000
916 #define _BDF_GLYPH_HEIGHT_CHECK 0x80000000
917
918 /*
919  * Auto correction messages.
920  */
921 #define ACMSG1 "FONT_ASCENT property missing.  Added \"FONT_ASCENT %hd\"."
922 #define ACMSG2 "FONT_DESCENT property missing.  Added \"FONT_DESCENT %hd\"."
923 #define ACMSG3 "Font width != actual width.  Old: %hd New: %hd."
924 #define ACMSG4 "Font left bearing != actual left bearing.  Old: %hd New: %hd."
925 #define ACMSG5 "Font ascent != actual ascent.  Old: %hd New: %hd."
926 #define ACMSG6 "Font descent != actual descent.  Old: %hd New: %hd."
927 #define ACMSG7 "Font height != actual height. Old: %hd New: %hd."
928 #define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made."
929 #define ACMSG9 "SWIDTH field missing at line %d.  Set automatically."
930 #define ACMSG10 "DWIDTH field missing at line %d.  Set to glyph width."
931 #define ACMSG11 "SIZE bits per pixel field adjusted to %hd."
932 #define ACMSG12 "Duplicate encoding %d (%s) changed to unencoded."
933 #define ACMSG13 "Glyph %d extra rows removed."
934 #define ACMSG14 "Glyph %d extra columns removed."
935 #define ACMSG15 "Incorrect glyph count: %d indicated but %d found."
936
937 /*
938  * Error messages.
939  */
940 #define ERRMSG1 "[line %d] Missing \"%s\" line."
941 #define ERRMSG2 "[line %d] Font header corrupted or missing fields."
942 #define ERRMSG3 "[line %d] Font glyphs corrupted or missing fields."
943
944 void
945 _bdf_add_acmsg(bdf_font_t *font, char *msg, unsigned int len)
946 {
947     char *cp;
948
949     if (font->acmsgs_len == 0)
950       font->acmsgs = (char *) malloc(len + 2);
951     else
952       font->acmsgs = (char *) realloc(font->acmsgs,
953                                       font->acmsgs_len + len + 2);
954
955     cp = font->acmsgs + font->acmsgs_len;
956     (void) memcpy(cp, msg, len);
957     cp += len;
958     *cp++ = '\n';
959     *cp = 0;
960     font->acmsgs_len += len + 1;
961 }
962
963 void
964 _bdf_add_comment(bdf_font_t *font, char *comment, unsigned int len)
965 {
966     char *cp;
967
968     if (font->comments_len == 0)
969       font->comments = (char *) malloc(len + 2);
970     else
971       font->comments = (char *) realloc(font->comments,
972                                         font->comments_len + len + 2);
973
974     cp = font->comments + font->comments_len;
975     (void) memcpy(cp, comment, len);
976     cp += len;
977     *cp++ = '\n';
978     *cp = 0;
979     font->comments_len += len + 1;
980 }
981
982 /*
983  * Set the spacing from the font name if it exists, or set it to the default
984  * specified in the options.
985  */
986 static void
987 _bdf_set_default_spacing(bdf_font_t *font, bdf_options_t *opts)
988 {
989     unsigned int len;
990     char name[128];
991     _bdf_list_t list;
992
993     if (font == 0 || font->name == 0 || font->name[0] == 0)
994       return;
995
996     font->spacing = opts->font_spacing;
997
998     len = (unsigned int) (strlen(font->name) + 1);
999     (void) memcpy(name, font->name, len);
1000     list.size = list.used = 0;
1001     _bdf_split("-", name, len, &list);
1002     if (list.used == 15) {
1003         switch (list.field[11][0]) {
1004           case 'C': case 'c': font->spacing = BDF_CHARCELL; break;
1005           case 'M': case 'm': font->spacing = BDF_MONOWIDTH; break;
1006           case 'P': case 'p': font->spacing = BDF_PROPORTIONAL; break;
1007         }
1008     }
1009     if (list.size > 0)
1010       free((char *) list.field);
1011 }
1012
1013 /*
1014  * Determine if the property is an atom or not.  If it is, then clean it up so
1015  * the double quotes are removed if they exist.
1016  */
1017 static int
1018 _bdf_is_atom(char *line, unsigned int linelen, char **name, char **value)
1019 {
1020     int hold;
1021     char *sp, *ep;
1022     bdf_property_t *p;
1023
1024     *name = sp = ep = line;
1025     while (*ep && *ep != ' ' && *ep != '\t')
1026       ep++;
1027
1028     hold = -1;
1029     if (*ep) {
1030         hold = *ep;
1031         *ep = 0;
1032     }
1033
1034     p = bdf_get_property(sp);
1035
1036     /*
1037      * Restore the character that was saved before any return can happen.
1038      */
1039     if (hold != -1)
1040       *ep = hold;
1041
1042     /*
1043      * If the propert exists and is not an atom, just return here.
1044      */
1045     if (p && p->format != BDF_ATOM)
1046       return 0;
1047
1048     /*
1049      * The property is an atom.  Trim all leading and trailing whitespace and
1050      * double quotes for the atom value.
1051      */
1052     sp = ep;
1053     ep = line + linelen;
1054
1055     /*
1056      * Trim the leading whitespace if it exists.
1057      */
1058     *sp++ = 0;
1059     while (*sp && (*sp == ' ' || *sp == '\t'))
1060       sp++;
1061
1062     /*
1063      * Trim the leading double quote if it exists.
1064      */
1065     if (*sp == '"')
1066       sp++;
1067     *value = sp;
1068
1069     /*
1070      * Trim the trailing whitespace if it exists.
1071      */
1072     while (ep > sp && (*(ep - 1) == ' ' || *(ep - 1) == '\t'))
1073       *--ep = 0;
1074
1075     /*
1076      * Trim the trailing double quote if it exists.
1077      */
1078     if (ep > sp && *(ep - 1) == '"')
1079       *--ep = 0;
1080
1081     return 1;
1082 }
1083
1084 static void
1085 _bdf_add_property(bdf_font_t *font, char *name, char *value)
1086 {
1087     unsigned int propid;
1088     hashnode hn;
1089     int len;
1090     bdf_property_t *prop, *fp;
1091
1092     /*
1093      * First, check to see if the property already exists in the font.
1094      */
1095     if ((hn = hash_lookup(name, (hashtable *) font->internal)) != 0) {
1096         /*
1097          * The property already exists in the font, so simply replace
1098          * the value of the property with the current value.
1099          */
1100         fp = font->props + (long) hn->data;
1101
1102         switch (fp->format) {
1103           case BDF_ATOM:
1104             /*
1105              * Delete the current atom if it exists.
1106              */
1107             if (fp->value.atom != 0)
1108               free(fp->value.atom);
1109
1110             if (value == 0)
1111               len = 1;
1112             else
1113               len = strlen(value) + 1;
1114             if (len > 1) {
1115                 fp->value.atom = (char *) malloc(len);
1116                 (void) memcpy(fp->value.atom, value, len);
1117             } else
1118               fp->value.atom = 0;
1119             break;
1120           case BDF_INTEGER:
1121             fp->value.int32 = _bdf_atol(value, 0, 10);
1122             break;
1123           case BDF_CARDINAL:
1124             fp->value.card32 = _bdf_atoul(value, 0, 10);
1125             break;
1126         }
1127         return;
1128     }
1129
1130     /*
1131      * See if this property type exists yet or not.  If not, create it.
1132      */
1133     hn = hash_lookup(name, &proptbl);
1134     if (hn == 0) {
1135         bdf_create_property(name, BDF_ATOM);
1136         hn = hash_lookup(name, &proptbl);
1137     }
1138
1139     /*
1140      * Allocate another property if this is overflow.
1141      */
1142     if (font->props_used == font->props_size) {
1143         if (font->props_size == 0)
1144           font->props = (bdf_property_t *) malloc(sizeof(bdf_property_t));
1145         else
1146           font->props = (bdf_property_t *)
1147               realloc((char *) font->props, sizeof(bdf_property_t) *
1148                       (font->props_size + 1));
1149         fp = font->props + font->props_size;
1150         (void) memset((char *) fp, 0, sizeof(bdf_property_t));
1151         font->props_size++;
1152     }
1153
1154     propid = (long) hn->data;
1155     if (propid >= _num_bdf_properties)
1156       prop = user_props + (propid - _num_bdf_properties);
1157     else
1158       prop = _bdf_properties + propid;
1159
1160     fp = font->props + font->props_used;
1161
1162     fp->name = prop->name;
1163     fp->format = prop->format;
1164     fp->builtin = prop->builtin;
1165
1166     switch (prop->format) {
1167       case BDF_ATOM:
1168         if (value == 0)
1169           len = 1;
1170         else
1171           len = strlen(value) + 1;
1172         if (len > 1) {
1173             fp->value.atom = (char *) malloc(len);
1174             (void) memcpy(fp->value.atom, value, len);
1175         } else
1176           fp->value.atom = 0;
1177         break;
1178       case BDF_INTEGER:
1179         fp->value.int32 = _bdf_atol(value, 0, 10);
1180         break;
1181       case BDF_CARDINAL:
1182         fp->value.card32 = _bdf_atoul(value, 0, 10);
1183         break;
1184     }
1185
1186     /*
1187      * If the property happens to be a comment, then it doesn't need
1188      * to be added to the internal hash table.
1189      */
1190     if (memcmp(name, "COMMENT", 7) != 0)
1191       /*
1192        * Add the property to the font property table.
1193        */
1194       hash_insert(fp->name, (void *) font->props_used,
1195                   (hashtable *) font->internal);
1196
1197     font->props_used++;
1198
1199     /*
1200      * Some special cases need to be handled here.  The DEFAULT_CHAR property
1201      * needs to be located if it exists in the property list, the FONT_ASCENT
1202      * and FONT_DESCENT need to be assigned if they are present, and the
1203      * SPACING property should override the default spacing.
1204      */
1205     if (memcmp(name, "DEFAULT_CHAR", 12) == 0)
1206       font->default_glyph = fp->value.int32;
1207     else if (memcmp(name, "FONT_ASCENT", 11) == 0)
1208       font->font_ascent = fp->value.int32;
1209     else if (memcmp(name, "FONT_DESCENT", 12) == 0)
1210       font->font_descent = fp->value.int32;
1211     else if (memcmp(name, "SPACING", 7) == 0) {
1212         if (fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P')
1213           font->spacing = BDF_PROPORTIONAL;
1214         else if (fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M')
1215           font->spacing = BDF_MONOWIDTH;
1216         else if (fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C')
1217           font->spacing = BDF_CHARCELL;
1218     }
1219 }
1220
1221 /*
1222  * Actually parse the glyph info and bitmaps.
1223  */
1224 static int
1225 _bdf_parse_glyphs(char *line, unsigned int linelen, unsigned int lineno,
1226                   void *call_data, void *client_data)
1227 {
1228     int c;
1229     char *s;
1230     unsigned char *bp;
1231     unsigned int i, slen = 0, nibbles;
1232     double ps, rx, dw, sw;
1233     /*_bdf_line_func_t *next;*/
1234     _bdf_parse_t *p;
1235     bdf_glyph_t *glyph;
1236     bdf_font_t *font;
1237     char nbuf[128];
1238
1239     /*next = (_bdf_line_func_t *) call_data;*/
1240     p = (_bdf_parse_t *) client_data;
1241
1242     font = p->font;
1243
1244     /*
1245      * Check for a comment.
1246      */
1247     if (memcmp(line, "COMMENT", 7) == 0) {
1248         linelen -= 7;
1249         s = line + 7;
1250         if (*s != 0) {
1251             s++;
1252             linelen--;
1253         }
1254         _bdf_add_comment(p->font, s, linelen);
1255         return 0;
1256     }
1257
1258     /*
1259      * The very first thing expected is the number of glyphs.
1260      */
1261     if (!(p->flags & _BDF_GLYPHS)) {
1262         if (memcmp(line, "CHARS", 5) != 0) {
1263             sprintf(nbuf, ERRMSG1, lineno, "CHARS");
1264             _bdf_add_acmsg(p->font, nbuf, strlen(nbuf));
1265             return BDF_MISSING_CHARS;
1266         }
1267         _bdf_split(" +", line, linelen, &p->list);
1268         p->cnt = font->glyphs_size = _bdf_atoul(p->list.field[1], 0, 10);
1269
1270         /*
1271          * Make sure the number of glyphs is non-zero.
1272          */
1273         if (p->cnt == 0)
1274           font->glyphs_size = 64;
1275
1276         font->glyphs = (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) *
1277                                               font->glyphs_size);
1278         /*
1279          * Make sure the glyph structures are initialized.
1280          */
1281         (void) memset((char *) font->glyphs, 0,
1282                       sizeof(bdf_glyph_t) * font->glyphs_size);
1283
1284         /*
1285          * Set up the callback to indicate the glyph loading is about to
1286          * begin.
1287          */
1288         if (p->callback != 0) {
1289             p->cb.reason = BDF_LOAD_START;
1290             p->cb.total = p->cnt;
1291             p->cb.current = 0;
1292             (*p->callback)(&p->cb, p->client_data);
1293         }
1294         p->flags |= _BDF_GLYPHS;
1295         return 0;
1296     }
1297
1298     /*
1299      * Check for the ENDFONT field.
1300      */
1301     if (memcmp(line, "ENDFONT", 7) == 0) {
1302         /*
1303          * Sort the glyphs by encoding.
1304          */
1305         qsort((char *) font->glyphs, font->glyphs_used, sizeof(bdf_glyph_t),
1306               by_encoding);
1307
1308         p->flags &= ~_BDF_START;
1309         return 0;
1310     }
1311
1312     /*
1313      * Check for the ENDCHAR field.
1314      */
1315     if (memcmp(line, "ENDCHAR", 7) == 0) {
1316         /*
1317          * Set up and call the callback if it was passed.
1318          */
1319         if (p->callback != 0) {
1320             p->cb.reason = BDF_LOADING;
1321             p->cb.total = font->glyphs_size;
1322             p->cb.current = font->glyphs_used;
1323             (*p->callback)(&p->cb, p->client_data);
1324         }
1325         p->glyph_enc = 0;
1326         p->flags &= ~_BDF_GLYPH_BITS;
1327         return 0;
1328     }
1329
1330     /*
1331      * Check to see if a glyph is being scanned but should be ignored
1332      * because it is an unencoded glyph.
1333      */
1334     if ((p->flags & _BDF_GLYPH) &&
1335         p->glyph_enc == -1 && p->opts->keep_unencoded == 0)
1336       return 0;
1337
1338     /*
1339      * Check for the STARTCHAR field.
1340      */
1341     if (memcmp(line, "STARTCHAR", 9) == 0) {
1342         /*
1343          * Set the character name in the parse info first until the
1344          * encoding can be checked for an unencoded character.
1345          */
1346         if (p->glyph_name != 0)
1347           free(p->glyph_name);
1348         _bdf_split(" +", line, linelen, &p->list);
1349         _bdf_shift(1, &p->list);
1350         s = _bdf_join(' ', &slen, &p->list);
1351         p->glyph_name = (char *) malloc(slen + 1);
1352         (void) memcpy(p->glyph_name, s, slen + 1);
1353         p->flags |= _BDF_GLYPH;
1354         return 0;
1355     }
1356
1357     /*
1358      * Check for the ENCODING field.
1359      */
1360     if (memcmp(line, "ENCODING", 8) == 0) {
1361         if (!(p->flags & _BDF_GLYPH)) {
1362             /*
1363              * Missing STARTCHAR field.
1364              */
1365             sprintf(nbuf, ERRMSG1, lineno, "STARTCHAR");
1366             _bdf_add_acmsg(font, nbuf, strlen(nbuf));
1367             return BDF_MISSING_STARTCHAR;
1368         }
1369         _bdf_split(" +", line, linelen, &p->list);
1370         p->glyph_enc = _bdf_atol(p->list.field[1], 0, 10);
1371
1372         /*
1373          * Check to see if this encoding has already been encountered.  If it
1374          * has then change it to unencoded so it gets added if indicated.
1375          */
1376         if (p->glyph_enc >= 0) {
1377             if (_bdf_glyph_modified(p->have, p->glyph_enc)) {
1378                 /*
1379                  * Add a message saying a glyph has been moved to the
1380                  * unencoded area.
1381                  */
1382                 sprintf(nbuf, ACMSG12, p->glyph_enc, p->glyph_name);
1383                 _bdf_add_acmsg(font, nbuf, strlen(nbuf));
1384                 p->glyph_enc = -1;
1385                 font->modified = 1;
1386             } else
1387               _bdf_set_glyph_modified(p->have, p->glyph_enc);
1388         }
1389
1390         if (p->glyph_enc >= 0) {
1391             /*
1392              * Make sure there are enough glyphs allocated in case the
1393              * number of characters happen to be wrong.
1394              */
1395             if (font->glyphs_used == font->glyphs_size) {
1396                 font->glyphs = (bdf_glyph_t *)
1397                     realloc((char *) font->glyphs,
1398                             sizeof(bdf_glyph_t) * (font->glyphs_size + 64));
1399                 (void) memset((char *) (font->glyphs + font->glyphs_size),
1400                               0, sizeof(bdf_glyph_t) << 6);
1401                 font->glyphs_size += 64;
1402             }
1403
1404             glyph = font->glyphs + font->glyphs_used++;
1405             glyph->name = p->glyph_name;
1406             glyph->encoding = p->glyph_enc;
1407
1408             /*
1409              * Reset the initial glyph info.
1410              */
1411             p->glyph_name = 0;
1412         } else {
1413             /*
1414              * Unencoded glyph.  Check to see if it should be added or not.
1415              */
1416             if (p->opts->keep_unencoded != 0) {
1417                 /*
1418                  * Allocate the next unencoded glyph.
1419                  */
1420                 if (font->unencoded_used == font->unencoded_size) {
1421                     if (font->unencoded_size == 0)
1422                       font->unencoded = (bdf_glyph_t *)
1423                           malloc(sizeof(bdf_glyph_t) << 2);
1424                     else
1425                       font->unencoded = (bdf_glyph_t *)
1426                           realloc((char *) font->unencoded,
1427                                   sizeof(bdf_glyph_t) *
1428                                   (font->unencoded_size + 4));
1429                     font->unencoded_size += 4;
1430                 }
1431
1432                 glyph = font->unencoded + font->unencoded_used;
1433                 glyph->name = p->glyph_name;
1434                 glyph->encoding = font->unencoded_used++;
1435             } else
1436               /*
1437                * Free up the glyph name if the unencoded shouldn't be
1438                * kept.
1439                */
1440               free(p->glyph_name);
1441
1442             p->glyph_name = 0;
1443         }
1444
1445         /*
1446          * Clear the flags that might be added when width and height are
1447          * checked for consistency.
1448          */
1449         p->flags &= ~(_BDF_GLYPH_WIDTH_CHECK|_BDF_GLYPH_HEIGHT_CHECK);
1450
1451         p->flags |= _BDF_ENCODING;
1452         return 0;
1453     }
1454
1455     /*
1456      * Point at the glyph being constructed.
1457      */
1458     if (p->glyph_enc == -1)
1459       glyph = font->unencoded + (font->unencoded_used - 1);
1460     else
1461       glyph = font->glyphs + (font->glyphs_used - 1);
1462
1463     /*
1464      * Check to see if a bitmap is being constructed.
1465      */
1466     if (p->flags & _BDF_BITMAP) {
1467         /*
1468          * If there are more rows than are specified in the glyph metrics,
1469          * ignore the remaining lines.
1470          */
1471         if (p->row >= glyph->bbx.height) {
1472             if (!(p->flags & _BDF_GLYPH_HEIGHT_CHECK)) {
1473                 sprintf(nbuf, ACMSG13, glyph->encoding);
1474                 _bdf_add_acmsg(font, nbuf, strlen(nbuf));
1475                 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
1476                 font->modified = 1;
1477             }
1478             return 0;
1479         }
1480
1481         /*
1482          * Only collect the number of nibbles indicated by the glyph metrics.
1483          * If there are more columns, they are simply ignored.
1484          */
1485         nibbles = p->bpr << 1;
1486         bp = glyph->bitmap + (p->row * p->bpr);
1487         for (i = 0, *bp = 0; i < nibbles; i++) {
1488             c = line[i];
1489             *bp = (*bp << 4) + a2i[c];
1490             if (i + 1 < nibbles && (i & 1))
1491               *++bp = 0;
1492         }
1493
1494         /*
1495          * If any line has extra columns, indicate they have been removed.
1496          */
1497         if ((line[nibbles] == '0' || a2i[(int) line[nibbles]] != 0) &&
1498             !(p->flags & _BDF_GLYPH_WIDTH_CHECK)) {
1499             sprintf(nbuf, ACMSG14, glyph->encoding);
1500             _bdf_add_acmsg(font, nbuf, strlen(nbuf));
1501             p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1502             font->modified = 1;
1503         }
1504
1505         p->row++;
1506         return 0;
1507     }
1508
1509     /*
1510      * Expect the SWIDTH (scalable width) field next.
1511      */
1512     if (memcmp(line, "SWIDTH", 6) == 0) {
1513         if (!(p->flags & _BDF_ENCODING)) {
1514             /*
1515              * Missing ENCODING field.
1516              */
1517             sprintf(nbuf, ERRMSG1, lineno, "ENCODING");
1518             _bdf_add_acmsg(font, nbuf, strlen(nbuf));
1519             return BDF_MISSING_ENCODING;
1520         }
1521         _bdf_split(" +", line, linelen, &p->list);
1522         glyph->swidth = _bdf_atoul(p->list.field[1], 0, 10);
1523         p->flags |= _BDF_SWIDTH;
1524         return 0;
1525     }
1526
1527     /*
1528      * Expect the DWIDTH (scalable width) field next.
1529      */
1530     if (memcmp(line, "DWIDTH", 6) == 0) {
1531         _bdf_split(" +", line, linelen, &p->list);
1532         glyph->dwidth = _bdf_atoul(p->list.field[1], 0, 10);
1533
1534         if (!(p->flags & _BDF_SWIDTH)) {
1535             /*
1536              * Missing SWIDTH field.  Add an auto correction message and set
1537              * the scalable width from the device width.
1538              */
1539             sprintf(nbuf, ACMSG9, lineno);
1540             _bdf_add_acmsg(font, nbuf, strlen(nbuf));
1541             ps = (double) font->point_size;
1542             rx = (double) font->resolution_x;
1543             dw = (double) glyph->dwidth;
1544             glyph->swidth = (unsigned short) ((dw * 72000.0) / (ps * rx));
1545         }
1546
1547         p->flags |= _BDF_DWIDTH;
1548         return 0;
1549     }
1550
1551     /*
1552      * Expect the BBX field next.
1553      */
1554     if (memcmp(line, "BBX", 3) == 0) {
1555         _bdf_split(" +", line, linelen, &p->list);
1556         glyph->bbx.width = _bdf_atos(p->list.field[1], 0, 10);
1557         glyph->bbx.height = _bdf_atos(p->list.field[2], 0, 10);
1558         glyph->bbx.x_offset = _bdf_atos(p->list.field[3], 0, 10);
1559         glyph->bbx.y_offset = _bdf_atos(p->list.field[4], 0, 10);
1560
1561         /*
1562          * Generate the ascent and descent of the character.
1563          */
1564         glyph->bbx.ascent = glyph->bbx.height + glyph->bbx.y_offset;
1565         glyph->bbx.descent = -glyph->bbx.y_offset;
1566
1567         /*
1568          * Determine the overall font bounding box as the characters are
1569          * loaded so corrections can be done later if indicated.
1570          */
1571         p->maxas = MAX(glyph->bbx.ascent, p->maxas);
1572         p->maxds = MAX(glyph->bbx.descent, p->maxds);
1573         p->rbearing = glyph->bbx.width + glyph->bbx.x_offset;
1574         p->maxrb = MAX(p->rbearing, p->maxrb);
1575         p->minlb = MIN(glyph->bbx.x_offset, p->minlb);
1576         p->maxlb = MAX(glyph->bbx.x_offset, p->maxlb);
1577
1578         if (!(p->flags & _BDF_DWIDTH)) {
1579             /*
1580              * Missing DWIDTH field.  Add an auto correction message and set
1581              * the device width to the glyph width.
1582              */
1583             sprintf(nbuf, ACMSG10, lineno);
1584             _bdf_add_acmsg(font, nbuf, strlen(nbuf));
1585             glyph->dwidth = glyph->bbx.width;
1586         }
1587
1588         /*
1589          * If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH
1590          * value if necessary.
1591          */
1592         if (p->opts->correct_metrics != 0) {
1593             /*
1594              * Determine the point size of the glyph.
1595              */
1596             ps = (double) font->point_size;
1597             rx = (double) font->resolution_x;
1598             dw = (double) glyph->dwidth;
1599             sw = (unsigned short) ((dw * 72000.0) / (ps * rx));
1600
1601             if (sw != glyph->swidth) {
1602                 glyph->swidth = sw;
1603                 if (p->glyph_enc == -1)
1604                   _bdf_set_glyph_modified(font->umod,
1605                                           font->unencoded_used - 1);
1606                 else
1607                   _bdf_set_glyph_modified(font->nmod, glyph->encoding);
1608                 p->flags |= _BDF_SWIDTH_ADJ;
1609                 font->modified = 1;
1610             }
1611         }
1612         p->flags |= _BDF_BBX;
1613         return 0;
1614     }
1615
1616     /*
1617      * And finally, gather up the bitmap.
1618      */
1619     if (memcmp(line, "BITMAP", 6) == 0) {
1620         if (!(p->flags & _BDF_BBX)) {
1621             /*
1622              * Missing BBX field.
1623              */
1624             sprintf(nbuf, ERRMSG1, lineno, "BBX");
1625             _bdf_add_acmsg(font, nbuf, strlen(nbuf));
1626             return BDF_MISSING_BBX;
1627         }
1628         /*
1629          * Allocate enough space for the bitmap.
1630          */
1631         p->bpr = ((glyph->bbx.width * p->font->bpp) + 7) >> 3;
1632         glyph->bytes = p->bpr * glyph->bbx.height;
1633         glyph->bitmap = (unsigned char *) malloc(glyph->bytes);
1634         p->row = 0;
1635         p->flags |= _BDF_BITMAP;
1636         return 0;
1637     }
1638
1639     return BDF_INVALID_LINE;
1640 }
1641
1642 /*
1643  * Load the font properties.
1644  */
1645 static int
1646 _bdf_parse_properties(char *line, unsigned int linelen, unsigned int lineno,
1647                       void *call_data, void *client_data)
1648 {
1649     unsigned int vlen;
1650     _bdf_line_func_t *next;
1651     _bdf_parse_t *p;
1652     char *name, *value, nbuf[128];
1653
1654     next = (_bdf_line_func_t *) call_data;
1655     p = (_bdf_parse_t *) client_data;
1656
1657     /*
1658      * Check for the end of the properties.
1659      */
1660     if (memcmp(line, "ENDPROPERTIES", 13) == 0) {
1661         /*
1662          * If the FONT_ASCENT or FONT_DESCENT properties have not been
1663          * encountered yet, then make sure they are added as properties and
1664          * make sure they are set from the font bounding box info.
1665          *
1666          * This is *always* done regardless of the options, because X11
1667          * requires these two fields to compile fonts.
1668          */
1669         if (bdf_get_font_property(p->font, "FONT_ASCENT") == 0) {
1670             p->font->font_ascent = p->font->bbx.ascent;
1671             sprintf(nbuf, "%hd", p->font->bbx.ascent);
1672             _bdf_add_property(p->font, "FONT_ASCENT", nbuf);
1673             sprintf(nbuf, ACMSG1, p->font->bbx.ascent);
1674             _bdf_add_acmsg(p->font, nbuf, strlen(nbuf));
1675             p->font->modified = 1;
1676         }
1677         if (bdf_get_font_property(p->font, "FONT_DESCENT") == 0) {
1678             p->font->font_descent = p->font->bbx.descent;
1679             sprintf(nbuf, "%hd", p->font->bbx.descent);
1680             _bdf_add_property(p->font, "FONT_DESCENT", nbuf);
1681             sprintf(nbuf, ACMSG2, p->font->bbx.descent);
1682             _bdf_add_acmsg(p->font, nbuf, strlen(nbuf));
1683             p->font->modified = 1;
1684         }
1685         p->flags &= ~_BDF_PROPS;
1686         *next = _bdf_parse_glyphs;
1687         return 0;
1688     }
1689
1690     /*
1691      * Ignore the _XFREE86_GLYPH_RANGES and _XMBDFED_INFO properties.
1692      */
1693     if (memcmp(line, "_XFREE86_GLYPH_RANGES", 21) == 0 ||
1694         memcmp(line, "_XMBDFED_INFO", 13) == 0)
1695       return 0;
1696
1697     /*
1698      * Handle COMMENT fields and properties in a special way to preserve
1699      * the spacing.
1700      */
1701     if (memcmp(line, "COMMENT", 7) == 0) {
1702         name = value = line;
1703         value += 7;
1704         if (*value)
1705           *value++ = 0;
1706         _bdf_add_property(p->font, name, value);
1707     } else if (_bdf_is_atom(line, linelen, &name, &value))
1708       _bdf_add_property(p->font, name, value);
1709     else {
1710         _bdf_split(" +", line, linelen, &p->list);
1711         name = p->list.field[0];
1712         _bdf_shift(1, &p->list);
1713         value = _bdf_join(' ', &vlen, &p->list);
1714         _bdf_add_property(p->font, name, value);
1715     }
1716
1717     return 0;
1718 }
1719
1720 /*
1721  * Load the font header.
1722  */
1723 static int
1724 _bdf_parse_start(char *line, unsigned int linelen, unsigned int lineno,
1725                  void *call_data, void *client_data)
1726 {
1727     unsigned int slen = 0;
1728     _bdf_line_func_t *next;
1729     _bdf_parse_t *p;
1730     bdf_font_t *font;
1731     char *s, nbuf[128];
1732
1733     next = (_bdf_line_func_t *) call_data;
1734     p = (_bdf_parse_t *) client_data;
1735
1736     /*
1737      * Check for a comment.  This is done to handle those fonts that have
1738      * comments before the STARTFONT line for some reason.
1739      */
1740     if (memcmp(line, "COMMENT", 7) == 0) {
1741         if (p->opts->keep_comments != 0 && p->font != 0) {
1742             linelen -= 7;
1743             s = line + 7;
1744             if (*s != 0) {
1745                 s++;
1746                 linelen--;
1747             }
1748             _bdf_add_comment(p->font, s, linelen);
1749         }
1750         return 0;
1751     }
1752
1753     if (!(p->flags & _BDF_START)) {
1754         if (memcmp(line, "STARTFONT", 9) != 0)
1755           /*
1756            * No STARTFONT field is a good indication of a problem.
1757            */
1758           return BDF_MISSING_START;
1759         p->flags = _BDF_START;
1760         p->font = font = (bdf_font_t *) calloc(1, sizeof(bdf_font_t));
1761         p->font->internal = (void *) malloc(sizeof(hashtable));
1762         hash_init((hashtable *) p->font->internal);
1763         p->font->spacing = p->opts->font_spacing;
1764         p->font->default_glyph = -1;
1765         return 0;
1766     }
1767
1768     /*
1769      * Check for the start of the properties.
1770      */
1771     if (memcmp(line, "STARTPROPERTIES", 15) == 0) {
1772         _bdf_split(" +", line, linelen, &p->list);
1773         p->cnt = p->font->props_size = _bdf_atoul(p->list.field[1], 0, 10);
1774         p->font->props = (bdf_property_t *)
1775             malloc(sizeof(bdf_property_t) * p->cnt);
1776         p->flags |= _BDF_PROPS;
1777         *next = _bdf_parse_properties;
1778         return 0;
1779     }
1780
1781     /*
1782      * Check for the FONTBOUNDINGBOX field.
1783      */
1784     if (memcmp(line, "FONTBOUNDINGBOX", 15) == 0) {
1785         if (!(p->flags & _BDF_SIZE)) {
1786             /*
1787              * Missing the SIZE field.
1788              */
1789             sprintf(nbuf, ERRMSG1, lineno, "SIZE");
1790             _bdf_add_acmsg(p->font, nbuf, strlen(nbuf));
1791             return BDF_MISSING_SIZE;
1792         }
1793         _bdf_split(" +", line, linelen, &p->list);
1794         p->font->bbx.width = _bdf_atos(p->list.field[1], 0, 10);
1795         p->font->bbx.height = _bdf_atos(p->list.field[2], 0, 10);
1796         p->font->bbx.x_offset = _bdf_atos(p->list.field[3], 0, 10);
1797         p->font->bbx.y_offset = _bdf_atos(p->list.field[4], 0, 10);
1798         p->font->bbx.ascent = p->font->bbx.height + p->font->bbx.y_offset;
1799         p->font->bbx.descent = -p->font->bbx.y_offset;
1800         p->flags |= _BDF_FONT_BBX;
1801         return 0;
1802     }
1803
1804     /*
1805      * The next thing to check for is the FONT field.
1806      */
1807     if (memcmp(line, "FONT", 4) == 0) {
1808         _bdf_split(" +", line, linelen, &p->list);
1809         _bdf_shift(1, &p->list);
1810         s = _bdf_join(' ', &slen, &p->list);
1811         p->font->name = (char *) malloc(slen + 1);
1812         (void) memcpy(p->font->name, s, slen + 1);
1813         /*
1814          * If the font name is an XLFD name, set the spacing to the one in the
1815          * font name.  If there is no spacing fall back on the default.
1816          */
1817         _bdf_set_default_spacing(p->font, p->opts);
1818         p->flags |= _BDF_FONT_NAME;
1819         return 0;
1820     }
1821
1822     /*
1823      * Check for the SIZE field.
1824      */
1825     if (memcmp(line, "SIZE", 4) == 0) {
1826         if (!(p->flags & _BDF_FONT_NAME)) {
1827             /*
1828              * Missing the FONT field.
1829              */
1830             sprintf(nbuf, ERRMSG1, lineno, "FONT");
1831             _bdf_add_acmsg(p->font, nbuf, strlen(nbuf));
1832             return BDF_MISSING_FONTNAME;
1833         }
1834         _bdf_split(" +", line, linelen, &p->list);
1835         p->font->point_size = _bdf_atoul(p->list.field[1], 0, 10);
1836         p->font->resolution_x = _bdf_atoul(p->list.field[2], 0, 10);
1837         p->font->resolution_y = _bdf_atoul(p->list.field[3], 0, 10);
1838
1839         /*
1840          * Check for the bits per pixel field.
1841          */
1842         if (p->list.used == 5) {
1843             p->font->bpp = _bdf_atos(p->list.field[4], 0, 10);
1844             if (p->font->bpp > 1 && (p->font->bpp & 1)) {
1845                 /*
1846                  * Move up to the next bits per pixel value if an odd number
1847                  * is encountered.
1848                  */
1849                 p->font->bpp++;
1850                 if (p->font->bpp <= 4) {
1851                     sprintf(nbuf, ACMSG11, p->font->bpp);
1852                     _bdf_add_acmsg(p->font, nbuf, strlen(nbuf));
1853                 }
1854             }
1855             if (p->font->bpp > 4) {
1856                 sprintf(nbuf, ACMSG11, p->font->bpp);
1857                 _bdf_add_acmsg(p->font, nbuf, strlen(nbuf));
1858                 p->font->bpp = 4;
1859             }
1860         } else
1861           p->font->bpp = 1;
1862
1863         p->flags |= _BDF_SIZE;
1864         return 0;
1865     }
1866
1867     return BDF_INVALID_LINE;
1868 }
1869
1870 /**************************************************************************
1871  *
1872  * API.
1873  *
1874  **************************************************************************/
1875
1876 void
1877 bdf_setup(void)
1878 {
1879     long i;
1880     bdf_property_t *prop;
1881
1882     hash_init(&proptbl);
1883     for (i = 0, prop = _bdf_properties; i < _num_bdf_properties; i++, prop++)
1884       hash_insert(prop->name, (void *) i, &proptbl);
1885 }
1886
1887 void
1888 bdf_cleanup(void)
1889 {
1890     unsigned int i;
1891     bdf_property_t *prop;
1892
1893     hash_free(&proptbl);
1894
1895     /*
1896      * Free up the user defined properties.
1897      */
1898     for (prop = user_props, i = 0; i < nuser_props; i++, prop++) {
1899         free(prop->name);
1900         if (prop->format == BDF_ATOM && prop->value.atom != 0)
1901           free(prop->value.atom);
1902     }
1903     if (nuser_props > 0)
1904       free((char *) user_props);
1905
1906     _bdf_glyph_name_cleanup();
1907 }
1908
1909 bdf_font_t *
1910 bdf_load_font(FILE *in, bdf_options_t *opts, bdf_callback_t callback,
1911               void *data)
1912 {
1913     int n;
1914     unsigned int lineno;
1915     char msgbuf[128];
1916     _bdf_parse_t p;
1917
1918     (void) memset((char *) &p, 0, sizeof(_bdf_parse_t));
1919     p.opts = (opts != 0) ? opts : &_bdf_opts;
1920     p.minlb = 32767;
1921     p.callback = callback;
1922     p.client_data = data;
1923     n = _bdf_readlines(fileno(in), _bdf_parse_start, (void *) &p, &lineno);
1924
1925     if (p.font != 0) {
1926         /*
1927          * If the font is not proportional, set the fonts monowidth
1928          * field to the width of the font bounding box.
1929          */
1930         if (p.font->spacing != BDF_PROPORTIONAL)
1931           p.font->monowidth = p.font->bbx.width;
1932
1933         /*
1934          * If the number of glyphs loaded is not that of the original count,
1935          * indicate the difference.
1936          */
1937         if (p.cnt != p.font->glyphs_used + p.font->unencoded_used) {
1938             sprintf(msgbuf, ACMSG15, p.cnt,
1939                     p.font->glyphs_used + p.font->unencoded_used);
1940             _bdf_add_acmsg(p.font, msgbuf, strlen(msgbuf));
1941             p.font->modified = 1;
1942         }
1943
1944         /*
1945          * Once the font has been loaded, adjust the overall font metrics if
1946          * necessary.
1947          */
1948         if (p.opts->correct_metrics != 0 &&
1949             (p.font->glyphs_used > 0 || p.font->unencoded_used > 0)) {
1950             if (p.maxrb - p.minlb != p.font->bbx.width) {
1951                 sprintf(msgbuf, ACMSG3, p.font->bbx.width, p.maxrb - p.minlb);
1952                 _bdf_add_acmsg(p.font, msgbuf, strlen(msgbuf));
1953                 p.font->bbx.width = p.maxrb - p.minlb;
1954                 p.font->modified = 1;
1955             }
1956             if (p.font->bbx.x_offset != p.minlb) {
1957                 sprintf(msgbuf, ACMSG4, p.font->bbx.x_offset, p.minlb);
1958                 _bdf_add_acmsg(p.font, msgbuf, strlen(msgbuf));
1959                 p.font->bbx.x_offset = p.minlb;
1960                 p.font->modified = 1;
1961             }
1962             if (p.font->bbx.ascent != p.maxas) {
1963                 sprintf(msgbuf, ACMSG5, p.font->bbx.ascent, p.maxas);
1964                 _bdf_add_acmsg(p.font, msgbuf, strlen(msgbuf));
1965                 p.font->bbx.ascent = p.maxas;
1966                 p.font->modified = 1;
1967             }
1968             if (p.font->bbx.descent != p.maxds) {
1969                 sprintf(msgbuf, ACMSG6, p.font->bbx.descent, p.maxds);
1970                 _bdf_add_acmsg(p.font, msgbuf, strlen(msgbuf));
1971                 p.font->bbx.descent = p.maxds;
1972                 p.font->bbx.y_offset = -p.maxds;
1973                 p.font->modified = 1;
1974             }
1975             if (p.maxas + p.maxds != p.font->bbx.height) {
1976                 sprintf(msgbuf, ACMSG7, p.font->bbx.height, p.maxas + p.maxds);
1977                 _bdf_add_acmsg(p.font, msgbuf, strlen(msgbuf));
1978             }
1979             p.font->bbx.height = p.maxas + p.maxds;
1980
1981             if (p.flags & _BDF_SWIDTH_ADJ)
1982               _bdf_add_acmsg(p.font, ACMSG8, strlen(ACMSG8));
1983         }
1984     }
1985
1986     /*
1987      * Last, if an error happened during loading, handle the messages.
1988      */
1989     if (n < 0 && callback != 0) {
1990         /*
1991          * An error was returned.  Alert the client.
1992          */
1993         p.cb.reason = BDF_ERROR;
1994         p.cb.errlineno = lineno;
1995         (*callback)(&p.cb, data);
1996     } else if (p.flags & _BDF_START) {
1997         if (p.font != 0) {
1998             /*
1999              * The ENDFONT field was never reached or did not exist.
2000              */
2001             if (!(p.flags & _BDF_GLYPHS))
2002               /*
2003                * Error happened while parsing header.
2004                */
2005               sprintf(msgbuf, ERRMSG2, lineno);
2006             else
2007               /*
2008                * Error happened when parsing glyphs.
2009                */
2010               sprintf(msgbuf, ERRMSG3, lineno);
2011
2012             _bdf_add_acmsg(p.font, msgbuf, strlen(msgbuf));
2013         }
2014
2015         if (callback != 0) {
2016             p.cb.reason = BDF_ERROR;
2017             p.cb.errlineno = lineno;
2018             (*callback)(&p.cb, data);
2019         }
2020     } else if (callback != 0) {
2021         /*
2022          * This forces the progress bar to always finish.
2023          */
2024         p.cb.current = p.cb.total;
2025         (*p.callback)(&p.cb, p.client_data);
2026     }
2027
2028     /*
2029      * Free up the list used during the parsing.
2030      */
2031     if (p.list.size > 0)
2032       free((char *) p.list.field);
2033
2034     if (p.font != 0) {
2035         /*
2036          * Make sure the comments are NULL terminated if they exist.
2037          */
2038         if (p.font->comments_len > 0) {
2039             p.font->comments = (char *) realloc(p.font->comments,
2040                                                 p.font->comments_len + 1);
2041             p.font->comments[p.font->comments_len] = 0;
2042         }
2043
2044         /*
2045          * Make sure the auto-correct messages are NULL terminated if they
2046          * exist.
2047          */
2048         if (p.font->acmsgs_len > 0) {
2049             p.font->acmsgs = (char *) realloc(p.font->acmsgs,
2050                                               p.font->acmsgs_len + 1);
2051             p.font->acmsgs[p.font->acmsgs_len] = 0;
2052         }
2053     }
2054
2055     return p.font;
2056 }
2057
2058 #ifdef HAVE_HBF
2059
2060 static int
2061 _bdf_parse_hbf_header(char *line, unsigned int linelen, unsigned int lineno,
2062                       void *call_data, void *client_data)
2063 {
2064     unsigned int vlen = 0;
2065     char *name, *value;
2066     _bdf_parse_t *p;
2067     /*_bdf_line_func_t *next;*/
2068     char nbuf[24];
2069
2070     /*next = (_bdf_line_func_t *) call_data;*/
2071     p = (_bdf_parse_t *) client_data;
2072
2073     /*
2074      * Check for comments.
2075      */
2076     if (memcmp(line, "COMMENT", 7) == 0) {
2077         if (p->opts->keep_comments != 0 && p->font != 0) {
2078             name = line;
2079             value = name + 7;
2080             vlen = linelen - 7;
2081             if (*value) {
2082                 *value++ = 0;
2083                 vlen--;
2084             }
2085             /*
2086              * If the properties are being parsed, add the comment as a
2087              * property.  Otherwise, simply add the comment in the normal
2088              * fashion.
2089              */
2090             if (p->flags & _BDF_PROPS)
2091               _bdf_add_property(p->font, name, value);
2092             else
2093               _bdf_add_comment(p->font, value, vlen);
2094         }
2095         return 0;
2096     }
2097
2098     if (!(p->flags & _BDF_START)) {
2099         if (memcmp(line, "HBF_START_FONT", 14) != 0)
2100           return -1;
2101         p->flags = _BDF_START;
2102         p->font = (bdf_font_t *) calloc(1, sizeof(bdf_font_t));
2103         /*
2104          * HBF fonts are always assumed to be 1 bit per pixel.
2105          */
2106         p->font->bpp = 1;
2107         p->font->internal = (void *) malloc(sizeof(hashtable));
2108         hash_init((hashtable *) p->font->internal);
2109         p->font->hbf = 1;
2110         p->font->spacing = p->opts->font_spacing;
2111         p->font->default_glyph = -1;
2112         return 0;
2113     }
2114
2115     /*
2116      * Check for the HBF_END_FONT field.
2117      */
2118     if (memcmp(line, "HBF_END_FONT", 12) == 0)
2119       /*
2120        * Need to perform some checks here to see whether some fields are
2121        * missing or not.
2122        */
2123       return 0;
2124
2125     /*
2126      * Check for HBF keywords which will be added as comments.  These should
2127      * never occur in the properties list.  Assume they won't.
2128      */
2129     if (memcmp(line, "HBF_", 4) == 0) {
2130         if (p->opts->keep_comments != 0)
2131           _bdf_add_comment(p->font, line, linelen);
2132         return 0;
2133     }
2134
2135     if (!(p->flags & _BDF_PROPS)) {
2136         /*
2137          * Check for the start of the properties.
2138          */
2139         if (memcmp(line, "STARTPROPERTIES", 15) == 0) {
2140             _bdf_split(" +", line, linelen, &p->list);
2141             p->cnt = p->font->props_size = _bdf_atoul(p->list.field[1], 0, 10);
2142             p->font->props = (bdf_property_t *)
2143                 malloc(sizeof(bdf_property_t) * p->cnt);
2144             p->flags |= _BDF_PROPS;
2145             return 0;
2146         }
2147
2148         /*
2149          * Check for the CHARS field.
2150          */
2151         if (memcmp(line, "CHARS", 5) == 0) {
2152             _bdf_split(" +", line, linelen, &p->list);
2153             p->cnt = p->font->glyphs_size =
2154                 _bdf_atoul(p->list.field[1], 0, 10);
2155             p->font->glyphs = (bdf_glyph_t *)
2156                 malloc(sizeof(bdf_glyph_t) * p->cnt);
2157             return 0;
2158         }
2159
2160         /*
2161          * Check for the FONTBOUNDINGBOX field.
2162          */
2163         if (memcmp(line, "FONTBOUNDINGBOX", 15) == 0) {
2164             if (!(p->flags & (_BDF_START|_BDF_FONT_NAME|_BDF_SIZE)))
2165               return -1;
2166             _bdf_split(" +", line, linelen, &p->list);
2167             p->font->bbx.width = _bdf_atos(p->list.field[1], 0, 10);
2168             p->font->bbx.height = _bdf_atos(p->list.field[2], 0, 10);
2169             p->font->bbx.x_offset = _bdf_atos(p->list.field[3], 0, 10);
2170             p->font->bbx.y_offset = _bdf_atos(p->list.field[4], 0, 10);
2171             p->font->bbx.ascent = p->font->bbx.height + p->font->bbx.y_offset;
2172             p->font->bbx.descent = -p->font->bbx.y_offset;
2173             p->flags |= _BDF_FONT_BBX;
2174             return 0;
2175         }
2176
2177         /*
2178          * The next thing to check for is the FONT field.
2179          */
2180         if (memcmp(line, "FONT", 4) == 0) {
2181             if (!(p->flags & _BDF_START))
2182               return -1;
2183             _bdf_split(" +", line, linelen, &p->list);
2184             _bdf_shift(1, &p->list);
2185             value = _bdf_join(' ', &vlen, &p->list);
2186             p->font->name = (char *) malloc(vlen + 1);
2187             (void) memcpy(p->font->name, value, vlen + 1);
2188             /*
2189              * If the font name is an XLFD name, set the spacing to the one in
2190              * the font name.  If there is no spacing fall back on the
2191              * default.
2192              */
2193             _bdf_set_default_spacing(p->font, p->opts);
2194             p->flags |= _BDF_FONT_NAME;
2195             return 0;
2196         }
2197
2198         /*
2199          * Check for the SIZE field.
2200          */
2201         if (memcmp(line, "SIZE", 4) == 0) {
2202             if (!(p->flags & (_BDF_START|_BDF_FONT_NAME)))
2203               return -1;
2204             _bdf_split(" +", line, linelen, &p->list);
2205             p->font->point_size = _bdf_atoul(p->list.field[1], 0, 10);
2206             p->font->resolution_x = _bdf_atoul(p->list.field[2], 0, 10);
2207             p->font->resolution_y = _bdf_atoul(p->list.field[3], 0, 10);
2208             p->flags |= _BDF_SIZE;
2209             return 0;
2210         }
2211     } else {
2212         /*
2213          * Check for the end of the properties.
2214          */
2215         if (memcmp(line, "ENDPROPERTIES", 13) == 0) {
2216             /*
2217              * If the FONT_ASCENT or FONT_DESCENT properties have not been
2218              * encountered yet, then make sure they are added as properties and
2219              * make sure they are set from the font bounding box info.
2220              *
2221              * This is *always* done regardless of the options, because X11
2222              * requires these two fields to compile fonts.
2223              */
2224             if (bdf_get_font_property(p->font, "FONT_ASCENT") == 0) {
2225                 p->font->font_ascent = p->font->bbx.ascent;
2226                 sprintf(nbuf, "%hd", p->font->bbx.ascent);
2227                 _bdf_add_property(p->font, "FONT_ASCENT", nbuf);
2228                 sprintf(nbuf, ACMSG1, p->font->bbx.ascent);
2229                 _bdf_add_acmsg(p->font, nbuf, strlen(nbuf));
2230                 p->font->modified = 1;
2231             }
2232             if (bdf_get_font_property(p->font, "FONT_DESCENT") == 0) {
2233                 p->font->font_descent = p->font->bbx.descent;
2234                 sprintf(nbuf, "%hd", p->font->bbx.descent);
2235                 _bdf_add_property(p->font, "FONT_DESCENT", nbuf);
2236                 sprintf(nbuf, ACMSG2, p->font->bbx.descent);
2237                 _bdf_add_acmsg(p->font, nbuf, strlen(nbuf));
2238                 p->font->modified = 1;
2239             }
2240             p->flags &= ~_BDF_PROPS;
2241             return 0;
2242         }
2243
2244         /*
2245          * Handle the next thing in the usual property fashion.
2246          */
2247         if (_bdf_is_atom(line, linelen, &name, &value))
2248           _bdf_add_property(p->font, name, value);
2249         else {
2250             _bdf_split(" +", line, linelen, &p->list);
2251             name = p->list.field[0];
2252             _bdf_shift(1, &p->list);
2253             value = _bdf_join(' ', &vlen, &p->list);
2254             _bdf_add_property(p->font, name, value);
2255         }
2256         return 0;
2257     }
2258
2259     /*
2260      * Anything else is an error.
2261      */
2262     return -1;
2263 }
2264
2265 #define CONST const
2266
2267 static void
2268 _bdf_add_hbf_glyph(HBF *hbf, unsigned int code, void *callback_data)
2269 {
2270     CONST unsigned char *bmap;
2271     unsigned int n;
2272     bdf_glyph_t *gp;
2273     bdf_font_t *font;
2274     _bdf_parse_t *p;
2275     HBF_BBOX *fbbx;
2276     double ps, rx, dw;
2277     char nbuf[24];
2278
2279     /*
2280      * Attempt to get the bitmap.
2281      */
2282     if ((bmap = hbfGetBitmap(hbf, code)) == 0)
2283       /*
2284        * Need some sort of error handling here.
2285        */
2286       return;
2287
2288     p = (_bdf_parse_t *) callback_data;
2289
2290     fbbx = hbfFontBBox(hbf);
2291
2292     font = p->font;
2293
2294     /*
2295      * Check to make sure there is enough space to hold this glyph.  If not,
2296      * allocate 10 more just in case.
2297      */
2298     if (font->glyphs_used == font->glyphs_size) {
2299         if (font->glyphs_size == 0)
2300           font->glyphs = (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * 16);
2301         else
2302           font->glyphs = (bdf_glyph_t *)
2303               realloc((char *) font->glyphs,
2304                       sizeof(bdf_glyph_t) * (font->glyphs_used + 16));
2305         gp = font->glyphs + font->glyphs_size;
2306         (void) memset((char *) gp, 0, sizeof(bdf_glyph_t) * 16);
2307         font->glyphs_size += 16;
2308     }
2309
2310     gp = font->glyphs + font->glyphs_used++;
2311
2312     /*
2313      * Set the glyph name.
2314      */
2315     sprintf(nbuf, "char%d", code);
2316     n = (unsigned int) strlen(nbuf);
2317     gp->name = (char *) malloc(n + 1);
2318     (void) memcpy(gp->name, nbuf, n + 1);
2319
2320     /*
2321      * Set encoding.
2322      */
2323     gp->encoding = (int) code;
2324
2325     /*
2326      * Set the device width.
2327      */
2328     gp->dwidth = (unsigned short) fbbx->hbf_width;
2329
2330     /*
2331      * Set the scalable width.
2332      */
2333     ps = (double) font->point_size;
2334     rx = (double) font->resolution_x;
2335     dw = (double) gp->dwidth;
2336     gp->swidth = (unsigned short) ((dw * 72000.0) / (ps * rx));
2337
2338     /*
2339      * Set the glyph bounding box.
2340      */
2341     gp->bbx.width = fbbx->hbf_width;
2342     gp->bbx.height = fbbx->hbf_height;
2343     gp->bbx.x_offset = fbbx->hbf_xDisplacement;
2344     gp->bbx.y_offset = fbbx->hbf_yDisplacement;
2345     gp->bbx.ascent = gp->bbx.height + gp->bbx.y_offset;
2346     gp->bbx.descent = -gp->bbx.y_offset;
2347
2348     /*
2349      * Add the bitmap by making a copy.  Assumes the font bbx is OK for
2350      * determining the number of bytes needed for the glyph bitmap.
2351      */
2352     gp->bytes = ((gp->bbx.width + 7) >> 3) * gp->bbx.height;
2353     gp->bitmap = (unsigned char *) malloc(gp->bytes);
2354     (void) memcpy((char *) gp->bitmap, (char *) bmap, gp->bytes);
2355
2356     /*
2357      * Call the callback if it was provided.
2358      */
2359     if (p->callback != 0) {
2360         p->cb.reason = BDF_LOADING;
2361         p->cb.total = font->glyphs_size;
2362         p->cb.current = font->glyphs_used;
2363         (*p->callback)(&p->cb, p->client_data);
2364     }
2365 }
2366
2367 bdf_font_t *
2368 bdf_load_hbf_font(char *filename, bdf_options_t *opts, bdf_callback_t callback,
2369                   void *data)
2370 {
2371     int /*n,*/ diff;
2372     unsigned int lineno;
2373     FILE *in;
2374     HBF *hbf;
2375     bdf_property_t *pp;
2376     char *name;
2377     _bdf_parse_t p;
2378
2379     if ((hbf = hbfOpen(filename)) == 0)
2380       return 0;
2381
2382     if ((in = fopen(hbfFileName(hbf), "r")) == 0) {
2383         hbfClose(hbf);
2384         return 0;
2385     }
2386
2387     /*
2388      * Parse the HBF header for properties and other things.
2389      */
2390     (void) memset((char *) &p, 0, sizeof(_bdf_parse_t));
2391     p.opts = (opts != 0) ? opts : &_bdf_opts;
2392     p.minlb = 32767;
2393     p.callback = callback;
2394     p.client_data = data;
2395
2396     /*n = */_bdf_readlines(fileno(in), _bdf_parse_hbf_header, (void *) &p,
2397                        &lineno);
2398
2399     fclose(in);
2400
2401     /*
2402      * Determine what spacing the font has so the monowidth field can be set
2403      * if necessary.
2404      */
2405     if ((pp = bdf_get_font_property(p.font, "SPACING")) != 0) {
2406         switch (pp->value.atom[0]) {
2407           case 'p': case 'P': p.font->spacing = BDF_PROPORTIONAL; break;
2408           case 'm': case 'M': p.font->spacing = BDF_MONOWIDTH; break;
2409           case 'c': case 'C': p.font->spacing = BDF_CHARCELL; break;
2410         }
2411     }
2412
2413     /*
2414      * Set the monowidth field if necessary.
2415      */
2416     if (p.font->spacing != BDF_PROPORTIONAL)
2417       p.font->monowidth = p.font->bbx.width;
2418
2419     /*
2420      * Before loading the glyphs, check to see if any glyph structures have
2421      * been added.  If not, check the HBF font for the number of characters.
2422      * Dynamically increasing glyph storage causes memory fragmentation on
2423      * some machines and crashes.  This takes care of the cases where the HBF
2424      * file does not provide a "CHARS n" line.
2425      */
2426     if (p.font->glyphs_size < hbfChars(hbf)) {
2427         if (p.font->glyphs_size == 0)
2428           p.font->glyphs = (bdf_glyph_t *)
2429               malloc(sizeof(bdf_glyph_t) * hbfChars(hbf));
2430         else
2431           p.font->glyphs = (bdf_glyph_t *)
2432               realloc((char *) p.font->glyphs,
2433                       sizeof(bdf_glyph_t) * hbfChars(hbf));
2434         diff = hbfChars(hbf) - p.font->glyphs_size;
2435         (void) memset((char *) (p.font->glyphs + p.font->glyphs_size), 0,
2436                       diff);
2437         p.font->glyphs_size = hbfChars(hbf);
2438     }
2439
2440     /*
2441      * Call the callback initially to set things up.
2442      */
2443     if (p.callback != 0) {
2444         p.cb.reason = BDF_LOAD_START;
2445         p.cb.total = p.font->glyphs_size;
2446         p.cb.current = 0;
2447         (*p.callback)(&p.cb, p.client_data);
2448     }
2449
2450     /*
2451      * Now load the glyphs.
2452      */
2453     hbfForEach(hbf, _bdf_add_hbf_glyph, (void *) &p);
2454
2455     /*
2456      * Close the HBF font.
2457      */
2458     hbfClose(hbf);
2459
2460     /*
2461      * Sort the glyphs by encoding.
2462      */
2463     qsort((char *) p.font->glyphs, p.font->glyphs_used, sizeof(bdf_glyph_t),
2464           by_encoding);
2465
2466     /*
2467      * After loading the HBF header, create an XLFD name.  If the XLFD name
2468      * cannot be made then preserve the name found in the HBF file.
2469      */
2470     if ((name = bdf_make_xlfd_name(p.font, "HBF", "Unknown")) != 0) {
2471         if (p.font->name != 0)
2472           /*
2473            * If a name already exists in the font, free it up.
2474            */
2475           free(p.font->name);
2476
2477         /*
2478          * Replace the old name with the XLFD name.
2479          */
2480         p.font->name = name;
2481     }
2482
2483     /*
2484      * Mark the font as being modified and generate a message that says
2485      * something about the font being converted from HBF format.
2486      */
2487     p.font->modified = 1;
2488     _bdf_add_acmsg(p.font, "Font converted from HBF to BDF.", 31);
2489
2490     return p.font;
2491 }
2492
2493 #endif /* HAVE_HBF */
2494
2495 /*
2496  * Crop the glyph bitmap to the minimum rectangle needed to hold the bits that
2497  * are set.  Adjust the metrics based on the provided bounding box.
2498  */
2499 void
2500 _bdf_crop_glyph(bdf_font_t *font, bdf_glyph_t *glyph)
2501 {
2502     int byte;
2503     unsigned short x, y, bpr, nbpr, col, colx, si, di;
2504     unsigned short minx, maxx, miny, maxy;
2505     unsigned int bytes;
2506     unsigned char *bmap, *masks;
2507     bdf_bbx_t nbbx;
2508
2509     if (glyph == 0)
2510       return;
2511
2512     (void) memcpy((char *) &nbbx, (char *) &glyph->bbx, sizeof(bdf_bbx_t));
2513
2514     bpr = ((glyph->bbx.width * font->bpp) + 7) >> 3;
2515
2516     maxx = maxy = 0;
2517     minx = miny = 32767;
2518
2519     masks = 0;
2520     switch (font->bpp) {
2521       case 1: masks = bdf_onebpp; break;
2522       case 2: masks = bdf_twobpp; break;
2523       case 4: masks = bdf_fourbpp; break;
2524       case 8: masks = bdf_eightbpp; break;
2525     }
2526
2527     for (y = 0; y < glyph->bbx.height; y++) {
2528         for (col = x = 0; x < glyph->bbx.width; x++, col += font->bpp) {
2529             si = (col & 7) / font->bpp;
2530             if (glyph->bitmap[(y * bpr) + (col >> 3)] & masks[si]) {
2531                 minx = MIN(minx, x);
2532                 maxx = MAX(maxx, x);
2533                 miny = MIN(miny, y);
2534                 maxy = MAX(maxy, y);
2535             }
2536         }
2537     }
2538
2539     /*
2540      * Handle an empty bitmap as a special case.
2541      */
2542     if (minx == 32767) {
2543         if (glyph->bytes > 0)
2544           free((char *) glyph->bitmap);
2545         glyph->bytes = 0;
2546         (void) memset((char *) &glyph->bbx, 0, sizeof(bdf_bbx_t));
2547         return;
2548     }
2549
2550     /*
2551      * Increment the max points so width and height calculations won't go
2552      * wrong.
2553      */
2554     maxx++;
2555     maxy++;
2556
2557     if (minx > 0)
2558       nbbx.x_offset += minx;
2559     if (maxx - minx != nbbx.width)
2560       nbbx.width = maxx - minx;
2561
2562     if (miny > 0)
2563       nbbx.ascent -= miny;
2564     if (maxy - miny != nbbx.height)
2565       nbbx.height = maxy - miny;
2566     nbbx.descent = nbbx.height - nbbx.ascent;
2567     nbbx.y_offset = -nbbx.descent;
2568
2569     nbpr = ((nbbx.width * font->bpp) + 7) >> 3;
2570
2571     /*
2572      * If nothing changed, then the glyph is already contained in the
2573      * minimum rectangle.
2574      */
2575     if (memcmp((char *) &nbbx, (char *) &glyph->bbx,
2576                sizeof(bdf_bbx_t)) == 0 ||
2577         (nbpr == bpr && nbbx.height == glyph->bbx.height))
2578       return;
2579
2580     /*
2581      * The metrics changed, so a new bitmap is needed.
2582      */
2583     bytes = nbpr * nbbx.height;
2584     bmap = (unsigned char *) malloc(bytes);
2585     (void) memset((char *) bmap, 0, bytes);
2586
2587     colx = minx * font->bpp;
2588     for (y = miny; y < maxy; y++) {
2589         for (col = x = minx; x < maxx; x++, col += font->bpp) {
2590             si = (col & 7) / font->bpp;
2591             byte = glyph->bitmap[(y * bpr) + (col >> 3)] & masks[si];
2592             if (byte) {
2593                 /*
2594                  * Position the pixel in the byte if necessary.
2595                  */
2596                 di = ((col - colx) & 7) / font->bpp;
2597                 if (di < si)
2598                   byte <<= (si - di) * font->bpp;
2599                 else if (di > si)
2600                   byte >>= (di - si) * font->bpp;
2601                 bmap[((y - miny) * nbpr) + ((col - colx) >> 3)] |= byte;
2602             }
2603         }
2604     }
2605
2606     if (glyph->bytes > 0)
2607       free((char *) glyph->bitmap);
2608     glyph->bytes = bytes;
2609     glyph->bitmap = bmap;
2610
2611     (void) memcpy((char *) &glyph->bbx, (char *) &nbbx, sizeof(bdf_bbx_t));
2612 }
2613
2614 /*
2615  * Pad a character-cell font glyph to match the bounds specified in the
2616  * provided bounding box.
2617  */
2618 void
2619 _bdf_pad_cell(bdf_font_t *font, bdf_glyph_t *glyph, bdf_glyph_t *cell)
2620 {
2621     bdf_bbx_t *bbx;
2622     unsigned short si, di, sx, byte;
2623     unsigned short x, y, dx, dy, bx, by, bpr, nbpr;
2624     unsigned char *bmap, *masks;
2625
2626     masks = 0;
2627     switch (font->bpp) {
2628       case 1: masks = bdf_onebpp; break;
2629       case 2: masks = bdf_twobpp; break;
2630       case 4: masks = bdf_fourbpp; break;
2631       case 8: masks = bdf_eightbpp; break;
2632     }
2633
2634     bbx = &font->bbx;
2635
2636     if (glyph->bbx.width == bbx->width && glyph->bbx.height == bbx->height) {
2637         /*
2638          * The glyph is already positioned in the cell.  Copy the bitmap
2639          * and return.
2640          */
2641         (void) memcpy((char *) cell->bitmap, (char *) glyph->bitmap,
2642                       cell->bytes);
2643         return;
2644     }
2645
2646     /*
2647      * Determine the X and Y location of the baseline.
2648      */
2649     bx = MYABS(bbx->x_offset - glyph->bbx.x_offset);
2650     by = (bbx->ascent + bbx->descent) + bbx->y_offset;
2651
2652     bpr = ((glyph->bbx.width * font->bpp) + 7) >> 3;
2653     nbpr = ((bbx->width * font->bpp) + 7) >> 3;
2654
2655     /*
2656      * Set various cell values and clear the cell bitmap.
2657      */
2658     bmap = cell->bitmap;
2659     (void) memset((char *) bmap, 0, cell->bytes);
2660
2661     for (dy = by - glyph->bbx.ascent, y = 0; y < glyph->bbx.height;
2662          y++, dy++) {
2663         for (dx = bx * font->bpp, sx = x = 0; x < glyph->bbx.width;
2664              x++, dx += font->bpp, sx += font->bpp) {
2665             si = (sx & 7) / font->bpp;
2666             byte = glyph->bitmap[(y * bpr) + (sx >> 3)] & masks[si];
2667             if (byte) {
2668                 di = (dx & 7) / font->bpp;
2669                 if (di < si)
2670                   byte <<= (si - di) * font->bpp;
2671                 else if (di > si)
2672                   byte >>= (di - si) * font->bpp;
2673                 bmap[(dy * nbpr) + (dx >> 3)] |= byte;
2674             }
2675         }
2676     }
2677 }
2678
2679 static char *unix_eol = "\n";
2680 static char *dos_eol = "\r\n";
2681 static char *mac_eol = "\r";
2682
2683 void
2684 bdf_save_font(FILE *out, bdf_font_t *font, bdf_options_t *opts,
2685               bdf_callback_t callback, void *data)
2686 {
2687     int len;
2688     unsigned int i, j, bpr, pcnt;
2689     double dw, ps, rx;
2690     char *sp, *ep, *eol;
2691     bdf_property_t *p;
2692     bdf_glyph_t *c, *cp, cell;
2693     bdf_callback_struct_t cb;
2694
2695     if (font == 0)
2696       return;
2697
2698     eol = 0;
2699     switch (opts->eol) {
2700       case BDF_UNIX_EOL: eol = unix_eol; break;
2701       case BDF_DOS_EOL: eol = dos_eol; break;
2702       case BDF_MAC_EOL: eol = mac_eol; break;
2703     }
2704
2705     /*
2706      * If the font is a character cell font, allocate some space for the
2707      * bitmap.
2708      */
2709     if (font->spacing == BDF_CHARCELL && opts->pad_cells != 0) {
2710         bpr = ((font->bbx.width * font->bpp) + 7) >> 3;
2711         cell.bytes = bpr * font->bbx.height;
2712         cell.bitmap = (unsigned char *) malloc(cell.bytes);
2713         (void) memcpy((char *) &cell.bbx, (char *) &font->bbx,
2714                       sizeof(bdf_bbx_t));
2715     }
2716
2717     /*
2718      * Emit the header.
2719      */
2720     fprintf(out, "STARTFONT 2.1%s", eol);
2721
2722     /*
2723      * Emit the comments.
2724      */
2725     if (font->comments_len > 0) {
2726         for (sp = font->comments; *sp; sp++) {
2727             ep = sp;
2728             while (*ep && *ep != '\n')
2729               ep++;
2730             len = (int) (ep - sp);
2731             fprintf(out, "COMMENT %.*s%s", len, sp, eol);
2732             sp = ep;
2733         }
2734     }
2735
2736     /*
2737      * Emit the font name.
2738      */
2739     fprintf(out, "FONT %s%s", font->name, eol);
2740
2741     /*
2742      * Emit the size info.
2743      */
2744     if (font->bpp == 1)
2745       fprintf(out, "SIZE %d %d %d%s", font->point_size,
2746               font->resolution_x, font->resolution_y, eol);
2747     else
2748       fprintf(out, "SIZE %d %d %d %hd%s", font->point_size,
2749               font->resolution_x, font->resolution_y, font->bpp, eol);
2750
2751     /*
2752      * Emit the bounding box.
2753      */
2754     fprintf(out, "FONTBOUNDINGBOX %hd %hd %hd %hd%s",
2755             font->bbx.width, font->bbx.height, font->bbx.x_offset,
2756             font->bbx.y_offset, eol);
2757
2758     /*
2759      * Emit the properties after counting how many are properties and
2760      * how many are comments.
2761      */
2762     for (i = pcnt = 0, p = font->props; i < font->props_used; i++, p++) {
2763         if (memcmp(p->name, "COMMENT", 7) != 0)
2764           pcnt++;
2765     }
2766
2767     fprintf(out, "STARTPROPERTIES %d%s", pcnt, eol);
2768     for (i = 0, p = font->props; i < font->props_used; i++, p++) {
2769         fprintf(out, "%s ", p->name);
2770         if (p->format == BDF_ATOM) {
2771             if (p->value.atom == 0)
2772               fprintf(out, "\"\"%s", eol);
2773             else
2774               fprintf(out, "\"%s\"%s", p->value.atom, eol);
2775         } else
2776           fprintf(out, "%d%s", p->value.int32, eol);
2777     }
2778
2779     fprintf(out, "ENDPROPERTIES%s", eol);
2780
2781     /*
2782      * Emit the number of bitmaps in the font.
2783      */
2784     fprintf(out, "CHARS %d%s", font->unencoded_used + font->glyphs_used, eol);
2785
2786     /*
2787      * Call the callback if it was passed to start the save.
2788      */
2789     if (callback != 0) {
2790         cb.reason = BDF_SAVE_START;
2791         cb.total = font->unencoded_used + font->glyphs_used;
2792         cb.current = 0;
2793         (*callback)(&cb, data);
2794     }
2795
2796     /*
2797      * Emit the unencoded bitmaps.
2798      */
2799     for (i = 0, cp = font->unencoded; i < font->unencoded_used; i++, cp++) {
2800         /*
2801          * If the font has character-cell spacing and the option to pad the
2802          * glyphs to the size of the font bbx is set, then pad the glyph.
2803          * Otherwise, crop the glyph to the minimum rectangle needed to hold
2804          * the bitmap.
2805          */
2806         if (font->spacing == BDF_CHARCELL && opts->pad_cells != 0) {
2807             /*
2808              * Point at the temporary glyph structure and copy the necessary
2809              * glyph info into it.
2810              */
2811             c = &cell;
2812             c->name = cp->name;
2813             c->encoding = cp->encoding;
2814             c->swidth = cp->swidth;
2815             c->dwidth = cp->dwidth;
2816             _bdf_pad_cell(font, cp, c);
2817         } else {
2818             c = cp;
2819             _bdf_crop_glyph(font, c);
2820         }
2821
2822         /*
2823          * If the font has monowidth or character-cell spacing, then assign
2824          * the font monowidth field to the device width and recalculate the
2825          * scalable width.
2826          */
2827         if (font->spacing != BDF_PROPORTIONAL) {
2828             c->dwidth = font->monowidth;
2829             ps = (double) font->point_size;
2830             rx = (double) font->resolution_x;
2831             dw = (double) c->dwidth;
2832             c->swidth = (unsigned short) ((dw * 72000.0) / (ps * rx));
2833         }
2834         if (c->name == 0)
2835           fprintf(out, "STARTCHAR unencoded%d%sENCODING -1%s", i, eol, eol);
2836         else
2837           fprintf(out, "STARTCHAR %s%sENCODING -1%s", c->name, eol, eol);
2838         fprintf(out, "SWIDTH %hd 0%sDWIDTH %hd 0%s",
2839                 c->swidth, eol, c->dwidth, eol);
2840         fprintf(out, "BBX %hd %hd %hd %hd%s", c->bbx.width, c->bbx.height,
2841                 c->bbx.x_offset, c->bbx.y_offset, eol);
2842         fprintf(out, "BITMAP%s", eol);
2843         bpr = ((c->bbx.width * font->bpp) + 7) >> 3;
2844         for (j = 0; bpr != 0 && j < c->bytes; j++) {
2845             if (j && j % bpr == 0)
2846               fprintf(out, eol);
2847             fprintf(out, "%02X", c->bitmap[j]);
2848         }
2849         /*
2850          * Handle empty bitmaps like this.
2851          */
2852         if (c->bbx.height > 0)
2853           fprintf(out, eol);
2854         fprintf(out, "ENDCHAR%s", eol);
2855
2856         /*
2857          * Call the callback if supplied.
2858          */
2859         if (callback != 0) {
2860             cb.reason = BDF_SAVING;
2861             cb.current++;
2862             (*callback)(&cb, data);
2863         }
2864     }
2865
2866     /*
2867      * Emit the other bitmaps.
2868      */
2869     for (i = 0, cp = font->glyphs; i < font->glyphs_used; i++, cp++) {
2870         /*
2871          * If the font has character-cell spacing and the option to pad the
2872          * glyphs to the size of the font bbx is set, then pad the glyph.
2873          * Otherwise, crop the glyph to the minimum rectangle needed to hold
2874          * the bitmap.
2875          */
2876         if (font->spacing == BDF_CHARCELL && opts->pad_cells != 0) {
2877             /*
2878              * Point at the temporary glyph structure and copy the necessary
2879              * glyph info into it.
2880              */
2881             c = &cell;
2882             c->name = cp->name;
2883             c->encoding = cp->encoding;
2884             c->swidth = cp->swidth;
2885             c->dwidth = cp->dwidth;
2886             _bdf_pad_cell(font, cp, c);
2887         } else {
2888             c = cp;
2889             _bdf_crop_glyph(font, c);
2890         }
2891
2892         /*
2893          * If the font has monowidth or character-cell spacing, then assign
2894          * the font monowidth field to the device width and recalculate the
2895          * scalable width.
2896          */
2897         if (font->spacing != BDF_PROPORTIONAL) {
2898             c->dwidth = font->monowidth;
2899             ps = (double) font->point_size;
2900             rx = (double) font->resolution_x;
2901             dw = (double) c->dwidth;
2902             c->swidth = (unsigned short) ((dw * 72000.0) / (ps * rx));
2903         }
2904         if (c->name == 0)
2905           fprintf(out, "STARTCHAR char%d%sENCODING %d%s",
2906                   c->encoding, eol, c->encoding, eol);
2907         else
2908           fprintf(out, "STARTCHAR %s%sENCODING %d%s",
2909                   c->name, eol, c->encoding, eol);
2910         fprintf(out, "SWIDTH %hd 0%sDWIDTH %hd 0%s",
2911                 c->swidth, eol, c->dwidth, eol);
2912         fprintf(out, "BBX %hd %hd %hd %hd%s", c->bbx.width, c->bbx.height,
2913                 c->bbx.x_offset, c->bbx.y_offset, eol);
2914         fprintf(out, "BITMAP%s", eol);
2915         bpr = ((c->bbx.width * font->bpp) + 7) >> 3;
2916         for (j = 0; bpr != 0 && j < c->bytes; j++) {
2917             if (j && j % bpr == 0)
2918               fprintf(out, eol);
2919             fprintf(out, "%02X", c->bitmap[j]);
2920         }
2921         /*
2922          * Handle empty bitmaps like this.
2923          */
2924         if (c->bbx.height > 0)
2925           fprintf(out, eol);
2926         fprintf(out, "ENDCHAR%s", eol);
2927
2928         /*
2929          * Call the callback if supplied.
2930          */
2931         if (callback != 0) {
2932             cb.reason = BDF_SAVING;
2933             cb.current++;
2934             (*callback)(&cb, data);
2935         }
2936     }
2937
2938     /*
2939      * Emit the trailer.
2940      */
2941     fprintf(out, "ENDFONT%s", eol);
2942
2943     /*
2944      * Always force a final call to the callback to make sure things
2945      * get cleaned up.
2946      */
2947     if (callback != 0) {
2948         cb.reason = BDF_SAVING;
2949         cb.current = cb.total;
2950         (*callback)(&cb, data);
2951     }
2952
2953     /*
2954      * If the font is a character cell font, clean up the temporary glyph.
2955      */
2956     if (font->spacing == BDF_CHARCELL && opts->pad_cells != 0)
2957       free((char *) cell.bitmap);
2958 }
2959
2960 /*
2961  * Routine to write a single set of SBIT metrics.
2962  */
2963 void
2964 bdf_save_sbit_metrics(FILE *out, bdf_font_t *font, bdf_options_t *opts,
2965                       char *appname)
2966 {
2967     char *eol;
2968
2969     eol = 0;
2970     switch (opts->eol) {
2971       case BDF_UNIX_EOL: eol = unix_eol; break;
2972       case BDF_DOS_EOL: eol = dos_eol; break;
2973       case BDF_MAC_EOL: eol = mac_eol; break;
2974     }
2975
2976     /*
2977      * Throw a simple header in.
2978      */
2979     if (appname)
2980       fprintf(out, ";%s; SBIT metrics file generated by \"%s\".%s;%s%s", eol,
2981               appname, eol, eol, eol);
2982
2983     /*
2984      * Save PPEM.
2985      */
2986     fprintf(out, ";%s; Pixels Per Em.%s;%s", eol, eol, eol);
2987     fprintf(out, "PPEM %d%s%s", font->point_size, eol, eol);
2988
2989     /*
2990      * If the font is character cell or monowidth, set this boolean.
2991      */
2992     if (font->spacing != BDF_PROPORTIONAL) {
2993         fprintf(out,
2994                 ";%s; Font is not proportional, so use mono advance.%s;%s",
2995                 eol, eol, eol);
2996         fprintf(out, "FORCECONSTANTMETRICS TRUE%s%s", eol, eol);
2997     } else {
2998         fprintf(out,
2999                 ";%s; Font is proportional, so do not use mono advance.%s;%s",
3000                 eol, eol, eol);
3001         fprintf(out, "FORCECONSTANTMETRICS FALSE%s%s", eol, eol);
3002     }
3003
3004     /*
3005      * Do the horizontal line metrics only.
3006      */
3007     fprintf(out, ";%s; Horizontal line metrics.%s;%s", eol, eol, eol);
3008
3009     fprintf(out, "H_ASCENDER %d%sH_DESCENDER %d%s", font->font_ascent, eol,
3010             font->font_descent, eol);
3011     fprintf(out, "H_WIDTHMAX %hd%s", font->bbx.width, eol);
3012     fprintf(out, "H_MINORIGINSB %hd%sH_MINADVANCEBL %hd%s",
3013             font->bbx.x_offset, eol,
3014             font->bbx.width + font->bbx.x_offset, eol);
3015     fprintf(out, "H_MAXBEFOREBL %hd%sH_MINAFTERBL %hd%s%s",
3016             font->bbx.ascent, eol, font->bbx.y_offset, eol, eol);
3017
3018     /*
3019      * Write the default caret info.
3020      */
3021     fprintf(out, ";%s; Caret slope and offset info.%s;%s", eol, eol, eol);
3022     fprintf(out, "CARETSLOPENUMERATOR 1%sCARETSLOPEDENOMINATOR 0%s", eol, eol);
3023     fprintf(out, "CARETOFFSET 0%s%s", eol, eol);
3024
3025     /*
3026      * Write the bitmap options.
3027      */
3028     fprintf(out, ";%s; Bitmap options.%s;%s", eol, eol, eol);
3029     fprintf(out, "DIRECTION H%sSTORAGE FAST%s%s", eol, eol, eol);
3030
3031     /*
3032      * Scaled bitmaps not implemented yet.
3033      */
3034     fprintf(out, ";%s; Scaled bitmap info (Not Yet Implemented).%s;%s",
3035             eol, eol, eol);
3036 }
3037
3038 /*
3039  * Special routine to dump the font in the Roman Czyborra's hex format.  It
3040  * only dumps the encoded glyphs and assumes the bitmaps have the correct
3041  * sizes.
3042  */
3043 void
3044 bdf_export_hex(FILE *out, bdf_font_t *font, bdf_options_t *opts,
3045                bdf_callback_t callback, void *data)
3046 {
3047     int bpr, fbpr, j, k;
3048     unsigned int i, ng;
3049     bdf_glyph_t *gp, cell;
3050     bdf_callback_struct_t cb;
3051
3052     if (font == 0 || out == 0)
3053       return;
3054
3055     if (font->glyphs_used == 0)
3056       return;
3057
3058     /*
3059      * Call the callback if it was passed to start the export.
3060      */
3061     if (callback != 0) {
3062         cb.reason = BDF_EXPORT_START;
3063         cb.total = font->glyphs_used;
3064         cb.current = 0;
3065         (*callback)(&cb, data);
3066     }
3067
3068     fbpr = ((font->bbx.width * font->bpp) + 7) >> 3;
3069     bpr = (((font->bbx.width >> 1) * font->bpp) + 7) >> 3;
3070     cell.bytes = fbpr * font->bbx.height;
3071     cell.bitmap = (unsigned char *) malloc(cell.bytes);
3072
3073     for (i = 0, ng = font->glyphs_used, gp = font->glyphs; i < ng; i++, gp++) {
3074         _bdf_pad_cell(font, gp, &cell);
3075         fprintf(out, "%04X:", gp->encoding & 0xffff);
3076         if (gp->bbx.width <= (font->bbx.width >> 1)) {
3077             for (j = 0; j < cell.bytes; j += fbpr) {
3078                 for (k = 0; k < bpr; k++)
3079                   fprintf(out, "%02X", cell.bitmap[j + k]);
3080             }
3081         } else {
3082             for (j = 0; j < cell.bytes; j++)
3083               fprintf(out, "%02X", cell.bitmap[j]);
3084         }
3085         if (cell.bytes > 0)
3086           putc('\n', out);
3087
3088         /*
3089          * Call the callback if supplied.
3090          */
3091         if (callback != 0) {
3092             cb.reason = BDF_EXPORTING;
3093             cb.current++;
3094             (*callback)(&cb, data);
3095         }
3096     }
3097
3098     /*
3099      * Clean up the cell.
3100      */
3101     free((char *) cell.bitmap);
3102
3103     /*
3104      * Always call a final callback to make sure the client gets a chance to
3105      * clean things up.
3106      */
3107     if (callback != 0) {
3108         cb.reason = BDF_EXPORTING;
3109         cb.current = cb.total;
3110         (*callback)(&cb, data);
3111     }
3112 }
3113
3114 static const unsigned char lookup[16] = {
3115    0x0, 0x8, 0x4, 0xC,
3116    0x2, 0xA, 0x6, 0xE,
3117    0x1, 0x9, 0x5, 0xD,
3118    0x3, 0xB, 0x7, 0xF };
3119
3120 static unsigned char byte_flip( const unsigned char n )
3121 {
3122    return (lookup[n&0x0F] << 4) | lookup[n>>4];
3123 }
3124
3125 void
3126 bdf_export_header(FILE *out, bdf_font_t *font, bdf_options_t *opts,
3127                bdf_callback_t callback, void *data)
3128 {
3129     int bpr, fbpr, j, k;
3130     unsigned int i, ng;
3131     bdf_glyph_t *gp, cell;
3132     bdf_callback_struct_t cb;
3133     bdf_property_t *fprop;
3134     char fname[32], weightname[32];
3135
3136     if (font == 0 || out == 0)
3137       return;
3138
3139     if (font->glyphs_used == 0)
3140       return;
3141
3142     /*
3143      * Call the callback if it was passed to start the export.
3144      */
3145     if (callback != 0) {
3146         cb.reason = BDF_EXPORT_START;
3147         cb.total = font->glyphs_used;
3148         cb.current = 0;
3149         (*callback)(&cb, data);
3150     }
3151
3152     fbpr = ((font->bbx.width * font->bpp) + 7) >> 3;
3153     bpr = (((font->bbx.width >> 1) * font->bpp) + 7) >> 3;
3154     cell.bytes = fbpr * font->bbx.height;
3155     cell.bitmap = (unsigned char *) malloc(cell.bytes);
3156
3157     fprop = bdf_get_font_property(font, "FAMILY_NAME");
3158 /*
3159     if (fprop != NULL && fprop->format == BDF_ATOM)
3160        fprintf(out, "fontname %s ", fprop->value.atom);
3161 */
3162     if (fprop != NULL && fprop->format == BDF_ATOM)
3163        strncpy(fname, fprop->value.atom, 32);
3164     else
3165        strncpy(fname, "NoName", 32);
3166
3167     fprop = bdf_get_font_property(font, "WEIGHT_NAME");
3168     if (fprop != NULL && fprop->format == BDF_ATOM)
3169        strncpy(weightname, fprop->value.atom, 32);
3170     else
3171        strncpy(weightname, "none", 32);
3172
3173     fprintf(out, "/* %s */\n", font->name);
3174     fprintf(out, "#define FONT_WIDTH_%s%s_%dx%d\t%d\n", fname, weightname, font->bbx.width, font->bbx.height, font->bbx.width);
3175     fprintf(out, "#define FONT_HEIGHT_%s%s_%dx%d\t%d\n", fname, weightname, font->bbx.width, font->bbx.height, font->bbx.height);
3176
3177     fprintf(out, "const uint8_t FONT_DATA_%s%s_%dx%d[%d][%d] = {\n", fname, weightname, font->bbx.width, font->bbx.height, font->glyphs_used, cell.bytes + ((font->spacing == BDF_PROPORTIONAL) ? 1 : 0));
3178
3179     for (i = 0, ng = font->glyphs_used, gp = font->glyphs; i < ng; i++, gp++) {
3180         _bdf_pad_cell(font, gp, &cell);
3181 /*
3182         fprintf(out, "%dx%d ", gp->bbx.width, gp->bbx.height);
3183         fprintf(out, "%04X:", gp->encoding & 0xffff);
3184 */
3185         if (font->spacing == BDF_PROPORTIONAL) {
3186             fprintf(out, "{/*w*/%d,",gp->dwidth /*gp->bbx.width*/);
3187         } else
3188             fprintf(out, "{");
3189 /*
3190         if (gp->bbx.width <= (font->bbx.width >> 1)) {
3191             for (j = 0; j < cell.bytes; j += fbpr) {
3192                 for (k = 0; k < bpr; k++)
3193                   fprintf(out, "a0x%02x,", cell.bitmap[j + k]);
3194             }
3195         } else*/ {
3196             for (j = 0; j < cell.bytes; j++)
3197               fprintf(out, "0x%02x,", byte_flip(cell.bitmap[j]));
3198         }
3199         if (cell.bytes > 0)
3200               fprintf(out, "},\n");
3201
3202         /*
3203          * Call the callback if supplied.
3204          */
3205         if (callback != 0) {
3206             cb.reason = BDF_EXPORTING;
3207             cb.current++;
3208             (*callback)(&cb, data);
3209         }
3210     }
3211     fprintf(out, "};\n");
3212
3213     /*
3214      * Clean up the cell.
3215      */
3216     free((char *) cell.bitmap);
3217
3218     /*
3219      * Always call a final callback to make sure the client gets a chance to
3220      * clean things up.
3221      */
3222     if (callback != 0) {
3223         cb.reason = BDF_EXPORTING;
3224         cb.current = cb.total;
3225         (*callback)(&cb, data);
3226     }
3227 }
3228
3229 void
3230 bdf_free_font(bdf_font_t *font)
3231 {
3232     unsigned int i;
3233     bdf_glyph_t *glyphs;
3234
3235     if (font == 0)
3236         return;
3237
3238     if (font->name != 0)
3239       free(font->name);
3240
3241     /*
3242      * Free up the internal hash table of property names.
3243      */
3244     hash_free((hashtable *) font->internal);
3245     free((char *) font->internal);
3246
3247     /*
3248      * Free up the comment info.
3249      */
3250     if (font->comments_len > 0)
3251       free(font->comments);
3252
3253     /*
3254      * Free up the auto-correction messages.
3255      */
3256     if (font->acmsgs_len > 0)
3257       free(font->acmsgs);
3258
3259     /*
3260      * Free up the properties.
3261      */
3262     for (i = 0; i < font->props_size; i++) {
3263         if (font->props[i].format == BDF_ATOM && font->props[i].value.atom)
3264           free(font->props[i].value.atom);
3265     }
3266
3267     if (font->props_size > 0 && font->props != 0)
3268       free((char *) font->props);
3269
3270     /*
3271      * Free up the character info.
3272      */
3273     for (i = 0, glyphs = font->glyphs; i < font->glyphs_used; i++, glyphs++) {
3274         if (glyphs->name)
3275           free(glyphs->name);
3276         if (glyphs->bytes > 0 && glyphs->bitmap != 0)
3277           free((char *) glyphs->bitmap);
3278     }
3279
3280     for (i = 0, glyphs = font->unencoded; i < font->unencoded_used;
3281          i++, glyphs++) {
3282         if (glyphs->name)
3283           free(glyphs->name);
3284         if (glyphs->bytes > 0)
3285           free((char *) glyphs->bitmap);
3286         if (glyphs->unicode.map_size > 0)
3287           free((char *) glyphs->unicode.map);
3288     }
3289
3290     if (font->glyphs_size > 0)
3291       free((char *) font->glyphs);
3292
3293     if (font->unencoded_size > 0)
3294       free((char *) font->unencoded);
3295
3296     /*
3297      * Free up the overflow storage if it was used.
3298      */
3299     for (i = 0, glyphs = font->overflow.glyphs; i < font->overflow.glyphs_used;
3300          i++, glyphs++) {
3301         if (glyphs->name != 0)
3302           free(glyphs->name);
3303         if (glyphs->bytes > 0)
3304           free((char *) glyphs->bitmap);;
3305         if (glyphs->unicode.map_size > 0)
3306           free((char *) glyphs->unicode.map);
3307     }
3308     if (font->overflow.glyphs_size > 0)
3309       free((char *) font->overflow.glyphs);
3310
3311     free((char *) font);
3312 }
3313
3314 void
3315 bdf_create_property(char *name, int format)
3316 {
3317     long n;
3318     bdf_property_t *p;
3319
3320     /*
3321      * First check to see if the property has
3322      * already been added or not.  If it has, then
3323      * simply ignore it.
3324      */
3325
3326     if (hash_lookup(name, &proptbl))
3327       return;
3328
3329     if (nuser_props == 0)
3330       user_props = (bdf_property_t *) malloc(sizeof(bdf_property_t));
3331     else
3332       user_props = (bdf_property_t *) realloc((char *) user_props,
3333                                               sizeof(bdf_property_t) *
3334                                               (nuser_props + 1));
3335
3336     p = user_props + nuser_props;
3337     (void) memset((char *) p, 0, sizeof(bdf_property_t));
3338     n = (unsigned int) (strlen(name) + 1);
3339     p->name = (char *) malloc(n);
3340     (void) memcpy(p->name, name, n);
3341     p->format = format;
3342     p->builtin = 0;
3343
3344     n = _num_bdf_properties + nuser_props;
3345     hash_insert(p->name, (void *) n, &proptbl);
3346
3347     nuser_props++;
3348 }
3349
3350 bdf_property_t *
3351 bdf_get_property(char *name)
3352 {
3353     hashnode hn;
3354     unsigned int propid;
3355
3356     if (name == 0 || *name == 0)
3357       return 0;
3358
3359     if ((hn = hash_lookup(name, &proptbl)) == 0)
3360       return 0;
3361
3362     propid = (long) hn->data;
3363     if (propid >= _num_bdf_properties)
3364       return user_props + (propid - _num_bdf_properties);
3365     return _bdf_properties + propid;
3366 }
3367
3368 /*
3369  * Routine to compare two property names.
3370  */
3371 static int
3372 by_prop_name(const void *a, const void *b)
3373 {
3374     bdf_property_t *p1, *p2;
3375
3376     p1 = (bdf_property_t *) a;
3377     p2 = (bdf_property_t *) b;
3378
3379     return strcmp(p1->name, p2->name);
3380 }
3381
3382 unsigned int
3383 bdf_property_list(bdf_property_t **props)
3384 {
3385     unsigned int n;
3386     bdf_property_t *p;
3387
3388     n = _num_bdf_properties + nuser_props;
3389     if (props != 0 && n != 0) {
3390         p = (bdf_property_t *) malloc(sizeof(bdf_property_t) * n);
3391         (void) memcpy((char *) p, (char *) _bdf_properties,
3392                       sizeof(bdf_property_t) * _num_bdf_properties);
3393         (void) memcpy((char *) (p + _num_bdf_properties), (char *) user_props,
3394                       sizeof(bdf_property_t) * nuser_props);
3395         qsort((char *) p, n, sizeof(bdf_property_t), by_prop_name);
3396         *props = p;
3397     }
3398     return n;
3399 }
3400
3401 int
3402 bdf_replace_comments(bdf_font_t *font, char *comments,
3403                      unsigned int comments_len)
3404 {
3405     if (font == 0 || comments_len == 0)
3406       return 0;
3407
3408     if (font->comments_len > 0)
3409       free(font->comments);
3410
3411     font->comments = (char *) malloc(comments_len + 1);
3412     (void) memcpy(font->comments, comments, comments_len);
3413     font->comments[comments_len] = 0;
3414     font->comments_len = comments_len;
3415     font->modified = 1;
3416     return 1;
3417 }
3418
3419 unsigned int
3420 bdf_font_property_list(bdf_font_t *font, bdf_property_t **props)
3421 {
3422     bdf_property_t *p;
3423
3424     if (font == 0 || font->props_used == 0)
3425       return 0;
3426
3427     if (props != 0) {
3428         p = (bdf_property_t *) malloc(sizeof(bdf_property_t) *
3429                                       font->props_used);
3430         (void) memcpy((char *) p, (char *) font->props,
3431                       sizeof(bdf_property_t) * font->props_used);
3432         qsort((char *) p, font->props_used, sizeof(bdf_property_t),
3433               by_prop_name);
3434         *props = p;
3435     }
3436
3437     return font->props_used;
3438 }
3439
3440 void
3441 bdf_add_font_property(bdf_font_t *font, bdf_property_t *property)
3442 {
3443     int len;
3444     unsigned int propid;
3445     hashnode hn;
3446     bdf_property_t *p, *ip;
3447
3448     if (property == 0 || property->name == 0 || property->name[0] == 0)
3449       return;
3450
3451     /*
3452      * If the font does not have a property hash table yet, make
3453      * sure it is allocated.
3454      */
3455     if (font->internal == 0) {
3456         font->internal = (void *) malloc(sizeof(hashtable));
3457         hash_init((hashtable *) font->internal);
3458     }
3459
3460     /*
3461      * See if the property is in the general property table yet.
3462      * If it isn't, then add it.
3463      */
3464     if ((hn = hash_lookup(property->name, &proptbl)) == 0)
3465       bdf_create_property(property->name, property->format);
3466     else {
3467         /*
3468          * If the property exists and is a user defined property, make sure
3469          * its format is updated to match the property being added.
3470          */
3471         propid = (long) hn->data;
3472         if (propid >= _num_bdf_properties) {
3473             p = user_props + (propid - _num_bdf_properties);
3474             if (p->format != property->format)
3475               p->format = property->format;
3476         }
3477     }
3478
3479     /*
3480      * If the font already has this property, then change the existing one.
3481      */
3482     hn = hash_lookup(property->name, (hashtable *) font->internal);
3483     if (hn != 0) {
3484         /*
3485          * Changing an existing property value.
3486          */
3487         p = font->props + ((long) hn->data);
3488
3489         /*
3490          * If the format changed, then free the atom value if the original
3491          * format was an atom.
3492          */
3493         if (p->format == BDF_ATOM && property->format != BDF_ATOM &&
3494             p->value.atom != 0)
3495           free((char *) p->value.atom);
3496         p->format = property->format;
3497
3498         switch (p->format) {
3499           case BDF_ATOM:
3500             /*
3501              * If the property value is the same, then just return.
3502              */
3503             if (property->value.atom == p->value.atom ||
3504                 (property->value.atom && p->value.atom &&
3505                  strcmp(property->value.atom, p->value.atom) == 0))
3506               return;
3507             if (property->value.atom == 0)
3508               len = 1;
3509             else
3510               len = strlen(property->value.atom) + 1;
3511             if (len > 1) {
3512                 p->value.atom = (char *) malloc(len);
3513                 (void) memcpy(p->value.atom, property->value.atom, len);
3514             } else
3515               p->value.atom = 0;
3516             break;
3517           case BDF_INTEGER:
3518             /*
3519              * If the property value is the same, then just return.
3520              */
3521             if (p->value.int32 == property->value.int32)
3522               return;
3523             p->value.int32 = property->value.int32;
3524             break;
3525           case BDF_CARDINAL:
3526             /*
3527              * If the property value is the same, then just return.
3528              */
3529             if (p->value.card32 == property->value.card32)
3530               return;
3531             p->value.card32 = property->value.card32;
3532             break;
3533         }
3534     } else {
3535         /*
3536          * New property being added.
3537          */
3538
3539         /*
3540          * Get the internal table entry for a pointer to the
3541          * name of the property.
3542          */
3543         hn = hash_lookup(property->name, &proptbl);
3544         propid = (long) hn->data;
3545         if (propid >= _num_bdf_properties)
3546           ip = user_props + (propid - _num_bdf_properties);
3547         else
3548           ip = _bdf_properties + propid;
3549
3550         /*
3551          * Add it to the property list first.
3552          */
3553         if (font->props_used == font->props_size) {
3554             if (font->props_size == 0)
3555               font->props = (bdf_property_t *) malloc(sizeof(bdf_property_t));
3556             else
3557               font->props = (bdf_property_t *)
3558                 realloc((char *) font->props, sizeof(bdf_property_t) *
3559                         (font->props_size + 1));
3560             font->props_size++;
3561         }
3562         p = font->props + font->props_used;
3563
3564         p->name = ip->name;
3565         p->format = ip->format;
3566         p->builtin = ip->builtin;
3567
3568         switch (p->format) {
3569           case BDF_ATOM:
3570             if (property->value.atom == 0)
3571               len = 1;
3572             else
3573               len = strlen(property->value.atom) + 1;
3574             if (len > 1) {
3575                 p->value.atom = (char *) malloc(len);
3576                 (void) memcpy(p->value.atom, property->value.atom, len);
3577             } else
3578               p->value.atom = 0;
3579             break;
3580           case BDF_INTEGER:
3581             p->value.int32 = property->value.int32;
3582             break;
3583           case BDF_CARDINAL:
3584             p->value.card32 = property->value.card32;
3585             break;
3586         }
3587
3588         /*
3589          * Now insert it into the internal hash table.
3590          */
3591         hash_insert(p->name, (void *) font->props_used,
3592                     (hashtable *) font->internal);
3593         font->props_used++;
3594     }
3595
3596     if (memcmp(property->name, "DEFAULT_CHAR", 12) == 0)
3597       /*
3598        * If the property just added is DEFAULT_CHAR, then make sure the
3599        * default_glyph field is set.
3600        */
3601       font->default_glyph = p->value.card32;
3602     else if (memcmp(property->name, "FONT_ASCENT", 11) == 0)
3603       /*
3604        * If the property just added is FONT_ASCENT, then adjust the
3605        * font_ascent field.
3606        */
3607       font->font_ascent = p->value.int32;
3608     else if (memcmp(property->name, "FONT_DESCENT", 12) == 0)
3609       /*
3610        * If the property just added is FONT_DESCENT, then adjust the
3611        * font_descent field.
3612        */
3613       font->font_descent = p->value.int32;
3614     else if (memcmp(property->name, "RESOLUTION_X", 12) == 0)
3615       /*
3616        * If the property just added is RESOLUTION_X, then adjust the
3617        * resolution_x field.
3618        */
3619       font->resolution_x = p->value.card32;
3620     else if (memcmp(property->name, "RESOLUTION_Y", 12) == 0)
3621       /*
3622        * If the property just added is RESOLUTION_Y, then adjust the
3623        * resolution_y field.
3624        */
3625       font->resolution_y = p->value.card32;
3626     else if (memcmp(property->name, "POINT_SIZE", 10) == 0)
3627       /*
3628        * If the property just added is POINT_SIZE, then adjust the
3629        * point_size field.
3630        */
3631       font->point_size = p->value.int32 / 10;
3632     else if (memcmp(property->name, "SPACING", 7) == 0) {
3633         /*
3634          * Make sure the font spacing is kept in synch if the property
3635          * changes.  If the spacing changes from proportional to one
3636          * of the others, force the monowidth to be set.
3637          */
3638         switch (p->value.atom[0]) {
3639           case 'C': case 'c':
3640             if (font->spacing == BDF_PROPORTIONAL)
3641               font->monowidth = font->bbx.width + font->bbx.x_offset;
3642             font->spacing = BDF_CHARCELL;
3643             break;
3644           case 'M': case 'm':
3645             if (font->spacing == BDF_PROPORTIONAL)
3646               font->monowidth = font->bbx.width + font->bbx.x_offset;
3647             font->spacing = BDF_MONOWIDTH;
3648             break;
3649           case 'P': case 'p': font->spacing = BDF_PROPORTIONAL; break;
3650         }
3651     }
3652
3653     /*
3654      * Make sure the font is marked as modified.
3655      */
3656     font->modified = 1;
3657 }
3658
3659 void
3660 bdf_delete_font_property(bdf_font_t *font, char *name)
3661 {
3662     hashnode hn;
3663     long off;
3664     bdf_property_t *p;
3665
3666     if (font == 0 || name == 0 || *name == 0 || font->props_used == 0)
3667       return;
3668
3669     if ((hn = hash_lookup(name, (hashtable *) font->internal)) == 0)
3670       return;
3671
3672     off = (long) hn->data;
3673     p = font->props + off;
3674
3675     /*
3676      * Delete the ATOM value if appropriate.
3677      */
3678     if (p->format == BDF_ATOM && p->value.atom != 0)
3679       free(p->value.atom);
3680
3681     /*
3682      * The property exists.  Two things needs to be done:
3683      * 1. Remove the property from the hash table.
3684      * 2. Remove the property from the font's list of properties.
3685      */
3686     hash_delete(name, (hashtable *) font->internal);
3687
3688     /*
3689      * Locate its offset in the font property list.
3690      */
3691     if (off < font->props_used - 1)
3692       /*
3693        * We have to shift the property list down.
3694        */
3695       _bdf_memmove((char *) p, (char *) (p + 1),
3696                    sizeof(bdf_property_t) * ((font->props_used - 1) - off));
3697     font->props_used--;
3698
3699     /*
3700      * If the font property happens to be DEFAULT_CHAR, then make sure the
3701      * default_glyph field is reset.
3702      */
3703     if (strncmp(name, "DEFAULT_CHAR", 12) == 0)
3704       font->default_glyph = -1;
3705
3706     /*
3707      * Update the hash table with the correct indexes.
3708      */
3709     for (off = 0, p = font->props; off < font->props_used; off++, p++)
3710       hash_insert(p->name, (void *) off, (hashtable *) font->internal);
3711
3712     /*
3713      * Mark the font as being modified.
3714      */
3715     font->modified = 1;
3716 }
3717
3718 bdf_property_t *
3719 bdf_get_font_property(bdf_font_t *font, char *name)
3720 {
3721     hashnode hn;
3722
3723     if (font == 0 || font->props_size == 0 || name == 0 || *name == 0)
3724       return 0;
3725
3726     hn = hash_lookup(name, (hashtable *) font->internal);
3727     return (hn) ? (font->props + ((long) hn->data)) : 0;
3728 }
3729
3730 typedef struct {
3731     bdf_options_t *opts;
3732     bdf_options_callback_t callback;
3733     void *client_data;
3734     _bdf_list_t list;
3735 } _bdf_opts_parse_t;
3736
3737 static int
3738 _bdf_get_boolean(char *val)
3739 {
3740     int ok;
3741
3742     ok = 0;
3743     if (val == 0 || *val == 0)
3744       return ok;
3745
3746     switch (val[0]) {
3747       case '0': case 'F': case 'f': case 'N': case 'n': ok = 0; break;
3748       case '1': case 'T': case 't': case 'Y': case 'y': ok = 1; break;
3749     }
3750     return ok;
3751 }
3752
3753 static int
3754 _bdf_parse_options(char *line, unsigned int linelen, unsigned int lineno,
3755                    void *call_data, void *client_data)
3756 {
3757     _bdf_list_t *lp;
3758     _bdf_opts_parse_t *p;
3759     int bpp;
3760
3761     p = (_bdf_opts_parse_t *) client_data;
3762     lp = &p->list;
3763
3764     /*
3765      * Split the line into fields.
3766      */
3767     _bdf_split(" \t+", line, linelen, lp);
3768
3769     if (lp->field[0][0] == 'b' &&
3770         memcmp(lp->field[0], "bits_per_pixel", 14) == 0) {
3771         if (lp->used < 2) {
3772             fprintf(stderr,
3773                     "bdf: warning: %d: incorrect number of fields %d.\n",
3774                     lineno, lp->used);
3775             fprintf(stderr,
3776                     "bdf: warning: %d: bits_per_pixel <1, 2, or 4>.\n",
3777                     lineno);
3778         } else {
3779             bpp = _bdf_atol(lp->field[1], 0, 10);
3780             if (!(bpp == 1 || bpp == 2 || bpp == 4)) {
3781                 fprintf(stderr,
3782                         "bdf: warning: %d: invalid bits per pixel %d.\n",
3783                         lineno, bpp);
3784                 fprintf(stderr,
3785                         "bdf: warning: %d: bits_per_pixel <1, 2, or 4>.\n",
3786                         lineno);
3787             } else
3788               p->opts->bits_per_pixel = bpp;
3789         }
3790         return 0;
3791     }
3792
3793     if (lp->field[0][0] == 'e' && memcmp(lp->field[0], "eol", 3) == 0) {
3794         if (lp->used < 2) {
3795             fprintf(stderr,
3796                     "bdf: warning: %d: incorrect number of fields %d.\n",
3797                     lineno, lp->used);
3798             fprintf(stderr,
3799                     "bdf: warning: %d: eol <eolname>.\n", lineno);
3800         } else {
3801             switch (lp->field[1][0]) {
3802               case 'u': case 'U': p->opts->eol = BDF_UNIX_EOL; break;
3803               case 'd': case 'D': p->opts->eol = BDF_DOS_EOL; break;
3804               case 'm': case 'M': p->opts->eol = BDF_MAC_EOL; break;
3805             }
3806         }
3807         return 0;
3808     }
3809
3810     if (lp->field[0][0] == 'c' &&
3811         memcmp(lp->field[0], "correct_metrics", 15) == 0) {
3812         if (lp->used < 2) {
3813             fprintf(stderr,
3814                     "bdf: warning: %d: incorrect number of fields %d.\n",
3815                     lineno, lp->used);
3816             fprintf(stderr,
3817                     "bdf: warning: %d: correct_metrics <boolean>.\n", lineno);
3818         } else
3819           p->opts->correct_metrics = _bdf_get_boolean(lp->field[1]);
3820
3821         return 0;
3822     }
3823
3824     if (lp->field[0][0] == 'k' &&
3825         memcmp(lp->field[0], "keep_unencoded", 14) == 0) {
3826         if (lp->used < 2) {
3827             fprintf(stderr,
3828                     "bdf: warning: %d: incorrect number of fields %d.\n",
3829                     lineno, lp->used);
3830             fprintf(stderr,
3831                     "bdf: warning: %d: keep_unencoded <boolean>.\n", lineno);
3832         } else
3833           p->opts->keep_unencoded = _bdf_get_boolean(lp->field[1]);
3834
3835         return 0;
3836     }
3837
3838     if (lp->field[0][0] == 'k' &&
3839         memcmp(lp->field[0], "keep_comments", 13) == 0) {
3840         if (lp->used < 2) {
3841             fprintf(stderr,
3842                     "bdf: warning: %d: incorrect number of fields %d.\n",
3843                     lineno, lp->used);
3844             fprintf(stderr,
3845                     "bdf: warning: %d: keep_comments <boolean>.\n", lineno);
3846         } else
3847           p->opts->keep_comments = _bdf_get_boolean(lp->field[1]);
3848
3849         return 0;
3850     }
3851
3852     if (lp->field[0][0] == 'p' &&
3853         memcmp(lp->field[0], "pad_character_cells", 19) == 0) {
3854         if (lp->used < 2) {
3855             fprintf(stderr,
3856                     "bdf: warning: %d: incorrect number of fields %d.\n",
3857                     lineno, lp->used);
3858             fprintf(stderr,
3859                     "bdf: warning: %d: pad_character_cells <boolean>.\n",
3860                     lineno);
3861         } else
3862           p->opts->pad_cells = _bdf_get_boolean(lp->field[1]);
3863
3864         return 0;
3865     }
3866
3867     if (lp->field[0][0] == 'p' &&
3868         memcmp(lp->field[0], "point_size", 10) == 0) {
3869         if (lp->used < 2) {
3870             fprintf(stderr,
3871                     "bdf: warning: %d: incorrect number of fields %d.\n",
3872                     lineno, lp->used);
3873             fprintf(stderr,
3874                     "bdf: warning: %d: point_size <integer>.\n", lineno);
3875         } else
3876           p->opts->point_size = _bdf_atol(lp->field[1], 0, 10);
3877         return 0;
3878     }
3879
3880     if (lp->field[0][0] == 'h' &&
3881         memcmp(lp->field[0], "horizontal_resolution", 21) == 0) {
3882         if (lp->used < 2) {
3883             fprintf(stderr,
3884                     "bdf: warning: %d: incorrect number of fields %d.\n",
3885                     lineno, lp->used);
3886             fprintf(stderr,
3887                     "bdf: warning: %d: horizontal_resolution <cardinal>.\n",
3888                     lineno);
3889         } else
3890           p->opts->resolution_x = _bdf_atoul(lp->field[1], 0, 10);
3891         return 0;
3892     }
3893
3894     if (lp->field[0][0] == 'v' &&
3895         memcmp(lp->field[0], "vertical_resolution", 19) == 0) {
3896         if (lp->used < 2) {
3897             fprintf(stderr,
3898                     "bdf: warning: %d: incorrect number of fields %d.\n",
3899                     lineno, lp->used);
3900             fprintf(stderr,
3901                     "bdf: warning: %d: vertical_resolution <cardinal>.\n",
3902                     lineno);
3903         } else
3904           p->opts->resolution_y = _bdf_atoul(lp->field[1], 0, 10);
3905         return 0;
3906     }
3907
3908     if (lp->field[0][0] == 'f' &&
3909         memcmp(lp->field[0], "font_spacing", 12) == 0) {
3910         if (lp->used < 2) {
3911             fprintf(stderr,
3912                     "bdf: warning: %d: incorrect number of fields %d.\n",
3913                     lineno, lp->used);
3914             fprintf(stderr,
3915                     "bdf: warning: %d: font_spacing <spacing name>.\n",
3916                     lineno);
3917         } else {
3918             switch (lp->field[1][0]) {
3919               case 'P': case 'p':
3920                 p->opts->font_spacing = BDF_PROPORTIONAL;
3921                 break;
3922               case 'M': case 'm':
3923                 p->opts->font_spacing = BDF_MONOWIDTH;
3924                 break;
3925               case 'C': case 'c':
3926                 p->opts->font_spacing = BDF_CHARCELL;
3927                 break;
3928               default:
3929                 fprintf(stderr,
3930                         "bdf: warning: %d: unknown font spacing '%s'.\n",
3931                         lineno, lp->field[1]);
3932             }
3933         }
3934         return 0;
3935     }
3936
3937     if (lp->field[0][0] == 'p' &&
3938         memcmp(lp->field[0], "property", 8) == 0) {
3939         if (lp->used < 3) {
3940             fprintf(stderr,
3941                     "bdf: warning: %d: incorrect number of fields %d.\n",
3942                     lineno, lp->used);
3943             fprintf(stderr,
3944                     "bdf: warning: %d: property <name> <type>.\n",
3945                     lineno);
3946         } else {
3947             switch (lp->field[2][0]) {
3948               case 'A': case 'a':
3949                 bdf_create_property(lp->field[1], BDF_ATOM);
3950                 break;
3951               case 'C': case 'c':
3952                 bdf_create_property(lp->field[1], BDF_CARDINAL);
3953                 break;
3954               case 'I': case 'i':
3955                 bdf_create_property(lp->field[1], BDF_INTEGER);
3956                 break;
3957               default:
3958                 fprintf(stderr,
3959                         "bdf: warning: %d: unknown property type '%s'.\n",
3960                         lineno, lp->field[2]);
3961             }
3962         }
3963         return 0;
3964     }
3965
3966     if (lp->field[0][0] == 'h' &&
3967         (memcmp(lp->field[0], "hint_truetype_glyphs", 20) == 0 ||
3968          memcmp(lp->field[0], "hint_opentype_glyphs", 20) == 0)) {
3969         if (lp->used < 2) {
3970             fprintf(stderr,
3971                     "bdf: warning: %d: incorrect number of fields %d.\n",
3972                     lineno, lp->used);
3973             fprintf(stderr,
3974                     "bdf: warning: %d: hint_opentype_glyphs <boolean>.\n",
3975                     lineno);
3976         } else {
3977 #ifdef HAVE_FREETYPE
3978             if (_bdf_get_boolean(lp->field[1]))
3979               p->opts->otf_flags &= ~FT_LOAD_NO_HINTING;
3980             else
3981               p->opts->otf_flags |= FT_LOAD_NO_HINTING;
3982 #else
3983             p->opts->otf_flags = 0;
3984 #endif /* HAVE_FREETYPE */
3985         }
3986
3987         return 0;
3988     }
3989
3990     if (lp->field[0][0] == 'g' &&
3991         memcmp(lp->field[0], "generate_ranges", 15) == 0)
3992       /*
3993        * Simply ignore the glyph ranges entry in the config file.
3994        */
3995       return 0;
3996
3997     /*
3998      * If the callback returns a non-zero value, the caller has handled the
3999      * unknown option found in the file.
4000      */
4001     if (p->callback != 0 &&
4002         (*p->callback)(p->opts, lp->field, lp->used, p->client_data) != 0)
4003       return 0;
4004
4005     fprintf(stderr, "bdf: warning: %d: unknown configuration option '%s'.\n",
4006             lineno, lp->field[0]);
4007     return 0;
4008 }
4009
4010 void
4011 bdf_load_options(FILE *in, bdf_options_t *opts,
4012                  bdf_options_callback_t callback, void *client_data)
4013 {
4014     unsigned int lineno;
4015     _bdf_opts_parse_t p;
4016
4017     /*
4018      * Don't bother loading the options if the file or options structure
4019      * is NULL.
4020      */
4021     if (in == 0 || opts == 0)
4022       return;
4023
4024     (void *) memset((char *) &p, 0, sizeof(_bdf_opts_parse_t));
4025     p.opts = opts;
4026     p.callback = callback;
4027     p.client_data = client_data;
4028     (void) _bdf_readlines(fileno(in), _bdf_parse_options, (void *) &p,
4029                           &lineno);
4030
4031     /*
4032      * Free up the list if there is any space allocated.
4033      */
4034     if (p.list.size > 0)
4035       free((char *) p.list.field);
4036 }
4037
4038 void
4039 bdf_save_options(FILE *out, bdf_options_t *opts)
4040 {
4041     unsigned int i;
4042
4043     if (out == 0 || opts == 0)
4044       return;
4045
4046     fprintf(out, "#\n# Metrics corrections.\n#\ncorrect_metrics ");
4047     if (opts->correct_metrics)
4048       fprintf(out, "true\n\n");
4049     else
4050       fprintf(out, "false\n\n");
4051
4052     fprintf(out, "#\n# Preserve unencoded glyphs.\n#\nkeep_unencoded ");
4053     if (opts->keep_unencoded)
4054       fprintf(out, "true\n\n");
4055     else
4056       fprintf(out, "false\n\n");
4057
4058     fprintf(out, "#\n# Preserve comments.\n#\nkeep_comments ");
4059     if (opts->keep_comments)
4060       fprintf(out, "true\n\n");
4061     else
4062       fprintf(out, "false\n\n");
4063
4064     fprintf(out, "#\n# Pad character cells.\n#\npad_character_cells ");
4065     if (opts->pad_cells)
4066       fprintf(out, "true\n\n");
4067     else
4068       fprintf(out, "false\n\n");
4069
4070     fprintf(out, "#\n# Font spacing.\n#\nfont_spacing ");
4071     switch (opts->font_spacing) {
4072       case BDF_PROPORTIONAL: fprintf(out, "proportional\n\n"); break;
4073       case BDF_MONOWIDTH: fprintf(out, "monowidth\n\n"); break;
4074       case BDF_CHARCELL: fprintf(out, "charactercell\n\n"); break;
4075     }
4076
4077     fprintf(out, "#\n# Point size.\n#\npoint_size %d\n\n", opts->point_size);
4078
4079     fprintf(out,
4080             "#\n# Horizontal resolution.\n#\nhorizontal_resolution %d\n\n",
4081             opts->resolution_x);
4082
4083     fprintf(out,
4084             "#\n# Vertical resolution.\n#\nvertical_resolution %d\n\n",
4085             opts->resolution_x);
4086
4087     fprintf(out,
4088             "#\n# Bits per pixel.\n#\nbits_per_pixel %d\n\n",
4089             opts->bits_per_pixel);
4090
4091     fprintf(out, "#\n# Hint OpenType glyphs.\n#\nhint_opentype_glyphs ");
4092 #ifdef HAVE_FREETYPE
4093     if (opts->otf_flags & FT_LOAD_NO_HINTING)
4094       fprintf(out, "false\n\n");
4095     else
4096       fprintf(out, "true\n\n");
4097 #else
4098     fprintf(out, "false\n\n");
4099 #endif /* HAVE_FREETYPE */
4100
4101     fprintf(out, "#\n# Set the EOL used when writing BDF fonts.\n#\neol ");
4102     switch (opts->eol) {
4103       case BDF_UNIX_EOL: fprintf(out, "unix\n\n"); break;
4104       case BDF_DOS_EOL: fprintf(out, "dos\n\n"); break;
4105       case BDF_MAC_EOL: fprintf(out, "mac\n\n"); break;
4106     }
4107
4108     /*
4109      * Write out the user defined properties if they exist.
4110      */
4111     if (nuser_props == 0)
4112       return;
4113
4114     fprintf(out, "#\n# User defined properties.\n#\n");
4115
4116     for (i = 0; i < nuser_props; i++) {
4117         fprintf(out, "property %s ", user_props[i].name);
4118         switch (user_props[i].format) {
4119           case BDF_ATOM: fprintf(out, "atom\n"); break;
4120           case BDF_CARDINAL: fprintf(out, "cardinal\n"); break;
4121           case BDF_INTEGER: fprintf(out, "integer\n"); break;
4122         }
4123     }
4124 }
4125
4126 void
4127 bdf_default_options(bdf_options_t *opts)
4128 {
4129     if (opts == 0)
4130       return;
4131
4132     (void) memcpy((char *) opts, (char *) &_bdf_opts, sizeof(bdf_options_t));
4133 }
4134
4135 bdf_font_t *
4136 bdf_new_font(char *name, int point_size, int resolution_x, int resolution_y,
4137              int spacing, int bpp)
4138 {
4139     int psize;
4140     char sp[2];
4141     bdf_font_t *font;
4142     double dp, dr;
4143     bdf_property_t prop;
4144
4145     font = (bdf_font_t *) calloc(1, sizeof(bdf_font_t));
4146     if (name != 0 && *name != 0) {
4147         font->name = (char *) malloc(strlen(name) + 1);
4148         (void) strcpy(font->name, name);
4149     }
4150
4151     font->bpp = bpp;
4152     font->point_size = point_size;
4153     font->resolution_x = resolution_x;
4154     font->resolution_y = resolution_y;
4155
4156     /*
4157      * Determine the pixel size of the new font based on the
4158      * point size and resolution.
4159      */
4160     dr = (double) resolution_y;
4161     dp = (double) (point_size * 10);
4162     psize = (int) (((dp * dr) / 722.7) + 0.5);
4163
4164     /*
4165      * Make the default width about 1.5 smaller than the height.
4166      */
4167     font->bbx.height = psize;
4168     font->bbx.width = ((double) psize) / 1.5;
4169
4170     /*
4171      * Now determine the default ascent and descent assuming a
4172      * the descent is about 1/4 the ascent.
4173      */
4174     font->bbx.descent = psize >> 2;
4175     font->bbx.ascent = psize - font->bbx.descent;
4176
4177     font->bbx.y_offset = -font->bbx.descent;
4178
4179     /*
4180      * Allocation the internal hash tables.
4181      */
4182     font->internal = (void *) malloc(sizeof(hashtable));
4183     hash_init((hashtable *) font->internal);
4184
4185     font->default_glyph = -1;
4186     font->spacing = spacing;
4187
4188     /*
4189      * Add various useful properties.
4190      */
4191     prop.name = "POINT_SIZE";
4192     prop.format = BDF_INTEGER;
4193     prop.value.int32 = font->point_size * 10;
4194     bdf_add_font_property(font, &prop);
4195
4196     prop.name = "PIXEL_SIZE";
4197     prop.format = BDF_INTEGER;
4198     prop.value.int32 = psize;
4199     bdf_add_font_property(font, &prop);
4200
4201     prop.name = "RESOLUTION_X";
4202     prop.format = BDF_CARDINAL;
4203     prop.value.card32 = (unsigned int) font->resolution_x;
4204     bdf_add_font_property(font, &prop);
4205
4206     prop.name = "RESOLUTION_Y";
4207     prop.format = BDF_CARDINAL;
4208     prop.value.card32 = (unsigned int) font->resolution_y;
4209     bdf_add_font_property(font, &prop);
4210
4211     prop.name = "FONT_ASCENT";
4212     prop.format = BDF_INTEGER;
4213     prop.value.int32 = (int) font->bbx.ascent;
4214     bdf_add_font_property(font, &prop);
4215
4216     prop.name = "FONT_DESCENT";
4217     prop.format = BDF_INTEGER;
4218     prop.value.int32 = (int) font->bbx.descent;
4219     bdf_add_font_property(font, &prop);
4220
4221     prop.name = "AVERAGE_WIDTH";
4222     prop.format = BDF_INTEGER;
4223     prop.value.int32 = font->bbx.width * 10;
4224     bdf_add_font_property(font, &prop);
4225
4226     sp[0] = 'P';
4227     sp[1] = 0;
4228     switch (spacing) {
4229       case BDF_PROPORTIONAL: sp[0] = 'P'; break;
4230       case BDF_MONOWIDTH: sp[0] = 'M'; break;
4231       case BDF_CHARCELL: sp[0] = 'C'; break;
4232     }
4233     prop.name = "SPACING";
4234     prop.format = BDF_ATOM;
4235     prop.value.atom = sp;
4236     bdf_add_font_property(font, &prop);
4237
4238     /*
4239      * Mark the font as unmodified.
4240      */
4241     font->modified = 0;
4242
4243     return font;
4244 }
4245
4246 void
4247 bdf_set_default_metrics(bdf_font_t *font)
4248 {
4249     int psize;
4250     double dp, dr;
4251     bdf_property_t prop;
4252
4253     /*
4254      * Determine the pixel size of the new font based on the
4255      * point size and resolution.
4256      */
4257     dr = (double) font->resolution_y;
4258     dp = (double) (font->point_size * 10);
4259     psize = (int) (((dp * dr) / 722.7) + 0.5);
4260
4261     /*
4262      * Make the default width about 1.5 smaller than the height.
4263      */
4264     font->bbx.height = psize;
4265     font->bbx.width = ((double) psize) / 1.5;
4266
4267     /*
4268      * Now determine the default ascent and descent assuming a
4269      * the descent is about 1/4 the ascent.
4270      */
4271     font->bbx.descent = psize >> 2;
4272     font->bbx.ascent = psize - font->bbx.descent;
4273
4274     font->bbx.y_offset = -font->bbx.descent;
4275
4276     font->default_glyph = -1;
4277
4278     /*
4279      * Add various useful properties.
4280      */
4281     prop.name = "FONT_ASCENT";
4282     prop.format = BDF_INTEGER;
4283     prop.value.int32 = (int) font->bbx.ascent;
4284     bdf_add_font_property(font, &prop);
4285
4286     prop.name = "FONT_DESCENT";
4287     prop.format = BDF_INTEGER;
4288     prop.value.int32 = (int) font->bbx.descent;
4289     bdf_add_font_property(font, &prop);
4290
4291     prop.name = "AVERAGE_WIDTH";
4292     prop.format = BDF_INTEGER;
4293     prop.value.int32 = font->bbx.width * 10;
4294     bdf_add_font_property(font, &prop);
4295 }
4296
4297 int
4298 bdf_glyph_modified(bdf_font_t *font, int which, int unencoded)
4299 {
4300     if (font == 0 || which < 0)
4301       return 0;
4302
4303     if (unencoded)
4304       return _bdf_glyph_modified(font->umod, which);
4305     else
4306       return _bdf_glyph_modified(font->nmod, which);
4307 }
4308
4309 void
4310 bdf_copy_glyphs(bdf_font_t *font, int start, int end,
4311                 bdf_glyphlist_t *glyphs, int unencoded)
4312 {
4313     int tmp, i, nc;
4314     bdf_glyph_t *cp, *dp;
4315     short maxas, maxds, maxrb, minlb, maxlb, rb;
4316
4317     if (start > end) {
4318         tmp = end;
4319         end = start;
4320         start = tmp;
4321     }
4322
4323     glyphs->bpp = font->bpp;
4324     glyphs->start = start;
4325     glyphs->end = end;
4326     glyphs->glyphs_used = 0;
4327
4328     tmp = (end - start) + 1;
4329     if (tmp > glyphs->glyphs_size) {
4330         if (glyphs->glyphs_size == 0)
4331           glyphs->glyphs = (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * tmp);
4332         else
4333           glyphs->glyphs = (bdf_glyph_t *) realloc((char *) glyphs->glyphs,
4334                                                    sizeof(bdf_glyph_t) * tmp);
4335         cp = glyphs->glyphs + glyphs->glyphs_size;
4336         (void) memset((char *) cp, 0,
4337                       sizeof(bdf_glyph_t) * (tmp - glyphs->glyphs_size));
4338         glyphs->glyphs_size = tmp;
4339     }
4340
4341     /*
4342      * Clear out bitmaps, names and any PSF Unicode mappings in the existing
4343      * entries.
4344      */
4345     for (cp = glyphs->glyphs, i = 0; i < glyphs->glyphs_size; i++, cp++) {
4346         if (cp->name != 0)
4347           free(cp->name);
4348         if (cp->bytes > 0)
4349           free((char *) cp->bitmap);
4350         if (cp->unicode.map_size > 0)
4351           free((char *) cp->unicode.map);
4352     }
4353
4354     /*
4355      * Zero out everything.
4356      */
4357     (void) memset((char *) &glyphs->bbx, 0, sizeof(bdf_bbx_t));
4358     (void) memset((char *) glyphs->glyphs, 0,
4359                   sizeof(bdf_glyph_t) * glyphs->glyphs_size);
4360
4361     /*
4362      * Initialize the bounds used to generate the overall bounding box for the
4363      * set of glyphs being copied.
4364      */
4365     minlb = font->bbx.width;
4366     maxlb = maxrb = maxas = maxds = 0;
4367
4368     /*
4369      * Do the copy.
4370      */
4371     nc = (unencoded == 0) ? font->glyphs_used : font->unencoded_used;
4372     cp = (unencoded == 0) ? font->glyphs : font->unencoded;
4373     dp = glyphs->glyphs;
4374
4375     for (i = 0;
4376          i < nc && ((unencoded && i <= end) || cp->encoding <= end);
4377          i++, cp++) {
4378         if ((unencoded && i >= start) || cp->encoding >= start) {
4379             (void) memcpy((char *) dp, (char *) cp, sizeof(bdf_glyph_t));
4380             if (cp->name != 0) {
4381                 dp->name = (char *) malloc(strlen(cp->name) + 1);
4382                 (void) strcpy(dp->name, cp->name);
4383             }
4384             if (cp->bytes > 0) {
4385                 dp->bytes = cp->bytes;
4386                 dp->bitmap = (unsigned char *) malloc(cp->bytes);
4387                 (void) memcpy((char *) dp->bitmap, (char *) cp->bitmap,
4388                               cp->bytes);
4389             }
4390             if (cp->unicode.map_used > 0) {
4391                 dp->unicode.map_used = dp->unicode.map_size =
4392                     cp->unicode.map_used;
4393                 dp->unicode.map =
4394                     (unsigned char *) malloc(dp->unicode.map_used);
4395                 (void) memcpy((char *) dp->unicode.map,
4396                               (char *) cp->unicode.map,
4397                               dp->unicode.map_used);
4398             }
4399
4400             /*
4401              * Determine the overall metrics for the group of characters being
4402              * copied.
4403              */
4404             maxas = MAX(cp->bbx.ascent, maxas);
4405             maxds = MAX(cp->bbx.descent, maxds);
4406             rb = cp->bbx.width + cp->bbx.x_offset;
4407             maxrb = MAX(rb, maxrb);
4408             minlb = MIN(cp->bbx.x_offset, minlb);
4409             maxlb = MAX(cp->bbx.x_offset, maxlb);
4410
4411             glyphs->glyphs_used++;
4412             dp++;
4413         }
4414     }
4415
4416     /*
4417      * Set the overall metrics for this set of glyphs.
4418      */
4419     glyphs->bbx.width = maxrb - minlb;
4420     glyphs->bbx.x_offset = minlb;
4421
4422     glyphs->bbx.height = maxas + maxds;
4423     glyphs->bbx.ascent = maxas;
4424     glyphs->bbx.descent = maxds;
4425     glyphs->bbx.y_offset = -maxds;
4426 }
4427
4428 bdf_glyph_t *
4429 _bdf_locate_glyph(bdf_font_t *font, int code, int unencoded)
4430 {
4431     int l, r, m, nc;
4432     bdf_glyph_t *gl;
4433
4434     if (code < 0 || font == 0)
4435       return 0;
4436
4437     if ((unencoded && font->unencoded_used == 0) ||
4438         font->glyphs_used == 0)
4439       return 0;
4440
4441     if (unencoded) {
4442         gl = font->unencoded;
4443         nc = font->unencoded_used;
4444     } else {
4445         gl = font->glyphs;
4446         nc = font->glyphs_used;
4447     }
4448     for (l = m = 0, r = nc - 1; l < r; ) {
4449         m = (l + r) >> 1;
4450         if (gl[m].encoding < code)
4451           l = m + 1;
4452         else if (gl[m].encoding > code)
4453           r = m - 1;
4454         else
4455           break;
4456     }
4457
4458     /*
4459      * Go back until we hit the beginning of the glyphs or until
4460      * we find the glyph with a code less than the specified code.
4461      */
4462     l = m;
4463     while (m > 0 && gl[m].encoding > code)
4464       m--;
4465
4466     /*
4467      * Look forward if necessary.
4468      */
4469     m = l;
4470     while (m < nc && gl[m].encoding < code)
4471       m++;
4472
4473     return (m < nc) ? &gl[m] : &gl[nc - 1];
4474 }
4475
4476 int
4477 bdf_delete_glyphs(bdf_font_t *font, int start, int end, int unencoded)
4478 {
4479     int i, n, nc, cnt, mod;
4480     bdf_glyph_t *cp, *sp, *ep;
4481
4482     mod = 0;
4483
4484     if (font == 0)
4485       return mod;
4486
4487     if (start > end) {
4488         cnt = end;
4489         end = start;
4490         start = cnt;
4491     }
4492
4493     nc = (unencoded == 0) ? font->glyphs_used : font->unencoded_used;
4494     cp = (unencoded == 0) ? font->glyphs : font->unencoded;
4495     sp = ep = 0;
4496
4497     for (i = 0; i < nc && cp->encoding <= end; i++, cp++) {
4498         if (cp->encoding >= start && sp == 0)
4499           sp = cp;
4500     }
4501     ep = cp;
4502     if (sp == 0)
4503       sp = ep;
4504
4505     if (ep > sp) {
4506         /*
4507          * There are some glyphs to delete.
4508          * 1. Free the name and bitmap fields of the glyphs being deleted.
4509          * 2. Move the end range down if necessary.
4510          * 3. Clear the glyphs on the end if a move was done.
4511          */
4512
4513         /*
4514          * Mark the font as being modified.
4515          */
4516         mod = font->modified = 1;
4517
4518         cnt = ep - sp;
4519
4520         for (cp = sp; cp < ep; cp++) {
4521             /*
4522              * Mark the glyphs being deleted as also being modified so the
4523              * empty cells can be shown correctly by the client programs.
4524              */
4525             if (unencoded)
4526               _bdf_set_glyph_modified(font->umod, cp->encoding);
4527             else
4528               _bdf_set_glyph_modified(font->nmod, cp->encoding);
4529
4530             if (cp->name != 0)
4531               free(cp->name);
4532             if (cp->bytes > 0)
4533               free((char *) cp->bitmap);
4534         }
4535
4536         cp = (unencoded == 0) ? font->glyphs : font->unencoded;
4537
4538         /*
4539          * Check to see if there are some glyphs that need to
4540          * be moved down.
4541          */
4542         if (ep - cp < nc) {
4543             /*
4544              * Shift the glyphs down.
4545              */
4546             n = nc - (ep - cp);
4547             _bdf_memmove((char *) sp, (char *) ep, sizeof(bdf_glyph_t) * n);
4548
4549             /*
4550              * Set the starting point for the clear.
4551              */
4552             ep = sp + n;
4553         } else
4554           /*
4555            * Set the starting point for the clear.
4556            */
4557           ep = sp;
4558
4559         /*
4560          * Clear the glyph space just moved.
4561          */
4562         n = nc - (ep - cp);
4563         (void) memset((char *) ep, 0, sizeof(bdf_glyph_t) * n);
4564
4565         /*
4566          * Adjust the number of glyphs used.
4567          */
4568         if (unencoded == 0)
4569           font->glyphs_used -= cnt;
4570         else
4571           font->unencoded_used -= cnt;
4572
4573         /*
4574          * If unencoded glyphs were deleted, re-encode all
4575          * of them to cause a shift when everything is redrawn.
4576          */
4577         if (unencoded != 0) {
4578             for (i = 0, cp = font->unencoded; i < font->unencoded_used;
4579                  i++, cp++) {
4580                 if (_bdf_glyph_modified(font->umod, cp->encoding)) {
4581                     _bdf_clear_glyph_modified(font->umod, cp->encoding);
4582                     _bdf_set_glyph_modified(font->umod, i);
4583                 }
4584                 cp->encoding = i;
4585             }
4586         }
4587     }
4588     return mod;
4589 }
4590
4591 /*
4592  * These values are intended to give pixels mapped from 1bpp to nbpp the
4593  * darkest available index, which is 1.
4594  */
4595 static unsigned char twobpp_ones[] = {0x40, 0x10, 0x04, 0x01};
4596 static unsigned char fourbpp_ones[] = {0x10, 0x01};
4597 static unsigned char eightbpp_ones[] = {0x01};
4598
4599 /*
4600  * Routines for quick and dirty dithering.
4601  */
4602 static void
4603 _bdf_one_to_n(bdf_glyphlist_t *gl, int n)
4604 {
4605     int i;
4606     unsigned short bpr, sbpr, bytes, col, sx, sy;
4607     unsigned char *nbmap, *ones = 0;
4608     bdf_glyph_t *gp;
4609
4610     if (gl == 0 || gl->glyphs_used == 0)
4611       return;
4612
4613     switch (n) {
4614       case 1: ones = bdf_onebpp; break;
4615       case 2: ones = twobpp_ones; break;
4616       case 4: ones = fourbpp_ones; break;
4617       case 8: ones = eightbpp_ones; break;
4618     }
4619
4620     gl->bpp = n;
4621     for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) {
4622         if (gp->bbx.width == 0 || gp->bbx.height == 0)
4623           continue;
4624         sbpr = (gp->bbx.width + 7) >> 3;
4625         bpr = ((gp->bbx.width * n) + 7) >> 3;
4626         bytes = bpr * gp->bbx.height;
4627         nbmap = (unsigned char *) malloc(bytes);
4628         (void) memset((char *) nbmap, 0, bytes);
4629
4630         for (sy = 0; sy < gp->bbx.height; sy++) {
4631             for (col = sx = 0; sx < gp->bbx.width; sx++, col += n) {
4632                 if (gp->bitmap[(sy * sbpr) + (sx >> 3)] & (0x80 >> (sx & 7)))
4633                   nbmap[(sy * bpr) + (col >> 3)] |= ones[(col & 7) / n];
4634             }
4635         }
4636         free((char *) gp->bitmap);
4637         gp->bytes = bytes;
4638         gp->bitmap = nbmap;
4639     }
4640 }
4641
4642 static void
4643 _bdf_n_to_one(bdf_glyphlist_t *gl)
4644 {
4645     int i;
4646     unsigned short bpr, sbpr, bytes, col, sx, sy;
4647     unsigned char *nbmap, *masks;
4648     bdf_glyph_t *gp;
4649
4650     if (gl == 0 || gl->glyphs_used == 0)
4651       return;
4652
4653     masks = 0;
4654     switch (gl->bpp) {
4655       case 1: masks = bdf_onebpp; break;
4656       case 2: masks = bdf_twobpp; break;
4657       case 4: masks = bdf_fourbpp; break;
4658       case 8: masks = bdf_eightbpp; break;
4659     }
4660
4661     for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) {
4662         if (gp->bbx.width == 0 || gp->bbx.height == 0)
4663           continue;
4664         sbpr = ((gp->bbx.width * gl->bpp) + 7) >> 3;
4665         bpr = (gp->bbx.width + 7) >> 3;
4666         bytes = bpr * gp->bbx.height;
4667         nbmap = (unsigned char *) malloc(bytes);
4668         (void) memset((char *) nbmap, 0, bytes);
4669
4670         for (sy = 0; sy < gp->bbx.height; sy++) {
4671             for (col = sx = 0; sx < gp->bbx.width; sx++, col += gl->bpp) {
4672                 if (gp->bitmap[(sy * sbpr) + (col >> 3)] &
4673                     masks[(col & 7) / gl->bpp])
4674                   nbmap[(sy * bpr) + (sx >> 3)] |= (0x80 >> (sx & 7));
4675             }
4676         }
4677         free((char *) gp->bitmap);
4678         gp->bytes = bytes;
4679         gp->bitmap = nbmap;
4680     }
4681     gl->bpp = 1;
4682 }
4683
4684 static void
4685 _bdf_two_to_four(bdf_glyphlist_t *gl)
4686 {
4687     int i;
4688     unsigned short bpr, sbpr, bytes, col, si, byte, sx, sy;
4689     unsigned char *nbmap, *masks;
4690     bdf_glyph_t *gp;
4691
4692     if (gl == 0 || gl->glyphs_used == 0)
4693       return;
4694
4695     masks = bdf_twobpp;
4696
4697     for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) {
4698         if (gp->bbx.width == 0 || gp->bbx.height == 0)
4699           continue;
4700         sbpr = ((gp->bbx.width << 1) + 7) >> 3;
4701         bpr = ((gp->bbx.width << 2) + 7) >> 3;
4702         bytes = bpr * gp->bbx.height;
4703         nbmap = (unsigned char *) malloc(bytes);
4704         (void) memset((char *) nbmap, 0, bytes);
4705
4706         for (sy = 0; sy < gp->bbx.height; sy++) {
4707             for (col = sx = 0; sx < gp->bbx.width; sx++, col += 2) {
4708                 si = (col & 7) >> 1;
4709                 byte = gp->bitmap[(sy * sbpr) + (col >> 3)] & masks[si];
4710                 if (byte) {
4711                     if (si < 3)
4712                       byte >>= (3 - si) << 1;
4713                     byte <<= 2;
4714                     if ((sx & 1) == 0)
4715                       byte <<= 4;
4716                     nbmap[(sy * bpr) + ((sx << 2) >> 3)] |= byte;
4717                 }
4718             }
4719         }
4720         free((char *) gp->bitmap);
4721         gp->bytes = bytes;
4722         gp->bitmap = nbmap;
4723     }
4724     gl->bpp = 4;
4725 }
4726
4727 static void
4728 _bdf_four_to_two(bdf_glyphlist_t *gl)
4729 {
4730     int i;
4731     unsigned short bpr, sbpr, bytes, col, si, byte, sx, sy;
4732     unsigned char *nbmap, *masks;
4733     bdf_glyph_t *gp;
4734
4735     if (gl == 0 || gl->glyphs_used == 0)
4736       return;
4737
4738     masks = bdf_fourbpp;
4739
4740     gl->bpp = 2;
4741     for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) {
4742         sbpr = ((gp->bbx.width << 2) + 7) >> 3;
4743         bpr = ((gp->bbx.width << 1) + 7) >> 3;
4744         bytes = bpr * gp->bbx.height;
4745         nbmap = (unsigned char *) malloc(bytes);
4746         (void) memset((char *) nbmap, 0, bytes);
4747
4748         for (sy = 0; sy < gp->bbx.height; sy++) {
4749             for (col = sx = 0; sx < gp->bbx.width; sx++, col += 4) {
4750                 si = (col & 7) >> 2;
4751                 byte = gp->bitmap[(sy * sbpr) + (col >> 3)] & masks[si];
4752                 if (byte) {
4753                     /*
4754                      * Shift the byte down to make an index.
4755                      */
4756                     if (si == 0)
4757                       byte >>= 4;
4758
4759                     /*
4760                      * Scale the index to two bits per pixel and shift it into
4761                      * place if necessary.
4762                      */
4763                     byte >>= 2;
4764                     /*
4765                      * Any non-zero byte has to remain non-zero, because index
4766                      * zero means no bits set.
4767                      */
4768                     if (byte == 0)
4769                       byte = 1;
4770
4771                     si = ((sx << 1) & 7) >> 1;
4772                     if (si < 3)
4773                       byte <<= (3 - si) << 1;
4774
4775                     nbmap[(sy * bpr) + ((sx << 1) >> 3)] |= byte;
4776                 }
4777             }
4778         }
4779         free((char *) gp->bitmap);
4780         gp->bytes = bytes;
4781         gp->bitmap = nbmap;
4782     }
4783 }
4784
4785 static void
4786 _bdf_two_to_eight(bdf_glyphlist_t *gl)
4787 {
4788     int i;
4789     unsigned short bpr, sbpr, bytes, col, si, byte, sx, sy;
4790     unsigned char *nbmap, *masks;
4791     bdf_glyph_t *gp;
4792
4793     if (gl == 0 || gl->glyphs_used == 0)
4794       return;
4795
4796     masks = bdf_twobpp;
4797
4798     for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) {
4799         if (gp->bbx.width == 0 || gp->bbx.height == 0)
4800           continue;
4801         sbpr = ((gp->bbx.width << 1) + 7) >> 3;
4802         bpr = gp->bbx.width;
4803         bytes = bpr * gp->bbx.height;
4804         nbmap = (unsigned char *) malloc(bytes);
4805         (void) memset((char *) nbmap, 0, bytes);
4806
4807         for (sy = 0; sy < gp->bbx.height; sy++) {
4808             for (col = sx = 0; sx < gp->bbx.width; sx++, col += 2) {
4809                 si = (col & 7) >> 1;
4810                 byte = gp->bitmap[(sy * sbpr) + (col >> 3)] & masks[si];
4811                 if (byte) {
4812                     /*
4813                      * Shift the byte down to make an index.
4814                      */
4815                     if (si < 3)
4816                       byte >>= (3 - si) * gl->bpp;
4817
4818                     /*
4819                      * Scale the index to four bits per pixel and shift it into
4820                      * place before adding it.
4821                      */
4822                     byte <<= 6;
4823                     nbmap[(sy * bpr) + sx] = byte;
4824                 }
4825             }
4826         }
4827         free((char *) gp->bitmap);
4828         gp->bytes = bytes;
4829         gp->bitmap = nbmap;
4830     }
4831     gl->bpp = 8;
4832 }
4833
4834 static void
4835 _bdf_eight_to_two(bdf_glyphlist_t *gl)
4836 {
4837     int i;
4838     unsigned short bpr, sbpr, bytes, si, byte, sx, sy;
4839     unsigned char *nbmap /*, *masks*/;
4840     bdf_glyph_t *gp;
4841
4842     if (gl == 0 || gl->glyphs_used == 0)
4843       return;
4844
4845     /*masks = bdf_fourbpp;*/
4846
4847     gl->bpp = 2;
4848     for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) {
4849         sbpr = gp->bbx.width;
4850         bpr = ((gp->bbx.width << 1) + 7) >> 3;
4851         bytes = bpr * gp->bbx.height;
4852         nbmap = (unsigned char *) malloc(bytes);
4853         (void) memset((char *) nbmap, 0, bytes);
4854
4855         for (sy = 0; sy < gp->bbx.height; sy++) {
4856             for (sx = 0; sx < gp->bbx.width; sx++) {
4857                 byte = gp->bitmap[(sy * sbpr) + sx];
4858                 if (byte) {
4859                     byte >>= 6;
4860                     if (byte == 0)
4861                       byte = 1;
4862
4863                     si = ((sx << 1) & 7) >> 1;
4864                     if (si < 3)
4865                       byte <<= (3 - si) << 1;
4866
4867                     nbmap[(sy * bpr) + ((sx << 1) >> 3)] |= byte;
4868                 }
4869             }
4870         }
4871         free((char *) gp->bitmap);
4872         gp->bytes = bytes;
4873         gp->bitmap = nbmap;
4874     }
4875 }
4876
4877 static void
4878 _bdf_four_to_eight(bdf_glyphlist_t *gl)
4879 {
4880     int i;
4881     unsigned short bpr, sbpr, bytes, col, si, byte, sx, sy;
4882     unsigned char *nbmap, *masks;
4883     bdf_glyph_t *gp;
4884
4885     if (gl == 0 || gl->glyphs_used == 0)
4886       return;
4887
4888     masks = bdf_fourbpp;
4889
4890     for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) {
4891         if (gp->bbx.width == 0 || gp->bbx.height == 0)
4892           continue;
4893         sbpr = ((gp->bbx.width << 2) + 7) >> 3;
4894         bpr = gp->bbx.width;
4895         bytes = bpr * gp->bbx.height;
4896         nbmap = (unsigned char *) malloc(bytes);
4897         (void) memset((char *) nbmap, 0, bytes);
4898
4899         for (sy = 0; sy < gp->bbx.height; sy++) {
4900             for (col = sx = 0; sx < gp->bbx.width; sx++, col += 4) {
4901                 si = (col & 7) >> 2;
4902                 byte = gp->bitmap[(sy * sbpr) + (col >> 3)] & masks[si];
4903                 if (byte) {
4904                     if (si == 0)
4905                       byte >>= 4;
4906
4907                     byte <<= 4;
4908                     nbmap[(sy * bpr) + sx] = byte;
4909                 }
4910             }
4911         }
4912         free((char *) gp->bitmap);
4913         gp->bytes = bytes;
4914         gp->bitmap = nbmap;
4915     }
4916     gl->bpp = 8;
4917 }
4918
4919 static void
4920 _bdf_eight_to_four(bdf_glyphlist_t *gl)
4921 {
4922     int i;
4923     unsigned short bpr, sbpr, bytes, col, si, byte, sx, sy;
4924     unsigned char *nbmap/*, *masks*/;
4925     bdf_glyph_t *gp;
4926
4927     if (gl == 0 || gl->glyphs_used == 0)
4928       return;
4929
4930     /*masks = bdf_twobpp;*/
4931
4932     for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) {
4933         if (gp->bbx.width == 0 || gp->bbx.height == 0)
4934           continue;
4935         sbpr = gp->bbx.width;
4936         bpr = ((gp->bbx.width << 2) + 7) >> 3;
4937         bytes = bpr * gp->bbx.height;
4938         nbmap = (unsigned char *) malloc(bytes);
4939         (void) memset((char *) nbmap, 0, bytes);
4940
4941         for (sy = 0; sy < gp->bbx.height; sy++) {
4942             for (col = sx = 0; sx < gp->bbx.width; sx++, col += 2) {
4943                 byte = gp->bitmap[(sy * sbpr) + sx];
4944                 if (byte) {
4945                     byte >>= 4;
4946                     if (byte == 0)
4947                       byte = 1;
4948
4949                     /*
4950                      * Scale the index to four bits per pixel and shift it into
4951                      * place before adding it.
4952                      */
4953                     si = (col & 7) >> 2;
4954                     if (si == 0)
4955                       byte <<= 4;
4956                     nbmap[(sy * bpr) + ((sx << 2) >> 3)] |= byte;
4957                 }
4958             }
4959         }
4960         free((char *) gp->bitmap);
4961         gp->bytes = bytes;
4962         gp->bitmap = nbmap;
4963     }
4964     gl->bpp = 4;
4965 }
4966
4967 /*
4968  * This only works on glyphs that exist.
4969  */
4970 int
4971 bdf_replace_mappings(bdf_font_t *font, int encoding, bdf_psf_unimap_t *map,
4972                      int unencoded)
4973 {
4974     bdf_glyph_t *gp;
4975
4976     if ((gp = _bdf_locate_glyph(font, encoding, unencoded)) == 0 ||
4977         gp->encoding != encoding)
4978       return 0;
4979
4980     if (map->map_size > gp->unicode.map_size) {
4981         if (gp->unicode.map_size == 0)
4982           gp->unicode.map = (unsigned char *)
4983               malloc(sizeof(unsigned char) * map->map_size);
4984         else
4985           gp->unicode.map =(unsigned char *)
4986               realloc((char *) gp->unicode.map,
4987                       sizeof(unsigned char) * map->map_size);
4988         gp->unicode.map_size = map->map_size;
4989     }
4990     gp->unicode.map_used = map->map_used;
4991     (void) memcpy((char *) gp->unicode.map, (char *) map->map,
4992                   sizeof(unsigned char) * map->map_used);
4993
4994     /*
4995      * Mark the glyph as modified.
4996      */
4997     if (unencoded)
4998       _bdf_set_glyph_modified(font->umod, gp->encoding);
4999     else
5000       _bdf_set_glyph_modified(font->nmod, gp->encoding);
5001
5002     font->modified = 1;
5003
5004     return 1;
5005 }
5006
5007 int
5008 bdf_replace_glyphs(bdf_font_t *font, int start, bdf_glyphlist_t *glyphs,
5009                    int unencoded)
5010 {
5011     int resize, appending;
5012     int i, n, ng, end, del, remaining, off[2];
5013     bdf_glyph_t *sgp, *gp, *dgp;
5014     short maxas, maxds, maxrb, minlb, maxlb, rb;
5015     double ps, rx, dw;
5016     bdf_bbx_t nbbx;
5017
5018     resize = 0;
5019
5020     if (font == 0)
5021       return resize;
5022
5023     /*
5024      * Dither the incoming bitmaps so they match the same bits per pixel as
5025      * the font.
5026      */
5027     if (glyphs->bpp != font->bpp) {
5028         if (glyphs->bpp == 1)
5029           _bdf_one_to_n(glyphs, font->bpp);
5030         else if (font->bpp == 1)
5031           _bdf_n_to_one(glyphs);
5032         else if (glyphs->bpp == 2) {
5033             if (font->bpp == 4)
5034               _bdf_two_to_four(glyphs);
5035             else
5036               _bdf_two_to_eight(glyphs);
5037         } else if (glyphs->bpp == 4) {
5038             if (font->bpp == 2)
5039               _bdf_four_to_two(glyphs);
5040             else
5041               _bdf_four_to_eight(glyphs);
5042         } else if (glyphs->bpp == 8) {
5043             if (font->bpp == 2)
5044               _bdf_eight_to_two(glyphs);
5045             else
5046               _bdf_eight_to_four(glyphs);
5047         }
5048     }
5049
5050     /*
5051      * Set the point size and horizontal resolution so the scalable width can
5052      * be determined.
5053      */
5054     ps = (double) font->point_size;
5055     rx = (double) font->resolution_x;
5056
5057     /*
5058      * Determine if a resize is needed.
5059      */
5060
5061     /*
5062      * Determine the bounding box for the font without the characters being
5063      * replaced.
5064      */
5065     minlb = 32767;
5066     maxlb = maxrb = maxas = maxds = 0;
5067
5068     /*
5069      * Get the font bounds.
5070      */
5071     maxas = MAX(font->bbx.ascent, maxas);
5072     maxds = MAX(font->bbx.descent, maxds);
5073     rb = font->bbx.width + font->bbx.x_offset;
5074     maxrb = MAX(rb, maxrb);
5075     minlb = MIN(font->bbx.x_offset, minlb);
5076     maxlb = MAX(font->bbx.x_offset, maxlb);
5077
5078     /*
5079      * Get the bounds of the incoming glyphs.
5080      */
5081     maxas = MAX(glyphs->bbx.ascent, maxas);
5082     maxds = MAX(glyphs->bbx.descent, maxds);
5083     rb = glyphs->bbx.width + glyphs->bbx.x_offset;
5084     maxrb = MAX(rb, maxrb);
5085     minlb = MIN(glyphs->bbx.x_offset, minlb);
5086     maxlb = MAX(glyphs->bbx.x_offset, maxlb);
5087
5088     /*
5089      * Set up the new font bounding box, minus the characters that are being
5090      * removed and with the new characters added.
5091      */
5092     nbbx.width = maxrb - minlb;
5093     nbbx.x_offset = minlb;
5094
5095     nbbx.height = maxas + maxds;
5096     nbbx.ascent = maxas;
5097     nbbx.descent = maxds;
5098     nbbx.y_offset = -maxds;
5099
5100     /*
5101      * Now determine if the combination of the glyphs removed and the new
5102      * glyphs cause the font bounding box to be changed.
5103      */
5104     resize = (nbbx.width > font->bbx.width ||
5105               nbbx.height > font->bbx.height) ? 1 : 0;
5106
5107     /*
5108      * Set the pointers to the glyphs.
5109      */
5110     ng = (unencoded == 0) ? font->glyphs_used : font->unencoded_used;
5111     sgp = gp = (unencoded == 0) ? font->glyphs : font->unencoded;
5112
5113     /*
5114      * Locate the closest glyph on or following `start'.
5115      */
5116     for (i = 0; i < ng && gp->encoding < start; i++, gp++) ;
5117
5118     appending = (i == ng);
5119
5120     /*
5121      * Set the starting point for copying the incoming glyphs.
5122      */
5123     dgp = gp;
5124
5125     n = glyphs->end - glyphs->start;
5126     end = start + n;
5127
5128     /*
5129      * Delete all the glyphs between `start' and `end'.
5130      */
5131     for (del = 0, i = start; i <= end; i++) {
5132         /*
5133          * Mark the character as being modified.
5134          */
5135         if (ng > 0 && !appending && gp->encoding == i) {
5136             if (unencoded == 0)
5137               _bdf_set_glyph_modified(font->nmod, i);
5138             else
5139               _bdf_set_glyph_modified(font->umod, i);
5140
5141             if (gp->name != 0)
5142               free(gp->name);
5143             if (gp->bytes > 0)
5144               free((char *) gp->bitmap);
5145             if (gp->unicode.map_size > 0)
5146               free((char *) gp->unicode.map);
5147             del++;
5148             gp++;
5149         }
5150     }
5151
5152     /*
5153      * Determine how many glyphs remain following the last one deleted.
5154      */
5155     remaining = ng - (gp - sgp);
5156
5157     if (glyphs->glyphs_used == 0) {
5158         /*
5159          * If the glyph list is empty, then shift any remaining glyphs down
5160          * to the destination.
5161          */
5162         _bdf_memmove((char *) dgp, (char *) gp,
5163                      sizeof(bdf_glyph_t) * remaining);
5164         if (unencoded == 0)
5165           font->glyphs_used -= del;
5166         else
5167           font->unencoded_used -= del;
5168     } else {
5169         /*
5170          * Insert the glyph list after making sure there is enough space to
5171          * hold them.  Also adjust the encoding and scalable width values
5172          * after copying the glyphs.
5173          */
5174         if (unencoded == 0) {
5175             n = (font->glyphs_used - del) + glyphs->glyphs_used;
5176             if (n > font->glyphs_size) {
5177                 off[0] = gp - sgp;
5178                 off[1] = dgp - sgp;
5179                 if (font->glyphs_size == 0)
5180                   font->glyphs = sgp =
5181                       (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * n);
5182                 else
5183                   font->glyphs = sgp =
5184                       (bdf_glyph_t *) realloc((char *) font->glyphs,
5185                                               sizeof(bdf_glyph_t) * n);
5186                 gp = sgp + off[0];
5187                 dgp = sgp + off[1];
5188                 font->glyphs_size = n;
5189             }
5190
5191             /*
5192              * Calculate how many will need to be shifted.
5193              */
5194             if ((n = glyphs->glyphs_used - del) >= font->glyphs_used)
5195               n = 0;
5196         } else {
5197             n = (font->unencoded_used - del) + glyphs->glyphs_used;
5198             if (n > font->unencoded_size) {
5199                 off[0] = gp - sgp;
5200                 off[1] = dgp - sgp;
5201                 if (font->unencoded_size == 0)
5202                   font->unencoded = sgp =
5203                       (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * n);
5204                 else
5205                   font->unencoded = sgp =
5206                       (bdf_glyph_t *) realloc((char *) font->unencoded,
5207                                               sizeof(bdf_glyph_t) * n);
5208                 gp = sgp + off[0];
5209                 dgp = sgp + off[1];
5210                 font->unencoded_size = n;
5211             }
5212
5213             /*
5214              * Calculate how many will need to be shifted.
5215              */
5216             if ((n = glyphs->glyphs_used - del) >= font->unencoded_used)
5217               n = 0;
5218         }
5219
5220         /*
5221          * Shift any following glyphs up or down if needed.
5222          */
5223         if (n)
5224           _bdf_memmove((char *) (gp + n), (char *) gp,
5225                        sizeof(bdf_glyph_t) * remaining);
5226
5227         /*
5228          * Copy the incoming glyphs, copy their names and bitmaps,
5229          * set their encodings, and set their scalable widths.
5230          */
5231         (void) memcpy((char *) dgp, (char *) glyphs->glyphs,
5232                       sizeof(bdf_glyph_t) * glyphs->glyphs_used);
5233         for (i = 0; i < glyphs->glyphs_used; i++, dgp++) {
5234             if (dgp->name != 0)
5235               dgp->name = (char *) _bdf_strdup((unsigned char *) dgp->name,
5236                                                strlen(dgp->name) + 1);
5237
5238             if (dgp->bytes > 0)
5239               dgp->bitmap = _bdf_strdup(dgp->bitmap, dgp->bytes);
5240
5241             if (dgp->unicode.map_size > 0)
5242               dgp->unicode.map = _bdf_strdup(dgp->unicode.map,
5243                                              dgp->unicode.map_size);
5244
5245             dgp->encoding = start + (dgp->encoding - glyphs->start);
5246
5247             /*
5248              * Mark the glyph as being modified in case it fills a cell that
5249              * was empty before.
5250              */
5251             _bdf_set_glyph_modified(font->nmod, dgp->encoding);
5252
5253             dw = (double) dgp->dwidth;
5254             dgp->swidth = (unsigned short) ((dw * 72000.0) / (ps * rx));
5255         }
5256
5257         /*
5258          * Adjust the count of glyphs.
5259          */
5260         ng = (ng - del) + glyphs->glyphs_used;
5261         if (unencoded == 0)
5262           font->glyphs_used = ng;
5263         else
5264           font->unencoded_used = ng;
5265     }
5266
5267     /*
5268      * Last, if the replacement was done in the unencoded section,
5269      * reencode all the glyphs so they show up properly.
5270      */
5271     if (unencoded != 0) {
5272         for (i = 0; i < ng; i++, sgp++) {
5273             if (_bdf_glyph_modified(font->umod, sgp->encoding)) {
5274                 _bdf_clear_glyph_modified(font->umod, sgp->encoding);
5275                 _bdf_set_glyph_modified(font->umod, i);
5276             }
5277             sgp->encoding = i;
5278         }
5279     }
5280
5281     if (resize)
5282       (void) memcpy((char *) &font->bbx, (char *) &nbbx, sizeof(bdf_bbx_t));
5283
5284     font->modified = 1;
5285
5286     return resize;
5287 }
5288
5289 int
5290 bdf_insert_glyphs(bdf_font_t *font, int start, bdf_glyphlist_t *glyphs)
5291 {
5292     int resize;
5293     unsigned int i, ng, n, which;
5294     bdf_glyph_t *gp;
5295
5296     resize = 0;
5297
5298     if (font == 0)
5299       return resize;
5300
5301     /*
5302      * Dither the incoming bitmaps so they match the same bits per pixel as
5303      * the font.
5304      */
5305     if (glyphs->bpp != font->bpp) {
5306         if (glyphs->bpp == 1)
5307           _bdf_one_to_n(glyphs, font->bpp);
5308         else if (font->bpp == 1)
5309           _bdf_n_to_one(glyphs);
5310         else if (glyphs->bpp == 2)
5311           _bdf_two_to_four(glyphs);
5312         else
5313           _bdf_four_to_two(glyphs);
5314     }
5315
5316     /*
5317      * Locate the starting glyph.
5318      */
5319     gp = font->glyphs;
5320     ng = font->glyphs_used;
5321     for (i = 0; i < ng && gp->encoding < start; i++, gp++) ;
5322
5323     /*
5324      * If there are no glyphs at the starting point, then simply do a replace.
5325      */
5326     if (i == ng)
5327       return bdf_replace_glyphs(font, start, glyphs, 0);
5328
5329     /*
5330      * Go through the glyphs that would be shifted due to the insertion and
5331      * determine if some of them will overflow the 0xffff boundary.
5332      */
5333     n = (glyphs->end - glyphs->start) + 1;
5334     for (which = i; i < ng; i++, gp++) {
5335         if (gp->encoding + n > 0xffff)
5336           break;
5337     }
5338
5339     if (i < ng) {
5340         /*
5341          * Some glyphs have to be moved to the unencoded area because they
5342          * would overflow the 0xffff boundary if they were moved up.
5343          */
5344         bdf_copy_glyphs(font, gp->encoding, font->glyphs[ng - 1].encoding,
5345                         &font->overflow, 0);
5346         bdf_delete_glyphs(font,  gp->encoding, font->glyphs[ng - 1].encoding,
5347                           0);
5348         resize += bdf_replace_glyphs(font, font->unencoded_used,
5349                                      &font->overflow, 1);
5350     }
5351
5352     /*
5353      * Go back to the insertion point and shift the remaining glyph encodings
5354      * up by `n'.
5355      */
5356     for (gp = font->glyphs + which; which < font->glyphs_used; which++, gp++) {
5357         /*
5358          * Mark the new glyph locations as being modified.
5359          */
5360         gp->encoding += n;
5361         _bdf_set_glyph_modified(font->nmod, gp->encoding);
5362     }
5363
5364     /*
5365      * Finally, mark the font as being modified and insert the new glyphs.
5366      */
5367     font->modified = 1;
5368
5369     return resize + bdf_replace_glyphs(font, start, glyphs, 0);
5370 }
5371
5372 static void
5373 _bdf_combine_glyphs(bdf_font_t *font, bdf_glyph_t *f, bdf_glyph_t *g)
5374 {
5375     unsigned short x, sx, sy, si, dx, dy, di, byte, dbpr, fbpr, gbpr;
5376     short maxas, maxds, maxrb, minlb, maxlb, rb;
5377     unsigned char *masks;
5378     bdf_bbx_t nbbx;
5379     bdf_glyph_t tmp;
5380
5381     /*
5382      * Determine the max bounding box for the two glyphs.
5383      */
5384     minlb = 32767;
5385     maxlb = maxrb = maxas = maxds = 0;
5386
5387     /*
5388      * Get the font glyph bounds.
5389      */
5390     maxas = MAX(f->bbx.ascent, maxas);
5391     maxds = MAX(f->bbx.descent, maxds);
5392     rb = f->bbx.width + f->bbx.x_offset;
5393     maxrb = MAX(rb, maxrb);
5394     minlb = MIN(f->bbx.x_offset, minlb);
5395     maxlb = MAX(f->bbx.x_offset, maxlb);
5396
5397     /*
5398      * Get the bounds of the incoming glyph.
5399      */
5400     maxas = MAX(g->bbx.ascent, maxas);
5401     maxds = MAX(g->bbx.descent, maxds);
5402     rb = g->bbx.width + g->bbx.x_offset;
5403     maxrb = MAX(rb, maxrb);
5404     minlb = MIN(g->bbx.x_offset, minlb);
5405     maxlb = MAX(g->bbx.x_offset, maxlb);
5406
5407     /*
5408      * Set up the new glyph bounding box.
5409      */
5410     nbbx.width = maxrb - minlb;
5411     nbbx.x_offset = minlb;
5412     nbbx.height = maxas + maxds;
5413     nbbx.ascent = maxas;
5414     nbbx.descent = maxds;
5415     nbbx.y_offset = -maxds;
5416
5417     masks = 0;
5418     switch (font->bpp) {
5419       case 1: masks = bdf_onebpp; break;
5420       case 2: masks = bdf_twobpp; break;
5421       case 4: masks = bdf_fourbpp; break;
5422       case 8: masks = bdf_eightbpp; break;
5423     }
5424
5425     fbpr = ((f->bbx.width * font->bpp) + 7) >> 3;
5426     gbpr = ((g->bbx.width * font->bpp) + 7) >> 3;
5427     dbpr = ((nbbx.width * font->bpp) + 7) >> 3;
5428
5429     if (memcmp((char *) &nbbx, (char *) &f->bbx, sizeof(bdf_bbx_t)) == 0) {
5430         /*
5431          * The largest is the first, so merge the second in with it.
5432          */
5433         dy = f->bbx.ascent - g->bbx.ascent;
5434         for (sy = 0; sy < g->bbx.height; sy++, dy++) {
5435             for (x = sx = 0; x < g->bbx.width; x++, sx += font->bpp) {
5436                 si = (sx & 7) / font->bpp;
5437                 if ((byte = g->bitmap[(sy * gbpr) + (sx >> 3)] & masks[si]))
5438                   /*
5439                    * No shifting of the byte is needed because the x offset
5440                    * is the same for both glyphs.
5441                    */
5442                   f->bitmap[(dy * fbpr) + (sx >> 3)] |= byte;
5443             }
5444         }
5445     } else if (memcmp((char *) &nbbx, (char *) &g->bbx,
5446                       sizeof(bdf_bbx_t)) == 0) {
5447         /*
5448          * The largest is the incoming glyph, so merge into that one and swap
5449          * it with the font glyph.
5450          */
5451         dy = g->bbx.ascent - f->bbx.ascent;
5452         for (sy = 0; sy < f->bbx.height; sy++, dy++) {
5453             for (x = sx = 0; x < f->bbx.width; x++, sx += font->bpp) {
5454                 si = (sx & 7) / font->bpp;
5455                 if ((byte = f->bitmap[(sy * gbpr) + (sx >> 3)] & masks[si]))
5456                   /*
5457                    * No shifting of the byte is needed because the x offset
5458                    * is the same for both glyphs.
5459                    */
5460                   g->bitmap[(dy * fbpr) + (sx >> 3)] |= byte;
5461             }
5462         }
5463
5464         /*
5465          * Now swap the two glyphs while preserving the name and encoding of
5466          * the first glyph.
5467          */
5468         tmp.swidth = g->swidth;
5469         tmp.dwidth = g->dwidth;
5470         tmp.bytes = g->bytes;
5471         tmp.bitmap = g->bitmap;
5472         (void) memcpy((char *) &tmp.bbx, (char *) &g->bbx, sizeof(bdf_bbx_t));
5473
5474         g->swidth = f->swidth;
5475         g->dwidth = f->dwidth;
5476         g->bytes = f->bytes;
5477         g->bitmap = f->bitmap;
5478         (void) memcpy((char *) &g->bbx, (char *) &f->bbx, sizeof(bdf_bbx_t));
5479
5480         f->swidth = tmp.swidth;
5481         f->dwidth = tmp.dwidth;
5482         f->bytes = tmp.bytes;
5483         f->bitmap = tmp.bitmap;
5484         (void) memcpy((char *) &f->bbx, (char *) &tmp.bbx, sizeof(bdf_bbx_t));
5485     } else {
5486         /*
5487          * Need a new bitmap for the combination of the two.
5488          */
5489         tmp.bytes = nbbx.height * dbpr;
5490         tmp.bitmap = (unsigned char *) malloc(tmp.bytes);
5491         (void) memset((char *) tmp.bitmap, 0, tmp.bytes);
5492
5493         /*
5494          * Merge the first glyph.
5495          */
5496         dy = nbbx.ascent - f->bbx.ascent;
5497         for (sy = 0; sy < f->bbx.height; sy++, dy++) {
5498             dx = MYABS(nbbx.x_offset - f->bbx.x_offset) * font->bpp;
5499             for (x = sx = 0; x < f->bbx.width; x++,
5500                      sx += font->bpp, dx += font->bpp) {
5501                 si = (sx & 7) / font->bpp;
5502                 if ((byte = f->bitmap[(sy * fbpr) + (sx >> 3)] & masks[si])) {
5503                     di = (dx & 7) / font->bpp;
5504                     if (di < si)
5505                       byte <<= (si - di) * font->bpp;
5506                     else if (di > si)
5507                       byte >>= (di - si) * font->bpp;
5508                     tmp.bitmap[(dy * dbpr) + (dx >> 3)] |= byte;
5509                 }
5510             }
5511         }
5512
5513         /*
5514          * Merge the second glyph.
5515          */
5516         dy = nbbx.ascent - g->bbx.ascent;
5517         for (sy = 0; sy < g->bbx.height; sy++, dy++) {
5518             dx = MYABS(nbbx.x_offset - g->bbx.x_offset) * font->bpp;
5519             for (x = sx = 0; x < g->bbx.width; x++,
5520                      sx += font->bpp, dx += font->bpp) {
5521                 si = (sx & 7) / font->bpp;
5522                 if ((byte = g->bitmap[(sy * gbpr) + (sx >> 3)] & masks[si])) {
5523                     di = (dx & 7) / font->bpp;
5524                     if (di < si)
5525                       byte <<= (si - di) * font->bpp;
5526                     else if (di > si)
5527                       byte >>= (di - si) * font->bpp;
5528                     tmp.bitmap[(dy * dbpr) + (dx >> 3)] |= byte;
5529                 }
5530             }
5531         }
5532
5533         /*
5534          * Now clear the font glyph and copy the temp glyph to it.
5535          */
5536         if (f->bytes > 0)
5537           free((char *) f->bitmap);
5538         f->bytes = tmp.bytes;
5539         f->bitmap = tmp.bitmap;
5540         (void) memcpy((char *) &f->bbx, (char *) &nbbx, sizeof(bdf_bbx_t));
5541
5542         /*
5543          * Set the device width.  Pay attention to whether the font is
5544          * monowidth or character cell.
5545          */
5546         if (font->spacing != BDF_PROPORTIONAL)
5547           f->dwidth = font->monowidth;
5548         else
5549           f->dwidth = MAX(f->dwidth, g->dwidth);
5550     }
5551 }
5552
5553 int
5554 bdf_merge_glyphs(bdf_font_t *font, int start, bdf_glyphlist_t *glyphs,
5555                  int unencoded)
5556 {
5557     int resize;
5558     int i, n, ng, end, add, enc, off;
5559     bdf_glyph_t *sgp, *gp, *dgp, *base;
5560     short maxas, maxds, maxrb, minlb, maxlb, rb;
5561     double ps, rx, dw;
5562     bdf_bbx_t nbbx;
5563
5564     resize = 0;
5565
5566     if (font == 0)
5567       return resize;
5568
5569     /*
5570      * If the glyphs are being merged in the unencoded area, simply append
5571      * them.  The unencoded area is simply storage.
5572      */
5573     if (unencoded)
5574       return bdf_replace_glyphs(font, font->unencoded_used, glyphs, unencoded);
5575
5576     /*
5577      * Dither the incoming bitmaps so they match the same bits per pixel as
5578      * the font.
5579      */
5580     if (glyphs->bpp != font->bpp) {
5581         if (glyphs->bpp == 1)
5582           _bdf_one_to_n(glyphs, font->bpp);
5583         else if (font->bpp == 1)
5584           _bdf_n_to_one(glyphs);
5585         else if (glyphs->bpp == 2)
5586           _bdf_two_to_four(glyphs);
5587         else
5588           _bdf_four_to_two(glyphs);
5589     }
5590
5591     /*
5592      * Set the point size and horizontal resolution so the scalable width can
5593      * be determined.
5594      */
5595     ps = (double) font->point_size;
5596     rx = (double) font->resolution_x;
5597
5598     /*
5599      * Determine if a resize is needed.
5600      */
5601
5602     /*
5603      * Determine the bounding box for the font without the characters being
5604      * replaced.
5605      */
5606     minlb = 32767;
5607     maxlb = maxrb = maxas = maxds = 0;
5608
5609     /*
5610      * Get the font bounds.
5611      */
5612     maxas = MAX(font->bbx.ascent, maxas);
5613     maxds = MAX(font->bbx.descent, maxds);
5614     rb = font->bbx.width + font->bbx.x_offset;
5615     maxrb = MAX(rb, maxrb);
5616     minlb = MIN(font->bbx.x_offset, minlb);
5617     maxlb = MAX(font->bbx.x_offset, maxlb);
5618
5619     /*
5620      * Get the bounds of the incoming glyphs.
5621      */
5622     maxas = MAX(glyphs->bbx.ascent, maxas);
5623     maxds = MAX(glyphs->bbx.descent, maxds);
5624     rb = glyphs->bbx.width + glyphs->bbx.x_offset;
5625     maxrb = MAX(rb, maxrb);
5626     minlb = MIN(glyphs->bbx.x_offset, minlb);
5627     maxlb = MAX(glyphs->bbx.x_offset, maxlb);
5628
5629     /*
5630      * Set up the new font bounding box, minus the characters that are being
5631      * removed and with the new characters added.
5632      */
5633     nbbx.width = maxrb - minlb;
5634     nbbx.x_offset = minlb;
5635
5636     nbbx.height = maxas + maxds;
5637     nbbx.ascent = maxas;
5638     nbbx.descent = maxds;
5639     nbbx.y_offset = -maxds;
5640
5641     /*
5642      * Now determine if the combination of the glyphs removed and the new
5643      * glyphs cause the font bounding box to be changed.
5644      */
5645     resize = (nbbx.width > font->bbx.width ||
5646               nbbx.height > font->bbx.height) ? 1 : 0;
5647
5648     /*
5649      * Set the pointers to the glyphs.
5650      */
5651     ng = (unencoded == 0) ? font->glyphs_used : font->unencoded_used;
5652     gp = (unencoded == 0) ? font->glyphs : font->unencoded;
5653
5654     /*
5655      * Locate the closest glyph on or following `start'.
5656      */
5657     for (i = 0; i < ng && gp->encoding < start; i++, gp++) ;
5658
5659     if (i == ng)
5660       /*
5661        * If the gylphs are being added off the end of the list, simply insert
5662        * them so any overflows can be handled.
5663        */
5664       return bdf_insert_glyphs(font, start, glyphs);
5665
5666     /*
5667      * Set the starting point for copying the incoming glyphs.
5668      */
5669     dgp = gp;
5670
5671     n = glyphs->end - glyphs->start;
5672     end = start + n;
5673
5674     /*
5675      * Count the number of glyphs that will be added and mark all the
5676      * glyphs that will be modified.
5677      */
5678     for (sgp = glyphs->glyphs, add = 0, i = start; i <= end; i++) {
5679         enc = (sgp->encoding - glyphs->start) + start;
5680
5681         /*
5682          * Mark the glyph as being modified.
5683          */
5684         if (unencoded == 0)
5685           _bdf_set_glyph_modified(font->nmod, enc);
5686         else
5687           _bdf_set_glyph_modified(font->umod, enc);
5688
5689         if (enc == gp->encoding)
5690           sgp++;
5691         else if (enc < gp->encoding) {
5692             add++;
5693             sgp++;
5694         }
5695
5696         if (gp->encoding == i)
5697           gp++;
5698     }
5699
5700     if (add > 0) {
5701         ng += add;
5702
5703         /*
5704          * Need to make room for some glyphs that will be added.
5705          */
5706         if (unencoded) {
5707             off = dgp - font->unencoded;
5708             if (font->unencoded_used == 0)
5709               font->unencoded =
5710                   (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * ng);
5711             else
5712               font->unencoded =
5713                   (bdf_glyph_t *) realloc((char *) font->unencoded,
5714                                           sizeof(bdf_glyph_t) * ng);
5715             dgp = font->unencoded + off;
5716             font->unencoded_used = ng;
5717         } else {
5718             off = dgp - font->glyphs;
5719             if (font->glyphs_used == 0)
5720               font->glyphs =
5721                   (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * ng);
5722             else
5723               font->glyphs =
5724                   (bdf_glyph_t *) realloc((char *) font->glyphs,
5725                                           sizeof(bdf_glyph_t) * ng);
5726             dgp = font->glyphs + off;
5727             font->glyphs_used = ng;
5728         }
5729     }
5730
5731     /*
5732      * Now go through and do two things:
5733      * 1. Insert new incoming glyphs.
5734      * 2. Combine two glyphs at the same location.
5735      */
5736     base = (!unencoded) ? font->glyphs : font->unencoded;
5737     for (gp = dgp, sgp = glyphs->glyphs, i = start; i <= end; i++) {
5738         enc = (sgp->encoding - glyphs->start) + start;
5739         if (enc < gp->encoding) {
5740             /*
5741              * Shift the glyphs up by one and add this one.
5742              */
5743             if (gp - base < ng)
5744               _bdf_memmove((char *) (gp + 1), (char *) gp,
5745                            sizeof(bdf_glyph_t) * (ng - (gp - base)));
5746             (void) memcpy((char *) gp, (char *) sgp, sizeof(bdf_glyph_t));
5747             gp->name = (char *) _bdf_strdup((unsigned char *) gp->name,
5748                                             strlen(gp->name) + 1);
5749             if (gp->bytes > 0)
5750               gp->bitmap = _bdf_strdup(gp->bitmap, gp->bytes);
5751             if (gp->unicode.map_size > 0)
5752               gp->unicode.map = _bdf_strdup(gp->unicode.map,
5753                                             gp->unicode.map_size);
5754             gp->encoding = i;
5755             sgp++;
5756             dw = (double) gp->dwidth;
5757             gp->swidth = (unsigned short) ((dw * 72000.0) / (ps * rx));
5758         } else if (enc == gp->encoding) {
5759             _bdf_combine_glyphs(font, gp, sgp);
5760             dw = (double) gp->dwidth;
5761             gp->swidth = (unsigned short) ((dw * 72000.0) / (ps * rx));
5762             sgp++;
5763         }
5764         if (gp->encoding == i)
5765           gp++;
5766     }
5767
5768     if (resize)
5769       (void) memcpy((char *) &font->bbx, (char *) &nbbx, sizeof(bdf_bbx_t));
5770
5771     font->modified = 1;
5772
5773     return resize;
5774 }
5775
5776 void
5777 bdf_set_modified(bdf_font_t *font, int modified)
5778 {
5779     if (font == 0 || font->modified == modified)
5780       return;
5781
5782     if (modified == 0) {
5783         /*
5784          * Clear out the modified bitmaps.
5785          */
5786         (void) memset((char *) font->nmod, 0, sizeof(unsigned int) * 2048);
5787         (void) memset((char *) font->umod, 0, sizeof(unsigned int) * 2048);
5788     }
5789     font->modified = modified;
5790 }
5791
5792 /**************************************************************************
5793  *
5794  * XLFD font name functions.
5795  *
5796  **************************************************************************/
5797
5798 static char *xlfdfields[] = {
5799     "FOUNDRY",
5800     "FAMILY_NAME",
5801     "WEIGHT_NAME",
5802     "SLANT",
5803     "SETWIDTH_NAME",
5804     "ADD_STYLE_NAME",
5805     "PIXEL_SIZE",
5806     "POINT_SIZE",
5807     "RESOLUTION_X",
5808     "RESOLUTION_Y",
5809     "SPACING",
5810     "AVERAGE_WIDTH",
5811     "CHARSET_REGISTRY",
5812     "CHARSET_ENCODING",
5813 };
5814
5815 int
5816 bdf_is_xlfd_property(char *name)
5817 {
5818     int i;
5819
5820     for (i = 0; i < 14; i++) {
5821         if (strcmp(name, xlfdfields[i]) == 0)
5822           return 1;
5823     }
5824     return 0;
5825 }
5826
5827 int
5828 bdf_has_xlfd_name(bdf_font_t *font)
5829 {
5830     unsigned int len;
5831     char name[256];
5832     _bdf_list_t list;
5833
5834     if (font == 0 || font->name == 0 || font->name[0] == 0)
5835       return 0;
5836
5837     len = (unsigned int) (strlen(font->name) + 1);
5838     (void) memcpy(name, font->name, len);
5839     list.size = list.used = 0;
5840     _bdf_split("-", name, len, &list);
5841     if (list.size > 0)
5842       free((char *) list.field);
5843
5844     return (list.used == 15);
5845 }
5846
5847 char *
5848 bdf_make_xlfd_name(bdf_font_t *font, char *foundry, char *family)
5849 {
5850     int len;
5851     double dp, dr;
5852     unsigned int i, width, used;
5853     unsigned short awidth, pxsize;
5854     bdf_property_t *pp;
5855     bdf_glyph_t *gp;
5856     char spacing, *name, *val, *np, nbuf[256];
5857
5858     if (font == 0 || bdf_has_xlfd_name(font))
5859       return 0;
5860
5861     np = nbuf;
5862
5863     /*
5864      * Add the FOUNDRY field.
5865      */
5866     if ((pp = bdf_get_font_property(font, "FOUNDRY")) != 0)
5867       foundry = pp->value.atom;
5868     sprintf(np, "-%s", foundry);
5869     np += strlen(np);
5870
5871     /*
5872      * Add the FAMILY_NAME field.
5873      */
5874     if ((pp = bdf_get_font_property(font, "FAMILY_NAME")) != 0)
5875       family = pp->value.atom;
5876     sprintf(np, "-%s", family);
5877     np += strlen(np);
5878
5879     /*
5880      * Add the WEIGHT_NAME field.
5881      */
5882     val = ((pp = bdf_get_font_property(font, "WEIGHT_NAME")) != 0) ?
5883         pp->value.atom : "Medium";
5884     if (val == 0)
5885       val = "Medium";
5886     sprintf(np, "-%s", val);
5887     np += strlen(np);
5888
5889     /*
5890      * Add the SLANT field.
5891      */
5892     val = ((pp = bdf_get_font_property(font, "SLANT")) != 0) ?
5893         pp->value.atom : "R";
5894     if (val == 0)
5895       val = "R";
5896     sprintf(np, "-%s", val);
5897     np += strlen(np);
5898
5899     /*
5900      * Add the SETWIDTH_NAME field.
5901      */
5902     val = ((pp = bdf_get_font_property(font, "SETWIDTH_NAME")) != 0) ?
5903         pp->value.atom : "Normal";
5904     if (val == 0)
5905       val = "Normal";
5906     sprintf(np, "-%s", val);
5907     np += strlen(np);
5908
5909     /*
5910      * Add the ADD_STYLE_NAME field.
5911      */
5912     val = ((pp = bdf_get_font_property(font, "ADD_STYLE_NAME")) != 0) ?
5913         pp->value.atom : "";
5914     if (val == 0)
5915       val = "";
5916     sprintf(np, "-%s", val);
5917     np += strlen(np);
5918
5919     /*
5920      * Add the PIXEL_SIZE field.
5921      */
5922     if ((pp = bdf_get_font_property(font, "PIXEL_SIZE")) != 0)
5923       sprintf(np, "-%d", pp->value.int32);
5924     else {
5925         /*
5926          * Determine the pixel size.
5927          */
5928         dp = (double) (font->point_size * 10);
5929         dr = (double) font->resolution_y;
5930         pxsize = (unsigned short) (((dp * dr) / 722.7) + 0.5);
5931         sprintf(np, "-%hd", pxsize);
5932     }
5933     np += strlen(np);
5934
5935     /*
5936      * Add the POINT_SIZE field.
5937      */
5938     if ((pp = bdf_get_font_property(font, "POINT_SIZE")) != 0)
5939       sprintf(np, "-%d", pp->value.int32);
5940     else
5941       sprintf(np, "-%d", font->point_size * 10);
5942     np += strlen(np);
5943
5944     /*
5945      * Add the RESOLUTION_X field.
5946      */
5947     if ((pp = bdf_get_font_property(font, "RESOLUTION_X")) != 0)
5948       sprintf(np, "-%d", pp->value.card32);
5949     else
5950       sprintf(np, "-%d", font->resolution_x);
5951     np += strlen(np);
5952
5953     /*
5954      * Add the RESOLUTION_Y field.
5955      */
5956     if ((pp = bdf_get_font_property(font, "RESOLUTION_Y")) != 0)
5957       sprintf(np, "-%d", pp->value.card32);
5958     else
5959       sprintf(np, "-%d", font->resolution_y);
5960     np += strlen(np);
5961
5962     /*
5963      * Add the SPACING field.
5964      */
5965     if ((pp = bdf_get_font_property(font, "SPACING")) != 0)
5966       spacing = pp->value.atom[0];
5967     else {
5968         spacing = 'P';
5969         switch (font->spacing) {
5970           case BDF_PROPORTIONAL: spacing = 'P'; break;
5971           case BDF_MONOWIDTH: spacing = 'M'; break;
5972           case BDF_CHARCELL: spacing = 'C'; break;
5973         }
5974     }
5975     sprintf(np, "-%c", spacing);
5976     np += strlen(np);
5977
5978     /*
5979      * Add the AVERAGE_WIDTH field.
5980      */
5981     if ((pp = bdf_get_font_property(font, "AVERAGE_WIDTH")) != 0)
5982       sprintf(np, "-%d", pp->value.int32);
5983     else {
5984         /*
5985          * Determine the average width of all the glyphs in the font.
5986          */
5987         width = 0;
5988         for (i = 0, gp = font->unencoded; i < font->unencoded_used; i++, gp++)
5989           width += gp->dwidth;
5990         for (i = 0, gp = font->glyphs; i < font->glyphs_used; i++, gp++)
5991           width += gp->dwidth;
5992
5993         used = font->unencoded_used + font->glyphs_used;
5994         if (used == 0)
5995           awidth = font->bbx.width * 10;
5996         else
5997           awidth = (unsigned short) ((((float) width) /
5998                                       ((float) used)) * 10.0);
5999         sprintf(np, "-%hd", awidth);
6000     }
6001     np += strlen(np);
6002
6003     /*
6004      * Add the CHARSET_REGISTRY field.
6005      */
6006     val = ((pp = bdf_get_font_property(font, "CHARSET_REGISTRY")) != 0) ?
6007         pp->value.atom : "FontSpecific";
6008     sprintf(np, "-%s", val);
6009     np += strlen(np);
6010
6011     /*
6012      * Add the CHARSET_ENCODING field.
6013      */
6014     val = ((pp = bdf_get_font_property(font, "CHARSET_ENCODING")) != 0) ?
6015         pp->value.atom : "0";
6016     sprintf(np, "-%s", val);
6017     np += strlen(np);
6018
6019     len = (np - nbuf) + 1;
6020     name = (char *) malloc(len);
6021     (void) memcpy(name, nbuf, len);
6022     return name;
6023 }
6024
6025 void
6026 bdf_update_name_from_properties(bdf_font_t *font)
6027 {
6028     unsigned int i;
6029     bdf_property_t *p;
6030     _bdf_list_t list;
6031     char *np, name[128], nname[128];
6032
6033     if (font == 0 || bdf_has_xlfd_name(font) == 0)
6034       return;
6035
6036     (void) memset((char *) &list, 0, sizeof(_bdf_list_t));
6037
6038     /*
6039      * Split the name into fields and shift out the first empty field.
6040      * This assumes that the font has a name.
6041      */
6042     i = (unsigned int) strlen(font->name);
6043     (void) memcpy(name, font->name, i + 1);
6044     _bdf_split("-", name, i, &list);
6045     _bdf_shift(1, &list);
6046
6047     /*
6048      * Initialize the pointer to the new name and add the '-' prefix.
6049      */
6050     np = nname;
6051     *np++ = '-';
6052     *np = 0;
6053
6054     for (i = 0; i < 14; i++) {
6055         if ((p = bdf_get_font_property(font, xlfdfields[i])) != 0) {
6056             /*
6057              * The property exists, so add it to the new font name.
6058              */
6059             switch (p->format) {
6060               case BDF_ATOM:
6061                 if (p->value.atom != 0)
6062                   sprintf(np, "%s", p->value.atom);
6063                 break;
6064               case BDF_CARDINAL:
6065                 sprintf(np, "%d", p->value.card32);
6066                 break;
6067               case BDF_INTEGER:
6068                 sprintf(np, "%d", p->value.int32);
6069                 break;
6070             }
6071         } else
6072           /*
6073            * The property does not exist, so add the original value to the
6074            * new font name.
6075            */
6076           sprintf(np, "%s", list.field[i]);
6077         np += strlen(np);
6078         if (i + 1 < 14) {
6079             *np++ = '-';
6080             *np = 0;
6081         }
6082     }
6083
6084     /*
6085      * Replace the existing font name with the new one.
6086      */
6087     free(font->name);
6088     i = (unsigned int) (strlen(nname) + 1);
6089     font->name = (char *) malloc(i);
6090     (void) memcpy(font->name, nname, i);
6091
6092     /*
6093      * Free up the list.
6094      */
6095     if (list.size > 0)
6096       free((char *) list.field);
6097
6098     font->modified = 1;
6099 }
6100
6101 int
6102 bdf_update_properties_from_name(bdf_font_t *font)
6103 {
6104     unsigned int i;
6105     bdf_property_t *p, prop;
6106     _bdf_list_t list;
6107     char name[128];
6108
6109     if (font == 0 || font->name == 0 || bdf_has_xlfd_name(font) == 0)
6110       return 0;
6111
6112     (void) memset((char *) &list, 0, sizeof(_bdf_list_t));
6113
6114     /*
6115      * Split the name into fields and shift out the first empty field.
6116      */
6117     i = (unsigned int) strlen(font->name);
6118     (void) memcpy(name, font->name, i + 1);
6119     _bdf_split("-", name, i, &list);
6120     _bdf_shift(1, &list);
6121
6122     for (i = 0; i < 14; i++) {
6123         p = bdf_get_property(xlfdfields[i]);
6124         prop.name = p->name;
6125         prop.format = p->format;
6126         switch (prop.format) {
6127           case BDF_ATOM:
6128             prop.value.atom = list.field[i];
6129             break;
6130           case BDF_CARDINAL:
6131             prop.value.card32 = _bdf_atoul(list.field[i], 0, 10);
6132             break;
6133           case BDF_INTEGER:
6134             prop.value.int32 = _bdf_atol(list.field[i], 0, 10);
6135             break;
6136         }
6137         bdf_add_font_property(font, &prop);
6138     }
6139
6140     /*
6141      * Free up the list.
6142      */
6143     if (list.size > 0)
6144       free((char *) list.field);
6145
6146     font->modified = 1;
6147
6148     return 1;
6149 }
6150
6151 int
6152 bdf_update_average_width(bdf_font_t *font)
6153 {
6154     int changed;
6155     unsigned int i;
6156     int oaw, awidth, used;
6157     bdf_glyph_t *gp;
6158     _bdf_list_t list;
6159     bdf_property_t *pp, prop;
6160     char *np, num[16], nbuf[128];
6161
6162     changed = 0;
6163
6164     used = font->unencoded_used + font->glyphs_used;
6165     if (used == 0)
6166       awidth = font->bbx.width * 10;
6167     else {
6168         for (i = 0, awidth = 0, gp = font->unencoded; i < font->unencoded_used;
6169              i++, gp++)
6170           awidth += gp->dwidth;
6171         for (i = 0, gp = font->glyphs; i < font->glyphs_used; i++, gp++)
6172           awidth += gp->dwidth;
6173         awidth = (int) ((((double) awidth) / ((double) used)) * 10.0);
6174     }
6175
6176     /*
6177      * Check to see if it is different than the average width in the font
6178      * name.
6179      */
6180     if (bdf_has_xlfd_name(font)) {
6181         (void) memset((char *) &list, 0, sizeof(_bdf_list_t));
6182         i = (unsigned int) strlen(font->name);
6183         (void) memcpy(nbuf, font->name, i + 1);
6184         _bdf_split("-", nbuf, i, &list);
6185         oaw = _bdf_atol(list.field[12], 0, 10);
6186         if (oaw != awidth) {
6187             /*
6188              * Construct a new font name with the new average width.
6189              */
6190             changed = 1;
6191             sprintf(num, "%d", awidth);
6192             used = strlen(num) - strlen(list.field[12]);
6193             if (used > 0) {
6194                 /*
6195                  * Resize the string used for the font name instead of
6196                  * creating a new one.
6197                  */
6198                 used += i;
6199                 font->name = (char *) realloc(font->name, used);
6200             }
6201
6202             /*
6203              * Copy the elements of the list back into the new font name.
6204              */
6205             np = font->name;
6206             *np++ = '-';
6207             for (i = 1; i < list.used; i++) {
6208                 if (i == 12)
6209                   strcpy(np, num);
6210                 else
6211                   strcpy(np, list.field[i]);
6212                 np += strlen(np);
6213                 if (i + 1 < list.used)
6214                   *np++ = '-';
6215             }
6216         }
6217
6218         /*
6219          * Clear up any space allocated for the list.
6220          */
6221         if (list.size > 0)
6222           free((char *) list.field);
6223     }
6224
6225     /*
6226      * Now check for the AVERAGE_WIDTH property.
6227      */
6228     if ((pp = bdf_get_font_property(font, "AVERAGE_WIDTH")) != 0) {
6229         if (pp->value.int32 != awidth) {
6230             changed = 1;
6231             pp->value.int32 = awidth;
6232         }
6233     } else {
6234         /*
6235          * Property doesn't exist yet, so add it.
6236          */
6237         changed = 1;
6238         prop.name = "AVERAGE_WIDTH";
6239         prop.format = BDF_INTEGER;
6240         prop.value.int32 = awidth;
6241         bdf_add_font_property(font, &prop);
6242     }
6243
6244     if (changed)
6245       font->modified = 1;
6246
6247     return changed;
6248 }
6249
6250 /*
6251  * Change the font bounding box and return a non-zero number if this causes
6252  * the font to get larger or smaller.
6253  */
6254 int
6255 bdf_set_font_bbx(bdf_font_t *font, bdf_metrics_t *metrics)
6256 {
6257     int resize;
6258
6259     resize = 0;
6260
6261     if (font == 0 || metrics == 0)
6262       return resize;
6263
6264     resize = (font->bbx.width != metrics->width ||
6265               font->bbx.height != metrics->height) ? 1 : 0;
6266
6267     font->bbx.width = metrics->width;
6268     font->bbx.height = metrics->height;
6269     font->bbx.x_offset = metrics->x_offset;
6270     font->bbx.y_offset = metrics->y_offset;
6271     font->bbx.ascent = metrics->ascent;
6272     font->bbx.descent = metrics->descent;
6273
6274     /*
6275      * If the font is not proportional, then make sure the monowidth field is
6276      * set to the font bounding box.
6277      */
6278     if (font->spacing != BDF_PROPORTIONAL)
6279       font->monowidth = font->bbx.width;
6280
6281     return resize;
6282 }
6283
6284 int
6285 bdf_translate_glyphs(bdf_font_t *font, short dx, short dy, int start,
6286                      int end, bdf_callback_t callback, void *data,
6287                      int unencoded)
6288 {
6289     int resize, diff;
6290     bdf_glyph_t *gp, *sp, *ep;
6291     bdf_callback_struct_t cb;
6292
6293     if (font == 0 || (dx == 0 && dy == 0))
6294       return 0;
6295
6296     if ((unencoded && font->unencoded_used == 0) || font->glyphs_used == 0)
6297       return 0;
6298
6299     /*
6300      * Call the progress initialization callback.
6301      */
6302     if (callback != 0) {
6303         cb.reason = BDF_TRANSLATE_START;
6304         cb.total = (end - start) + 1;
6305         cb.current = 0;
6306         (*callback)(&cb, data);
6307     }
6308
6309     /*
6310      * Locate the first and last glyphs to be shifted.
6311      */
6312     sp = _bdf_locate_glyph(font, start, unencoded);
6313     ep = _bdf_locate_glyph(font, end, unencoded);
6314     for (resize = 0, gp = sp; sp <= ep; sp++) {
6315         /*
6316          * Call the callback if one was provided.
6317          */
6318         if (sp != gp && callback != 0) {
6319             cb.reason = BDF_TRANSLATING;
6320             cb.current = (sp->encoding - start) + 1;
6321             (*callback)(&cb, data);
6322         }
6323
6324         /*
6325          * Apply the X translation.
6326          */
6327         if (dx != 0) {
6328             sp->bbx.x_offset += dx;
6329             diff = sp->bbx.x_offset - font->bbx.x_offset;
6330             if (sp->bbx.x_offset < font->bbx.x_offset) {
6331                 font->bbx.x_offset = sp->bbx.x_offset;
6332                 font->bbx.width += MYABS(diff);
6333                 resize = 1;
6334             } else if (sp->bbx.width + sp->bbx.x_offset >
6335                        font->bbx.width + font->bbx.x_offset) {
6336                 font->bbx.width += MYABS(diff);
6337                 resize = 1;
6338             }
6339
6340             /*
6341              * Mark the glyph as modified appropriately.
6342              */
6343             if (unencoded)
6344               _bdf_set_glyph_modified(font->umod, sp->encoding);
6345             else
6346               _bdf_set_glyph_modified(font->nmod, sp->encoding);
6347         }
6348
6349         /*
6350          * Apply the Y translation.
6351          */
6352         if (dy != 0) {
6353             sp->bbx.y_offset += dy;
6354             sp->bbx.descent = -sp->bbx.y_offset;
6355             sp->bbx.ascent = sp->bbx.height - sp->bbx.descent;
6356             diff = sp->bbx.y_offset - font->bbx.y_offset;
6357             if (sp->bbx.y_offset < font->bbx.y_offset) {
6358                 font->bbx.y_offset = sp->bbx.y_offset;
6359                 font->bbx.descent = -font->bbx.y_offset;
6360                 font->bbx.height += MYABS(diff);
6361                 resize = 1;
6362             } else if (sp->bbx.ascent > font->bbx.ascent) {
6363                 font->bbx.ascent += MYABS(diff);
6364                 font->bbx.height += MYABS(diff);
6365                 resize = 1;
6366             }
6367
6368             /*
6369              * Mark the glyph as modified appropriately.
6370              */
6371             if (unencoded)
6372               _bdf_set_glyph_modified(font->umod, sp->encoding);
6373             else
6374               _bdf_set_glyph_modified(font->nmod, sp->encoding);
6375         }
6376     }
6377
6378     /*
6379      * Call the callback one more time to make sure the client knows
6380      * this is done.
6381      */
6382     if (callback != 0 && cb.current < cb.total) {
6383         cb.reason = BDF_TRANSLATING;
6384         cb.current = cb.total;
6385         (*callback)(&cb, data);
6386     }
6387
6388     if (resize)
6389       font->modified = 1;
6390
6391     return resize;
6392 }
6393
6394 static void
6395 _bdf_resize_rotation(bdf_font_t *font, int mul90, short degrees,
6396                      bdf_glyph_t *glyph, bdf_bitmap_t *scratch,
6397                      unsigned short *width, unsigned short *height)
6398 {
6399     unsigned short w, h, wd, ht, bytes;
6400     short cx, cy, x1, y1, x2, y2;
6401     double dx1, dy1, dx2, dy2;
6402
6403     w = h = 0;
6404
6405     cx = glyph->bbx.width >> 1;
6406     cy = glyph->bbx.height >> 1;
6407
6408     /*
6409      * Rotate the lower left and upper right corners and check for a potential
6410      * resize.
6411      */
6412     x1 = 0;
6413     y1 = glyph->bbx.height;
6414     x2 = glyph->bbx.width;
6415     y2 = 0;
6416
6417     dx1 = (double) (x1 - cx);
6418     dy1 = (double) (y1 - cy);
6419     dx2 = (double) (x2 - cx);
6420     dy2 = (double) (y2 - cx);
6421
6422     if (mul90) {
6423         x1 = cx + (short) ((dx1 * _bdf_cos_tbl[degrees]) -
6424                            (dy1 * _bdf_sin_tbl[degrees]));
6425         y1 = cy + (short) ((dx1 * _bdf_sin_tbl[degrees]) +
6426                            (dy1 * _bdf_cos_tbl[degrees]));
6427         x2 = cx + (short) ((dx2 * _bdf_cos_tbl[degrees]) -
6428                            (dy2 * _bdf_sin_tbl[degrees]));
6429         y2 = cy + (short) ((dx2 * _bdf_sin_tbl[degrees]) +
6430                            (dy2 * _bdf_cos_tbl[degrees]));
6431     } else {
6432         x1 = cx + _bdf_ceiling((dx1 * _bdf_cos_tbl[degrees]) -
6433                                (dy1 * _bdf_sin_tbl[degrees]));
6434         y1 = cy + _bdf_ceiling((dx1 * _bdf_sin_tbl[degrees]) +
6435                                (dy1 * _bdf_cos_tbl[degrees]));
6436         x2 = cx + _bdf_ceiling((dx2 * _bdf_cos_tbl[degrees]) -
6437                                (dy2 * _bdf_sin_tbl[degrees]));
6438         y2 = cy + _bdf_ceiling((dx2 * _bdf_sin_tbl[degrees]) +
6439                                (dy2 * _bdf_cos_tbl[degrees]));
6440     }
6441
6442     wd = MYABS(x2 - x1);
6443     ht = MYABS(y2 - y1);
6444
6445     w = MAX(wd, w);
6446     h = MAX(ht, h);
6447
6448     if (wd > font->bbx.width)
6449       font->bbx.width += wd - font->bbx.width;
6450     if (ht > font->bbx.height) {
6451         font->bbx.ascent += ht - font->bbx.height;
6452         font->bbx.height += ht - font->bbx.height;
6453     }
6454
6455     /*
6456      * Rotate the upper left and lower right corners and check for a potential
6457      * resize.
6458      */
6459     x1 = 0;
6460     y1 = 0;
6461     x2 = glyph->bbx.width;
6462     y2 = glyph->bbx.height;
6463
6464     dx1 = (double) (x1 - cx);
6465     dy1 = (double) (y1 - cy);
6466     dx2 = (double) (x2 - cx);
6467     dy2 = (double) (y2 - cx);
6468
6469     if (mul90) {
6470         x1 = cx + (short) ((dx1 * _bdf_cos_tbl[degrees]) -
6471                            (dy1 * _bdf_sin_tbl[degrees]));
6472         y1 = cy + (short) ((dx1 * _bdf_sin_tbl[degrees]) +
6473                            (dy1 * _bdf_cos_tbl[degrees]));
6474         x2 = cx + (short) ((dx2 * _bdf_cos_tbl[degrees]) -
6475                            (dy2 * _bdf_sin_tbl[degrees]));
6476         y2 = cy + (short) ((dx2 * _bdf_sin_tbl[degrees]) +
6477                            (dy2 * _bdf_cos_tbl[degrees]));
6478     } else {
6479         x1 = cx + _bdf_ceiling((dx1 * _bdf_cos_tbl[degrees]) -
6480                                (dy1 * _bdf_sin_tbl[degrees]));
6481         y1 = cy + _bdf_ceiling((dx1 * _bdf_sin_tbl[degrees]) +
6482                                (dy1 * _bdf_cos_tbl[degrees]));
6483         x2 = cx + _bdf_ceiling((dx2 * _bdf_cos_tbl[degrees]) -
6484                                (dy2 * _bdf_sin_tbl[degrees]));
6485         y2 = cy + _bdf_ceiling((dx2 * _bdf_sin_tbl[degrees]) +
6486                                (dy2 * _bdf_cos_tbl[degrees]));
6487     }
6488
6489     wd = MYABS(x2 - x1);
6490     ht = MYABS(y2 - y1);
6491
6492     w = MAX(wd, w);
6493     h = MAX(ht, h);
6494
6495     if (wd > font->bbx.width)
6496       font->bbx.width += wd - font->bbx.width;
6497     if (ht > font->bbx.height) {
6498         font->bbx.ascent += ht - font->bbx.height;
6499         font->bbx.height += ht - font->bbx.height;
6500     }
6501
6502     if (font->bbx.width > scratch->width ||
6503         font->bbx.height > scratch->height) {
6504         scratch->width = MAX(font->bbx.width, scratch->width);
6505         scratch->height = MAX(font->bbx.height, scratch->height);
6506         bytes = (((font->bbx.width * font->bpp) + 7) >> 3) * font->bbx.height;
6507         if (scratch->bytes == 0)
6508           scratch->bitmap = (unsigned char *) malloc(bytes);
6509         else
6510           scratch->bitmap = (unsigned char *)
6511               realloc((char *) scratch->bitmap, bytes);
6512         scratch->bytes = bytes;
6513     }
6514
6515     /*
6516      * Clear the bitmap.
6517      */
6518     (void) memset((char *) scratch->bitmap, 0, scratch->bytes);
6519
6520     /*
6521      * Return the new glyph width and height.
6522      */
6523     *width = w;
6524     *height = h;
6525 }
6526
6527 int
6528 bdf_rotate_glyphs(bdf_font_t *font, short degrees, int start,
6529                   int end, bdf_callback_t callback, void *data,
6530                   int unencoded)
6531 {
6532     int mul90, bpr, sbpr;
6533     unsigned short wd, ht, si, di, byte, col;
6534     short x, y, cx, cy, nx, ny, ox, oy, shiftx, shifty;
6535     bdf_glyph_t *gp, *sp, *ep;
6536     unsigned char *masks;
6537     double dx, dy;
6538     bdf_bitmap_t scratch;
6539     bdf_callback_struct_t cb;
6540
6541     if (font == 0 ||
6542         (unencoded && font->unencoded_used == 0) ||
6543         font->glyphs_used == 0 ||
6544         degrees == 0)
6545       return 0;
6546
6547     while (degrees < 0)
6548       degrees += 360;
6549     while (degrees >= 360)
6550       degrees -= 360;
6551
6552     mul90 = ((degrees % 90) == 0) ? 1 : 0;
6553
6554     masks = 0;
6555     switch (font->bpp) {
6556       case 1: masks = bdf_onebpp; break;
6557       case 2: masks = bdf_twobpp; break;
6558       case 4: masks = bdf_fourbpp; break;
6559       case 8: masks = bdf_eightbpp; break;
6560     }
6561
6562     /*
6563      * Initialize the scratch bitmap.
6564      */
6565     (void) memset((char *) &scratch, 0, sizeof(bdf_bitmap_t));
6566
6567     /*
6568      * Call the progress initialization callback.
6569      */
6570     if (callback != 0) {
6571         cb.reason = BDF_ROTATE_START;
6572         cb.total = (end - start) + 1;
6573         cb.current = 0;
6574         (*callback)(&cb, data);
6575     }
6576
6577     sp = _bdf_locate_glyph(font, start, unencoded);
6578     ep = _bdf_locate_glyph(font, end, unencoded);
6579     for (gp = sp; sp <= ep; sp++) {
6580         /*
6581          * Call the callback if one was provided.
6582          */
6583         if (sp != gp && callback != 0) {
6584             cb.reason = BDF_ROTATING;
6585             cb.current = (sp->encoding - start) + 1;
6586             (*callback)(&cb, data);
6587         }
6588
6589         /*
6590          * Resize the bitmap, adjust the font bounding box, and get the new
6591          * glyph width and height.
6592          */
6593         _bdf_resize_rotation(font, mul90, degrees, sp, &scratch, &wd, &ht);
6594
6595         cx = sp->bbx.width >> 1;
6596         cy = sp->bbx.height >> 1;
6597
6598         shiftx = shifty = 0;
6599         sbpr = ((wd * font->bpp) + 7) >> 3;
6600         bpr = ((sp->bbx.width * font->bpp) + 7) >> 3;
6601         for (y = 0; y < sp->bbx.height; y++) {
6602             for (col = x = 0; x < sp->bbx.width; x++, col += font->bpp) {
6603                 si = (col & 7) / font->bpp;
6604                 byte = sp->bitmap[(y * bpr) + (col >> 3)] & masks[si];
6605                 if (byte) {
6606                     dx = (double) (x - cx);
6607                     dy = (double) (y - cy);
6608                     if (mul90) {
6609                         nx = cx + (short) ((dx * _bdf_cos_tbl[degrees]) -
6610                                            (dy * _bdf_sin_tbl[degrees]));
6611                         ny = cy + (short) ((dx * _bdf_sin_tbl[degrees]) +
6612                                            (dy * _bdf_cos_tbl[degrees]));
6613                     } else {
6614                         nx = cx + _bdf_ceiling((dx * _bdf_cos_tbl[degrees]) -
6615                                                (dy * _bdf_sin_tbl[degrees]));
6616                         ny = cy + _bdf_ceiling((dx * _bdf_sin_tbl[degrees]) +
6617                                                (dy * _bdf_cos_tbl[degrees]));
6618                     }
6619                     if (nx < 0) {
6620                         shiftx = MIN(shiftx, nx);
6621                         nx += wd;
6622                     } else if (nx >= wd) {
6623                         ox = (nx - wd) + 1;
6624                         shiftx = MAX(shiftx, ox);
6625                         nx -= wd;
6626                     }
6627                     if (ny < 0) {
6628                         shifty = MIN(shifty, ny);
6629                         ny += ht;
6630                     } else if (ny >= ht) {
6631                         oy = (ny - ht) + 1;
6632                         shifty = MAX(shifty, oy);
6633                         ny -= ht;
6634                     }
6635                     nx *= font->bpp;
6636                     di = (nx & 7) / font->bpp;
6637                     if (di < si)
6638                       byte <<= (si - di) * font->bpp;
6639                     else if (di > si)
6640                       byte >>= (di - si) * font->bpp;
6641                     scratch.bitmap[(ny * sbpr) + (nx >> 3)] |= byte;
6642                 }
6643             }
6644         }
6645         /*
6646          * Resize the glyph bitmap if necessary.
6647          */
6648         if (wd != sp->bbx.width || ht != sp->bbx.height) {
6649             sp->bbx.width = wd;
6650             sp->bbx.height = ht;
6651             sp->bbx.ascent = ht - sp->bbx.descent;
6652             sp->bytes = (((wd * font->bpp) + 7) >> 3) * ht;
6653             sp->bitmap = (unsigned char *)
6654                 realloc((char *) sp->bitmap, sp->bytes);
6655         }
6656         (void) memset((char *) sp->bitmap, 0, sp->bytes);
6657
6658         /*
6659          * Copy the glyph from the scratch area to the glyph bitmap,
6660          * adjusting for any shift values encountered.
6661          */
6662         bpr = ((sp->bbx.width * font->bpp) + 7) >> 3;
6663         for (y = 0; y < sp->bbx.height; y++) {
6664             for (col = x = 0; x < sp->bbx.width; x++, col += font->bpp) {
6665                 si = (col & 7) / font->bpp;
6666                 byte = scratch.bitmap[(y * bpr) + (col >> 3)] & masks[si];
6667                 if (byte) {
6668                     nx = x - shiftx;
6669                     ny = y - shifty;
6670                     if (nx < 0)
6671                       nx += sp->bbx.width;
6672                     else if (nx >= sp->bbx.width)
6673                       nx -= sp->bbx.width;
6674                     if (ny < 0)
6675                       ny += sp->bbx.height;
6676                     else if (ny >= sp->bbx.height)
6677                       ny -= sp->bbx.height;
6678                     nx *= font->bpp;
6679                     di = (nx & 7) / font->bpp;
6680                     if (di < si)
6681                       byte <<= (si - di) * font->bpp;
6682                     else if (di > si)
6683                       byte >>= (di - si) * font->bpp;
6684                     sp->bitmap[(ny * bpr) + (nx >> 3)] |= byte;
6685                 }
6686             }
6687         }
6688         /*
6689          * Mark the glyph as modified.
6690          */
6691         if (unencoded)
6692           _bdf_set_glyph_modified(font->umod, sp->encoding);
6693         else
6694           _bdf_set_glyph_modified(font->nmod, sp->encoding);
6695     }
6696
6697     /*
6698      * Call the callback one more time to make sure the client knows
6699      * this is done.
6700      */
6701     if (callback != 0 && cb.current < cb.total) {
6702         cb.reason = BDF_TRANSLATING;
6703         cb.current = cb.total;
6704         (*callback)(&cb, data);
6705     }
6706
6707     if (scratch.bytes > 0)
6708       free((char *) scratch.bitmap);
6709
6710     /*
6711      * Rotations always change things, so just return a value indicating this.
6712      */
6713     font->modified = 1;
6714     return 1;
6715 }
6716
6717 static void
6718 _bdf_resize_shear(bdf_font_t *font, int neg, short degrees,
6719                   bdf_glyph_t *glyph, bdf_bitmap_t *scratch,
6720                   unsigned short *width, unsigned short *height)
6721 {
6722     unsigned short wd, w, bytes;
6723     short x1, y1, x2, y2;
6724
6725     w = 0;
6726     *height = glyph->bbx.height;
6727
6728     /*
6729      * Shear the lower left and upper right corners and check for a potential
6730      * resize.
6731      */
6732     x1 = 0;
6733     y1 = glyph->bbx.height;
6734     x2 = glyph->bbx.width;
6735     y2 = 0;
6736
6737     if (neg) {
6738         x1 += (short) ((double) y1 * _bdf_tan_tbl[degrees]);
6739         x2 += (short) ((double) y2 * _bdf_tan_tbl[degrees]);
6740     } else {
6741         x1 += (short) ((double) (glyph->bbx.height - y1) *
6742                        _bdf_tan_tbl[degrees]);
6743         x2 += (short) ((double) (glyph->bbx.height - y2) *
6744                        _bdf_tan_tbl[degrees]);
6745     }
6746
6747     wd = MYABS(x2 - x1);
6748     w = MAX(w, wd);
6749
6750     if (wd > font->bbx.width)
6751       font->bbx.width += wd - font->bbx.width;
6752
6753     /*
6754      * Shear the upper left and lower right corners and check for a potential
6755      * resize.
6756      */
6757     x1 = 0;
6758     y1 = 0;
6759     x2 = glyph->bbx.width;
6760     y2 = glyph->bbx.height;
6761
6762     if (neg) {
6763         x1 += (short) ((double) y1 * _bdf_tan_tbl[degrees]);
6764         x2 += (short) ((double) y2 * _bdf_tan_tbl[degrees]);
6765     } else {
6766         x1 += (short) ((double) (glyph->bbx.height - y1) *
6767                        _bdf_tan_tbl[degrees]);
6768         x2 += (short) ((double) (glyph->bbx.height - y2) *
6769                        _bdf_tan_tbl[degrees]);
6770     }
6771
6772     wd = MYABS(x2 - x1);
6773     w = MAX(w, wd);
6774
6775     if (wd > font->bbx.width)
6776       font->bbx.width += wd - font->bbx.width;
6777
6778     if (font->bbx.width > scratch->width ||
6779         font->bbx.height > scratch->height) {
6780         scratch->width = MAX(font->bbx.width, scratch->width);
6781         scratch->height = MAX(font->bbx.height, scratch->height);
6782         bytes = (((font->bbx.width * font->bpp) + 7) >> 3) * font->bbx.height;
6783         if (scratch->bytes == 0)
6784           scratch->bitmap = (unsigned char *) malloc(bytes);
6785         else
6786           scratch->bitmap = (unsigned char *)
6787               realloc((char *) scratch->bitmap, bytes);
6788         scratch->bytes = bytes;
6789     }
6790
6791     /*
6792      * Clear the bitmap.
6793      */
6794     (void) memset((char *) scratch->bitmap, 0, scratch->bytes);
6795
6796     /*
6797      * Return the new glyph width.
6798      */
6799     *width = w;
6800 }
6801
6802 int
6803 bdf_shear_glyphs(bdf_font_t *font, short degrees, int start,
6804                  int end, bdf_callback_t callback, void *data,
6805                  int unencoded)
6806 {
6807     int neg, bpr, sbpr;
6808     unsigned short wd, ht, si, di, byte, col;
6809     short x, y, nx, shiftx, ox;
6810     bdf_glyph_t *gp, *sp, *ep;
6811     unsigned char *masks;
6812     bdf_bitmap_t scratch;
6813     bdf_callback_struct_t cb;
6814
6815     if (font == 0 || (unencoded && font->unencoded_used == 0) ||
6816         font->glyphs_used == 0)
6817       return 0;
6818
6819     if (degrees == 0 || degrees < -45 || degrees > 45)
6820       return 0;
6821
6822     if ((neg = (degrees < 0)))
6823       degrees = -degrees;
6824
6825     masks = 0;
6826     switch (font->bpp) {
6827       case 1: masks = bdf_onebpp; break;
6828       case 2: masks = bdf_twobpp; break;
6829       case 4: masks = bdf_fourbpp; break;
6830       case 8: masks = bdf_eightbpp; break;
6831     }
6832
6833     /*
6834      * Initialize the scratch bitmap.
6835      */
6836     (void) memset((char *) &scratch, 0, sizeof(bdf_bitmap_t));
6837
6838     /*
6839      * Call the progress initialization callback.
6840      */
6841     if (callback != 0) {
6842         cb.reason = BDF_SHEAR_START;
6843         cb.total = (end - start) + 1;
6844         cb.current = 0;
6845         (*callback)(&cb, data);
6846     }
6847
6848     sp = _bdf_locate_glyph(font, start, unencoded);
6849     ep = _bdf_locate_glyph(font, end, unencoded);
6850     for (gp = sp; sp <= ep; sp++) {
6851         /*
6852          * Call the callback if one was provided.
6853          */
6854         if (sp != gp && callback != 0) {
6855             cb.reason = BDF_SHEARING;
6856             cb.current = (sp->encoding - start) + 1;
6857             (*callback)(&cb, data);
6858         }
6859
6860         /*
6861          * Resize the bitmap, adjust the font bounding box, and get the new
6862          * glyph width and height.
6863          */
6864         _bdf_resize_shear(font, neg, degrees, sp, &scratch, &wd, &ht);
6865
6866         shiftx = 0;
6867         sbpr = ((wd * font->bpp) + 7) >> 3;
6868         bpr = ((sp->bbx.width * font->bpp) + 7) >> 3;
6869         for (y = 0; y < sp->bbx.height; y++) {
6870             for (col = x = 0; x < sp->bbx.width; x++, col += font->bpp) {
6871                 si = (col & 7) / font->bpp;
6872                 byte = sp->bitmap[(y * bpr) + (col >> 3)] & masks[si];
6873                 if (byte) {
6874                     if (neg)
6875                       nx = x + (short) ((double) y * _bdf_tan_tbl[degrees]);
6876                     else
6877                       nx = x + (short) ((double) (sp->bbx.height - y) *
6878                                         _bdf_tan_tbl[degrees]);
6879
6880                     if (nx < 0) {
6881                         shiftx = MIN(shiftx, nx);
6882                         nx += wd;
6883                     } else if (nx >= wd) {
6884                         ox = (nx - wd) + 1;
6885                         shiftx = MAX(shiftx, ox);
6886                         nx -= wd;
6887                     }
6888                     nx *= font->bpp;
6889                     di = (nx & 7) / font->bpp;
6890                     if (di < si)
6891                       byte <<= (si - di) * font->bpp;
6892                     else if (di > si)
6893                       byte >>= (di - si) * font->bpp;
6894                     scratch.bitmap[(y * sbpr) + (nx >> 3)] |= byte;
6895                 }
6896             }
6897         }
6898         /*
6899          * Resize the glyph bitmap if necessary.
6900          */
6901         if (wd != sp->bbx.width || ht != sp->bbx.height) {
6902             sp->bbx.width = wd;
6903             sp->bbx.height = ht;
6904             sp->bbx.ascent = ht - sp->bbx.descent;
6905             sp->bytes = (((wd * font->bpp) + 7) >> 3) * ht;
6906             sp->bitmap = (unsigned char *)
6907                 realloc((char *) sp->bitmap, sp->bytes);
6908         }
6909         (void) memset((char *) sp->bitmap, 0, sp->bytes);
6910
6911         /*
6912          * Copy the glyph from the scratch area to the glyph bitmap,
6913          * adjusting for any shift values encountered.
6914          */
6915         bpr = ((sp->bbx.width * font->bpp) + 7) >> 3;
6916         for (y = 0; y < sp->bbx.height; y++) {
6917             for (col = x = 0; x < sp->bbx.width; x++, col += font->bpp) {
6918                 si = (col & 7) / font->bpp;
6919                 byte = scratch.bitmap[(y * bpr) + (col >> 3)] & masks[si];
6920                 if (byte) {
6921                     nx = x - shiftx;
6922                     if (nx < 0)
6923                       nx += sp->bbx.width;
6924                     else if (nx >= sp->bbx.width)
6925                       nx -= sp->bbx.width;
6926                     nx *= font->bpp;
6927                     di = (nx & 7) / font->bpp;
6928                     if (di < si)
6929                       byte <<= (si - di) * font->bpp;
6930                     else if (di > si)
6931                       byte >>= (di - si) * font->bpp;
6932                     sp->bitmap[(y * bpr) + (nx >> 3)] |= byte;
6933                 }
6934             }
6935         }
6936         /*
6937          * Mark the glyph as modified.
6938          */
6939         if (unencoded)
6940           _bdf_set_glyph_modified(font->umod, sp->encoding);
6941         else
6942           _bdf_set_glyph_modified(font->nmod, sp->encoding);
6943     }
6944
6945     /*
6946      * Call the callback one more time to make sure the client knows
6947      * this is done.
6948      */
6949     if (callback != 0 && cb.current < cb.total) {
6950         cb.reason = BDF_TRANSLATING;
6951         cb.current = cb.total;
6952         (*callback)(&cb, data);
6953     }
6954
6955     if (scratch.bytes > 0)
6956       free((char *) scratch.bitmap);
6957
6958     /*
6959      * Rotations always change things, so just return a value indicating this.
6960      */
6961     font->modified = 1;
6962     return 1;
6963 }
6964
6965 static void
6966 _bdf_widen_by(bdf_font_t *f, bdf_glyph_t *g, bdf_bitmap_t *s, int n)
6967 {
6968     int bytes, sbpr, dbpr, col;
6969     short x, y, si, di;
6970     unsigned char *bmap, *masks;
6971
6972     masks = 0;
6973     switch (f->bpp) {
6974       case 1: masks = bdf_onebpp; break;
6975       case 2: masks = bdf_twobpp; break;
6976       case 4: masks = bdf_fourbpp; break;
6977       case 8: masks = bdf_eightbpp; break;
6978     }
6979
6980     s->height = g->bbx.height;
6981     s->width = g->bbx.width + n;
6982
6983     bytes = (((s->width * f->bpp) + 7) >> 3) * s->height;
6984
6985     if (s->bytes == 0)
6986       s->bitmap = (unsigned char *) malloc(bytes);
6987     else
6988       s->bitmap = (unsigned char *)
6989           realloc((char *) s->bitmap, bytes);
6990     s->bytes = bytes;
6991
6992     (void) memset((char *) s->bitmap, 0, s->bytes);
6993
6994     /*
6995      * Copy the glyph bitmap to the scratch area, and then swap the bitmaps.
6996      */
6997     sbpr = ((g->bbx.width * f->bpp) + 7) >> 3;
6998     dbpr = ((s->width * f->bpp) + 7) >> 3;
6999     for (y = 0; y < g->bbx.height; y++) {
7000         for (col = x = 0; x < g->bbx.width; x++, col += f->bpp) {
7001             si = (col & 7) / f->bpp;
7002             bytes = g->bitmap[(y * sbpr) + (col >> 3)] & masks[si];
7003             if (bytes) {
7004                 di = ((x * f->bpp) & 7) / f->bpp;
7005                 if (di < si)
7006                   bytes <<= (si - di) * f->bpp;
7007                 else if (di > si)
7008                   bytes >>= (di - si) * f->bpp;
7009                 s->bitmap[(y * dbpr) + (col >> 3)] |= bytes;
7010             }
7011         }
7012     }
7013     g->bbx.width = s->width;
7014
7015     /*
7016      * Swap the bytes and bitmap fields from the scratch area and the glyph.
7017      */
7018     bytes = g->bytes;
7019     g->bytes = s->bytes;
7020     s->bytes = bytes;
7021
7022     bmap = g->bitmap;
7023     g->bitmap = s->bitmap;
7024     s->bitmap = bmap;
7025 }
7026
7027 int
7028 bdf_embolden_glyphs(bdf_font_t *font, int start, int end,
7029                     bdf_callback_t callback, void *data, int unencoded,
7030                     int *resize)
7031 {
7032     int mod, gmod, bpr;
7033     short x, y;
7034     unsigned short si, di, b1, b2, col;
7035     unsigned char *masks;
7036     bdf_glyph_t *gp, *sp, *ep;
7037     bdf_bitmap_t scratch;
7038     bdf_callback_struct_t cb;
7039
7040     if (font == 0 || (unencoded && font->unencoded_used == 0) ||
7041         font->glyphs_used == 0)
7042       return 0;
7043
7044     /*
7045      * Initialize the scratch bitmap which may be needed.
7046      */
7047     (void) memset((char *) &scratch, 0, sizeof(bdf_bitmap_t));
7048
7049     mod = 0;
7050     gp = 0;
7051
7052     masks = 0;
7053     switch (font->bpp) {
7054       case 1: masks = bdf_onebpp; break;
7055       case 2: masks = bdf_twobpp; break;
7056       case 4: masks = bdf_fourbpp; break;
7057       case 8: masks = bdf_eightbpp; break;
7058     }
7059
7060     /*
7061      * Call the progress initialization callback.
7062      */
7063     if (callback != 0) {
7064         cb.reason = BDF_EMBOLDEN_START;
7065         cb.total = (end - start) + 1;
7066         cb.current = 0;
7067         (*callback)(&cb, data);
7068     }
7069
7070     /*
7071      * Initialize the resize flag for the caller.
7072      */
7073     *resize = 0;
7074
7075     sp = _bdf_locate_glyph(font, start, unencoded);
7076     ep = _bdf_locate_glyph(font, end, unencoded);
7077     for (; sp <= ep; sp++) {
7078         /*
7079          * Call the callback if one was provided.
7080          */
7081         if (sp != gp && callback != 0) {
7082             cb.reason = BDF_EMBOLDENING;
7083             cb.current = (sp->encoding - start) + 1;
7084             (*callback)(&cb, data);
7085         }
7086
7087         if (font->spacing == BDF_PROPORTIONAL ||
7088             (font->spacing == BDF_MONOWIDTH &&
7089              sp->bbx.width < font->bbx.width)) {
7090             /*
7091              * Only widen the glyph if it is within reason.
7092              */
7093             _bdf_widen_by(font, sp, &scratch, 1);
7094
7095             if (sp->bbx.width > font->bbx.width) {
7096                 /*
7097                  * Bump the font width up by the difference.
7098                  */
7099                 font->bbx.width += sp->bbx.width - font->bbx.width;
7100                 *resize = 1;
7101             }
7102         }
7103
7104         gmod = 0;
7105         bpr = ((sp->bbx.width * font->bpp) + 7) >> 3;
7106         for (y = 0; y < sp->bbx.height; y++) {
7107             col = (sp->bbx.width - 1) * font->bpp;
7108             for (x = sp->bbx.width - 1; x > 0; x--, col -= font->bpp) {
7109                 si = (col & 7) / font->bpp;
7110                 di = ((col - font->bpp) & 7) / font->bpp;
7111                 b1 = (x == sp->bbx.width) ? 0 :
7112                     sp->bitmap[(y * bpr) + (col >> 3)] & masks[si];
7113                 b2 = sp->bitmap[(y * bpr) + ((col - font->bpp) >> 3)] &
7114                     masks[di];
7115                 if (!b1 && b2) {
7116                     if (di < si)
7117                       b2 >>= (si - di) * font->bpp;
7118                     else if (di > si)
7119                       b2 <<= (di - si) * font->bpp;
7120                     sp->bitmap[(y * bpr) + (col >> 3)] |= b2;
7121                     gmod = mod = 1;
7122                 }
7123             }
7124         }
7125         /*
7126          * Mark the glyph as modified.
7127          */
7128         if (gmod) {
7129             if (unencoded)
7130               _bdf_set_glyph_modified(font->umod, sp->encoding);
7131             else
7132               _bdf_set_glyph_modified(font->nmod, sp->encoding);
7133         }
7134     }
7135
7136     /*
7137      * Call the callback one more time to make sure the client knows
7138      * this is done.
7139      */
7140     if (callback != 0 && cb.current < cb.total) {
7141         cb.reason = BDF_EMBOLDENING;
7142         cb.current = cb.total;
7143         (*callback)(&cb, data);
7144     }
7145
7146     /*
7147      * Deallocate the scratch bitmap if necessary.
7148      */
7149     if (scratch.bytes > 0)
7150       free((char *) scratch.bitmap);
7151
7152     font->modified = mod;
7153
7154     return mod;
7155 }
7156
7157 static int _endian = 1;
7158 static char *little_endian = (char *) &_endian;
7159
7160 int
7161 bdf_little_endian(void)
7162 {
7163     return *little_endian;
7164 }