PageRenderTime 82ms CodeModel.GetById 16ms app.highlight 61ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/groff/src/devices/xditview/device.c

https://bitbucket.org/freebsd/freebsd-head/
C | 565 lines | 479 code | 67 blank | 19 comment | 134 complexity | e4c649fae8fb48595016917c9940c857 MD5 | raw file
  1/* device.c */
  2
  3#ifdef HAVE_CONFIG_H
  4#include <config.h>
  5#endif
  6
  7#include <stdio.h>
  8#include <ctype.h>
  9#include <stdlib.h>
 10#include <string.h>
 11
 12#include <X11/Xos.h>
 13#include <X11/Intrinsic.h>
 14
 15#include "device.h"
 16#include "defs.h"
 17
 18#ifndef isascii
 19#define isascii(c) (1)
 20#endif
 21
 22/* Name of environment variable containing path to be used for
 23searching for device and font description files. */
 24#define FONTPATH_ENV_VAR  "GROFF_FONT_PATH"
 25
 26#define WS " \t\r\n"
 27
 28#ifndef INT_MIN
 29/* Minimum and maximum values a `signed int' can hold.  */
 30#define INT_MIN (-INT_MAX-1)
 31#define INT_MAX 2147483647
 32#endif
 33
 34#define CHAR_TABLE_SIZE 307
 35
 36struct _DeviceFont {
 37    char *name;
 38    int special;
 39    DeviceFont *next;
 40    Device *dev;
 41    struct charinfo *char_table[CHAR_TABLE_SIZE];
 42    struct charinfo *code_table[256];
 43};
 44
 45struct charinfo {
 46    int width;
 47    int code;
 48    struct charinfo *next;
 49    struct charinfo *code_next;
 50    char name[1];
 51};
 52
 53static char *current_filename = 0;
 54static int current_lineno = -1;
 55
 56static void error(const char *s);
 57static FILE *open_device_file(const char *, const char *, char **);
 58static DeviceFont *load_font(Device *, const char *);
 59static Device *new_device(const char *);
 60static DeviceFont *new_font(const char *, Device *);
 61static void delete_font(DeviceFont *);
 62static unsigned hash_name(const char *);
 63static struct charinfo *add_char(DeviceFont *, const char *, int, int);
 64static int read_charset_section(DeviceFont *, FILE *);
 65static char *canonicalize_name(const char *);
 66static int scale_round(int, int, int);
 67
 68static
 69Device *new_device(const char *name)
 70{
 71    Device *dev;
 72
 73    dev = XtNew(Device);
 74    dev->sizescale = 1;
 75    dev->res = 0;
 76    dev->unitwidth = 0;
 77    dev->fonts = 0;
 78    dev->X11 = 0;
 79    dev->paperlength = 0;
 80    dev->paperwidth = 0;
 81    dev->name = XtNewString(name);
 82    return dev;
 83}
 84
 85void device_destroy(Device *dev)
 86{
 87    DeviceFont *f;
 88    
 89    if (!dev)
 90	return;
 91    f = dev->fonts;
 92    while (f) {
 93	DeviceFont *tem = f;
 94	f = f->next;
 95	delete_font(tem);
 96    }
 97    
 98    XtFree(dev->name);
 99    XtFree((char *)dev);
100}
101
102Device *device_load(const char *name)
103{
104    Device *dev;
105    FILE *fp;
106    int err = 0;
107    char buf[256];
108
109    fp = open_device_file(name, "DESC", &current_filename);
110    if (!fp)
111	return 0;
112    dev = new_device(name);
113    current_lineno = 0;
114    while (fgets(buf, sizeof(buf), fp)) {
115	char *p;
116	current_lineno++;
117	p = strtok(buf, WS);
118	if (p) {
119	    int *np = 0;
120	    char *q;
121
122	    if (strcmp(p, "charset") == 0)
123		break;
124	    if (strcmp(p, "X11") == 0)
125		dev->X11 = 1;
126	    else if (strcmp(p, "sizescale") == 0)
127		np = &dev->sizescale;
128 	    else if (strcmp(p, "res") == 0)
129		np = &dev->res;
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;
136	    
137	    if (np) {
138		q = strtok((char *)0, WS);
139		if (!q || sscanf(q, "%d", np) != 1 || *np <= 0) {
140		    error("bad argument");
141		    err = 1;
142		    break;
143		}
144	    }	
145	}
146    }
147    fclose(fp);
148    current_lineno = -1;
149    if (!err) {
150	if (dev->res == 0) {
151	    error("missing res line");
152	    err = 1;
153	}
154	else if (dev->unitwidth == 0) {
155	    error("missing unitwidth line");
156	    err = 1;
157	}
158    }
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;
163    if (err) {
164	device_destroy(dev);
165	dev = 0;
166    }
167    XtFree(current_filename);
168    current_filename = 0;
169    return dev;
170}
171
172
173DeviceFont *device_find_font(Device *dev, const char *name)
174{
175    DeviceFont *f;
176
177    if (!dev)
178	return 0;
179    for (f = dev->fonts; f; f = f->next)
180	if (strcmp(f->name, name) == 0)
181	    return f;
182    return load_font(dev, name);
183}
184
185static
186DeviceFont *load_font(Device *dev, const char *name)
187{
188    FILE *fp;
189    char buf[256];
190    DeviceFont *f;
191    int special = 0;
192
193    fp = open_device_file(dev->name, name, &current_filename);
194    if (!fp)
195	return 0;
196    current_lineno = 0;
197    for (;;) {
198	char *p;
199
200	if (!fgets(buf, sizeof(buf), fp)) {
201	    error("no charset line");
202	    return 0;
203	}
204	current_lineno++;
205	p = strtok(buf, WS);
206	/* charset must be on a line by itself */
207	if (p && strcmp(p, "charset") == 0 && strtok((char *)0, WS) == 0)
208	    break;
209	if (p && strcmp(p, "special") == 0)
210	    special = 1;
211    }
212    f = new_font(name, dev);
213    f->special = special;
214    if (!read_charset_section(f, fp)) {
215	delete_font(f);
216	f = 0;
217    }
218    else {
219	f->next = dev->fonts;
220	dev->fonts = f;
221    }
222    fclose(fp);
223    XtFree(current_filename);
224    current_filename = 0;
225    return f;
226}
227
228static
229DeviceFont *new_font(const char *name, Device *dev)
230{
231    int i;
232    DeviceFont *f;
233
234    f = XtNew(DeviceFont);
235    f->name = XtNewString(name);
236    f->dev = dev;
237    f->special = 0;
238    f->next = 0;
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;
243    return f;
244}
245
246static
247void delete_font(DeviceFont *f)
248{
249    int i;
250
251    if (!f)
252	return;
253    XtFree(f->name);
254    for (i = 0; i < CHAR_TABLE_SIZE; i++) {
255	struct charinfo *ptr = f->char_table[i];
256	while (ptr) {
257	    struct charinfo *tem = ptr;
258	    ptr = ptr->next;
259	    XtFree((char *)tem);
260	}
261    }
262    XtFree((char *)f);
263}
264
265
266static
267unsigned hash_name(const char *name)
268{
269    unsigned n = 0;
270    /* XXX do better than this */
271    while (*name)
272	n = (n << 1) ^ *name++;
273
274    return n;
275}
276
277static
278int scale_round(int n, int x, int y)
279{
280  int y2;
281
282  if (x == 0)
283    return 0;
284  y2 = y/2;
285  if (n >= 0) {
286    if (n <= (INT_MAX - y2)/x)
287      return (n*x + y2)/y;
288    return (int)(n*(double)x/(double)y + .5);
289  }
290  else {
291    if (-(unsigned)n <= (-(unsigned)INT_MIN - y2)/x)
292      return (n*x - y2)/y;
293    return (int)(n*(double)x/(double)y + .5);
294  }
295}
296
297static
298char *canonicalize_name(const char *s)
299{
300    static char ch[2];
301    if (s[0] == 'c' && s[1] == 'h' && s[2] == 'a' && s[3] == 'r') {
302	const char *p;
303	int n;
304
305	for (p = s + 4; *p; p++)
306	    if (!isascii(*p) || !isdigit((unsigned char)*p))
307		return (char *)s;
308	n = atoi(s + 4);
309	if (n >= 0 && n <= 0xff) {
310	    ch[0] = (char)n;
311	    return ch;
312	}
313    }
314    return (char *)s;
315}
316
317/* Return 1 if the character is present in the font; widthp gets the
318width if non-null. */
319
320int device_char_width(DeviceFont *f, int ps, const char *name, int *widthp)
321{
322    struct charinfo *p;
323
324    name = canonicalize_name(name);
325    for (p = f->char_table[hash_name(name) % CHAR_TABLE_SIZE];; p = p->next) {
326	if (!p)
327	    return 0;
328	if (strcmp(p->name, name) == 0)
329	    break;
330    }
331    *widthp = scale_round(p->width, ps, f->dev->unitwidth);
332    return 1;
333}
334
335int device_code_width(DeviceFont *f, int ps, int code, int *widthp)
336{
337    struct charinfo *p;
338
339    for (p = f->code_table[code & 0xff];; p = p->code_next) {
340	if (!p)
341	    return 0;
342	if (p->code == code)
343	    break;
344    }
345    *widthp = scale_round(p->width, ps, f->dev->unitwidth);
346    return 1;
347}
348
349char *device_name_for_code(DeviceFont *f, int code)
350{
351    static struct charinfo *state = 0;
352    if (f)
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;
358	    return name;
359	}
360    return 0;
361}
362
363int device_font_special(DeviceFont *f)
364{
365    return f->special;
366}
367    
368static
369struct charinfo *add_char(DeviceFont *f, const char *name, int width, int code)
370{
371    struct charinfo **pp;
372    struct charinfo *ci;
373    
374    name = canonicalize_name(name);
375    if (strcmp(name, "---") == 0)
376	name = "";
377
378    ci = (struct charinfo *)XtMalloc(XtOffsetOf(struct charinfo, name[0])
379				     + strlen(name) + 1);
380    
381    strcpy(ci->name, name);
382    ci->width = width;
383    ci->code = code;
384    
385    if (*name != '\0') {
386	pp = &f->char_table[hash_name(name) % CHAR_TABLE_SIZE];
387	ci->next = *pp;
388	*pp = ci;
389    }
390    pp = &f->code_table[code & 0xff];
391    ci->code_next = *pp;
392    *pp = ci;
393    return ci;
394}
395
396/* Return non-zero for success. */
397
398static
399int read_charset_section(DeviceFont *f, FILE *fp)
400{
401    struct charinfo *last_charinfo = 0;
402    char buf[256];
403
404    while (fgets(buf, sizeof(buf), fp)) {
405	char *name;
406	int width;
407	int code;
408	char *p;
409
410	current_lineno++;
411	name = strtok(buf, WS);
412	if (!name)
413	    continue;		/* ignore blank lines */
414	p = strtok((char *)0, WS);
415	if (!p)			/* end of charset section */
416	    break;
417	if (strcmp(p, "\"") == 0) {
418	    if (!last_charinfo) {
419		error("first line of charset section cannot use `\"'");
420		return 0;
421	    }
422	    else
423		(void)add_char(f, name,
424			       last_charinfo->width, last_charinfo->code);
425	}
426	else {
427	    char *q;
428	    if (sscanf(p, "%d", &width) != 1) {
429		error("bad width field");
430		return 0;
431	    }
432	    p = strtok((char *)0, WS);
433	    if (!p) {
434		error("missing type field");
435		return 0;
436	    }
437	    p = strtok((char *)0, WS);
438	    if (!p) {
439		error("missing code field");
440		return 0;
441	    }
442	    code = (int)strtol(p, &q, 0);
443	    if (q == p) {
444		error("bad code field");
445		return 0;
446	    }
447	    last_charinfo = add_char(f, name, width, code);
448	}
449    }
450    return 1;
451}
452
453static
454FILE *find_file(const char *file, char **result)
455{
456  char *buf = NULL;
457  int bufsiz = 0;
458  int flen;
459  FILE *fp;
460  char *path;
461  char *env;
462
463  env = getenv(FONTPATH_ENV_VAR);
464  path = XtMalloc(((env && *env) ? strlen(env) + 1 : 0)
465		  + strlen(FONTPATH) + 1);
466  *path = '\0';
467  if (env && *env) {
468    strcat(path, env);
469    strcat(path, ":");
470  }
471  strcat(path, FONTPATH);
472
473  *result = NULL;
474  
475  if (file == NULL)
476    return NULL;
477  if (*file == '\0')
478    return NULL;
479  
480  if (*file == '/') {
481    fp = fopen(file, "r");
482    if (fp)
483      *result = XtNewString(file);
484    return fp;
485  }
486  
487  flen = strlen(file);
488  
489  while (*path) {
490    int len;
491    char *start, *end;
492    
493    start = path;
494    end = strchr(path, ':');
495    if (end)
496      path = end + 1;
497    else
498      path = end = strchr(path, '\0');
499    if (start >= end)
500      continue;
501    if (end[-1] == '/')
502      --end;
503    len = (end - start) + 1 + flen + 1;
504    if (len > bufsiz) {
505      if (buf)
506	buf = XtRealloc(buf, len);
507      else
508	buf = XtMalloc(len);
509      bufsiz = len;
510    }
511    memcpy(buf, start, end - start);
512    buf[end - start] = '/';
513    strcpy(buf + (end - start) + 1, file);
514    fp = fopen(buf, "r");
515    if (fp) {
516      *result = buf;
517      return fp;
518    }
519  }
520  XtFree(buf);
521  return NULL;
522}
523
524static
525FILE *open_device_file(const char *device_name, const char *file_name,
526		       char **result)
527{
528  char *buf;
529  FILE *fp;
530
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);
534  if (!fp) {
535      fprintf(stderr, "can't find device file `%s'\n", file_name);
536      fflush(stderr);
537  }
538  XtFree(buf);
539  return fp;
540}
541
542static
543void error(const char *s)
544{
545    if (current_filename) {
546	fprintf(stderr, "%s:", current_filename);
547	if (current_lineno > 0)
548	    fprintf(stderr, "%d:", current_lineno);
549	putc(' ', stderr);
550    }
551    fputs(s, stderr);
552    putc('\n', stderr);
553    fflush(stderr);
554}
555
556/*
557Local Variables:
558c-indent-level: 4
559c-continued-statement-offset: 4
560c-brace-offset: -4
561c-argdecl-indent: 4
562c-label-offset: -4
563c-tab-always-indent: nil
564End:
565*/