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