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