1114402Sru// -*- C++ -*- 2151497Sru/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004, 2005 3114402Sru Free Software Foundation, Inc. 4114402Sru Written by James Clark (jjc@jclark.com) 5114402Sru 6114402SruThis file is part of groff. 7114402Sru 8114402Srugroff is free software; you can redistribute it and/or modify it under 9114402Sruthe terms of the GNU General Public License as published by the Free 10114402SruSoftware Foundation; either version 2, or (at your option) any later 11114402Sruversion. 12114402Sru 13114402Srugroff is distributed in the hope that it will be useful, but WITHOUT ANY 14114402SruWARRANTY; without even the implied warranty of MERCHANTABILITY or 15114402SruFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16114402Srufor more details. 17114402Sru 18114402SruYou should have received a copy of the GNU General Public License along 19114402Sruwith groff; see the file COPYING. If not, write to the Free Software 20151497SruFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */ 21114402Sru 22114402Sru#include "lib.h" 23114402Sru 24114402Sru#include <ctype.h> 25114402Sru#include <assert.h> 26114402Sru#include <math.h> 27114402Sru#include <stdlib.h> 28114402Sru#include "errarg.h" 29114402Sru#include "error.h" 30114402Sru#include "cset.h" 31114402Sru#include "font.h" 32114402Sru#include "paper.h" 33114402Sru 34114402Sruconst char *const WS = " \t\n\r"; 35114402Sru 36114402Srustruct font_char_metric { 37114402Sru char type; 38114402Sru int code; 39114402Sru int width; 40114402Sru int height; 41114402Sru int depth; 42114402Sru int pre_math_space; 43114402Sru int italic_correction; 44114402Sru int subscript_correction; 45114402Sru char *special_device_coding; 46114402Sru}; 47114402Sru 48114402Srustruct font_kern_list { 49114402Sru int i1; 50114402Sru int i2; 51114402Sru int amount; 52114402Sru font_kern_list *next; 53114402Sru 54114402Sru font_kern_list(int, int, int, font_kern_list * = 0); 55114402Sru}; 56114402Sru 57114402Srustruct font_widths_cache { 58114402Sru font_widths_cache *next; 59114402Sru int point_size; 60114402Sru int *width; 61114402Sru 62114402Sru font_widths_cache(int, int, font_widths_cache * = 0); 63114402Sru ~font_widths_cache(); 64114402Sru}; 65114402Sru 66114402Sru/* text_file */ 67114402Sru 68114402Srustruct text_file { 69114402Sru FILE *fp; 70114402Sru char *path; 71114402Sru int lineno; 72114402Sru int size; 73114402Sru int skip_comments; 74151497Sru int silent; 75114402Sru char *buf; 76114402Sru text_file(FILE *fp, char *p); 77114402Sru ~text_file(); 78114402Sru int next(); 79114402Sru void error(const char *format, 80114402Sru const errarg &arg1 = empty_errarg, 81114402Sru const errarg &arg2 = empty_errarg, 82114402Sru const errarg &arg3 = empty_errarg); 83114402Sru}; 84114402Sru 85114402Srutext_file::text_file(FILE *p, char *s) 86151497Sru: fp(p), path(s), lineno(0), size(0), skip_comments(1), silent(0), buf(0) 87114402Sru{ 88114402Sru} 89114402Sru 90114402Srutext_file::~text_file() 91114402Sru{ 92114402Sru a_delete buf; 93114402Sru a_delete path; 94114402Sru if (fp) 95114402Sru fclose(fp); 96114402Sru} 97114402Sru 98114402Sruint text_file::next() 99114402Sru{ 100114402Sru if (fp == 0) 101114402Sru return 0; 102114402Sru if (buf == 0) { 103114402Sru buf = new char[128]; 104114402Sru size = 128; 105114402Sru } 106114402Sru for (;;) { 107114402Sru int i = 0; 108114402Sru for (;;) { 109114402Sru int c = getc(fp); 110114402Sru if (c == EOF) 111114402Sru break; 112114402Sru if (invalid_input_char(c)) 113114402Sru error("invalid input character code `%1'", int(c)); 114114402Sru else { 115114402Sru if (i + 1 >= size) { 116114402Sru char *old_buf = buf; 117114402Sru buf = new char[size*2]; 118114402Sru memcpy(buf, old_buf, size); 119114402Sru a_delete old_buf; 120114402Sru size *= 2; 121114402Sru } 122114402Sru buf[i++] = c; 123114402Sru if (c == '\n') 124114402Sru break; 125114402Sru } 126114402Sru } 127114402Sru if (i == 0) 128114402Sru break; 129114402Sru buf[i] = '\0'; 130114402Sru lineno++; 131114402Sru char *ptr = buf; 132114402Sru while (csspace(*ptr)) 133114402Sru ptr++; 134114402Sru if (*ptr != 0 && (!skip_comments || *ptr != '#')) 135114402Sru return 1; 136114402Sru } 137114402Sru return 0; 138114402Sru} 139114402Sru 140114402Sruvoid text_file::error(const char *format, 141114402Sru const errarg &arg1, 142114402Sru const errarg &arg2, 143114402Sru const errarg &arg3) 144114402Sru{ 145151497Sru if (!silent) 146151497Sru error_with_file_and_line(path, lineno, format, arg1, arg2, arg3); 147114402Sru} 148114402Sru 149114402Sru 150114402Sru/* font functions */ 151114402Sru 152114402Srufont::font(const char *s) 153114402Sru: ligatures(0), kern_hash_table(0), space_width(0), ch_index(0), nindices(0), 154114402Sru ch(0), ch_used(0), ch_size(0), special(0), widths_cache(0) 155114402Sru{ 156114402Sru name = new char[strlen(s) + 1]; 157114402Sru strcpy(name, s); 158114402Sru internalname = 0; 159114402Sru slant = 0.0; 160114402Sru // load(); // for testing 161114402Sru} 162114402Sru 163114402Srufont::~font() 164114402Sru{ 165114402Sru for (int i = 0; i < ch_used; i++) 166114402Sru if (ch[i].special_device_coding) 167114402Sru a_delete ch[i].special_device_coding; 168114402Sru a_delete ch; 169114402Sru a_delete ch_index; 170114402Sru if (kern_hash_table) { 171114402Sru for (int i = 0; i < KERN_HASH_TABLE_SIZE; i++) { 172114402Sru font_kern_list *kerns = kern_hash_table[i]; 173114402Sru while (kerns) { 174114402Sru font_kern_list *tem = kerns; 175114402Sru kerns = kerns->next; 176114402Sru delete tem; 177114402Sru } 178114402Sru } 179114402Sru a_delete kern_hash_table; 180114402Sru } 181114402Sru a_delete name; 182114402Sru a_delete internalname; 183114402Sru while (widths_cache) { 184114402Sru font_widths_cache *tem = widths_cache; 185114402Sru widths_cache = widths_cache->next; 186114402Sru delete tem; 187114402Sru } 188114402Sru} 189114402Sru 190114402Srustatic int scale_round(int n, int x, int y) 191114402Sru{ 192114402Sru assert(x >= 0 && y > 0); 193114402Sru int y2 = y/2; 194114402Sru if (x == 0) 195114402Sru return 0; 196114402Sru if (n >= 0) { 197114402Sru if (n <= (INT_MAX - y2)/x) 198114402Sru return (n*x + y2)/y; 199114402Sru return int(n*double(x)/double(y) + .5); 200114402Sru } 201114402Sru else { 202114402Sru if (-(unsigned)n <= (-(unsigned)INT_MIN - y2)/x) 203114402Sru return (n*x - y2)/y; 204114402Sru return int(n*double(x)/double(y) - .5); 205114402Sru } 206114402Sru} 207114402Sru 208114402Sruinline int font::scale(int w, int sz) 209114402Sru{ 210114402Sru return sz == unitwidth ? w : scale_round(w, sz, unitwidth); 211114402Sru} 212114402Sru 213114402Sruint font::unit_scale(double *value, char unit) 214114402Sru{ 215114402Sru // we scale everything to inch 216114402Sru double divisor = 0; 217114402Sru switch (unit) { 218114402Sru case 'i': 219114402Sru divisor = 1; 220114402Sru break; 221114402Sru case 'p': 222114402Sru divisor = 72; 223114402Sru break; 224114402Sru case 'P': 225114402Sru divisor = 6; 226114402Sru break; 227114402Sru case 'c': 228114402Sru divisor = 2.54; 229114402Sru break; 230114402Sru default: 231114402Sru assert(0); 232114402Sru break; 233114402Sru } 234114402Sru if (divisor) { 235114402Sru *value /= divisor; 236114402Sru return 1; 237114402Sru } 238114402Sru return 0; 239114402Sru} 240114402Sru 241114402Sruint font::get_skew(int c, int point_size, int sl) 242114402Sru{ 243114402Sru int h = get_height(c, point_size); 244114402Sru return int(h*tan((slant+sl)*PI/180.0) + .5); 245114402Sru} 246114402Sru 247114402Sruint font::contains(int c) 248114402Sru{ 249114402Sru return c >= 0 && c < nindices && ch_index[c] >= 0; 250114402Sru} 251114402Sru 252114402Sruint font::is_special() 253114402Sru{ 254114402Sru return special; 255114402Sru} 256114402Sru 257114402Srufont_widths_cache::font_widths_cache(int ps, int ch_size, 258114402Sru font_widths_cache *p) 259114402Sru: next(p), point_size(ps) 260114402Sru{ 261114402Sru width = new int[ch_size]; 262114402Sru for (int i = 0; i < ch_size; i++) 263114402Sru width[i] = -1; 264114402Sru} 265114402Sru 266114402Srufont_widths_cache::~font_widths_cache() 267114402Sru{ 268114402Sru a_delete width; 269114402Sru} 270114402Sru 271114402Sruint font::get_width(int c, int point_size) 272114402Sru{ 273114402Sru assert(c >= 0 && c < nindices); 274114402Sru int i = ch_index[c]; 275114402Sru assert(i >= 0); 276114402Sru 277151497Sru if (point_size == unitwidth || font::unscaled_charwidths) 278114402Sru return ch[i].width; 279114402Sru 280114402Sru if (!widths_cache) 281114402Sru widths_cache = new font_widths_cache(point_size, ch_size); 282114402Sru else if (widths_cache->point_size != point_size) { 283114402Sru font_widths_cache **p; 284114402Sru for (p = &widths_cache; *p; p = &(*p)->next) 285114402Sru if ((*p)->point_size == point_size) 286114402Sru break; 287114402Sru if (*p) { 288114402Sru font_widths_cache *tem = *p; 289114402Sru *p = (*p)->next; 290114402Sru tem->next = widths_cache; 291114402Sru widths_cache = tem; 292114402Sru } 293114402Sru else 294114402Sru widths_cache = new font_widths_cache(point_size, ch_size, widths_cache); 295114402Sru } 296114402Sru int &w = widths_cache->width[i]; 297114402Sru if (w < 0) 298114402Sru w = scale(ch[i].width, point_size); 299114402Sru return w; 300114402Sru} 301114402Sru 302114402Sruint font::get_height(int c, int point_size) 303114402Sru{ 304114402Sru assert(c >= 0 && c < nindices && ch_index[c] >= 0); 305114402Sru return scale(ch[ch_index[c]].height, point_size); 306114402Sru} 307114402Sru 308114402Sruint font::get_depth(int c, int point_size) 309114402Sru{ 310114402Sru assert(c >= 0 && c < nindices && ch_index[c] >= 0); 311114402Sru return scale(ch[ch_index[c]].depth, point_size); 312114402Sru} 313114402Sru 314114402Sruint font::get_italic_correction(int c, int point_size) 315114402Sru{ 316114402Sru assert(c >= 0 && c < nindices && ch_index[c] >= 0); 317114402Sru return scale(ch[ch_index[c]].italic_correction, point_size); 318114402Sru} 319114402Sru 320114402Sruint font::get_left_italic_correction(int c, int point_size) 321114402Sru{ 322114402Sru assert(c >= 0 && c < nindices && ch_index[c] >= 0); 323114402Sru return scale(ch[ch_index[c]].pre_math_space, point_size); 324114402Sru} 325114402Sru 326114402Sruint font::get_subscript_correction(int c, int point_size) 327114402Sru{ 328114402Sru assert(c >= 0 && c < nindices && ch_index[c] >= 0); 329114402Sru return scale(ch[ch_index[c]].subscript_correction, point_size); 330114402Sru} 331114402Sru 332114402Sruint font::get_space_width(int point_size) 333114402Sru{ 334114402Sru return scale(space_width, point_size); 335114402Sru} 336114402Sru 337114402Srufont_kern_list::font_kern_list(int c1, int c2, int n, font_kern_list *p) 338114402Sru: i1(c1), i2(c2), amount(n), next(p) 339114402Sru{ 340114402Sru} 341114402Sru 342114402Sruinline int font::hash_kern(int i1, int i2) 343114402Sru{ 344114402Sru int n = ((i1 << 10) + i2) % KERN_HASH_TABLE_SIZE; 345114402Sru return n < 0 ? -n : n; 346114402Sru} 347114402Sru 348114402Sruvoid font::add_kern(int i1, int i2, int amount) 349114402Sru{ 350114402Sru if (!kern_hash_table) { 351114402Sru kern_hash_table = new font_kern_list *[int(KERN_HASH_TABLE_SIZE)]; 352114402Sru for (int i = 0; i < KERN_HASH_TABLE_SIZE; i++) 353114402Sru kern_hash_table[i] = 0; 354114402Sru } 355114402Sru font_kern_list **p = kern_hash_table + hash_kern(i1, i2); 356114402Sru *p = new font_kern_list(i1, i2, amount, *p); 357114402Sru} 358114402Sru 359114402Sruint font::get_kern(int i1, int i2, int point_size) 360114402Sru{ 361114402Sru if (kern_hash_table) { 362114402Sru for (font_kern_list *p = kern_hash_table[hash_kern(i1, i2)]; p; p = p->next) 363114402Sru if (i1 == p->i1 && i2 == p->i2) 364114402Sru return scale(p->amount, point_size); 365114402Sru } 366114402Sru return 0; 367114402Sru} 368114402Sru 369114402Sruint font::has_ligature(int mask) 370114402Sru{ 371114402Sru return mask & ligatures; 372114402Sru} 373114402Sru 374114402Sruint font::get_character_type(int c) 375114402Sru{ 376114402Sru assert(c >= 0 && c < nindices && ch_index[c] >= 0); 377114402Sru return ch[ch_index[c]].type; 378114402Sru} 379114402Sru 380114402Sruint font::get_code(int c) 381114402Sru{ 382114402Sru assert(c >= 0 && c < nindices && ch_index[c] >= 0); 383114402Sru return ch[ch_index[c]].code; 384114402Sru} 385114402Sru 386114402Sruconst char *font::get_name() 387114402Sru{ 388114402Sru return name; 389114402Sru} 390114402Sru 391114402Sruconst char *font::get_internal_name() 392114402Sru{ 393114402Sru return internalname; 394114402Sru} 395114402Sru 396114402Sruconst char *font::get_special_device_encoding(int c) 397114402Sru{ 398114402Sru assert(c >= 0 && c < nindices && ch_index[c] >= 0); 399151497Sru return ch[ch_index[c]].special_device_coding; 400114402Sru} 401114402Sru 402151497Sruconst char *font::get_image_generator() 403114402Sru{ 404151497Sru return image_generator; 405151497Sru} 406151497Sru 407151497Sruvoid font::alloc_ch_index(int idx) 408151497Sru{ 409114402Sru if (nindices == 0) { 410114402Sru nindices = 128; 411151497Sru if (idx >= nindices) 412151497Sru nindices = idx + 10; 413151497Sru ch_index = new int[nindices]; 414114402Sru for (int i = 0; i < nindices; i++) 415114402Sru ch_index[i] = -1; 416114402Sru } 417114402Sru else { 418114402Sru int old_nindices = nindices; 419114402Sru nindices *= 2; 420151497Sru if (idx >= nindices) 421151497Sru nindices = idx + 10; 422151497Sru int *old_ch_index = ch_index; 423151497Sru ch_index = new int[nindices]; 424151497Sru memcpy(ch_index, old_ch_index, sizeof(int)*old_nindices); 425114402Sru for (int i = old_nindices; i < nindices; i++) 426114402Sru ch_index[i] = -1; 427114402Sru a_delete old_ch_index; 428114402Sru } 429114402Sru} 430114402Sru 431114402Sruvoid font::extend_ch() 432114402Sru{ 433114402Sru if (ch == 0) 434114402Sru ch = new font_char_metric[ch_size = 16]; 435114402Sru else { 436114402Sru int old_ch_size = ch_size; 437114402Sru ch_size *= 2; 438114402Sru font_char_metric *old_ch = ch; 439114402Sru ch = new font_char_metric[ch_size]; 440114402Sru memcpy(ch, old_ch, old_ch_size*sizeof(font_char_metric)); 441114402Sru a_delete old_ch; 442114402Sru } 443114402Sru} 444114402Sru 445114402Sruvoid font::compact() 446114402Sru{ 447114402Sru int i; 448114402Sru for (i = nindices - 1; i >= 0; i--) 449114402Sru if (ch_index[i] >= 0) 450114402Sru break; 451114402Sru i++; 452114402Sru if (i < nindices) { 453151497Sru int *old_ch_index = ch_index; 454151497Sru ch_index = new int[i]; 455151497Sru memcpy(ch_index, old_ch_index, i*sizeof(int)); 456114402Sru a_delete old_ch_index; 457114402Sru nindices = i; 458114402Sru } 459114402Sru if (ch_used < ch_size) { 460114402Sru font_char_metric *old_ch = ch; 461114402Sru ch = new font_char_metric[ch_used]; 462114402Sru memcpy(ch, old_ch, ch_used*sizeof(font_char_metric)); 463114402Sru a_delete old_ch; 464114402Sru ch_size = ch_used; 465114402Sru } 466114402Sru} 467114402Sru 468151497Sruvoid font::add_entry(int idx, const font_char_metric &metric) 469114402Sru{ 470151497Sru assert(idx >= 0); 471151497Sru if (idx >= nindices) 472151497Sru alloc_ch_index(idx); 473151497Sru assert(idx < nindices); 474114402Sru if (ch_used + 1 >= ch_size) 475114402Sru extend_ch(); 476114402Sru assert(ch_used + 1 < ch_size); 477151497Sru ch_index[idx] = ch_used; 478114402Sru ch[ch_used++] = metric; 479114402Sru} 480114402Sru 481114402Sruvoid font::copy_entry(int new_index, int old_index) 482114402Sru{ 483114402Sru assert(new_index >= 0 && old_index >= 0 && old_index < nindices); 484114402Sru if (new_index >= nindices) 485114402Sru alloc_ch_index(new_index); 486114402Sru ch_index[new_index] = ch_index[old_index]; 487114402Sru} 488114402Sru 489151497Srufont *font::load_font(const char *s, int *not_found, int head_only) 490114402Sru{ 491114402Sru font *f = new font(s); 492151497Sru if (!f->load(not_found, head_only)) { 493114402Sru delete f; 494114402Sru return 0; 495114402Sru } 496114402Sru return f; 497114402Sru} 498114402Sru 499114402Srustatic char *trim_arg(char *p) 500114402Sru{ 501114402Sru if (!p) 502114402Sru return 0; 503114402Sru while (csspace(*p)) 504114402Sru p++; 505114402Sru char *q = strchr(p, '\0'); 506114402Sru while (q > p && csspace(q[-1])) 507114402Sru q--; 508114402Sru *q = '\0'; 509114402Sru return p; 510114402Sru} 511114402Sru 512114402Sruint font::scan_papersize(const char *p, 513114402Sru const char **size, double *length, double *width) 514114402Sru{ 515114402Sru double l, w; 516114402Sru char lu[2], wu[2]; 517114402Sru const char *pp = p; 518114402Sru int test_file = 1; 519114402Sru char line[255]; 520114402Sruagain: 521114402Sru if (csdigit(*pp)) { 522114402Sru if (sscanf(pp, "%lf%1[ipPc],%lf%1[ipPc]", &l, lu, &w, wu) == 4 523114402Sru && l > 0 && w > 0 524114402Sru && unit_scale(&l, lu[0]) && unit_scale(&w, wu[0])) { 525114402Sru if (length) 526114402Sru *length = l; 527114402Sru if (width) 528114402Sru *width = w; 529114402Sru if (size) 530114402Sru *size = "custom"; 531114402Sru return 1; 532114402Sru } 533114402Sru } 534114402Sru else { 535114402Sru int i; 536114402Sru for (i = 0; i < NUM_PAPERSIZES; i++) 537114402Sru if (strcasecmp(papersizes[i].name, pp) == 0) { 538114402Sru if (length) 539114402Sru *length = papersizes[i].length; 540114402Sru if (width) 541114402Sru *width = papersizes[i].width; 542114402Sru if (size) 543114402Sru *size = papersizes[i].name; 544114402Sru return 1; 545114402Sru } 546114402Sru if (test_file) { 547114402Sru FILE *f = fopen(p, "r"); 548114402Sru if (f) { 549114402Sru fgets(line, 254, f); 550114402Sru fclose(f); 551114402Sru test_file = 0; 552114402Sru char *linep = strchr(line, '\0'); 553114402Sru // skip final newline, if any 554114402Sru if (*(--linep) == '\n') 555114402Sru *linep = '\0'; 556114402Sru pp = line; 557114402Sru goto again; 558114402Sru } 559114402Sru } 560114402Sru } 561114402Sru return 0; 562114402Sru} 563114402Sru 564114402Sru// If the font can't be found, then if not_found is non-NULL, it will be set 565114402Sru// to 1 otherwise a message will be printed. 566114402Sru 567151497Sruint font::load(int *not_found, int head_only) 568114402Sru{ 569114402Sru char *path; 570114402Sru FILE *fp; 571114402Sru if ((fp = open_file(name, &path)) == NULL) { 572114402Sru if (not_found) 573114402Sru *not_found = 1; 574114402Sru else 575114402Sru error("can't find font file `%1'", name); 576114402Sru return 0; 577114402Sru } 578114402Sru text_file t(fp, path); 579114402Sru t.skip_comments = 1; 580151497Sru t.silent = head_only; 581114402Sru char *p; 582114402Sru for (;;) { 583114402Sru if (!t.next()) { 584114402Sru t.error("missing charset command"); 585114402Sru return 0; 586114402Sru } 587114402Sru p = strtok(t.buf, WS); 588114402Sru if (strcmp(p, "name") == 0) { 589114402Sru } 590114402Sru else if (strcmp(p, "spacewidth") == 0) { 591114402Sru p = strtok(0, WS); 592114402Sru int n; 593114402Sru if (p == 0 || sscanf(p, "%d", &n) != 1 || n <= 0) { 594114402Sru t.error("bad argument for spacewidth command"); 595114402Sru return 0; 596114402Sru } 597114402Sru space_width = n; 598114402Sru } 599114402Sru else if (strcmp(p, "slant") == 0) { 600114402Sru p = strtok(0, WS); 601114402Sru double n; 602114402Sru if (p == 0 || sscanf(p, "%lf", &n) != 1 || n >= 90.0 || n <= -90.0) { 603114402Sru t.error("bad argument for slant command", p); 604114402Sru return 0; 605114402Sru } 606114402Sru slant = n; 607114402Sru } 608114402Sru else if (strcmp(p, "ligatures") == 0) { 609114402Sru for (;;) { 610114402Sru p = strtok(0, WS); 611114402Sru if (p == 0 || strcmp(p, "0") == 0) 612114402Sru break; 613114402Sru if (strcmp(p, "ff") == 0) 614114402Sru ligatures |= LIG_ff; 615114402Sru else if (strcmp(p, "fi") == 0) 616114402Sru ligatures |= LIG_fi; 617114402Sru else if (strcmp(p, "fl") == 0) 618114402Sru ligatures |= LIG_fl; 619114402Sru else if (strcmp(p, "ffi") == 0) 620114402Sru ligatures |= LIG_ffi; 621114402Sru else if (strcmp(p, "ffl") == 0) 622114402Sru ligatures |= LIG_ffl; 623114402Sru else { 624114402Sru t.error("unrecognised ligature `%1'", p); 625114402Sru return 0; 626114402Sru } 627114402Sru } 628114402Sru } 629114402Sru else if (strcmp(p, "internalname") == 0) { 630114402Sru p = strtok(0, WS); 631114402Sru if (!p) { 632114402Sru t.error("`internalname command requires argument"); 633114402Sru return 0; 634114402Sru } 635114402Sru internalname = new char[strlen(p) + 1]; 636114402Sru strcpy(internalname, p); 637114402Sru } 638114402Sru else if (strcmp(p, "special") == 0) { 639114402Sru special = 1; 640114402Sru } 641114402Sru else if (strcmp(p, "kernpairs") != 0 && strcmp(p, "charset") != 0) { 642114402Sru char *command = p; 643114402Sru p = strtok(0, "\n"); 644114402Sru handle_unknown_font_command(command, trim_arg(p), t.path, t.lineno); 645114402Sru } 646114402Sru else 647114402Sru break; 648114402Sru } 649151497Sru if (head_only) 650151497Sru return 1; 651114402Sru char *command = p; 652114402Sru int had_charset = 0; 653114402Sru t.skip_comments = 0; 654114402Sru while (command) { 655114402Sru if (strcmp(command, "kernpairs") == 0) { 656114402Sru for (;;) { 657114402Sru if (!t.next()) { 658114402Sru command = 0; 659114402Sru break; 660114402Sru } 661114402Sru char *c1 = strtok(t.buf, WS); 662114402Sru if (c1 == 0) 663114402Sru continue; 664114402Sru char *c2 = strtok(0, WS); 665114402Sru if (c2 == 0) { 666114402Sru command = c1; 667114402Sru break; 668114402Sru } 669114402Sru p = strtok(0, WS); 670114402Sru if (p == 0) { 671114402Sru t.error("missing kern amount"); 672114402Sru return 0; 673114402Sru } 674114402Sru int n; 675114402Sru if (sscanf(p, "%d", &n) != 1) { 676114402Sru t.error("bad kern amount `%1'", p); 677114402Sru return 0; 678114402Sru } 679114402Sru int i1 = name_to_index(c1); 680114402Sru if (i1 < 0) { 681114402Sru t.error("invalid character `%1'", c1); 682114402Sru return 0; 683114402Sru } 684114402Sru int i2 = name_to_index(c2); 685114402Sru if (i2 < 0) { 686114402Sru t.error("invalid character `%1'", c2); 687114402Sru return 0; 688114402Sru } 689114402Sru add_kern(i1, i2, n); 690114402Sru } 691114402Sru } 692114402Sru else if (strcmp(command, "charset") == 0) { 693114402Sru had_charset = 1; 694114402Sru int last_index = -1; 695114402Sru for (;;) { 696114402Sru if (!t.next()) { 697114402Sru command = 0; 698114402Sru break; 699114402Sru } 700114402Sru char *nm = strtok(t.buf, WS); 701114402Sru if (nm == 0) 702114402Sru continue; // I dont think this should happen 703114402Sru p = strtok(0, WS); 704114402Sru if (p == 0) { 705114402Sru command = nm; 706114402Sru break; 707114402Sru } 708114402Sru if (p[0] == '"') { 709114402Sru if (last_index == -1) { 710114402Sru t.error("first charset entry is duplicate"); 711114402Sru return 0; 712114402Sru } 713114402Sru if (strcmp(nm, "---") == 0) { 714114402Sru t.error("unnamed character cannot be duplicate"); 715114402Sru return 0; 716114402Sru } 717151497Sru int idx = name_to_index(nm); 718151497Sru if (idx < 0) { 719114402Sru t.error("invalid character `%1'", nm); 720114402Sru return 0; 721114402Sru } 722151497Sru copy_entry(idx, last_index); 723114402Sru } 724114402Sru else { 725114402Sru font_char_metric metric; 726114402Sru metric.height = 0; 727114402Sru metric.depth = 0; 728114402Sru metric.pre_math_space = 0; 729114402Sru metric.italic_correction = 0; 730114402Sru metric.subscript_correction = 0; 731114402Sru int nparms = sscanf(p, "%d,%d,%d,%d,%d,%d", 732114402Sru &metric.width, &metric.height, &metric.depth, 733114402Sru &metric.italic_correction, 734114402Sru &metric.pre_math_space, 735114402Sru &metric.subscript_correction); 736114402Sru if (nparms < 1) { 737114402Sru t.error("bad width for `%1'", nm); 738114402Sru return 0; 739114402Sru } 740114402Sru p = strtok(0, WS); 741114402Sru if (p == 0) { 742114402Sru t.error("missing character type for `%1'", nm); 743114402Sru return 0; 744114402Sru } 745114402Sru int type; 746114402Sru if (sscanf(p, "%d", &type) != 1) { 747114402Sru t.error("bad character type for `%1'", nm); 748114402Sru return 0; 749114402Sru } 750114402Sru if (type < 0 || type > 255) { 751114402Sru t.error("character type `%1' out of range", type); 752114402Sru return 0; 753114402Sru } 754114402Sru metric.type = type; 755114402Sru p = strtok(0, WS); 756114402Sru if (p == 0) { 757114402Sru t.error("missing code for `%1'", nm); 758114402Sru return 0; 759114402Sru } 760114402Sru char *ptr; 761114402Sru metric.code = (int)strtol(p, &ptr, 0); 762114402Sru if (metric.code == 0 && ptr == p) { 763114402Sru t.error("bad code `%1' for character `%2'", p, nm); 764114402Sru return 0; 765114402Sru } 766114402Sru p = strtok(0, WS); 767114402Sru if ((p == NULL) || (strcmp(p, "--") == 0)) { 768114402Sru metric.special_device_coding = NULL; 769114402Sru } 770114402Sru else { 771151497Sru char *nam = new char[strlen(p) + 1]; 772151497Sru strcpy(nam, p); 773151497Sru metric.special_device_coding = nam; 774114402Sru } 775114402Sru if (strcmp(nm, "---") == 0) { 776114402Sru last_index = number_to_index(metric.code); 777114402Sru add_entry(last_index, metric); 778114402Sru } 779114402Sru else { 780114402Sru last_index = name_to_index(nm); 781114402Sru if (last_index < 0) { 782114402Sru t.error("invalid character `%1'", nm); 783114402Sru return 0; 784114402Sru } 785114402Sru add_entry(last_index, metric); 786114402Sru copy_entry(number_to_index(metric.code), last_index); 787114402Sru } 788114402Sru } 789114402Sru } 790114402Sru if (last_index == -1) { 791114402Sru t.error("I didn't seem to find any characters"); 792114402Sru return 0; 793114402Sru } 794114402Sru } 795114402Sru else { 796114402Sru t.error("unrecognised command `%1' after `kernpairs' or `charset' command", command); 797114402Sru return 0; 798114402Sru } 799114402Sru } 800114402Sru if (!had_charset) { 801114402Sru t.error("missing charset command"); 802114402Sru return 0; 803114402Sru } 804114402Sru if (space_width == 0) 805114402Sru space_width = scale_round(unitwidth, res, 72*3*sizescale); 806114402Sru compact(); 807114402Sru return 1; 808114402Sru} 809114402Sru 810114402Srustatic struct { 811114402Sru const char *command; 812114402Sru int *ptr; 813114402Sru} table[] = { 814114402Sru { "res", &font::res }, 815114402Sru { "hor", &font::hor }, 816114402Sru { "vert", &font::vert }, 817114402Sru { "unitwidth", &font::unitwidth }, 818114402Sru { "paperwidth", &font::paperwidth }, 819114402Sru { "paperlength", &font::paperlength }, 820114402Sru { "spare1", &font::biggestfont }, 821114402Sru { "biggestfont", &font::biggestfont }, 822114402Sru { "spare2", &font::spare2 }, 823151497Sru { "sizescale", &font::sizescale }, 824114402Sru }; 825114402Sru 826114402Sruint font::load_desc() 827114402Sru{ 828114402Sru int nfonts = 0; 829114402Sru FILE *fp; 830114402Sru char *path; 831114402Sru if ((fp = open_file("DESC", &path)) == 0) { 832114402Sru error("can't find `DESC' file"); 833114402Sru return 0; 834114402Sru } 835114402Sru text_file t(fp, path); 836114402Sru t.skip_comments = 1; 837114402Sru res = 0; 838114402Sru while (t.next()) { 839114402Sru char *p = strtok(t.buf, WS); 840114402Sru int found = 0; 841114402Sru unsigned int idx; 842114402Sru for (idx = 0; !found && idx < sizeof(table)/sizeof(table[0]); idx++) 843114402Sru if (strcmp(table[idx].command, p) == 0) 844114402Sru found = 1; 845114402Sru if (found) { 846114402Sru char *q = strtok(0, WS); 847114402Sru if (!q) { 848114402Sru t.error("missing value for command `%1'", p); 849114402Sru return 0; 850114402Sru } 851114402Sru //int *ptr = &(this->*(table[idx-1].ptr)); 852114402Sru int *ptr = table[idx-1].ptr; 853114402Sru if (sscanf(q, "%d", ptr) != 1) { 854114402Sru t.error("bad number `%1'", q); 855114402Sru return 0; 856114402Sru } 857114402Sru } 858114402Sru else if (strcmp("family", p) == 0) { 859114402Sru p = strtok(0, WS); 860114402Sru if (!p) { 861114402Sru t.error("family command requires an argument"); 862114402Sru return 0; 863114402Sru } 864114402Sru char *tem = new char[strlen(p)+1]; 865114402Sru strcpy(tem, p); 866114402Sru family = tem; 867114402Sru } 868114402Sru else if (strcmp("fonts", p) == 0) { 869114402Sru p = strtok(0, WS); 870114402Sru if (!p || sscanf(p, "%d", &nfonts) != 1 || nfonts <= 0) { 871114402Sru t.error("bad number of fonts `%1'", p); 872114402Sru return 0; 873114402Sru } 874114402Sru font_name_table = (const char **)new char *[nfonts+1]; 875114402Sru for (int i = 0; i < nfonts; i++) { 876114402Sru p = strtok(0, WS); 877114402Sru while (p == 0) { 878114402Sru if (!t.next()) { 879114402Sru t.error("end of file while reading list of fonts"); 880114402Sru return 0; 881114402Sru } 882114402Sru p = strtok(t.buf, WS); 883114402Sru } 884114402Sru char *temp = new char[strlen(p)+1]; 885114402Sru strcpy(temp, p); 886114402Sru font_name_table[i] = temp; 887114402Sru } 888114402Sru p = strtok(0, WS); 889114402Sru if (p != 0) { 890114402Sru t.error("font count does not match number of fonts"); 891114402Sru return 0; 892114402Sru } 893114402Sru font_name_table[nfonts] = 0; 894114402Sru } 895114402Sru else if (strcmp("papersize", p) == 0) { 896114402Sru p = strtok(0, WS); 897114402Sru if (!p) { 898114402Sru t.error("papersize command requires an argument"); 899114402Sru return 0; 900114402Sru } 901114402Sru int found_paper = 0; 902114402Sru while (p) { 903114402Sru double unscaled_paperwidth, unscaled_paperlength; 904114402Sru if (scan_papersize(p, &papersize, &unscaled_paperlength, 905114402Sru &unscaled_paperwidth)) { 906114402Sru paperwidth = int(unscaled_paperwidth * res + 0.5); 907114402Sru paperlength = int(unscaled_paperlength * res + 0.5); 908114402Sru found_paper = 1; 909114402Sru break; 910114402Sru } 911114402Sru p = strtok(0, WS); 912114402Sru } 913114402Sru if (!found_paper) { 914114402Sru t.error("bad paper size"); 915114402Sru return 0; 916114402Sru } 917114402Sru } 918151497Sru else if (strcmp("unscaled_charwidths", p) == 0) 919151497Sru unscaled_charwidths = 1; 920114402Sru else if (strcmp("pass_filenames", p) == 0) 921114402Sru pass_filenames = 1; 922114402Sru else if (strcmp("sizes", p) == 0) { 923114402Sru int n = 16; 924114402Sru sizes = new int[n]; 925114402Sru int i = 0; 926114402Sru for (;;) { 927114402Sru p = strtok(0, WS); 928114402Sru while (p == 0) { 929114402Sru if (!t.next()) { 930114402Sru t.error("list of sizes must be terminated by `0'"); 931114402Sru return 0; 932114402Sru } 933114402Sru p = strtok(t.buf, WS); 934114402Sru } 935114402Sru int lower, upper; 936114402Sru switch (sscanf(p, "%d-%d", &lower, &upper)) { 937114402Sru case 1: 938114402Sru upper = lower; 939114402Sru // fall through 940114402Sru case 2: 941114402Sru if (lower <= upper && lower >= 0) 942114402Sru break; 943114402Sru // fall through 944114402Sru default: 945114402Sru t.error("bad size range `%1'", p); 946114402Sru return 0; 947114402Sru } 948114402Sru if (i + 2 > n) { 949114402Sru int *old_sizes = sizes; 950114402Sru sizes = new int[n*2]; 951114402Sru memcpy(sizes, old_sizes, n*sizeof(int)); 952114402Sru n *= 2; 953114402Sru a_delete old_sizes; 954114402Sru } 955114402Sru sizes[i++] = lower; 956114402Sru if (lower == 0) 957114402Sru break; 958114402Sru sizes[i++] = upper; 959114402Sru } 960114402Sru if (i == 1) { 961114402Sru t.error("must have some sizes"); 962114402Sru return 0; 963114402Sru } 964114402Sru } 965114402Sru else if (strcmp("styles", p) == 0) { 966114402Sru int style_table_size = 5; 967114402Sru style_table = (const char **)new char *[style_table_size]; 968114402Sru int j; 969114402Sru for (j = 0; j < style_table_size; j++) 970114402Sru style_table[j] = 0; 971114402Sru int i = 0; 972114402Sru for (;;) { 973114402Sru p = strtok(0, WS); 974114402Sru if (p == 0) 975114402Sru break; 976114402Sru // leave room for terminating 0 977114402Sru if (i + 1 >= style_table_size) { 978114402Sru const char **old_style_table = style_table; 979114402Sru style_table_size *= 2; 980114402Sru style_table = (const char **)new char*[style_table_size]; 981114402Sru for (j = 0; j < i; j++) 982114402Sru style_table[j] = old_style_table[j]; 983114402Sru for (; j < style_table_size; j++) 984114402Sru style_table[j] = 0; 985114402Sru a_delete old_style_table; 986114402Sru } 987114402Sru char *tem = new char[strlen(p) + 1]; 988114402Sru strcpy(tem, p); 989114402Sru style_table[i++] = tem; 990114402Sru } 991114402Sru } 992114402Sru else if (strcmp("tcommand", p) == 0) 993114402Sru tcommand = 1; 994114402Sru else if (strcmp("use_charnames_in_special", p) == 0) 995114402Sru use_charnames_in_special = 1; 996151497Sru else if (strcmp("image_generator", p) == 0) { 997151497Sru p = strtok(0, WS); 998151497Sru if (!p) { 999151497Sru t.error("image_generator command requires an argument"); 1000151497Sru return 0; 1001151497Sru } 1002151497Sru image_generator = strsave(p); 1003151497Sru } 1004114402Sru else if (strcmp("charset", p) == 0) 1005114402Sru break; 1006114402Sru else if (unknown_desc_command_handler) { 1007114402Sru char *command = p; 1008114402Sru p = strtok(0, "\n"); 1009114402Sru (*unknown_desc_command_handler)(command, trim_arg(p), t.path, t.lineno); 1010114402Sru } 1011114402Sru } 1012114402Sru if (res == 0) { 1013114402Sru t.error("missing `res' command"); 1014114402Sru return 0; 1015114402Sru } 1016114402Sru if (unitwidth == 0) { 1017114402Sru t.error("missing `unitwidth' command"); 1018114402Sru return 0; 1019114402Sru } 1020114402Sru if (font_name_table == 0) { 1021114402Sru t.error("missing `fonts' command"); 1022114402Sru return 0; 1023114402Sru } 1024114402Sru if (sizes == 0) { 1025114402Sru t.error("missing `sizes' command"); 1026114402Sru return 0; 1027114402Sru } 1028114402Sru if (sizescale < 1) { 1029114402Sru t.error("bad `sizescale' value"); 1030114402Sru return 0; 1031114402Sru } 1032114402Sru if (hor < 1) { 1033114402Sru t.error("bad `hor' value"); 1034114402Sru return 0; 1035114402Sru } 1036114402Sru if (vert < 1) { 1037114402Sru t.error("bad `vert' value"); 1038114402Sru return 0; 1039114402Sru } 1040114402Sru return 1; 1041114402Sru} 1042114402Sru 1043114402Sruvoid font::handle_unknown_font_command(const char *, const char *, 1044114402Sru const char *, int) 1045114402Sru{ 1046114402Sru} 1047114402Sru 1048114402SruFONT_COMMAND_HANDLER 1049114402Srufont::set_unknown_desc_command_handler(FONT_COMMAND_HANDLER func) 1050114402Sru{ 1051114402Sru FONT_COMMAND_HANDLER prev = unknown_desc_command_handler; 1052114402Sru unknown_desc_command_handler = func; 1053114402Sru return prev; 1054114402Sru} 1055