groff: update vendor branch to v1.20.1
[dragonfly.git] / contrib / groff / src / libs / libgroff / font.cpp
CommitLineData
92d0a6a6 1// -*- C++ -*-
4d3e9548
JL
2/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004, 2005,
3 2006, 2008, 2009
92d0a6a6
JR
4 Free Software Foundation, Inc.
5 Written by James Clark (jjc@jclark.com)
6
7This file is part of groff.
8
9groff is free software; you can redistribute it and/or modify it under
10the terms of the GNU General Public License as published by the Free
4d3e9548
JL
11Software Foundation, either version 3 of the License, or
12(at your option) any later version.
92d0a6a6
JR
13
14groff is distributed in the hope that it will be useful, but WITHOUT ANY
15WARRANTY; without even the implied warranty of MERCHANTABILITY or
16FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17for more details.
18
4d3e9548
JL
19You should have received a copy of the GNU General Public License
20along with this program. If not, see <http://www.gnu.org/licenses/>. */
92d0a6a6
JR
21
22#include "lib.h"
23
24#include <ctype.h>
25#include <assert.h>
26#include <math.h>
27#include <stdlib.h>
28#include "errarg.h"
29#include "error.h"
30#include "cset.h"
31#include "font.h"
4d3e9548 32#include "unicode.h"
92d0a6a6
JR
33#include "paper.h"
34
35const char *const WS = " \t\n\r";
36
37struct font_char_metric {
38 char type;
39 int code;
40 int width;
41 int height;
42 int depth;
43 int pre_math_space;
44 int italic_correction;
45 int subscript_correction;
46 char *special_device_coding;
47};
48
49struct font_kern_list {
4d3e9548
JL
50 glyph *glyph1;
51 glyph *glyph2;
92d0a6a6
JR
52 int amount;
53 font_kern_list *next;
54
4d3e9548 55 font_kern_list(glyph *, glyph *, int, font_kern_list * = 0);
92d0a6a6
JR
56};
57
58struct font_widths_cache {
59 font_widths_cache *next;
60 int point_size;
61 int *width;
62
63 font_widths_cache(int, int, font_widths_cache * = 0);
64 ~font_widths_cache();
65};
66
67/* text_file */
68
69struct text_file {
70 FILE *fp;
71 char *path;
72 int lineno;
73 int size;
74 int skip_comments;
465b256c 75 int silent;
92d0a6a6
JR
76 char *buf;
77 text_file(FILE *fp, char *p);
78 ~text_file();
79 int next();
80 void error(const char *format,
81 const errarg &arg1 = empty_errarg,
82 const errarg &arg2 = empty_errarg,
83 const errarg &arg3 = empty_errarg);
84};
85
86text_file::text_file(FILE *p, char *s)
465b256c 87: fp(p), path(s), lineno(0), size(0), skip_comments(1), silent(0), buf(0)
92d0a6a6
JR
88{
89}
90
91text_file::~text_file()
92{
93 a_delete buf;
94 a_delete path;
95 if (fp)
96 fclose(fp);
97}
98
99int text_file::next()
100{
101 if (fp == 0)
102 return 0;
103 if (buf == 0) {
104 buf = new char[128];
105 size = 128;
106 }
107 for (;;) {
108 int i = 0;
109 for (;;) {
110 int c = getc(fp);
111 if (c == EOF)
112 break;
113 if (invalid_input_char(c))
114 error("invalid input character code `%1'", int(c));
115 else {
116 if (i + 1 >= size) {
117 char *old_buf = buf;
118 buf = new char[size*2];
119 memcpy(buf, old_buf, size);
120 a_delete old_buf;
121 size *= 2;
122 }
123 buf[i++] = c;
124 if (c == '\n')
125 break;
126 }
127 }
128 if (i == 0)
129 break;
130 buf[i] = '\0';
131 lineno++;
132 char *ptr = buf;
133 while (csspace(*ptr))
134 ptr++;
135 if (*ptr != 0 && (!skip_comments || *ptr != '#'))
136 return 1;
137 }
138 return 0;
139}
140
141void text_file::error(const char *format,
142 const errarg &arg1,
143 const errarg &arg2,
144 const errarg &arg3)
145{
465b256c
JR
146 if (!silent)
147 error_with_file_and_line(path, lineno, format, arg1, arg2, arg3);
92d0a6a6
JR
148}
149
150
151/* font functions */
152
153font::font(const char *s)
4d3e9548
JL
154: ligatures(0), kern_hash_table(0), space_width(0), special(0),
155 ch_index(0), nindices(0), ch(0), ch_used(0), ch_size(0), widths_cache(0)
92d0a6a6
JR
156{
157 name = new char[strlen(s) + 1];
158 strcpy(name, s);
159 internalname = 0;
160 slant = 0.0;
4d3e9548 161 zoom = 0;
92d0a6a6
JR
162 // load(); // for testing
163}
164
165font::~font()
166{
167 for (int i = 0; i < ch_used; i++)
168 if (ch[i].special_device_coding)
169 a_delete ch[i].special_device_coding;
170 a_delete ch;
171 a_delete ch_index;
172 if (kern_hash_table) {
173 for (int i = 0; i < KERN_HASH_TABLE_SIZE; i++) {
174 font_kern_list *kerns = kern_hash_table[i];
175 while (kerns) {
176 font_kern_list *tem = kerns;
177 kerns = kerns->next;
178 delete tem;
179 }
180 }
181 a_delete kern_hash_table;
182 }
183 a_delete name;
184 a_delete internalname;
185 while (widths_cache) {
186 font_widths_cache *tem = widths_cache;
187 widths_cache = widths_cache->next;
188 delete tem;
189 }
190}
191
192static int scale_round(int n, int x, int y)
193{
194 assert(x >= 0 && y > 0);
195 int y2 = y/2;
196 if (x == 0)
197 return 0;
198 if (n >= 0) {
4d3e9548
JL
199 if (n <= (INT_MAX - y2) / x)
200 return (n * x + y2) / y;
201 return int(n * double(x) / double(y) + .5);
92d0a6a6
JR
202 }
203 else {
4d3e9548
JL
204 if (-(unsigned)n <= (-(unsigned)INT_MIN - y2) / x)
205 return (n * x - y2) / y;
206 return int(n * double(x) / double(y) - .5);
92d0a6a6
JR
207 }
208}
209
4d3e9548
JL
210static int scale_round(int n, int x, int y, int z)
211{
212 assert(x >= 0 && y > 0 && z > 0);
213 if (x == 0)
214 return 0;
215 if (n >= 0)
216 return int((n * double(x) / double(y)) * (double(z) / 1000.0) + .5);
217 else
218 return int((n * double(x) / double(y)) * (double(z) / 1000.0) - .5);
219}
220
92d0a6a6
JR
221inline int font::scale(int w, int sz)
222{
4d3e9548
JL
223 if (zoom)
224 return scale_round(w, sz, unitwidth, zoom);
225 else
226 return sz == unitwidth ? w : scale_round(w, sz, unitwidth);
92d0a6a6
JR
227}
228
229int font::unit_scale(double *value, char unit)
230{
231 // we scale everything to inch
232 double divisor = 0;
233 switch (unit) {
234 case 'i':
235 divisor = 1;
236 break;
237 case 'p':
238 divisor = 72;
239 break;
240 case 'P':
241 divisor = 6;
242 break;
243 case 'c':
244 divisor = 2.54;
245 break;
246 default:
247 assert(0);
248 break;
249 }
250 if (divisor) {
251 *value /= divisor;
252 return 1;
253 }
254 return 0;
255}
256
4d3e9548 257int font::get_skew(glyph *g, int point_size, int sl)
92d0a6a6 258{
4d3e9548
JL
259 int h = get_height(g, point_size);
260 return int(h * tan((slant + sl) * PI / 180.0) + .5);
92d0a6a6
JR
261}
262
4d3e9548 263int font::contains(glyph *g)
92d0a6a6 264{
4d3e9548
JL
265 int idx = glyph_to_index(g);
266 assert(idx >= 0);
267 // Explicitly enumerated glyph?
268 if (idx < nindices && ch_index[idx] >= 0)
269 return 1;
270 if (is_unicode) {
271 // Unicode font
272 const char *nm = glyph_to_name(g);
273 if (nm != NULL) {
274 // ASCII character?
275 if (nm[0] == 'c' && nm[1] == 'h' && nm[2] == 'a' && nm[3] == 'r'
276 && (nm[4] >= '0' && nm[4] <= '9')) {
277 int n = (nm[4] - '0');
278 if (nm[5] == '\0')
279 return 1;
280 if (n > 0 && (nm[5] >= '0' && nm[5] <= '9')) {
281 n = 10*n + (nm[5] - '0');
282 if (nm[6] == '\0')
283 return 1;
284 if (nm[6] >= '0' && nm[6] <= '9') {
285 n = 10*n + (nm[6] - '0');
286 if (nm[7] == '\0' && n < 128)
287 return 1;
288 }
289 }
290 }
291 // Unicode character?
292 if (check_unicode_name(nm))
293 return 1;
294 // If `nm' is a single letter `x', the glyph name is `\x'.
295 char buf[] = { '\\', '\0', '\0' };
296 if (nm[1] == '\0') {
297 buf[1] = nm[0];
298 nm = buf;
299 }
300 // groff glyph name that maps to Unicode?
301 const char *unicode = glyph_name_to_unicode(nm);
302 if (unicode != NULL && strchr(unicode, '_') == NULL)
303 return 1;
304 }
305 // Numbered character?
306 int n = glyph_to_number(g);
307 if (n >= 0)
308 return 1;
309 }
310 return 0;
92d0a6a6
JR
311}
312
313int font::is_special()
314{
315 return special;
316}
317
318font_widths_cache::font_widths_cache(int ps, int ch_size,
319 font_widths_cache *p)
320: next(p), point_size(ps)
321{
322 width = new int[ch_size];
323 for (int i = 0; i < ch_size; i++)
324 width[i] = -1;
325}
326
327font_widths_cache::~font_widths_cache()
328{
329 a_delete width;
330}
331
4d3e9548 332int font::get_width(glyph *g, int point_size)
92d0a6a6 333{
4d3e9548
JL
334 int idx = glyph_to_index(g);
335 assert(idx >= 0);
336 int real_size;
337 if (!zoom)
338 real_size = point_size;
339 else
340 {
341 if (point_size <= (INT_MAX - 500) / zoom)
342 real_size = (point_size * zoom + 500) / 1000;
343 else
344 real_size = int(point_size * double(zoom) / 1000.0 + .5);
345 }
346 if (idx < nindices && ch_index[idx] >= 0) {
347 // Explicitly enumerated glyph
348 int i = ch_index[idx];
349 if (real_size == unitwidth || font::unscaled_charwidths)
350 return ch[i].width;
92d0a6a6 351
4d3e9548
JL
352 if (!widths_cache)
353 widths_cache = new font_widths_cache(real_size, ch_size);
354 else if (widths_cache->point_size != real_size) {
355 font_widths_cache **p;
356 for (p = &widths_cache; *p; p = &(*p)->next)
357 if ((*p)->point_size == real_size)
358 break;
359 if (*p) {
360 font_widths_cache *tem = *p;
361 *p = (*p)->next;
362 tem->next = widths_cache;
363 widths_cache = tem;
364 }
365 else
366 widths_cache = new font_widths_cache(real_size, ch_size,
367 widths_cache);
92d0a6a6 368 }
4d3e9548
JL
369 int &w = widths_cache->width[i];
370 if (w < 0)
371 w = scale(ch[i].width, point_size);
372 return w;
373 }
374 if (is_unicode) {
375 // Unicode font
376 int width = 24; // value found in the original font files
377 // XXX: this must be eventually moved back to the
378 // font description file!
379 if (real_size == unitwidth || font::unscaled_charwidths)
380 return width;
92d0a6a6 381 else
4d3e9548
JL
382 return scale(width, point_size);
383 }
384 abort();
385}
386
387int font::get_height(glyph *g, int point_size)
388{
389 int idx = glyph_to_index(g);
390 assert(idx >= 0);
391 if (idx < nindices && ch_index[idx] >= 0) {
392 // Explicitly enumerated glyph
393 return scale(ch[ch_index[idx]].height, point_size);
394 }
395 if (is_unicode) {
396 // Unicode font
397 return 0; // value found in the original font files
398 // XXX: this must be eventually moved back to the
399 // font description file!
400 }
401 abort();
402}
403
404int font::get_depth(glyph *g, int point_size)
405{
406 int idx = glyph_to_index(g);
407 assert(idx >= 0);
408 if (idx < nindices && ch_index[idx] >= 0) {
409 // Explicitly enumerated glyph
410 return scale(ch[ch_index[idx]].depth, point_size);
92d0a6a6 411 }
4d3e9548
JL
412 if (is_unicode) {
413 // Unicode font
414 return 0; // value found in the original font files
415 // XXX: this must be eventually moved back to the
416 // font description file!
417 }
418 abort();
92d0a6a6
JR
419}
420
4d3e9548 421int font::get_italic_correction(glyph *g, int point_size)
92d0a6a6 422{
4d3e9548
JL
423 int idx = glyph_to_index(g);
424 assert(idx >= 0);
425 if (idx < nindices && ch_index[idx] >= 0) {
426 // Explicitly enumerated glyph
427 return scale(ch[ch_index[idx]].italic_correction, point_size);
428 }
429 if (is_unicode) {
430 // Unicode font
431 return 0; // value found in the original font files
432 // XXX: this must be eventually moved back to the
433 // font description file!
434 }
435 abort();
92d0a6a6
JR
436}
437
4d3e9548 438int font::get_left_italic_correction(glyph *g, int point_size)
92d0a6a6 439{
4d3e9548
JL
440 int idx = glyph_to_index(g);
441 assert(idx >= 0);
442 if (idx < nindices && ch_index[idx] >= 0) {
443 // Explicitly enumerated glyph
444 return scale(ch[ch_index[idx]].pre_math_space, point_size);
445 }
446 if (is_unicode) {
447 // Unicode font
448 return 0; // value found in the original font files
449 // XXX: this must be eventually moved back to the
450 // font description file!
451 }
452 abort();
92d0a6a6
JR
453}
454
4d3e9548 455int font::get_subscript_correction(glyph *g, int point_size)
92d0a6a6 456{
4d3e9548
JL
457 int idx = glyph_to_index(g);
458 assert(idx >= 0);
459 if (idx < nindices && ch_index[idx] >= 0) {
460 // Explicitly enumerated glyph
461 return scale(ch[ch_index[idx]].subscript_correction, point_size);
462 }
463 if (is_unicode) {
464 // Unicode font
465 return 0; // value found in the original font files
466 // XXX: this must be eventually moved back to the
467 // font description file!
468 }
469 abort();
92d0a6a6
JR
470}
471
4d3e9548 472void font::set_zoom(int factor)
92d0a6a6 473{
4d3e9548
JL
474 assert(factor >= 0);
475 if (factor == 1000)
476 zoom = 0;
477 else
478 zoom = factor;
92d0a6a6
JR
479}
480
4d3e9548 481int font::get_zoom()
92d0a6a6 482{
4d3e9548 483 return zoom;
92d0a6a6
JR
484}
485
486int font::get_space_width(int point_size)
487{
488 return scale(space_width, point_size);
489}
490
4d3e9548
JL
491font_kern_list::font_kern_list(glyph *g1, glyph *g2, int n, font_kern_list *p)
492: glyph1(g1), glyph2(g2), amount(n), next(p)
92d0a6a6
JR
493{
494}
495
4d3e9548 496inline int font::hash_kern(glyph *g1, glyph *g2)
92d0a6a6 497{
4d3e9548
JL
498 int n = ((glyph_to_index(g1) << 10) + glyph_to_index(g2))
499 % KERN_HASH_TABLE_SIZE;
92d0a6a6
JR
500 return n < 0 ? -n : n;
501}
502
4d3e9548 503void font::add_kern(glyph *g1, glyph *g2, int amount)
92d0a6a6
JR
504{
505 if (!kern_hash_table) {
506 kern_hash_table = new font_kern_list *[int(KERN_HASH_TABLE_SIZE)];
507 for (int i = 0; i < KERN_HASH_TABLE_SIZE; i++)
508 kern_hash_table[i] = 0;
509 }
4d3e9548
JL
510 font_kern_list **p = kern_hash_table + hash_kern(g1, g2);
511 *p = new font_kern_list(g1, g2, amount, *p);
92d0a6a6
JR
512}
513
4d3e9548 514int font::get_kern(glyph *g1, glyph *g2, int point_size)
92d0a6a6
JR
515{
516 if (kern_hash_table) {
4d3e9548
JL
517 for (font_kern_list *p = kern_hash_table[hash_kern(g1, g2)]; p;
518 p = p->next)
519 if (g1 == p->glyph1 && g2 == p->glyph2)
92d0a6a6
JR
520 return scale(p->amount, point_size);
521 }
522 return 0;
523}
524
525int font::has_ligature(int mask)
526{
527 return mask & ligatures;
528}
529
4d3e9548 530int font::get_character_type(glyph *g)
92d0a6a6 531{
4d3e9548
JL
532 int idx = glyph_to_index(g);
533 assert(idx >= 0);
534 if (idx < nindices && ch_index[idx] >= 0) {
535 // Explicitly enumerated glyph
536 return ch[ch_index[idx]].type;
537 }
538 if (is_unicode) {
539 // Unicode font
540 return 0; // value found in the original font files
541 // XXX: this must be eventually moved back to the
542 // font description file!
543 }
544 abort();
92d0a6a6
JR
545}
546
4d3e9548 547int font::get_code(glyph *g)
92d0a6a6 548{
4d3e9548
JL
549 int idx = glyph_to_index(g);
550 assert(idx >= 0);
551 if (idx < nindices && ch_index[idx] >= 0) {
552 // Explicitly enumerated glyph
553 return ch[ch_index[idx]].code;
554 }
555 if (is_unicode) {
556 // Unicode font
557 const char *nm = glyph_to_name(g);
558 if (nm != NULL) {
559 // ASCII character?
560 if (nm[0] == 'c' && nm[1] == 'h' && nm[2] == 'a' && nm[3] == 'r'
561 && (nm[4] >= '0' && nm[4] <= '9')) {
562 int n = (nm[4] - '0');
563 if (nm[5] == '\0')
564 return n;
565 if (n > 0 && (nm[5] >= '0' && nm[5] <= '9')) {
566 n = 10*n + (nm[5] - '0');
567 if (nm[6] == '\0')
568 return n;
569 if (nm[6] >= '0' && nm[6] <= '9') {
570 n = 10*n + (nm[6] - '0');
571 if (nm[7] == '\0' && n < 128)
572 return n;
573 }
574 }
575 }
576 // Unicode character?
577 if (check_unicode_name(nm)) {
578 char *ignore;
579 return (int)strtol(nm + 1, &ignore, 16);
580 }
581 // If `nm' is a single letter `x', the glyph name is `\x'.
582 char buf[] = { '\\', '\0', '\0' };
583 if (nm[1] == '\0') {
584 buf[1] = nm[0];
585 nm = buf;
586 }
587 // groff glyphs that map to Unicode?
588 const char *unicode = glyph_name_to_unicode(nm);
589 if (unicode != NULL && strchr(unicode, '_') == NULL) {
590 char *ignore;
591 return (int)strtol(unicode, &ignore, 16);
592 }
593 }
594 // Numbered character?
595 int n = glyph_to_number(g);
596 if (n >= 0)
597 return n;
598 }
599 // The caller must check `contains(g)' before calling get_code(g).
600 abort();
92d0a6a6
JR
601}
602
603const char *font::get_name()
604{
605 return name;
606}
607
608const char *font::get_internal_name()
609{
610 return internalname;
611}
612
4d3e9548 613const char *font::get_special_device_encoding(glyph *g)
92d0a6a6 614{
4d3e9548
JL
615 int idx = glyph_to_index(g);
616 assert(idx >= 0);
617 if (idx < nindices && ch_index[idx] >= 0) {
618 // Explicitly enumerated glyph
619 return ch[ch_index[idx]].special_device_coding;
620 }
621 if (is_unicode) {
622 // Unicode font
623 return NULL;
624 }
625 abort();
465b256c
JR
626}
627
628const char *font::get_image_generator()
629{
630 return image_generator;
92d0a6a6
JR
631}
632
633void font::alloc_ch_index(int idx)
634{
635 if (nindices == 0) {
636 nindices = 128;
637 if (idx >= nindices)
638 nindices = idx + 10;
639 ch_index = new int[nindices];
640 for (int i = 0; i < nindices; i++)
641 ch_index[i] = -1;
642 }
643 else {
644 int old_nindices = nindices;
645 nindices *= 2;
646 if (idx >= nindices)
647 nindices = idx + 10;
648 int *old_ch_index = ch_index;
649 ch_index = new int[nindices];
650 memcpy(ch_index, old_ch_index, sizeof(int)*old_nindices);
651 for (int i = old_nindices; i < nindices; i++)
652 ch_index[i] = -1;
653 a_delete old_ch_index;
654 }
655}
656
657void font::extend_ch()
658{
659 if (ch == 0)
660 ch = new font_char_metric[ch_size = 16];
661 else {
662 int old_ch_size = ch_size;
663 ch_size *= 2;
664 font_char_metric *old_ch = ch;
665 ch = new font_char_metric[ch_size];
666 memcpy(ch, old_ch, old_ch_size*sizeof(font_char_metric));
667 a_delete old_ch;
668 }
669}
670
671void font::compact()
672{
673 int i;
674 for (i = nindices - 1; i >= 0; i--)
675 if (ch_index[i] >= 0)
676 break;
677 i++;
678 if (i < nindices) {
679 int *old_ch_index = ch_index;
680 ch_index = new int[i];
681 memcpy(ch_index, old_ch_index, i*sizeof(int));
682 a_delete old_ch_index;
683 nindices = i;
684 }
685 if (ch_used < ch_size) {
686 font_char_metric *old_ch = ch;
687 ch = new font_char_metric[ch_used];
688 memcpy(ch, old_ch, ch_used*sizeof(font_char_metric));
689 a_delete old_ch;
690 ch_size = ch_used;
691 }
692}
693
4d3e9548 694void font::add_entry(glyph *g, const font_char_metric &metric)
92d0a6a6 695{
4d3e9548 696 int idx = glyph_to_index(g);
92d0a6a6
JR
697 assert(idx >= 0);
698 if (idx >= nindices)
699 alloc_ch_index(idx);
700 assert(idx < nindices);
701 if (ch_used + 1 >= ch_size)
702 extend_ch();
703 assert(ch_used + 1 < ch_size);
704 ch_index[idx] = ch_used;
705 ch[ch_used++] = metric;
706}
707
4d3e9548 708void font::copy_entry(glyph *new_glyph, glyph *old_glyph)
92d0a6a6 709{
4d3e9548
JL
710 int new_index = glyph_to_index(new_glyph);
711 int old_index = glyph_to_index(old_glyph);
92d0a6a6
JR
712 assert(new_index >= 0 && old_index >= 0 && old_index < nindices);
713 if (new_index >= nindices)
714 alloc_ch_index(new_index);
715 ch_index[new_index] = ch_index[old_index];
716}
717
465b256c 718font *font::load_font(const char *s, int *not_found, int head_only)
92d0a6a6
JR
719{
720 font *f = new font(s);
465b256c 721 if (!f->load(not_found, head_only)) {
92d0a6a6
JR
722 delete f;
723 return 0;
724 }
725 return f;
726}
727
728static char *trim_arg(char *p)
729{
730 if (!p)
731 return 0;
732 while (csspace(*p))
733 p++;
734 char *q = strchr(p, '\0');
735 while (q > p && csspace(q[-1]))
736 q--;
737 *q = '\0';
738 return p;
739}
740
741int font::scan_papersize(const char *p,
742 const char **size, double *length, double *width)
743{
744 double l, w;
745 char lu[2], wu[2];
746 const char *pp = p;
747 int test_file = 1;
748 char line[255];
749again:
750 if (csdigit(*pp)) {
751 if (sscanf(pp, "%lf%1[ipPc],%lf%1[ipPc]", &l, lu, &w, wu) == 4
752 && l > 0 && w > 0
753 && unit_scale(&l, lu[0]) && unit_scale(&w, wu[0])) {
754 if (length)
755 *length = l;
756 if (width)
757 *width = w;
758 if (size)
759 *size = "custom";
760 return 1;
761 }
762 }
763 else {
764 int i;
765 for (i = 0; i < NUM_PAPERSIZES; i++)
766 if (strcasecmp(papersizes[i].name, pp) == 0) {
767 if (length)
768 *length = papersizes[i].length;
769 if (width)
770 *width = papersizes[i].width;
771 if (size)
772 *size = papersizes[i].name;
773 return 1;
774 }
775 if (test_file) {
776 FILE *f = fopen(p, "r");
777 if (f) {
778 fgets(line, 254, f);
779 fclose(f);
780 test_file = 0;
781 char *linep = strchr(line, '\0');
782 // skip final newline, if any
783 if (*(--linep) == '\n')
784 *linep = '\0';
785 pp = line;
786 goto again;
787 }
788 }
789 }
790 return 0;
791}
792
793// If the font can't be found, then if not_found is non-NULL, it will be set
794// to 1 otherwise a message will be printed.
795
465b256c 796int font::load(int *not_found, int head_only)
92d0a6a6 797{
4d3e9548
JL
798 if (strcmp(name, "DESC") == 0) {
799 if (not_found)
800 *not_found = 1;
801 else
802 error("`DESC' is not a valid font file name");
803 return 0;
804 }
92d0a6a6
JR
805 char *path;
806 FILE *fp;
807 if ((fp = open_file(name, &path)) == NULL) {
808 if (not_found)
809 *not_found = 1;
810 else
811 error("can't find font file `%1'", name);
812 return 0;
813 }
814 text_file t(fp, path);
815 t.skip_comments = 1;
465b256c 816 t.silent = head_only;
92d0a6a6
JR
817 char *p;
818 for (;;) {
819 if (!t.next()) {
4d3e9548
JL
820 p = 0;
821 break;
92d0a6a6
JR
822 }
823 p = strtok(t.buf, WS);
824 if (strcmp(p, "name") == 0) {
825 }
826 else if (strcmp(p, "spacewidth") == 0) {
827 p = strtok(0, WS);
828 int n;
829 if (p == 0 || sscanf(p, "%d", &n) != 1 || n <= 0) {
4d3e9548 830 t.error("bad argument for `spacewidth' command");
92d0a6a6
JR
831 return 0;
832 }
833 space_width = n;
834 }
835 else if (strcmp(p, "slant") == 0) {
836 p = strtok(0, WS);
837 double n;
838 if (p == 0 || sscanf(p, "%lf", &n) != 1 || n >= 90.0 || n <= -90.0) {
4d3e9548 839 t.error("bad argument for `slant' command", p);
92d0a6a6
JR
840 return 0;
841 }
842 slant = n;
843 }
844 else if (strcmp(p, "ligatures") == 0) {
845 for (;;) {
846 p = strtok(0, WS);
847 if (p == 0 || strcmp(p, "0") == 0)
848 break;
849 if (strcmp(p, "ff") == 0)
850 ligatures |= LIG_ff;
851 else if (strcmp(p, "fi") == 0)
852 ligatures |= LIG_fi;
853 else if (strcmp(p, "fl") == 0)
854 ligatures |= LIG_fl;
855 else if (strcmp(p, "ffi") == 0)
856 ligatures |= LIG_ffi;
857 else if (strcmp(p, "ffl") == 0)
858 ligatures |= LIG_ffl;
859 else {
860 t.error("unrecognised ligature `%1'", p);
861 return 0;
862 }
863 }
864 }
865 else if (strcmp(p, "internalname") == 0) {
866 p = strtok(0, WS);
867 if (!p) {
4d3e9548 868 t.error("`internalname' command requires argument");
92d0a6a6
JR
869 return 0;
870 }
871 internalname = new char[strlen(p) + 1];
872 strcpy(internalname, p);
873 }
874 else if (strcmp(p, "special") == 0) {
875 special = 1;
876 }
877 else if (strcmp(p, "kernpairs") != 0 && strcmp(p, "charset") != 0) {
878 char *command = p;
879 p = strtok(0, "\n");
880 handle_unknown_font_command(command, trim_arg(p), t.path, t.lineno);
881 }
882 else
883 break;
884 }
92d0a6a6 885 int had_charset = 0;
4d3e9548
JL
886 if (p == 0) {
887 if (!is_unicode) {
888 t.error("missing charset command");
889 return 0;
92d0a6a6 890 }
4d3e9548
JL
891 } else {
892 char *command = p;
893 t.skip_comments = 0;
894 while (command) {
895 if (strcmp(command, "kernpairs") == 0) {
896 if (head_only)
897 return 1;
898 for (;;) {
899 if (!t.next()) {
900 command = 0;
901 break;
92d0a6a6 902 }
4d3e9548
JL
903 char *c1 = strtok(t.buf, WS);
904 if (c1 == 0)
905 continue;
906 char *c2 = strtok(0, WS);
907 if (c2 == 0) {
908 command = c1;
909 break;
92d0a6a6
JR
910 }
911 p = strtok(0, WS);
912 if (p == 0) {
4d3e9548 913 t.error("missing kern amount");
92d0a6a6
JR
914 return 0;
915 }
4d3e9548
JL
916 int n;
917 if (sscanf(p, "%d", &n) != 1) {
918 t.error("bad kern amount `%1'", p);
92d0a6a6
JR
919 return 0;
920 }
4d3e9548
JL
921 glyph *g1 = name_to_glyph(c1);
922 glyph *g2 = name_to_glyph(c2);
923 add_kern(g1, g2, n);
924 }
925 }
926 else if (strcmp(command, "charset") == 0) {
927 if (head_only)
928 return 1;
929 had_charset = 1;
930 glyph *last_glyph = NULL;
931 for (;;) {
932 if (!t.next()) {
933 command = 0;
934 break;
92d0a6a6 935 }
4d3e9548
JL
936 char *nm = strtok(t.buf, WS);
937 if (nm == 0)
938 continue; // I dont think this should happen
92d0a6a6
JR
939 p = strtok(0, WS);
940 if (p == 0) {
4d3e9548
JL
941 command = nm;
942 break;
92d0a6a6 943 }
4d3e9548
JL
944 if (p[0] == '"') {
945 if (last_glyph == NULL) {
946 t.error("first charset entry is duplicate");
947 return 0;
948 }
949 if (strcmp(nm, "---") == 0) {
950 t.error("unnamed character cannot be duplicate");
951 return 0;
952 }
953 glyph *g = name_to_glyph(nm);
954 copy_entry(g, last_glyph);
92d0a6a6
JR
955 }
956 else {
4d3e9548
JL
957 font_char_metric metric;
958 metric.height = 0;
959 metric.depth = 0;
960 metric.pre_math_space = 0;
961 metric.italic_correction = 0;
962 metric.subscript_correction = 0;
963 int nparms = sscanf(p, "%d,%d,%d,%d,%d,%d",
964 &metric.width, &metric.height, &metric.depth,
965 &metric.italic_correction,
966 &metric.pre_math_space,
967 &metric.subscript_correction);
968 if (nparms < 1) {
969 t.error("bad width for `%1'", nm);
970 return 0;
971 }
972 p = strtok(0, WS);
973 if (p == 0) {
974 t.error("missing character type for `%1'", nm);
975 return 0;
976 }
977 int type;
978 if (sscanf(p, "%d", &type) != 1) {
979 t.error("bad character type for `%1'", nm);
92d0a6a6
JR
980 return 0;
981 }
4d3e9548
JL
982 if (type < 0 || type > 255) {
983 t.error("character type `%1' out of range", type);
984 return 0;
985 }
986 metric.type = type;
987 p = strtok(0, WS);
988 if (p == 0) {
989 t.error("missing code for `%1'", nm);
990 return 0;
991 }
992 char *ptr;
993 metric.code = (int)strtol(p, &ptr, 0);
994 if (metric.code == 0 && ptr == p) {
995 t.error("bad code `%1' for character `%2'", p, nm);
996 return 0;
997 }
998 p = strtok(0, WS);
999 if ((p == NULL) || (strcmp(p, "--") == 0)) {
1000 metric.special_device_coding = NULL;
1001 }
1002 else {
1003 char *nam = new char[strlen(p) + 1];
1004 strcpy(nam, p);
1005 metric.special_device_coding = nam;
1006 }
1007 if (strcmp(nm, "---") == 0) {
1008 last_glyph = number_to_glyph(metric.code);
1009 add_entry(last_glyph, metric);
1010 }
1011 else {
1012 last_glyph = name_to_glyph(nm);
1013 add_entry(last_glyph, metric);
1014 copy_entry(number_to_glyph(metric.code), last_glyph);
1015 }
92d0a6a6
JR
1016 }
1017 }
4d3e9548
JL
1018 if (last_glyph == NULL) {
1019 t.error("I didn't seem to find any characters");
1020 return 0;
1021 }
92d0a6a6 1022 }
4d3e9548
JL
1023 else {
1024 t.error("unrecognised command `%1' "
1025 "after `kernpairs' or `charset' command",
1026 command);
92d0a6a6
JR
1027 return 0;
1028 }
1029 }
4d3e9548 1030 compact();
92d0a6a6 1031 }
4d3e9548
JL
1032 if (!is_unicode && !had_charset) {
1033 t.error("missing `charset' command");
92d0a6a6
JR
1034 return 0;
1035 }
4d3e9548
JL
1036 if (space_width == 0) {
1037 if (zoom)
1038 space_width = scale_round(unitwidth, res, 72 * 3 * sizescale, zoom);
1039 else
1040 space_width = scale_round(unitwidth, res, 72 * 3 * sizescale);
1041 }
92d0a6a6
JR
1042 return 1;
1043}
1044
1045static struct {
1046 const char *command;
1047 int *ptr;
1048} table[] = {
1049 { "res", &font::res },
1050 { "hor", &font::hor },
1051 { "vert", &font::vert },
1052 { "unitwidth", &font::unitwidth },
1053 { "paperwidth", &font::paperwidth },
1054 { "paperlength", &font::paperlength },
1055 { "spare1", &font::biggestfont },
1056 { "biggestfont", &font::biggestfont },
1057 { "spare2", &font::spare2 },
465b256c 1058 { "sizescale", &font::sizescale },
92d0a6a6
JR
1059 };
1060
1061int font::load_desc()
1062{
1063 int nfonts = 0;
1064 FILE *fp;
1065 char *path;
1066 if ((fp = open_file("DESC", &path)) == 0) {
1067 error("can't find `DESC' file");
1068 return 0;
1069 }
1070 text_file t(fp, path);
1071 t.skip_comments = 1;
1072 res = 0;
1073 while (t.next()) {
1074 char *p = strtok(t.buf, WS);
1075 int found = 0;
1076 unsigned int idx;
1077 for (idx = 0; !found && idx < sizeof(table)/sizeof(table[0]); idx++)
1078 if (strcmp(table[idx].command, p) == 0)
1079 found = 1;
1080 if (found) {
1081 char *q = strtok(0, WS);
1082 if (!q) {
1083 t.error("missing value for command `%1'", p);
1084 return 0;
1085 }
1086 //int *ptr = &(this->*(table[idx-1].ptr));
1087 int *ptr = table[idx-1].ptr;
1088 if (sscanf(q, "%d", ptr) != 1) {
1089 t.error("bad number `%1'", q);
1090 return 0;
1091 }
1092 }
1093 else if (strcmp("family", p) == 0) {
1094 p = strtok(0, WS);
1095 if (!p) {
1096 t.error("family command requires an argument");
1097 return 0;
1098 }
1099 char *tem = new char[strlen(p)+1];
1100 strcpy(tem, p);
1101 family = tem;
1102 }
1103 else if (strcmp("fonts", p) == 0) {
1104 p = strtok(0, WS);
1105 if (!p || sscanf(p, "%d", &nfonts) != 1 || nfonts <= 0) {
1106 t.error("bad number of fonts `%1'", p);
1107 return 0;
1108 }
1109 font_name_table = (const char **)new char *[nfonts+1];
1110 for (int i = 0; i < nfonts; i++) {
1111 p = strtok(0, WS);
1112 while (p == 0) {
1113 if (!t.next()) {
1114 t.error("end of file while reading list of fonts");
1115 return 0;
1116 }
1117 p = strtok(t.buf, WS);
1118 }
1119 char *temp = new char[strlen(p)+1];
1120 strcpy(temp, p);
1121 font_name_table[i] = temp;
1122 }
1123 p = strtok(0, WS);
1124 if (p != 0) {
1125 t.error("font count does not match number of fonts");
1126 return 0;
1127 }
1128 font_name_table[nfonts] = 0;
1129 }
1130 else if (strcmp("papersize", p) == 0) {
1131 p = strtok(0, WS);
1132 if (!p) {
1133 t.error("papersize command requires an argument");
1134 return 0;
1135 }
1136 int found_paper = 0;
1137 while (p) {
1138 double unscaled_paperwidth, unscaled_paperlength;
1139 if (scan_papersize(p, &papersize, &unscaled_paperlength,
1140 &unscaled_paperwidth)) {
1141 paperwidth = int(unscaled_paperwidth * res + 0.5);
1142 paperlength = int(unscaled_paperlength * res + 0.5);
1143 found_paper = 1;
1144 break;
1145 }
1146 p = strtok(0, WS);
1147 }
1148 if (!found_paper) {
1149 t.error("bad paper size");
1150 return 0;
1151 }
1152 }
465b256c
JR
1153 else if (strcmp("unscaled_charwidths", p) == 0)
1154 unscaled_charwidths = 1;
92d0a6a6
JR
1155 else if (strcmp("pass_filenames", p) == 0)
1156 pass_filenames = 1;
1157 else if (strcmp("sizes", p) == 0) {
1158 int n = 16;
1159 sizes = new int[n];
1160 int i = 0;
1161 for (;;) {
1162 p = strtok(0, WS);
1163 while (p == 0) {
1164 if (!t.next()) {
1165 t.error("list of sizes must be terminated by `0'");
1166 return 0;
1167 }
1168 p = strtok(t.buf, WS);
1169 }
1170 int lower, upper;
1171 switch (sscanf(p, "%d-%d", &lower, &upper)) {
1172 case 1:
1173 upper = lower;
1174 // fall through
1175 case 2:
1176 if (lower <= upper && lower >= 0)
1177 break;
1178 // fall through
1179 default:
1180 t.error("bad size range `%1'", p);
1181 return 0;
1182 }
1183 if (i + 2 > n) {
1184 int *old_sizes = sizes;
1185 sizes = new int[n*2];
1186 memcpy(sizes, old_sizes, n*sizeof(int));
1187 n *= 2;
1188 a_delete old_sizes;
1189 }
1190 sizes[i++] = lower;
1191 if (lower == 0)
1192 break;
1193 sizes[i++] = upper;
1194 }
1195 if (i == 1) {
1196 t.error("must have some sizes");
1197 return 0;
1198 }
1199 }
1200 else if (strcmp("styles", p) == 0) {
1201 int style_table_size = 5;
1202 style_table = (const char **)new char *[style_table_size];
1203 int j;
1204 for (j = 0; j < style_table_size; j++)
1205 style_table[j] = 0;
1206 int i = 0;
1207 for (;;) {
1208 p = strtok(0, WS);
1209 if (p == 0)
1210 break;
1211 // leave room for terminating 0
1212 if (i + 1 >= style_table_size) {
1213 const char **old_style_table = style_table;
1214 style_table_size *= 2;
1215 style_table = (const char **)new char*[style_table_size];
1216 for (j = 0; j < i; j++)
1217 style_table[j] = old_style_table[j];
1218 for (; j < style_table_size; j++)
1219 style_table[j] = 0;
1220 a_delete old_style_table;
1221 }
1222 char *tem = new char[strlen(p) + 1];
1223 strcpy(tem, p);
1224 style_table[i++] = tem;
1225 }
1226 }
1227 else if (strcmp("tcommand", p) == 0)
1228 tcommand = 1;
1229 else if (strcmp("use_charnames_in_special", p) == 0)
1230 use_charnames_in_special = 1;
4d3e9548
JL
1231 else if (strcmp("unicode", p) == 0)
1232 is_unicode = 1;
465b256c
JR
1233 else if (strcmp("image_generator", p) == 0) {
1234 p = strtok(0, WS);
1235 if (!p) {
1236 t.error("image_generator command requires an argument");
1237 return 0;
1238 }
1239 image_generator = strsave(p);
1240 }
92d0a6a6
JR
1241 else if (strcmp("charset", p) == 0)
1242 break;
1243 else if (unknown_desc_command_handler) {
1244 char *command = p;
1245 p = strtok(0, "\n");
1246 (*unknown_desc_command_handler)(command, trim_arg(p), t.path, t.lineno);
1247 }
1248 }
1249 if (res == 0) {
1250 t.error("missing `res' command");
1251 return 0;
1252 }
1253 if (unitwidth == 0) {
1254 t.error("missing `unitwidth' command");
1255 return 0;
1256 }
1257 if (font_name_table == 0) {
1258 t.error("missing `fonts' command");
1259 return 0;
1260 }
1261 if (sizes == 0) {
1262 t.error("missing `sizes' command");
1263 return 0;
1264 }
1265 if (sizescale < 1) {
1266 t.error("bad `sizescale' value");
1267 return 0;
1268 }
1269 if (hor < 1) {
1270 t.error("bad `hor' value");
1271 return 0;
1272 }
1273 if (vert < 1) {
1274 t.error("bad `vert' value");
1275 return 0;
1276 }
1277 return 1;
1278}
1279
1280void font::handle_unknown_font_command(const char *, const char *,
1281 const char *, int)
1282{
1283}
1284
1285FONT_COMMAND_HANDLER
1286font::set_unknown_desc_command_handler(FONT_COMMAND_HANDLER func)
1287{
1288 FONT_COMMAND_HANDLER prev = unknown_desc_command_handler;
1289 unknown_desc_command_handler = func;
1290 return prev;
1291}