home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / groff / libgroff / font.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-30  |  17.9 KB  |  820 lines

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