home *** CD-ROM | disk | FTP | other *** search
/ Aminet 10 / aminetcdnumber101996.iso / Aminet / util / gnu / groff_src.lha / groff-1.10src / libgroff / font.cc < prev    next >
C/C++ Source or Header  |  1995-06-22  |  20KB  |  912 lines

  1. // -*- C++ -*-
  2. /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
  3.      Written by James Clark (jjc@jclark.com)
  4.  
  5. This file is part of groff.
  6.  
  7. groff is free software; you can redistribute it and/or modify it under
  8. the terms of the GNU General Public License as published by the Free
  9. Software Foundation; either version 2, or (at your option) any later
  10. version.
  11.  
  12. groff is distributed in the hope that it will be useful, but WITHOUT ANY
  13. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15. for more details.
  16.  
  17. You should have received a copy of the GNU General Public License along
  18. with groff; see the file COPYING.  If not, write to the Free Software
  19. Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  20.  
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <ctype.h>
  24. #include <assert.h>
  25. #include <math.h>
  26. #include <stdlib.h>
  27. #include "errarg.h"
  28. #include "error.h"
  29. #include "cset.h"
  30. #include "font.h"
  31. #include "lib.h"
  32.  
  33. const char *const WS = " \t\n\r";
  34.  
  35. struct font_char_metric {
  36.   char type;
  37.   int code;
  38.   int width;
  39.   int height;
  40.   int depth;
  41.   int pre_math_space;
  42.   int italic_correction;
  43.   int subscript_correction;
  44. };
  45.  
  46. struct font_kern_list {
  47.   int i1;
  48.   int i2;
  49.   int amount;
  50.   font_kern_list *next;
  51.  
  52.   font_kern_list(int, int, int, font_kern_list * = 0);
  53. };
  54.  
  55. struct font_widths_cache {
  56.   font_widths_cache *next;
  57.   int point_size;
  58.   int *width;
  59.  
  60.   font_widths_cache(int, int, font_widths_cache *);
  61.   ~font_widths_cache();
  62. };
  63.  
  64. /* text_file */
  65.  
  66. struct text_file {
  67.   FILE *fp;
  68.   char *path;
  69.   int lineno;
  70.   int size;
  71.   int skip_comments;
  72.   char *buf;
  73.   text_file(FILE *fp, char *p);
  74.   ~text_file();
  75.   int next();
  76.   void error(const char *format, 
  77.          const errarg &arg1 = empty_errarg,
  78.          const errarg &arg2 = empty_errarg,
  79.          const errarg &arg3 = empty_errarg);
  80. };
  81.  
  82. text_file::text_file(FILE *p, char *s) 
  83. : lineno(0), buf(0), size(0), skip_comments(1), fp(p), path(s)
  84. {
  85. }
  86.  
  87. text_file::~text_file()
  88. {
  89.   a_delete buf;
  90.   a_delete path;
  91.   if (fp)
  92.     fclose(fp);
  93. }
  94.  
  95.  
  96. int text_file::next()
  97. {
  98.   if (fp == 0)
  99.     return 0;
  100.   if (buf == 0) {
  101.     buf = new char [128];
  102.     size = 128;
  103.   }
  104.   for (;;) {
  105.     int i = 0;
  106.     for (;;) {
  107.       int c = getc(fp);
  108.       if (c == EOF)
  109.     break;
  110.       if (illegal_input_char(c))
  111.     error("illegal input character code `%1'", int(c));
  112.       else {
  113.     if (i + 1 >= size) {
  114.       char *old_buf = buf;
  115.       buf = new char[size*2];
  116.       memcpy(buf, old_buf, size);
  117.       a_delete old_buf;
  118.       size *= 2;
  119.     }
  120.     buf[i++] = c;
  121.     if (c == '\n')
  122.       break;
  123.       }
  124.     }
  125.     if (i == 0)
  126.       break;
  127.     buf[i] = '\0';
  128.     lineno++;
  129.     char *ptr = buf;
  130.     while (csspace(*ptr))
  131.       ptr++;
  132.     if (*ptr != 0 && (!skip_comments || *ptr != '#'))
  133.       return 1;
  134.   }
  135.   return 0;
  136. }
  137.  
  138. void text_file::error(const char *format, 
  139.               const errarg &arg1,
  140.               const errarg &arg2,
  141.               const errarg &arg3)
  142. {
  143.   error_with_file_and_line(path, lineno, format, arg1, arg2, arg3);
  144. }
  145.  
  146.  
  147. /* font functions */
  148.  
  149. font::font(const char *s)
  150. : special(0), ligatures(0), kern_hash_table(0), space_width(0),
  151.   ch(0), ch_used(0), ch_size(0), ch_index(0), nindices(0), widths_cache(0)
  152. {
  153.   name = new char[strlen(s) + 1];
  154.   strcpy(name, s);
  155.   internalname = 0;
  156.   slant = 0.0;
  157.   // load();            // for testing
  158. }
  159.  
  160. font::~font()
  161. {
  162.   a_delete ch;
  163.   a_delete ch_index;
  164.   if (kern_hash_table) {
  165.     for (int i = 0; i < KERN_HASH_TABLE_SIZE; i++) {
  166.       font_kern_list *kerns = kern_hash_table[i];
  167.       while (kerns) {
  168.     font_kern_list *tem = kerns;
  169.     kerns = kerns->next;
  170.     delete tem;
  171.       }
  172.     }
  173.     a_delete kern_hash_table;
  174.   }
  175.   a_delete name;
  176.   a_delete internalname;
  177.   while (widths_cache) {
  178.     font_widths_cache *tem = widths_cache;
  179.     widths_cache = widths_cache->next;
  180.     delete tem;
  181.   }
  182. }
  183.  
  184. static int scale_round(int n, int x, int y)
  185. {
  186.   assert(x >= 0 && y > 0);
  187.   int y2 = y/2;
  188.   if (x == 0)
  189.     return 0;
  190.   if (n >= 0) {
  191.     if (n <= (INT_MAX - y2)/x)
  192.       return (n*x + y2)/y;
  193.     return int(n*double(x)/double(y) + .5);
  194.   }
  195.   else {
  196.     if (-(unsigned)n <= (-(unsigned)INT_MIN - y2)/x)
  197.       return (n*x - y2)/y;
  198.     return int(n*double(x)/double(y) - .5);
  199.   }
  200. }
  201.  
  202. inline int font::scale(int w, int sz)
  203. {
  204.   return sz == unitwidth ? w : scale_round(w, sz, unitwidth);
  205. }
  206.  
  207. int font::get_skew(int c, int point_size, int sl)
  208. {
  209.   int h = get_height(c, point_size);
  210.   return int(h*tan((slant+sl)*PI/180.0) + .5);
  211. }
  212.  
  213. int font::contains(int c)
  214. {
  215.   return c >= 0 && c < nindices && ch_index[c] >= 0;
  216. }
  217.  
  218. int font::is_special()
  219. {
  220.   return special;
  221. }
  222.  
  223. font_widths_cache::font_widths_cache(int ps, int ch_size,
  224.                      font_widths_cache *p = 0)
  225. : next(p), point_size(ps)
  226. {
  227.   width = new int[ch_size];
  228.   for (int i = 0; i < ch_size; i++)
  229.     width[i] = -1;
  230. }
  231.  
  232. font_widths_cache::~font_widths_cache()
  233. {
  234.   a_delete width;
  235. }
  236.  
  237. int font::get_width(int c, int point_size)
  238. {
  239.   assert(c >= 0 && c < nindices);
  240.   int i = ch_index[c];
  241.   assert(i >= 0);
  242.  
  243.   if (point_size == unitwidth)
  244.     return ch[i].width;
  245.  
  246.   if (!widths_cache)
  247.     widths_cache = new font_widths_cache(point_size, ch_size);
  248.   else if (widths_cache->point_size != point_size) {
  249.     font_widths_cache **p;
  250.     for (p = &widths_cache; *p; p = &(*p)->next)
  251.       if ((*p)->point_size == point_size)
  252.     break;
  253.     if (*p) {
  254.       font_widths_cache *tem = *p;
  255.       *p = (*p)->next;
  256.       tem->next = widths_cache;
  257.       widths_cache = tem;
  258.     }
  259.     else
  260.       widths_cache = new font_widths_cache(point_size, ch_size, widths_cache);
  261.   }
  262.   int &w = widths_cache->width[i];
  263.   if (w < 0)
  264.     w = scale(ch[i].width, point_size);
  265.   return w;
  266. }
  267.  
  268. int font::get_height(int c, int point_size)
  269. {
  270.   assert(c >= 0 && c < nindices && ch_index[c] >= 0);
  271.   return scale(ch[ch_index[c]].height, point_size);
  272. }
  273.  
  274. int font::get_depth(int c, int point_size)
  275. {
  276.   assert(c >= 0 && c < nindices && ch_index[c] >= 0);
  277.   return scale(ch[ch_index[c]].depth, point_size);
  278. }
  279.  
  280. int font::get_italic_correction(int c, int point_size)
  281. {
  282.   assert(c >= 0 && c < nindices && ch_index[c] >= 0);
  283.   return scale(ch[ch_index[c]].italic_correction, point_size);
  284. }
  285.  
  286. int font::get_left_italic_correction(int c, int point_size)
  287. {
  288.   assert(c >= 0 && c < nindices && ch_index[c] >= 0);
  289.   return scale(ch[ch_index[c]].pre_math_space, point_size);
  290. }
  291.  
  292. int font::get_subscript_correction(int c, int point_size)
  293. {
  294.   assert(c >= 0 && c < nindices && ch_index[c] >= 0);
  295.   return scale(ch[ch_index[c]].subscript_correction, point_size);
  296. }
  297.  
  298. int font::get_space_width(int point_size)
  299. {
  300.   return scale(space_width, point_size);
  301. }
  302.  
  303. font_kern_list::font_kern_list(int c1, int c2, int n, font_kern_list *p)
  304.      : i1(c1), i2(c2), amount(n), next(p)
  305. {
  306. }
  307.  
  308. inline int font::hash_kern(int i1, int i2)
  309. {
  310.   int n = ((i1 << 10) + i2) % KERN_HASH_TABLE_SIZE;
  311.   return n < 0 ? -n : n;
  312. }
  313.  
  314. void font::add_kern(int i1, int i2, int amount)
  315. {
  316.   if (!kern_hash_table) {
  317.     kern_hash_table = new font_kern_list *[KERN_HASH_TABLE_SIZE];
  318.     for (int i = 0; i < KERN_HASH_TABLE_SIZE; i++)
  319.       kern_hash_table[i] = 0;
  320.   }
  321.   font_kern_list **p = kern_hash_table + hash_kern(i1, i2);
  322.   *p = new font_kern_list(i1, i2, amount, *p);
  323. }
  324.  
  325. int font::get_kern(int i1, int i2, int point_size)
  326. {
  327.   if (kern_hash_table) {
  328.     for (font_kern_list *p = kern_hash_table[hash_kern(i1, i2)]; p; p = p->next)
  329.       if (i1 == p->i1 && i2 == p->i2)
  330.     return scale(p->amount, point_size);
  331.   }
  332.   return 0;
  333. }
  334.  
  335. int font::has_ligature(int mask)
  336. {
  337.   return mask & ligatures;
  338. }
  339.  
  340. int font::get_character_type(int c)
  341. {
  342.   assert(c >= 0 && c < nindices && ch_index[c] >= 0);
  343.   return ch[ch_index[c]].type;
  344. }
  345.  
  346. int font::get_code(int c)
  347. {
  348.   assert(c >= 0 && c < nindices && ch_index[c] >= 0);
  349.   return ch[ch_index[c]].code;
  350. }
  351.  
  352. const char *font::get_name()
  353. {
  354.   return name;
  355. }
  356.  
  357. const char *font::get_internal_name()
  358. {
  359.   return internalname;
  360. }
  361.  
  362. void font::alloc_ch_index(int index)
  363. {
  364.   if (nindices == 0) {
  365.     nindices = 128;
  366.     if (index >= nindices)
  367.       nindices = index + 10;
  368.     ch_index = new short[nindices];
  369.     for (int i = 0; i < nindices; i++)
  370.       ch_index[i] = -1;
  371.   }
  372.   else {
  373.     int old_nindices = nindices;
  374.     nindices *= 2;
  375.     if (index >= nindices)
  376.       nindices = index + 10;
  377.     short *old_ch_index = ch_index;
  378.     ch_index = new short[nindices];
  379.     memcpy(ch_index, old_ch_index, sizeof(short)*old_nindices);
  380.     for (int i = old_nindices; i < nindices; i++)
  381.       ch_index[i] = -1;
  382.     a_delete old_ch_index;
  383.   }
  384. }
  385.  
  386. void font::extend_ch()
  387. {
  388.   if (ch == 0)
  389.     ch = new font_char_metric[ch_size = 16];
  390.   else {
  391.     int old_ch_size = ch_size;
  392.     ch_size *= 2;
  393.     font_char_metric *old_ch = ch;
  394.     ch = new font_char_metric[ch_size];
  395.     memcpy(ch, old_ch, old_ch_size*sizeof(font_char_metric));
  396.     a_delete old_ch;
  397.   }
  398. }
  399.  
  400. void font::compact()
  401. {
  402.   int i;
  403.   for (i = nindices - 1; i >= 0; i--)
  404.     if (ch_index[i] >= 0)
  405.       break;
  406.   i++;
  407.   if (i < nindices) {
  408.     short *old_ch_index = ch_index;
  409.     ch_index = new short[i];
  410.     memcpy(ch_index, old_ch_index, i*sizeof(short));
  411.     a_delete old_ch_index;
  412.     nindices = i;
  413.   }
  414.   if (ch_used < ch_size) {
  415.     font_char_metric *old_ch = ch;
  416.     ch = new font_char_metric[ch_used];
  417.     memcpy(ch, old_ch, ch_used*sizeof(font_char_metric));
  418.     a_delete old_ch;
  419.     ch_size = ch_used;
  420.   }
  421. }
  422.  
  423. void font::add_entry(int index, const font_char_metric &metric)
  424. {
  425.   assert(index >= 0);
  426.   if (index >= nindices)
  427.     alloc_ch_index(index);
  428.   assert(index < nindices);
  429.   if (ch_used + 1 >= ch_size)
  430.     extend_ch();
  431.   assert(ch_used + 1 < ch_size);
  432.   ch_index[index] = ch_used;
  433.   ch[ch_used++] = metric;
  434. }
  435.  
  436. void font::copy_entry(int new_index, int old_index)
  437. {
  438.   assert(new_index >= 0 && old_index >= 0 && old_index < nindices);
  439.   if (new_index >= nindices)
  440.     alloc_ch_index(new_index);
  441.   ch_index[new_index] = ch_index[old_index];
  442. }
  443.  
  444. font *font::load_font(const char *s, int *not_found)
  445. {
  446.   font *f = new font(s);
  447.   if (!f->load(not_found)) {
  448.     delete f;
  449.     return 0;
  450.   }
  451.   return f;
  452. }
  453.  
  454. static char *trim_arg(char *p)
  455. {
  456.   if (!p)
  457.     return 0;
  458.   while (csspace(*p))
  459.     p++;
  460.   char *q = strchr(p, '\0');
  461.   while (q > p && csspace(q[-1]))
  462.     q--;
  463.   *q = '\0';
  464.   return p;
  465. }
  466.  
  467. // If the font can't be found, then if not_found is NULL it will be set
  468. // to 1 otherwise a message will be printed.
  469.  
  470. int font::load(int *not_found)
  471. {
  472.   char *path;
  473.   FILE *fp;
  474.   if ((fp = open_file(name, &path)) == NULL) {
  475.     if (not_found)
  476.       *not_found = 1;
  477.     else
  478.       error("can't find font file `%1'", name);
  479.     return 0;
  480.   }
  481.   text_file t(fp, path);
  482.   t.skip_comments = 1;
  483.   char *p;
  484.   for (;;) {
  485.     if (!t.next()) {
  486.       t.error("missing charset command");
  487.       return 0;
  488.     }
  489.     p = strtok(t.buf, WS);
  490.     if (strcmp(p, "name") == 0) {
  491.     }
  492.     else if (strcmp(p, "spacewidth") == 0) {
  493.       p = strtok(0, WS);
  494.       int n;
  495.       if (p == 0 || sscanf(p, "%d", &n) != 1 || n <= 0) {
  496.     t.error("bad argument for spacewidth command");
  497.     return 0;
  498.       }
  499.       space_width = n;
  500.     }
  501.     else if (strcmp(p, "slant") == 0) {
  502.       p = strtok(0, WS);
  503.       double n;
  504.       if (p == 0 || sscanf(p, "%lf", &n) != 1 || n >= 90.0 || n <= -90.0) {
  505.     t.error("bad argument for slant command", p);
  506.     return 0;
  507.       }
  508.       slant = n;
  509.     }
  510.     else if (strcmp(p, "ligatures") == 0) {
  511.       for (;;) {
  512.     p = strtok(0, WS);
  513.     if (p == 0 || strcmp(p, "0") == 0)
  514.       break;
  515.     if (strcmp(p, "ff") == 0)
  516.       ligatures |= LIG_ff;
  517.     else if (strcmp(p, "fi") == 0)
  518.       ligatures |= LIG_fi;
  519.     else if (strcmp(p, "fl") == 0)
  520.       ligatures |= LIG_fl;
  521.     else if (strcmp(p, "ffi") == 0)
  522.       ligatures |= LIG_ffi;
  523.     else if (strcmp(p, "ffl") == 0)
  524.       ligatures |= LIG_ffl;
  525.     else {
  526.       t.error("unrecognised ligature `%1'", p);
  527.       return 0;
  528.     }
  529.       }
  530.     }
  531.     else if (strcmp(p, "internalname") == 0) {
  532.       p = strtok(0, WS);
  533.       if (!p) {
  534.     t.error("`internalname command requires argument");
  535.     return 0;
  536.       }
  537.       internalname = new char[strlen(p) + 1];
  538.       strcpy(internalname, p);
  539.     }
  540.     else if (strcmp(p, "special") == 0) {
  541.       special = 1;
  542.     }
  543.     else if (strcmp(p, "kernpairs") != 0 && strcmp(p, "charset") != 0) {
  544.       char *command = p;
  545.       p = strtok(0, "\n");
  546.       handle_unknown_font_command(command, trim_arg(p), t.path, t.lineno);
  547.     }
  548.     else
  549.       break;
  550.   }
  551.   char *command = p;
  552.   int had_charset = 0;
  553.   t.skip_comments = 0;
  554.   while (command) {
  555.     if (strcmp(command, "kernpairs") == 0) {
  556.       for (;;) {
  557.     if (!t.next()) {
  558.       command = 0;
  559.       break;
  560.     }
  561.     char *c1 = strtok(t.buf, WS);
  562.     if (c1 == 0)
  563.       continue;
  564.     char *c2 = strtok(0, WS);
  565.     if (c2 == 0) {
  566.       command = c1;
  567.       break;
  568.     }
  569.     p = strtok(0, WS);
  570.     if (p == 0) {
  571.       t.error("missing kern amount");
  572.       return 0;
  573.     }
  574.     int n;
  575.     if (sscanf(p, "%d", &n) != 1) {
  576.       t.error("bad kern amount `%1'", p);
  577.       return 0;
  578.     }
  579.     int i1 = name_to_index(c1);
  580.     if (i1 < 0) {
  581.       t.error("illegal character `%1'", c1);
  582.       return 0;
  583.     }
  584.     int i2 = name_to_index(c2);
  585.     if (i2 < 0) {
  586.       t.error("illegal character `%1'", c2);
  587.       return 0;
  588.     }
  589.     add_kern(i1, i2, n);
  590.       }
  591.     }
  592.     else if (strcmp(command, "charset") == 0) {
  593.       had_charset = 1;
  594.       int last_index = -1;
  595.       for (;;) {
  596.     if (!t.next()) {
  597.       command = 0;
  598.       break;
  599.     }
  600.     char *nm = strtok(t.buf, WS);
  601.     if (nm == 0)
  602.       continue;            // I dont think this should happen
  603.     p = strtok(0, WS);
  604.     if (p == 0) {
  605.       command = nm;
  606.       break;
  607.     }
  608.     if (p[0] == '"') {
  609.       if (last_index == -1) {
  610.         t.error("first charset entry is duplicate");
  611.         return 0;
  612.       }
  613.       if (strcmp(nm, "---") == 0) {
  614.         t.error("unnamed character cannot be duplicate");
  615.         return 0;
  616.       }
  617.       int index = name_to_index(nm);
  618.       if (index < 0) {
  619.         t.error("illegal character `%1'", nm);
  620.         return 0;
  621.       }
  622.       copy_entry(index, last_index);
  623.     }
  624.     else {
  625.       font_char_metric metric;
  626.       metric.height = 0;
  627.       metric.depth = 0;
  628.       metric.pre_math_space = 0;
  629.       metric.italic_correction = 0;
  630.       metric.subscript_correction = 0;
  631.       int nparms = sscanf(p, "%d,%d,%d,%d,%d,%d",
  632.                   &metric.width, &metric.height, &metric.depth,
  633.                   &metric.italic_correction,
  634.                   &metric.pre_math_space,
  635.                   &metric.subscript_correction);
  636.       if (nparms < 1) {
  637.         t.error("bad width for `%1'", nm);
  638.         return 0;
  639.       }
  640.       p = strtok(0, WS);
  641.       if (p == 0) {
  642.         t.error("missing character type for `%1'", nm);
  643.         return 0;
  644.       }
  645.       int type;
  646.       if (sscanf(p, "%d", &type) != 1) {
  647.         t.error("bad character type for `%1'", nm);
  648.         return 0;
  649.       }
  650.       if (type < 0 || type > 255) {
  651.         t.error("character code `%1' out of range", type);
  652.         return 0;
  653.       }
  654.       metric.type = type;
  655.       p = strtok(0, WS);
  656.       if (p == 0) {
  657.         t.error("missing code for `%1'", nm);
  658.         return 0;
  659.       }
  660.       char *ptr;
  661.       metric.code = (int)strtol(p, &ptr, 0);
  662.       if (metric.code == 0 && ptr == p) {
  663.         t.error("bad code `%1' for character `%2'", p, nm);
  664.         return 0;
  665.       }
  666.       if (strcmp(nm, "---") == 0) {
  667.         last_index = number_to_index(metric.code);
  668.         add_entry(last_index, metric);
  669.       }
  670.       else {
  671.         last_index = name_to_index(nm);
  672.         if (last_index < 0) {
  673.           t.error("illegal character `%1'", nm);
  674.           return 0;
  675.         }
  676.         add_entry(last_index, metric);
  677.         copy_entry(number_to_index(metric.code), last_index);
  678.       }
  679.     }
  680.       }
  681.       if (last_index == -1) {
  682.     t.error("I didn't seem to find any characters");
  683.     return 0;
  684.       }
  685.     }
  686.     else {
  687.       t.error("unrecognised command `%1' after `kernpairs' or `charset' command", command);
  688.       return 0;
  689.     }
  690.   }
  691.   if (!had_charset) {
  692.     t.error("missing charset command");
  693.     return 0;
  694.   }
  695.   if (space_width == 0)
  696.     space_width = scale_round(unitwidth, res, 72*3*sizescale);
  697.   compact();
  698.   return 1;
  699. }
  700.  
  701. static struct {
  702.   const char *command;
  703.   int *ptr;
  704. } table[] = {
  705.   { "res", &font::res },
  706.   { "hor", &font::hor },
  707.   { "vert", &font::vert },
  708.   { "unitwidth", &font::unitwidth },
  709.   { "paperwidth", &font::paperwidth },
  710.   { "paperlength", &font::paperlength },
  711.   { "spare1", &font::biggestfont },
  712.   { "biggestfont", &font::biggestfont },
  713.   { "spare2", &font::spare2 },
  714.   { "sizescale", &font::sizescale }
  715.   };
  716.  
  717.  
  718. int font::load_desc()
  719. {
  720.   int nfonts = 0;
  721.   FILE *fp;
  722.   char *path;
  723.   if ((fp = open_file("DESC", &path)) == 0) {
  724.     error("can't find `DESC' file");
  725.     return 0;
  726.   }
  727.   text_file t(fp, path);
  728.   t.skip_comments = 1;
  729.   res = 0;
  730.   while (t.next()) {
  731.     char *p = strtok(t.buf, WS);
  732.     int found = 0;
  733.     int i;
  734.     for (i = 0; !found && i < sizeof(table)/sizeof(table[0]); i++)
  735.       if (strcmp(table[i].command, p) == 0)
  736.     found = 1;
  737.     if (found) {
  738.       char *q = strtok(0, WS);
  739.       if (!q) {
  740.     t.error("missing value for command `%1'", p);
  741.     return 0;
  742.       }
  743.       //int *ptr = &(this->*(table[i-1].ptr));
  744.       int *ptr = table[i-1].ptr;
  745.       if (sscanf(q, "%d", ptr) != 1) {
  746.     t.error("bad number `%1'", q);
  747.     return 0;
  748.       }
  749.     }
  750.     else if (strcmp("tcommand", p) == 0) {
  751.       tcommand = 1;
  752.     }
  753.     else if (strcmp("family", p) == 0) {
  754.       p = strtok(0, WS);
  755.       if (!p) {
  756.     t.error("family command requires an argument");
  757.     return 0;
  758.       }
  759.       char *tem = new char[strlen(p)+1];
  760.       strcpy(tem, p);
  761.       family = tem;
  762.     }
  763.     else if (strcmp("fonts", p) == 0) {
  764.       p = strtok(0, WS);
  765.       if (!p || sscanf(p, "%d", &nfonts) != 1 || nfonts <= 0) {
  766.     t.error("bad number of fonts `%1'", p);
  767.     return 0;
  768.       }
  769.       font_name_table = (const char **)new char *[nfonts+1]; 
  770.       for (int i = 0; i < nfonts; i++) {
  771.     p = strtok(0, WS);
  772.     while (p == 0) {
  773.       if (!t.next()) {
  774.         t.error("end of file while reading list of fonts");
  775.         return 0;
  776.       }
  777.       p = strtok(t.buf, WS);
  778.     }
  779.     char *temp = new char[strlen(p)+1];
  780.     strcpy(temp, p);
  781.     font_name_table[i] = temp;
  782.       }
  783.       p = strtok(0, WS);
  784.       if (p != 0) {
  785.     t.error("font count does not match number of fonts");
  786.     return 0;
  787.       }
  788.       font_name_table[nfonts] = 0;
  789.     }
  790.     else if (strcmp("sizes", p) == 0) {
  791.       int n = 16;
  792.       sizes = new int[n];
  793.       int i = 0;
  794.       for (;;) {
  795.     p = strtok(0, WS);
  796.     while (p == 0) {
  797.       if (!t.next()) {
  798.         t.error("list of sizes must be terminated by `0'");
  799.         return 0;
  800.       }
  801.       p = strtok(t.buf, WS);
  802.     }
  803.     int lower, upper;
  804.     switch (sscanf(p, "%d-%d", &lower, &upper)) {
  805.     case 1:
  806.       upper = lower;
  807.       // fall through
  808.     case 2:
  809.       if (lower <= upper && lower >= 0)
  810.         break;
  811.       // fall through
  812.     default:
  813.       t.error("bad size range `%1'", p);
  814.       return 0;
  815.     }
  816.     if (i + 2 > n) {
  817.       int *old_sizes = sizes;
  818.       sizes = new int[n*2];
  819.       memcpy(sizes, old_sizes, n*sizeof(int));
  820.       n *= 2;
  821.       a_delete old_sizes;
  822.     }
  823.     sizes[i++] = lower;
  824.     if (lower == 0)
  825.       break;
  826.     sizes[i++] = upper;
  827.       }
  828.       if (i == 1) {
  829.     t.error("must have some sizes");
  830.     return 0;
  831.       }
  832.     }
  833.     else if (strcmp("styles", p) == 0) {
  834.       int style_table_size = 5;
  835.       style_table = (const char **)new char *[style_table_size];
  836.       int j;
  837.       for (j = 0; j < style_table_size; j++)
  838.     style_table[j] = 0;
  839.       int i = 0;
  840.       for (;;) {
  841.     p = strtok(0, WS);
  842.     if (p == 0)
  843.       break;
  844.     // leave room for terminating 0
  845.     if (i + 1 >= style_table_size) {
  846.       const char **old_style_table = style_table;
  847.       style_table_size *= 2;
  848.       style_table = (const char **)new char*[style_table_size];
  849.       for (j = 0; j < i; j++)
  850.         style_table[j] = old_style_table[j];
  851.       for (; j < style_table_size; j++)
  852.         style_table[j] = 0;
  853.       a_delete old_style_table;
  854.     }
  855.     char *tem = new char[strlen(p) + 1];
  856.     strcpy(tem, p);
  857.     style_table[i++] = tem;
  858.       }
  859.     }
  860.     else if (strcmp("charset", p) == 0)
  861.       break;
  862.     else if (unknown_desc_command_handler) {
  863.       char *command = p;
  864.       p = strtok(0, "\n");
  865.       (*unknown_desc_command_handler)(command, trim_arg(p), t.path, t.lineno);
  866.     }
  867.   }
  868.   if (res == 0) {
  869.     t.error("missing `res' command");
  870.     return 0;
  871.   }
  872.   if (unitwidth == 0) {
  873.     t.error("missing `unitwidth' command");
  874.     return 0;
  875.   }
  876.   if (font_name_table == 0) {
  877.     t.error("missing `fonts' command");
  878.     return 0;
  879.   }
  880.   if (sizes == 0) {
  881.     t.error("missing `sizes' command");
  882.     return 0;
  883.   }
  884.   if (sizescale < 1) {
  885.     t.error("bad `sizescale' value");
  886.     return 0;
  887.   }
  888.   if (hor < 1) {
  889.     t.error("bad `hor' value");
  890.     return 0;
  891.   }
  892.   if (vert < 1) {
  893.     t.error("bad `vert' value");
  894.     return 0;
  895.   }
  896.   return 1;
  897. }      
  898.  
  899. void font::handle_unknown_font_command(const char *, const char *,
  900.                        const char *, int)
  901. {
  902. }
  903.  
  904. FONT_COMMAND_HANDLER
  905. font::set_unknown_desc_command_handler(FONT_COMMAND_HANDLER func)
  906. {
  907.   FONT_COMMAND_HANDLER prev = unknown_desc_command_handler;
  908.   unknown_desc_command_handler = func;
  909.   return prev;
  910. }
  911.  
  912.