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