No empty .Rs/.Re
[netbsd-mini2440.git] / gnu / dist / groff / src / libs / libgroff / font.cpp
blob04dd0163501d7e32c663cf342f17a1dc0780f56b
1 /* $NetBSD$ */
3 // -*- C++ -*-
4 /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004, 2005
5 Free Software Foundation, Inc.
6 Written by James Clark (jjc@jclark.com)
8 This file is part of groff.
10 groff is free software; you can redistribute it and/or modify it under
11 the terms of the GNU General Public License as published by the Free
12 Software Foundation; either version 2, or (at your option) any later
13 version.
15 groff is distributed in the hope that it will be useful, but WITHOUT ANY
16 WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 for more details.
20 You should have received a copy of the GNU General Public License along
21 with groff; see the file COPYING. If not, write to the Free Software
22 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
24 #include "lib.h"
26 #include <ctype.h>
27 #include <assert.h>
28 #include <math.h>
29 #include <stdlib.h>
30 #include "errarg.h"
31 #include "error.h"
32 #include "cset.h"
33 #include "font.h"
34 #include "paper.h"
36 const char *const WS = " \t\n\r";
38 struct font_char_metric {
39 char type;
40 int code;
41 int width;
42 int height;
43 int depth;
44 int pre_math_space;
45 int italic_correction;
46 int subscript_correction;
47 char *special_device_coding;
50 struct font_kern_list {
51 int i1;
52 int i2;
53 int amount;
54 font_kern_list *next;
56 font_kern_list(int, int, int, font_kern_list * = 0);
59 struct font_widths_cache {
60 font_widths_cache *next;
61 int point_size;
62 int *width;
64 font_widths_cache(int, int, font_widths_cache * = 0);
65 ~font_widths_cache();
68 /* text_file */
70 struct text_file {
71 FILE *fp;
72 char *path;
73 int lineno;
74 int size;
75 int skip_comments;
76 int silent;
77 char *buf;
78 text_file(FILE *fp, char *p);
79 ~text_file();
80 int next();
81 void error(const char *format,
82 const errarg &arg1 = empty_errarg,
83 const errarg &arg2 = empty_errarg,
84 const errarg &arg3 = empty_errarg);
87 text_file::text_file(FILE *p, char *s)
88 : fp(p), path(s), lineno(0), size(0), skip_comments(1), silent(0), buf(0)
92 text_file::~text_file()
94 a_delete buf;
95 a_delete path;
96 if (fp)
97 fclose(fp);
100 int text_file::next()
102 if (fp == 0)
103 return 0;
104 if (buf == 0) {
105 buf = new char[128];
106 size = 128;
108 for (;;) {
109 int i = 0;
110 for (;;) {
111 int c = getc(fp);
112 if (c == EOF)
113 break;
114 if (invalid_input_char(c))
115 error("invalid input character code `%1'", int(c));
116 else {
117 if (i + 1 >= size) {
118 char *old_buf = buf;
119 buf = new char[size*2];
120 memcpy(buf, old_buf, size);
121 a_delete old_buf;
122 size *= 2;
124 buf[i++] = c;
125 if (c == '\n')
126 break;
129 if (i == 0)
130 break;
131 buf[i] = '\0';
132 lineno++;
133 char *ptr = buf;
134 while (csspace(*ptr))
135 ptr++;
136 if (*ptr != 0 && (!skip_comments || *ptr != '#'))
137 return 1;
139 return 0;
142 void text_file::error(const char *format,
143 const errarg &arg1,
144 const errarg &arg2,
145 const errarg &arg3)
147 if (!silent)
148 error_with_file_and_line(path, lineno, format, arg1, arg2, arg3);
152 /* font functions */
154 font::font(const char *s)
155 : ligatures(0), kern_hash_table(0), space_width(0), ch_index(0), nindices(0),
156 ch(0), ch_used(0), ch_size(0), special(0), widths_cache(0)
158 name = new char[strlen(s) + 1];
159 strcpy(name, s);
160 internalname = 0;
161 slant = 0.0;
162 // load(); // for testing
165 font::~font()
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;
181 a_delete kern_hash_table;
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;
192 static int scale_round(int n, int x, int y)
194 assert(x >= 0 && y > 0);
195 int y2 = y/2;
196 if (x == 0)
197 return 0;
198 if (n >= 0) {
199 if (n <= (INT_MAX - y2)/x)
200 return (n*x + y2)/y;
201 return int(n*double(x)/double(y) + .5);
203 else {
204 if (-(unsigned)n <= (-(unsigned)INT_MIN - y2)/x)
205 return (n*x - y2)/y;
206 return int(n*double(x)/double(y) - .5);
210 inline int font::scale(int w, int sz)
212 return sz == unitwidth ? w : scale_round(w, sz, unitwidth);
215 int font::unit_scale(double *value, char unit)
217 // we scale everything to inch
218 double divisor = 0;
219 switch (unit) {
220 case 'i':
221 divisor = 1;
222 break;
223 case 'p':
224 divisor = 72;
225 break;
226 case 'P':
227 divisor = 6;
228 break;
229 case 'c':
230 divisor = 2.54;
231 break;
232 default:
233 assert(0);
234 break;
236 if (divisor) {
237 *value /= divisor;
238 return 1;
240 return 0;
243 int font::get_skew(int c, int point_size, int sl)
245 int h = get_height(c, point_size);
246 return int(h*tan((slant+sl)*PI/180.0) + .5);
249 int font::contains(int c)
251 return c >= 0 && c < nindices && ch_index[c] >= 0;
254 int font::is_special()
256 return special;
259 font_widths_cache::font_widths_cache(int ps, int ch_size,
260 font_widths_cache *p)
261 : next(p), point_size(ps)
263 width = new int[ch_size];
264 for (int i = 0; i < ch_size; i++)
265 width[i] = -1;
268 font_widths_cache::~font_widths_cache()
270 a_delete width;
273 int font::get_width(int c, int point_size)
275 assert(c >= 0 && c < nindices);
276 int i = ch_index[c];
277 assert(i >= 0);
279 if (point_size == unitwidth || font::unscaled_charwidths)
280 return ch[i].width;
282 if (!widths_cache)
283 widths_cache = new font_widths_cache(point_size, ch_size);
284 else if (widths_cache->point_size != point_size) {
285 font_widths_cache **p;
286 for (p = &widths_cache; *p; p = &(*p)->next)
287 if ((*p)->point_size == point_size)
288 break;
289 if (*p) {
290 font_widths_cache *tem = *p;
291 *p = (*p)->next;
292 tem->next = widths_cache;
293 widths_cache = tem;
295 else
296 widths_cache = new font_widths_cache(point_size, ch_size, widths_cache);
298 int &w = widths_cache->width[i];
299 if (w < 0)
300 w = scale(ch[i].width, point_size);
301 return w;
304 int font::get_height(int c, int point_size)
306 assert(c >= 0 && c < nindices && ch_index[c] >= 0);
307 return scale(ch[ch_index[c]].height, point_size);
310 int font::get_depth(int c, int point_size)
312 assert(c >= 0 && c < nindices && ch_index[c] >= 0);
313 return scale(ch[ch_index[c]].depth, point_size);
316 int font::get_italic_correction(int c, int point_size)
318 assert(c >= 0 && c < nindices && ch_index[c] >= 0);
319 return scale(ch[ch_index[c]].italic_correction, point_size);
322 int font::get_left_italic_correction(int c, int point_size)
324 assert(c >= 0 && c < nindices && ch_index[c] >= 0);
325 return scale(ch[ch_index[c]].pre_math_space, point_size);
328 int font::get_subscript_correction(int c, int point_size)
330 assert(c >= 0 && c < nindices && ch_index[c] >= 0);
331 return scale(ch[ch_index[c]].subscript_correction, point_size);
334 int font::get_space_width(int point_size)
336 return scale(space_width, point_size);
339 font_kern_list::font_kern_list(int c1, int c2, int n, font_kern_list *p)
340 : i1(c1), i2(c2), amount(n), next(p)
344 inline int font::hash_kern(int i1, int i2)
346 int n = ((i1 << 10) + i2) % KERN_HASH_TABLE_SIZE;
347 return n < 0 ? -n : n;
350 void font::add_kern(int i1, int i2, int amount)
352 if (!kern_hash_table) {
353 kern_hash_table = new font_kern_list *[int(KERN_HASH_TABLE_SIZE)];
354 for (int i = 0; i < KERN_HASH_TABLE_SIZE; i++)
355 kern_hash_table[i] = 0;
357 font_kern_list **p = kern_hash_table + hash_kern(i1, i2);
358 *p = new font_kern_list(i1, i2, amount, *p);
361 int font::get_kern(int i1, int i2, int point_size)
363 if (kern_hash_table) {
364 for (font_kern_list *p = kern_hash_table[hash_kern(i1, i2)]; p; p = p->next)
365 if (i1 == p->i1 && i2 == p->i2)
366 return scale(p->amount, point_size);
368 return 0;
371 int font::has_ligature(int mask)
373 return mask & ligatures;
376 int font::get_character_type(int c)
378 assert(c >= 0 && c < nindices && ch_index[c] >= 0);
379 return ch[ch_index[c]].type;
382 int font::get_code(int c)
384 assert(c >= 0 && c < nindices && ch_index[c] >= 0);
385 return ch[ch_index[c]].code;
388 const char *font::get_name()
390 return name;
393 const char *font::get_internal_name()
395 return internalname;
398 const char *font::get_special_device_encoding(int c)
400 assert(c >= 0 && c < nindices && ch_index[c] >= 0);
401 return ch[ch_index[c]].special_device_coding;
404 const char *font::get_image_generator()
406 return image_generator;
409 void font::alloc_ch_index(int idx)
411 if (nindices == 0) {
412 nindices = 128;
413 if (idx >= nindices)
414 nindices = idx + 10;
415 ch_index = new int[nindices];
416 for (int i = 0; i < nindices; i++)
417 ch_index[i] = -1;
419 else {
420 int old_nindices = nindices;
421 nindices *= 2;
422 if (idx >= nindices)
423 nindices = idx + 10;
424 int *old_ch_index = ch_index;
425 ch_index = new int[nindices];
426 memcpy(ch_index, old_ch_index, sizeof(int)*old_nindices);
427 for (int i = old_nindices; i < nindices; i++)
428 ch_index[i] = -1;
429 a_delete old_ch_index;
433 void font::extend_ch()
435 if (ch == 0)
436 ch = new font_char_metric[ch_size = 16];
437 else {
438 int old_ch_size = ch_size;
439 ch_size *= 2;
440 font_char_metric *old_ch = ch;
441 ch = new font_char_metric[ch_size];
442 memcpy(ch, old_ch, old_ch_size*sizeof(font_char_metric));
443 a_delete old_ch;
447 void font::compact()
449 int i;
450 for (i = nindices - 1; i >= 0; i--)
451 if (ch_index[i] >= 0)
452 break;
453 i++;
454 if (i < nindices) {
455 int *old_ch_index = ch_index;
456 ch_index = new int[i];
457 memcpy(ch_index, old_ch_index, i*sizeof(int));
458 a_delete old_ch_index;
459 nindices = i;
461 if (ch_used < ch_size) {
462 font_char_metric *old_ch = ch;
463 ch = new font_char_metric[ch_used];
464 memcpy(ch, old_ch, ch_used*sizeof(font_char_metric));
465 a_delete old_ch;
466 ch_size = ch_used;
470 void font::add_entry(int idx, const font_char_metric &metric)
472 assert(idx >= 0);
473 if (idx >= nindices)
474 alloc_ch_index(idx);
475 assert(idx < nindices);
476 if (ch_used + 1 >= ch_size)
477 extend_ch();
478 assert(ch_used + 1 < ch_size);
479 ch_index[idx] = ch_used;
480 ch[ch_used++] = metric;
483 void font::copy_entry(int new_index, int old_index)
485 assert(new_index >= 0 && old_index >= 0 && old_index < nindices);
486 if (new_index >= nindices)
487 alloc_ch_index(new_index);
488 ch_index[new_index] = ch_index[old_index];
491 font *font::load_font(const char *s, int *not_found, int head_only)
493 font *f = new font(s);
494 if (!f->load(not_found, head_only)) {
495 delete f;
496 return 0;
498 return f;
501 static char *trim_arg(char *p)
503 if (!p)
504 return 0;
505 while (csspace(*p))
506 p++;
507 char *q = strchr(p, '\0');
508 while (q > p && csspace(q[-1]))
509 q--;
510 *q = '\0';
511 return p;
514 int font::scan_papersize(const char *p,
515 const char **size, double *length, double *width)
517 double l, w;
518 char lu[2], wu[2];
519 const char *pp = p;
520 int test_file = 1;
521 char line[255];
522 again:
523 if (csdigit(*pp)) {
524 if (sscanf(pp, "%lf%1[ipPc],%lf%1[ipPc]", &l, lu, &w, wu) == 4
525 && l > 0 && w > 0
526 && unit_scale(&l, lu[0]) && unit_scale(&w, wu[0])) {
527 if (length)
528 *length = l;
529 if (width)
530 *width = w;
531 if (size)
532 *size = "custom";
533 return 1;
536 else {
537 int i;
538 for (i = 0; i < NUM_PAPERSIZES; i++)
539 if (strcasecmp(papersizes[i].name, pp) == 0) {
540 if (length)
541 *length = papersizes[i].length;
542 if (width)
543 *width = papersizes[i].width;
544 if (size)
545 *size = papersizes[i].name;
546 return 1;
548 if (test_file) {
549 FILE *f = fopen(p, "r");
550 if (f) {
551 fgets(line, 254, f);
552 fclose(f);
553 test_file = 0;
554 char *linep = strchr(line, '\0');
555 // skip final newline, if any
556 if (*(--linep) == '\n')
557 *linep = '\0';
558 pp = line;
559 goto again;
563 return 0;
566 // If the font can't be found, then if not_found is non-NULL, it will be set
567 // to 1 otherwise a message will be printed.
569 int font::load(int *not_found, int head_only)
571 char *path;
572 FILE *fp;
573 if ((fp = open_file(name, &path)) == NULL) {
574 if (not_found)
575 *not_found = 1;
576 else
577 error("can't find font file `%1'", name);
578 return 0;
580 text_file t(fp, path);
581 t.skip_comments = 1;
582 t.silent = head_only;
583 char *p;
584 for (;;) {
585 if (!t.next()) {
586 t.error("missing charset command");
587 return 0;
589 p = strtok(t.buf, WS);
590 if (strcmp(p, "name") == 0) {
592 else if (strcmp(p, "spacewidth") == 0) {
593 p = strtok(0, WS);
594 int n;
595 if (p == 0 || sscanf(p, "%d", &n) != 1 || n <= 0) {
596 t.error("bad argument for spacewidth command");
597 return 0;
599 space_width = n;
601 else if (strcmp(p, "slant") == 0) {
602 p = strtok(0, WS);
603 double n;
604 if (p == 0 || sscanf(p, "%lf", &n) != 1 || n >= 90.0 || n <= -90.0) {
605 t.error("bad argument for slant command", p);
606 return 0;
608 slant = n;
610 else if (strcmp(p, "ligatures") == 0) {
611 for (;;) {
612 p = strtok(0, WS);
613 if (p == 0 || strcmp(p, "0") == 0)
614 break;
615 if (strcmp(p, "ff") == 0)
616 ligatures |= LIG_ff;
617 else if (strcmp(p, "fi") == 0)
618 ligatures |= LIG_fi;
619 else if (strcmp(p, "fl") == 0)
620 ligatures |= LIG_fl;
621 else if (strcmp(p, "ffi") == 0)
622 ligatures |= LIG_ffi;
623 else if (strcmp(p, "ffl") == 0)
624 ligatures |= LIG_ffl;
625 else {
626 t.error("unrecognised ligature `%1'", p);
627 return 0;
631 else if (strcmp(p, "internalname") == 0) {
632 p = strtok(0, WS);
633 if (!p) {
634 t.error("`internalname command requires argument");
635 return 0;
637 internalname = new char[strlen(p) + 1];
638 strcpy(internalname, p);
640 else if (strcmp(p, "special") == 0) {
641 special = 1;
643 else if (strcmp(p, "kernpairs") != 0 && strcmp(p, "charset") != 0) {
644 char *command = p;
645 p = strtok(0, "\n");
646 handle_unknown_font_command(command, trim_arg(p), t.path, t.lineno);
648 else
649 break;
651 if (head_only)
652 return 1;
653 char *command = p;
654 int had_charset = 0;
655 t.skip_comments = 0;
656 while (command) {
657 if (strcmp(command, "kernpairs") == 0) {
658 for (;;) {
659 if (!t.next()) {
660 command = 0;
661 break;
663 char *c1 = strtok(t.buf, WS);
664 if (c1 == 0)
665 continue;
666 char *c2 = strtok(0, WS);
667 if (c2 == 0) {
668 command = c1;
669 break;
671 p = strtok(0, WS);
672 if (p == 0) {
673 t.error("missing kern amount");
674 return 0;
676 int n;
677 if (sscanf(p, "%d", &n) != 1) {
678 t.error("bad kern amount `%1'", p);
679 return 0;
681 int i1 = name_to_index(c1);
682 if (i1 < 0) {
683 t.error("invalid character `%1'", c1);
684 return 0;
686 int i2 = name_to_index(c2);
687 if (i2 < 0) {
688 t.error("invalid character `%1'", c2);
689 return 0;
691 add_kern(i1, i2, n);
694 else if (strcmp(command, "charset") == 0) {
695 had_charset = 1;
696 int last_index = -1;
697 for (;;) {
698 if (!t.next()) {
699 command = 0;
700 break;
702 char *nm = strtok(t.buf, WS);
703 if (nm == 0)
704 continue; // I dont think this should happen
705 p = strtok(0, WS);
706 if (p == 0) {
707 command = nm;
708 break;
710 if (p[0] == '"') {
711 if (last_index == -1) {
712 t.error("first charset entry is duplicate");
713 return 0;
715 if (strcmp(nm, "---") == 0) {
716 t.error("unnamed character cannot be duplicate");
717 return 0;
719 int idx = name_to_index(nm);
720 if (idx < 0) {
721 t.error("invalid character `%1'", nm);
722 return 0;
724 copy_entry(idx, last_index);
726 else {
727 font_char_metric metric;
728 metric.height = 0;
729 metric.depth = 0;
730 metric.pre_math_space = 0;
731 metric.italic_correction = 0;
732 metric.subscript_correction = 0;
733 int nparms = sscanf(p, "%d,%d,%d,%d,%d,%d",
734 &metric.width, &metric.height, &metric.depth,
735 &metric.italic_correction,
736 &metric.pre_math_space,
737 &metric.subscript_correction);
738 if (nparms < 1) {
739 t.error("bad width for `%1'", nm);
740 return 0;
742 p = strtok(0, WS);
743 if (p == 0) {
744 t.error("missing character type for `%1'", nm);
745 return 0;
747 int type;
748 if (sscanf(p, "%d", &type) != 1) {
749 t.error("bad character type for `%1'", nm);
750 return 0;
752 if (type < 0 || type > 255) {
753 t.error("character type `%1' out of range", type);
754 return 0;
756 metric.type = type;
757 p = strtok(0, WS);
758 if (p == 0) {
759 t.error("missing code for `%1'", nm);
760 return 0;
762 char *ptr;
763 metric.code = (int)strtol(p, &ptr, 0);
764 if (metric.code == 0 && ptr == p) {
765 t.error("bad code `%1' for character `%2'", p, nm);
766 return 0;
768 p = strtok(0, WS);
769 if ((p == NULL) || (strcmp(p, "--") == 0)) {
770 metric.special_device_coding = NULL;
772 else {
773 char *nam = new char[strlen(p) + 1];
774 strcpy(nam, p);
775 metric.special_device_coding = nam;
777 if (strcmp(nm, "---") == 0) {
778 last_index = number_to_index(metric.code);
779 add_entry(last_index, metric);
781 else {
782 last_index = name_to_index(nm);
783 if (last_index < 0) {
784 t.error("invalid character `%1'", nm);
785 return 0;
787 add_entry(last_index, metric);
788 copy_entry(number_to_index(metric.code), last_index);
792 if (last_index == -1) {
793 t.error("I didn't seem to find any characters");
794 return 0;
797 else {
798 t.error("unrecognised command `%1' after `kernpairs' or `charset' command", command);
799 return 0;
802 if (!had_charset) {
803 t.error("missing charset command");
804 return 0;
806 if (space_width == 0)
807 space_width = scale_round(unitwidth, res, 72*3*sizescale);
808 compact();
809 return 1;
812 static struct {
813 const char *command;
814 int *ptr;
815 } table[] = {
816 { "res", &font::res },
817 { "hor", &font::hor },
818 { "vert", &font::vert },
819 { "unitwidth", &font::unitwidth },
820 { "paperwidth", &font::paperwidth },
821 { "paperlength", &font::paperlength },
822 { "spare1", &font::biggestfont },
823 { "biggestfont", &font::biggestfont },
824 { "spare2", &font::spare2 },
825 { "sizescale", &font::sizescale },
828 int font::load_desc()
830 int nfonts = 0;
831 FILE *fp;
832 char *path;
833 if ((fp = open_file("DESC", &path)) == 0) {
834 error("can't find `DESC' file");
835 return 0;
837 text_file t(fp, path);
838 t.skip_comments = 1;
839 res = 0;
840 while (t.next()) {
841 char *p = strtok(t.buf, WS);
842 int found = 0;
843 unsigned int idx;
844 for (idx = 0; !found && idx < sizeof(table)/sizeof(table[0]); idx++)
845 if (strcmp(table[idx].command, p) == 0)
846 found = 1;
847 if (found) {
848 char *q = strtok(0, WS);
849 if (!q) {
850 t.error("missing value for command `%1'", p);
851 return 0;
853 //int *ptr = &(this->*(table[idx-1].ptr));
854 int *ptr = table[idx-1].ptr;
855 if (sscanf(q, "%d", ptr) != 1) {
856 t.error("bad number `%1'", q);
857 return 0;
860 else if (strcmp("family", p) == 0) {
861 p = strtok(0, WS);
862 if (!p) {
863 t.error("family command requires an argument");
864 return 0;
866 char *tem = new char[strlen(p)+1];
867 strcpy(tem, p);
868 family = tem;
870 else if (strcmp("fonts", p) == 0) {
871 p = strtok(0, WS);
872 if (!p || sscanf(p, "%d", &nfonts) != 1 || nfonts <= 0) {
873 t.error("bad number of fonts `%1'", p);
874 return 0;
876 font_name_table = (const char **)new char *[nfonts+1];
877 for (int i = 0; i < nfonts; i++) {
878 p = strtok(0, WS);
879 while (p == 0) {
880 if (!t.next()) {
881 t.error("end of file while reading list of fonts");
882 return 0;
884 p = strtok(t.buf, WS);
886 char *temp = new char[strlen(p)+1];
887 strcpy(temp, p);
888 font_name_table[i] = temp;
890 p = strtok(0, WS);
891 if (p != 0) {
892 t.error("font count does not match number of fonts");
893 return 0;
895 font_name_table[nfonts] = 0;
897 else if (strcmp("papersize", p) == 0) {
898 p = strtok(0, WS);
899 if (!p) {
900 t.error("papersize command requires an argument");
901 return 0;
903 int found_paper = 0;
904 while (p) {
905 double unscaled_paperwidth, unscaled_paperlength;
906 if (scan_papersize(p, &papersize, &unscaled_paperlength,
907 &unscaled_paperwidth)) {
908 paperwidth = int(unscaled_paperwidth * res + 0.5);
909 paperlength = int(unscaled_paperlength * res + 0.5);
910 found_paper = 1;
911 break;
913 p = strtok(0, WS);
915 if (!found_paper) {
916 t.error("bad paper size");
917 return 0;
920 else if (strcmp("unscaled_charwidths", p) == 0)
921 unscaled_charwidths = 1;
922 else if (strcmp("pass_filenames", p) == 0)
923 pass_filenames = 1;
924 else if (strcmp("sizes", p) == 0) {
925 int n = 16;
926 sizes = new int[n];
927 int i = 0;
928 for (;;) {
929 p = strtok(0, WS);
930 while (p == 0) {
931 if (!t.next()) {
932 t.error("list of sizes must be terminated by `0'");
933 return 0;
935 p = strtok(t.buf, WS);
937 int lower, upper;
938 switch (sscanf(p, "%d-%d", &lower, &upper)) {
939 case 1:
940 upper = lower;
941 // fall through
942 case 2:
943 if (lower <= upper && lower >= 0)
944 break;
945 // fall through
946 default:
947 t.error("bad size range `%1'", p);
948 return 0;
950 if (i + 2 > n) {
951 int *old_sizes = sizes;
952 sizes = new int[n*2];
953 memcpy(sizes, old_sizes, n*sizeof(int));
954 n *= 2;
955 a_delete old_sizes;
957 sizes[i++] = lower;
958 if (lower == 0)
959 break;
960 sizes[i++] = upper;
962 if (i == 1) {
963 t.error("must have some sizes");
964 return 0;
967 else if (strcmp("styles", p) == 0) {
968 int style_table_size = 5;
969 style_table = (const char **)new char *[style_table_size];
970 int j;
971 for (j = 0; j < style_table_size; j++)
972 style_table[j] = 0;
973 int i = 0;
974 for (;;) {
975 p = strtok(0, WS);
976 if (p == 0)
977 break;
978 // leave room for terminating 0
979 if (i + 1 >= style_table_size) {
980 const char **old_style_table = style_table;
981 style_table_size *= 2;
982 style_table = (const char **)new char*[style_table_size];
983 for (j = 0; j < i; j++)
984 style_table[j] = old_style_table[j];
985 for (; j < style_table_size; j++)
986 style_table[j] = 0;
987 a_delete old_style_table;
989 char *tem = new char[strlen(p) + 1];
990 strcpy(tem, p);
991 style_table[i++] = tem;
994 else if (strcmp("tcommand", p) == 0)
995 tcommand = 1;
996 else if (strcmp("use_charnames_in_special", p) == 0)
997 use_charnames_in_special = 1;
998 else if (strcmp("image_generator", p) == 0) {
999 p = strtok(0, WS);
1000 if (!p) {
1001 t.error("image_generator command requires an argument");
1002 return 0;
1004 image_generator = strsave(p);
1006 else if (strcmp("charset", p) == 0)
1007 break;
1008 else if (unknown_desc_command_handler) {
1009 char *command = p;
1010 p = strtok(0, "\n");
1011 (*unknown_desc_command_handler)(command, trim_arg(p), t.path, t.lineno);
1014 if (res == 0) {
1015 t.error("missing `res' command");
1016 return 0;
1018 if (unitwidth == 0) {
1019 t.error("missing `unitwidth' command");
1020 return 0;
1022 if (font_name_table == 0) {
1023 t.error("missing `fonts' command");
1024 return 0;
1026 if (sizes == 0) {
1027 t.error("missing `sizes' command");
1028 return 0;
1030 if (sizescale < 1) {
1031 t.error("bad `sizescale' value");
1032 return 0;
1034 if (hor < 1) {
1035 t.error("bad `hor' value");
1036 return 0;
1038 if (vert < 1) {
1039 t.error("bad `vert' value");
1040 return 0;
1042 return 1;
1045 void font::handle_unknown_font_command(const char *, const char *,
1046 const char *, int)
1050 FONT_COMMAND_HANDLER
1051 font::set_unknown_desc_command_handler(FONT_COMMAND_HANDLER func)
1053 FONT_COMMAND_HANDLER prev = unknown_desc_command_handler;
1054 unknown_desc_command_handler = func;
1055 return prev;