8 #include <X11/Intrinsic.h>
13 #define FONTPATH "/usr/local/share/groff/font:/usr/local/lib/font:/usr/lib/font"
17 #define isascii(c) (1)
22 extern char *strtok();
25 extern char *strchr();
28 extern char *getenv();
31 /* Name of environment variable containing path to be used for
32 searching for device and font description files. */
33 #define FONTPATH_ENV_VAR "GROFF_FONT_PATH"
38 /* Minimum and maximum values a `signed int' can hold. */
39 #define INT_MIN (-INT_MAX-1)
40 #define INT_MAX 2147483647
43 #define CHAR_TABLE_SIZE 307
50 struct charinfo *char_table[CHAR_TABLE_SIZE];
51 struct charinfo *code_table[256];
57 struct charinfo *next;
58 struct charinfo *code_next;
62 static char *current_filename = 0;
63 static int current_lineno = -1;
66 static FILE *open_device_file();
67 static DeviceFont *load_font();
68 static Device *new_device();
69 static DeviceFont *new_font();
70 static void delete_font();
71 static unsigned hash_name();
72 static struct charinfo *add_char();
73 static int read_charset_section();
74 static char *canonicalize_name();
77 Device *new_device(name)
90 dev->name = XtNewString(name);
94 void device_destroy(dev)
112 Device *device_load(name)
120 fp = open_device_file(name, "DESC", ¤t_filename);
123 dev = new_device(name);
125 while (fgets(buf, sizeof(buf), fp)) {
133 if (strcmp(p, "charset") == 0)
135 if (strcmp(p, "X11") == 0)
137 else if (strcmp(p, "sizescale") == 0)
138 np = &dev->sizescale;
139 else if (strcmp(p, "res") == 0)
141 else if (strcmp(p, "unitwidth") == 0)
142 np = &dev->unitwidth;
143 else if (strcmp(p, "paperwidth") == 0)
144 np = &dev->paperwidth;
145 else if (strcmp(p, "paperlength") == 0)
146 np = &dev->paperlength;
149 q = strtok((char *)0, WS);
150 if (!q || sscanf(q, "%d", np) != 1 || *np <= 0) {
151 error("bad argument");
162 error("missing res line");
165 else if (dev->unitwidth == 0) {
166 error("missing unitwidth line");
170 if (dev->paperlength == 0)
171 dev->paperlength = dev->res*11;
172 if (dev->paperwidth == 0)
173 dev->paperwidth = dev->res*8 + dev->res/2;
178 XtFree(current_filename);
179 current_filename = 0;
184 DeviceFont *device_find_font(dev, name)
192 for (f = dev->fonts; f; f = f->next)
193 if (strcmp(f->name, name) == 0)
195 return load_font(dev, name);
199 DeviceFont *load_font(dev, name)
208 fp = open_device_file(dev->name, name, ¤t_filename);
215 if (!fgets(buf, sizeof(buf), fp)) {
216 error("no charset line");
221 /* charset must be on a line by itself */
222 if (p && strcmp(p, "charset") == 0 && strtok((char *)0, WS) == 0)
224 if (p && strcmp(p, "special") == 0)
227 f = new_font(name, dev);
228 f->special = special;
229 if (!read_charset_section(f, fp)) {
234 f->next = dev->fonts;
238 XtFree(current_filename);
239 current_filename = 0;
244 DeviceFont *new_font(name, dev)
251 f = XtNew(DeviceFont);
252 f->name = XtNewString(name);
256 for (i = 0; i < CHAR_TABLE_SIZE; i++)
257 f->char_table[i] = 0;
258 for (i = 0; i < 256; i++)
259 f->code_table[i] = 0;
272 for (i = 0; i < CHAR_TABLE_SIZE; i++) {
273 struct charinfo *ptr = f->char_table[i];
275 struct charinfo *tem = ptr;
285 unsigned hash_name(name)
289 /* XXX do better than this */
291 n = (n << 1) ^ *name++;
297 int scale_round(n, x, y)
306 if (n <= (INT_MAX - y2)/x)
308 return (int)(n*(double)x/(double)y + .5);
311 if (-(unsigned)n <= (-(unsigned)INT_MIN - y2)/x)
313 return (int)(n*(double)x/(double)y + .5);
318 char *canonicalize_name(s)
322 if (s[0] == 'c' && s[1] == 'h' && s[2] == 'a' && s[3] == 'r') {
326 for (p = s + 4; *p; p++)
327 if (!isascii(*p) || !isdigit((unsigned char)*p))
330 if (n >= 0 && n <= 0xff) {
338 /* Return 1 if the character is present in the font; widthp gets the
339 width if non-null. */
341 int device_char_width(f, ps, name, widthp)
349 name = canonicalize_name(name);
350 for (p = f->char_table[hash_name(name) % CHAR_TABLE_SIZE];; p = p->next) {
353 if (strcmp(p->name, name) == 0)
356 *widthp = scale_round(p->width, ps, f->dev->unitwidth);
360 int device_code_width(f, ps, code, widthp)
368 for (p = f->code_table[code & 0xff];; p = p->code_next) {
374 *widthp = scale_round(p->width, ps, f->dev->unitwidth);
378 char *device_name_for_code(f, code)
382 static struct charinfo *state = 0;
384 state = f->code_table[code & 0xff];
385 for (; state; state = state->code_next)
386 if (state->code == code && state->name[0] != '\0') {
387 char *name = state->name;
388 state = state->code_next;
394 int device_font_special(f)
401 struct charinfo *add_char(f, name, width, code)
406 struct charinfo **pp;
409 name = canonicalize_name(name);
410 if (strcmp(name, "---") == 0)
413 ci = (struct charinfo *)XtMalloc(XtOffsetOf(struct charinfo, name[0])
416 strcpy(ci->name, name);
421 pp = &f->char_table[hash_name(name) % CHAR_TABLE_SIZE];
425 pp = &f->code_table[code & 0xff];
431 /* Return non-zero for success. */
434 int read_charset_section(f, fp)
438 struct charinfo *last_charinfo = 0;
441 while (fgets(buf, sizeof(buf), fp)) {
448 name = strtok(buf, WS);
450 continue; /* ignore blank lines */
451 p = strtok((char *)0, WS);
452 if (!p) /* end of charset section */
454 if (strcmp(p, "\"") == 0) {
455 if (!last_charinfo) {
456 error("first line of charset section cannot use `\"'");
460 (void)add_char(f, name,
461 last_charinfo->width, last_charinfo->code);
465 if (sscanf(p, "%d", &width) != 1) {
466 error("bad width field");
469 p = strtok((char *)0, WS);
471 error("missing type field");
474 p = strtok((char *)0, WS);
476 error("missing code field");
479 code = (int)strtol(p, &q, 0);
481 error("bad code field");
484 last_charinfo = add_char(f, name, width, code);
491 FILE *find_file(file, result)
492 char *file, **result;
501 env = getenv(FONTPATH_ENV_VAR);
502 path = XtMalloc(((env && *env) ? strlen(env) + 1 : 0)
503 + strlen(FONTPATH) + 1);
509 strcat(path, FONTPATH);
519 fp = fopen(file, "r");
521 *result = XtNewString(file);
532 end = strchr(path, ':');
536 path = end = strchr(path, '\0');
541 len = (end - start) + 1 + flen + 1;
544 buf = XtRealloc(buf, len);
549 memcpy(buf, start, end - start);
550 buf[end - start] = '/';
551 strcpy(buf + (end - start) + 1, file);
552 fp = fopen(buf, "r");
563 FILE *open_device_file(device_name, file_name, result)
564 char *device_name, *file_name, **result;
569 buf = XtMalloc(3 + strlen(device_name) + 1 + strlen(file_name) + 1);
570 sprintf(buf, "dev%s/%s", device_name, file_name);
571 fp = find_file(buf, result);
573 fprintf(stderr, "can't find device file `%s'\n", file_name);
584 if (current_filename) {
585 fprintf(stderr, "%s:", current_filename);
586 if (current_lineno > 0)
587 fprintf(stderr, "%d:", current_lineno);
598 c-continued-statement-offset: 4
602 c-tab-always-indent: nil