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