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
)
309 else if (-(unsigned)n
<= (-(unsigned)INT_MIN
- y2
)/x
)
311 return (int)(n
*(double)x
/(double)y
+ .5);
315 char *canonicalize_name(s
)
319 if (s
[0] == 'c' && s
[1] == 'h' && s
[2] == 'a' && s
[3] == 'r') {
323 for (p
= s
+ 4; *p
; p
++)
324 if (!isascii(*p
) || !isdigit((unsigned char)*p
))
327 if (n
>= 0 && n
<= 0xff) {
335 /* Return 1 if the character is present in the font; widthp gets the
336 width if non-null. */
338 int device_char_width(f
, ps
, name
, widthp
)
346 name
= canonicalize_name(name
);
347 for (p
= f
->char_table
[hash_name(name
) % CHAR_TABLE_SIZE
];; p
= p
->next
) {
350 if (strcmp(p
->name
, name
) == 0)
353 *widthp
= scale_round(p
->width
, ps
, f
->dev
->unitwidth
);
357 int device_code_width(f
, ps
, code
, widthp
)
365 for (p
= f
->code_table
[code
& 0xff];; p
= p
->code_next
) {
371 *widthp
= scale_round(p
->width
, ps
, f
->dev
->unitwidth
);
375 char *device_name_for_code(f
, code
)
379 static struct charinfo
*state
= 0;
381 state
= f
->code_table
[code
& 0xff];
382 for (; state
; state
= state
->code_next
)
383 if (state
->code
== code
&& state
->name
[0] != '\0') {
384 char *name
= state
->name
;
385 state
= state
->code_next
;
391 int device_font_special(f
)
398 struct charinfo
*add_char(f
, name
, width
, code
)
403 struct charinfo
**pp
;
406 name
= canonicalize_name(name
);
407 if (strcmp(name
, "---") == 0)
410 ci
= (struct charinfo
*)XtMalloc(XtOffsetOf(struct charinfo
, name
[0])
413 strcpy(ci
->name
, name
);
418 pp
= &f
->char_table
[hash_name(name
) % CHAR_TABLE_SIZE
];
422 pp
= &f
->code_table
[code
& 0xff];
428 /* Return non-zero for success. */
431 int read_charset_section(f
, fp
)
435 struct charinfo
*last_charinfo
= 0;
438 while (fgets(buf
, sizeof(buf
), fp
)) {
445 name
= strtok(buf
, WS
);
447 continue; /* ignore blank lines */
448 p
= strtok((char *)0, WS
);
449 if (!p
) /* end of charset section */
451 if (strcmp(p
, "\"") == 0) {
452 if (!last_charinfo
) {
453 error("first line of charset section cannot use `\"'");
457 (void)add_char(f
, name
,
458 last_charinfo
->width
, last_charinfo
->code
);
462 if (sscanf(p
, "%d", &width
) != 1) {
463 error("bad width field");
466 p
= strtok((char *)0, WS
);
468 error("missing type field");
471 p
= strtok((char *)0, WS
);
473 error("missing code field");
476 code
= (int)strtol(p
, &q
, 0);
478 error("bad code field");
481 last_charinfo
= add_char(f
, name
, width
, code
);
488 FILE *find_file(file
, result
)
489 char *file
, **result
;
498 env
= getenv(FONTPATH_ENV_VAR
);
499 path
= XtMalloc(((env
&& *env
) ? strlen(env
) + 1 : 0)
500 + strlen(FONTPATH
) + 1);
506 strcat(path
, FONTPATH
);
516 fp
= fopen(file
, "r");
518 *result
= XtNewString(file
);
529 end
= strchr(path
, ':');
533 path
= end
= strchr(path
, '\0');
538 len
= (end
- start
) + 1 + flen
+ 1;
541 buf
= XtRealloc(buf
, len
);
546 memcpy(buf
, start
, end
- start
);
547 buf
[end
- start
] = '/';
548 strcpy(buf
+ (end
- start
) + 1, file
);
549 fp
= fopen(buf
, "r");
560 FILE *open_device_file(device_name
, file_name
, result
)
561 char *device_name
, *file_name
, **result
;
566 buf
= XtMalloc(3 + strlen(device_name
) + 1 + strlen(file_name
) + 1);
567 sprintf(buf
, "dev%s/%s", device_name
, file_name
);
568 fp
= find_file(buf
, result
);
570 fprintf(stderr
, "can't find device file `%s'\n", file_name
);
581 if (current_filename
) {
582 fprintf(stderr
, "%s:", current_filename
);
583 if (current_lineno
> 0)
584 fprintf(stderr
, "%d:", current_lineno
);
595 c-continued-statement-offset: 4
599 c-tab-always-indent: nil