7 #include <X11/Intrinsic.h>
12 #define FONTPATH "/usr/local/share/groff/font:/usr/local/lib/font:/usr/lib/font"
16 #define isascii(c) (1)
21 extern char *strtok();
24 extern char *strchr();
27 extern char *getenv();
30 /* Name of environment variable containing path to be used for
31 searching for device and font description files. */
32 #define FONTPATH_ENV_VAR "GROFF_FONT_PATH"
37 /* Minimum and maximum values a `signed int' can hold. */
38 #define INT_MIN (-INT_MAX-1)
39 #define INT_MAX 2147483647
42 #define CHAR_TABLE_SIZE 307
49 struct charinfo *char_table[CHAR_TABLE_SIZE];
50 struct charinfo *code_table[256];
56 struct charinfo *next;
57 struct charinfo *code_next;
61 static char *current_filename = 0;
62 static int current_lineno = -1;
65 static FILE *open_device_file();
66 static DeviceFont *load_font();
67 static Device *new_device();
68 static DeviceFont *new_font();
69 static void delete_font();
70 static unsigned hash_name();
71 static struct charinfo *add_char();
72 static int read_charset_section();
73 static char *canonicalize_name();
76 Device *new_device(name)
89 dev->name = XtNewString(name);
93 void device_destroy(dev)
111 Device *device_load(name)
119 fp = open_device_file(name, "DESC", ¤t_filename);
122 dev = new_device(name);
124 while (fgets(buf, sizeof(buf), fp)) {
132 if (strcmp(p, "charset") == 0)
134 if (strcmp(p, "X11") == 0)
136 else if (strcmp(p, "sizescale") == 0)
137 np = &dev->sizescale;
138 else if (strcmp(p, "res") == 0)
140 else if (strcmp(p, "unitwidth") == 0)
141 np = &dev->unitwidth;
142 else if (strcmp(p, "paperwidth") == 0)
143 np = &dev->paperwidth;
144 else if (strcmp(p, "paperlength") == 0)
145 np = &dev->paperlength;
148 q = strtok((char *)0, WS);
149 if (!q || sscanf(q, "%d", np) != 1 || *np <= 0) {
150 error("bad argument");
161 error("missing res line");
164 else if (dev->unitwidth == 0) {
165 error("missing unitwidth line");
169 if (dev->paperlength == 0)
170 dev->paperlength = dev->res*11;
171 if (dev->paperwidth == 0)
172 dev->paperwidth = dev->res*8 + dev->res/2;
177 XtFree(current_filename);
178 current_filename = 0;
183 DeviceFont *device_find_font(dev, name)
191 for (f = dev->fonts; f; f = f->next)
192 if (strcmp(f->name, name) == 0)
194 return load_font(dev, name);
198 DeviceFont *load_font(dev, name)
207 fp = open_device_file(dev->name, name, ¤t_filename);
214 if (!fgets(buf, sizeof(buf), fp)) {
215 error("no charset line");
220 /* charset must be on a line by itself */
221 if (p && strcmp(p, "charset") == 0 && strtok((char *)0, WS) == 0)
223 if (p && strcmp(p, "special") == 0)
226 f = new_font(name, dev);
227 f->special = special;
228 if (!read_charset_section(f, fp)) {
233 f->next = dev->fonts;
237 XtFree(current_filename);
238 current_filename = 0;
243 DeviceFont *new_font(name, dev)
250 f = XtNew(DeviceFont);
251 f->name = XtNewString(name);
255 for (i = 0; i < CHAR_TABLE_SIZE; i++)
256 f->char_table[i] = 0;
257 for (i = 0; i < 256; i++)
258 f->code_table[i] = 0;
271 for (i = 0; i < CHAR_TABLE_SIZE; i++) {
272 struct charinfo *ptr = f->char_table[i];
274 struct charinfo *tem = ptr;
284 unsigned hash_name(name)
288 /* XXX do better than this */
290 n = (n << 1) ^ *name++;
296 int scale_round(n, x, y)
305 if (n <= (INT_MAX - y2)/x)
308 else if (-(unsigned)n <= (-(unsigned)INT_MIN - y2)/x)
310 return (int)(n*(double)x/(double)y + .5);
314 char *canonicalize_name(s)
318 if (s[0] == 'c' && s[1] == 'h' && s[2] == 'a' && s[3] == 'r') {
322 for (p = s + 4; *p; p++)
323 if (!isascii(*p) || !isdigit((unsigned char)*p))
326 if (n >= 0 && n <= 0xff) {
334 /* Return 1 if the character is present in the font; widthp gets the
335 width if non-null. */
337 int device_char_width(f, ps, name, widthp)
345 name = canonicalize_name(name);
346 for (p = f->char_table[hash_name(name) % CHAR_TABLE_SIZE];; p = p->next) {
349 if (strcmp(p->name, name) == 0)
352 *widthp = scale_round(p->width, ps, f->dev->unitwidth);
356 int device_code_width(f, ps, code, widthp)
364 for (p = f->code_table[code & 0xff];; p = p->code_next) {
370 *widthp = scale_round(p->width, ps, f->dev->unitwidth);
374 char *device_name_for_code(f, code)
378 static struct charinfo *state = 0;
380 state = f->code_table[code & 0xff];
381 for (; state; state = state->code_next)
382 if (state->code == code && state->name[0] != '\0') {
383 char *name = state->name;
384 state = state->code_next;
390 int device_font_special(f)
397 struct charinfo *add_char(f, name, width, code)
402 struct charinfo **pp;
405 name = canonicalize_name(name);
406 if (strcmp(name, "---") == 0)
409 ci = (struct charinfo *)XtMalloc(XtOffsetOf(struct charinfo, name[0])
412 strcpy(ci->name, name);
417 pp = &f->char_table[hash_name(name) % CHAR_TABLE_SIZE];
421 pp = &f->code_table[code & 0xff];
427 /* Return non-zero for success. */
430 int read_charset_section(f, fp)
434 struct charinfo *last_charinfo = 0;
437 while (fgets(buf, sizeof(buf), fp)) {
444 name = strtok(buf, WS);
446 continue; /* ignore blank lines */
447 p = strtok((char *)0, WS);
448 if (!p) /* end of charset section */
450 if (strcmp(p, "\"") == 0) {
451 if (!last_charinfo) {
452 error("first line of charset section cannot use `\"'");
456 (void)add_char(f, name,
457 last_charinfo->width, last_charinfo->code);
461 if (sscanf(p, "%d", &width) != 1) {
462 error("bad width field");
465 p = strtok((char *)0, WS);
467 error("missing type field");
470 p = strtok((char *)0, WS);
472 error("missing code field");
475 code = (int)strtol(p, &q, 0);
477 error("bad code field");
480 last_charinfo = add_char(f, name, width, code);
487 FILE *find_file(file, result)
488 char *file, **result;
497 env = getenv(FONTPATH_ENV_VAR);
498 path = XtMalloc(((env && *env) ? strlen(env) + 1 : 0)
499 + strlen(FONTPATH) + 1);
505 strcat(path, FONTPATH);
515 fp = fopen(file, "r");
517 *result = XtNewString(file);
528 end = strchr(path, ':');
532 path = end = strchr(path, '\0');
537 len = (end - start) + 1 + flen + 1;
540 buf = XtRealloc(buf, len);
545 memcpy(buf, start, end - start);
546 buf[end - start] = '/';
547 strcpy(buf + (end - start) + 1, file);
548 fp = fopen(buf, "r");
559 FILE *open_device_file(device_name, file_name, result)
560 char *device_name, *file_name, **result;
565 buf = XtMalloc(3 + strlen(device_name) + 1 + strlen(file_name) + 1);
566 sprintf(buf, "dev%s/%s", device_name, file_name);
567 fp = find_file(buf, result);
569 fprintf(stderr, "can't find device file `%s'\n", file_name);
580 if (current_filename) {
581 fprintf(stderr, "%s:", current_filename);
582 if (current_lineno > 0)
583 fprintf(stderr, "%d:", current_lineno);
594 c-continued-statement-offset: 4
598 c-tab-always-indent: nil