PageRenderTime 59ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/src/freebsd/contrib/groff/src/libs/libgroff/font.cpp

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