13 #include <X11/Intrinsic.h>
19 #define isascii(c) (1)
22 /* Name of environment variable containing path to be used for
23 searching for device and font description files. */
24 #define FONTPATH_ENV_VAR "GROFF_FONT_PATH"
29 /* Minimum and maximum values a `signed int' can hold. */
30 #define INT_MIN (-INT_MAX-1)
31 #define INT_MAX 2147483647
34 #define CHAR_TABLE_SIZE 307
41 struct charinfo *char_table[CHAR_TABLE_SIZE];
42 struct charinfo *code_table[256];
48 struct charinfo *next;
49 struct charinfo *code_next;
53 static char *current_filename = 0;
54 static int current_lineno = -1;
56 static void error(const char *s);
57 static FILE *open_device_file(const char *, const char *, char **);
58 static DeviceFont *load_font(Device *, const char *);
59 static Device *new_device(const char *);
60 static DeviceFont *new_font(const char *, Device *);
61 static void delete_font(DeviceFont *);
62 static unsigned hash_name(const char *);
63 static struct charinfo *add_char(DeviceFont *, const char *, int, int);
64 static int read_charset_section(DeviceFont *, FILE *);
65 static char *canonicalize_name(const char *);
66 static int scale_round(int, int, int);
69 Device *new_device(const char *name)
81 dev->name = XtNewString(name);
85 void device_destroy(Device *dev)
102 Device *device_load(const char *name)
109 fp = open_device_file(name, "DESC", ¤t_filename);
112 dev = new_device(name);
114 while (fgets(buf, sizeof(buf), fp)) {
122 if (strcmp(p, "charset") == 0)
124 if (strcmp(p, "X11") == 0)
126 else if (strcmp(p, "sizescale") == 0)
127 np = &dev->sizescale;
128 else if (strcmp(p, "res") == 0)
130 else if (strcmp(p, "unitwidth") == 0)
131 np = &dev->unitwidth;
132 else if (strcmp(p, "paperwidth") == 0)
133 np = &dev->paperwidth;
134 else if (strcmp(p, "paperlength") == 0)
135 np = &dev->paperlength;
138 q = strtok((char *)0, WS);
139 if (!q || sscanf(q, "%d", np) != 1 || *np <= 0) {
140 error("bad argument");
151 error("missing res line");
154 else if (dev->unitwidth == 0) {
155 error("missing unitwidth line");
159 if (dev->paperlength == 0)
160 dev->paperlength = dev->res*11;
161 if (dev->paperwidth == 0)
162 dev->paperwidth = dev->res*8 + dev->res/2;
167 XtFree(current_filename);
168 current_filename = 0;
173 DeviceFont *device_find_font(Device *dev, const char *name)
179 for (f = dev->fonts; f; f = f->next)
180 if (strcmp(f->name, name) == 0)
182 return load_font(dev, name);
186 DeviceFont *load_font(Device *dev, const char *name)
193 fp = open_device_file(dev->name, name, ¤t_filename);
200 if (!fgets(buf, sizeof(buf), fp)) {
201 error("no charset line");
206 /* charset must be on a line by itself */
207 if (p && strcmp(p, "charset") == 0 && strtok((char *)0, WS) == 0)
209 if (p && strcmp(p, "special") == 0)
212 f = new_font(name, dev);
213 f->special = special;
214 if (!read_charset_section(f, fp)) {
219 f->next = dev->fonts;
223 XtFree(current_filename);
224 current_filename = 0;
229 DeviceFont *new_font(const char *name, Device *dev)
234 f = XtNew(DeviceFont);
235 f->name = XtNewString(name);
239 for (i = 0; i < CHAR_TABLE_SIZE; i++)
240 f->char_table[i] = 0;
241 for (i = 0; i < 256; i++)
242 f->code_table[i] = 0;
247 void delete_font(DeviceFont *f)
254 for (i = 0; i < CHAR_TABLE_SIZE; i++) {
255 struct charinfo *ptr = f->char_table[i];
257 struct charinfo *tem = ptr;
267 unsigned hash_name(const char *name)
270 /* XXX do better than this */
272 n = (n << 1) ^ *name++;
278 int scale_round(int n, int x, int y)
286 if (n <= (INT_MAX - y2)/x)
288 return (int)(n*(double)x/(double)y + .5);
291 if (-(unsigned)n <= (-(unsigned)INT_MIN - y2)/x)
293 return (int)(n*(double)x/(double)y + .5);
298 char *canonicalize_name(const char *s)
301 if (s[0] == 'c' && s[1] == 'h' && s[2] == 'a' && s[3] == 'r') {
305 for (p = s + 4; *p; p++)
306 if (!isascii(*p) || !isdigit((unsigned char)*p))
309 if (n >= 0 && n <= 0xff) {
317 /* Return 1 if the character is present in the font; widthp gets the
318 width if non-null. */
320 int device_char_width(DeviceFont *f, int ps, const char *name, int *widthp)
324 name = canonicalize_name(name);
325 for (p = f->char_table[hash_name(name) % CHAR_TABLE_SIZE];; p = p->next) {
328 if (strcmp(p->name, name) == 0)
331 *widthp = scale_round(p->width, ps, f->dev->unitwidth);
335 int device_code_width(DeviceFont *f, int ps, int code, int *widthp)
339 for (p = f->code_table[code & 0xff];; p = p->code_next) {
345 *widthp = scale_round(p->width, ps, f->dev->unitwidth);
349 char *device_name_for_code(DeviceFont *f, int code)
351 static struct charinfo *state = 0;
353 state = f->code_table[code & 0xff];
354 for (; state; state = state->code_next)
355 if (state->code == code && state->name[0] != '\0') {
356 char *name = state->name;
357 state = state->code_next;
363 int device_font_special(DeviceFont *f)
369 struct charinfo *add_char(DeviceFont *f, const char *name, int width, int code)
371 struct charinfo **pp;
374 name = canonicalize_name(name);
375 if (strcmp(name, "---") == 0)
378 ci = (struct charinfo *)XtMalloc(XtOffsetOf(struct charinfo, name[0])
381 strcpy(ci->name, name);
386 pp = &f->char_table[hash_name(name) % CHAR_TABLE_SIZE];
390 pp = &f->code_table[code & 0xff];
396 /* Return non-zero for success. */
399 int read_charset_section(DeviceFont *f, FILE *fp)
401 struct charinfo *last_charinfo = 0;
404 while (fgets(buf, sizeof(buf), fp)) {
411 name = strtok(buf, WS);
413 continue; /* ignore blank lines */
414 p = strtok((char *)0, WS);
415 if (!p) /* end of charset section */
417 if (strcmp(p, "\"") == 0) {
418 if (!last_charinfo) {
419 error("first line of charset section cannot use `\"'");
423 (void)add_char(f, name,
424 last_charinfo->width, last_charinfo->code);
428 if (sscanf(p, "%d", &width) != 1) {
429 error("bad width field");
432 p = strtok((char *)0, WS);
434 error("missing type field");
437 p = strtok((char *)0, WS);
439 error("missing code field");
442 code = (int)strtol(p, &q, 0);
444 error("bad code field");
447 last_charinfo = add_char(f, name, width, code);
454 FILE *find_file(const char *file, char **result)
463 env = getenv(FONTPATH_ENV_VAR);
464 path = XtMalloc(((env && *env) ? strlen(env) + 1 : 0)
465 + strlen(FONTPATH) + 1);
471 strcat(path, FONTPATH);
481 fp = fopen(file, "r");
483 *result = XtNewString(file);
494 end = strchr(path, ':');
498 path = end = strchr(path, '\0');
503 len = (end - start) + 1 + flen + 1;
506 buf = XtRealloc(buf, len);
511 memcpy(buf, start, end - start);
512 buf[end - start] = '/';
513 strcpy(buf + (end - start) + 1, file);
514 fp = fopen(buf, "r");
525 FILE *open_device_file(const char *device_name, const char *file_name,
531 buf = XtMalloc(3 + strlen(device_name) + 1 + strlen(file_name) + 1);
532 sprintf(buf, "dev%s/%s", device_name, file_name);
533 fp = find_file(buf, result);
535 fprintf(stderr, "can't find device file `%s'\n", file_name);
543 void error(const char *s)
545 if (current_filename) {
546 fprintf(stderr, "%s:", current_filename);
547 if (current_lineno > 0)
548 fprintf(stderr, "%d:", current_lineno);
559 c-continued-statement-offset: 4
563 c-tab-always-indent: nil