/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
- /* device.c */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #include <stdio.h>
- #include <ctype.h>
- #include <stdlib.h>
- #include <string.h>
- #include <X11/Xos.h>
- #include <X11/Intrinsic.h>
- #include "device.h"
- #include "defs.h"
- #ifndef isascii
- #define isascii(c) (1)
- #endif
- /* Name of environment variable containing path to be used for
- searching for device and font description files. */
- #define FONTPATH_ENV_VAR "GROFF_FONT_PATH"
- #define WS " \t\r\n"
- #ifndef INT_MIN
- /* Minimum and maximum values a `signed int' can hold. */
- #define INT_MIN (-INT_MAX-1)
- #define INT_MAX 2147483647
- #endif
- #define CHAR_TABLE_SIZE 307
- struct _DeviceFont {
- char *name;
- int special;
- DeviceFont *next;
- Device *dev;
- struct charinfo *char_table[CHAR_TABLE_SIZE];
- struct charinfo *code_table[256];
- };
- struct charinfo {
- int width;
- int code;
- struct charinfo *next;
- struct charinfo *code_next;
- char name[1];
- };
- static char *current_filename = 0;
- static int current_lineno = -1;
- static void error(const char *s);
- static FILE *open_device_file(const char *, const char *, char **);
- static DeviceFont *load_font(Device *, const char *);
- static Device *new_device(const char *);
- static DeviceFont *new_font(const char *, Device *);
- static void delete_font(DeviceFont *);
- static unsigned hash_name(const char *);
- static struct charinfo *add_char(DeviceFont *, const char *, int, int);
- static int read_charset_section(DeviceFont *, FILE *);
- static char *canonicalize_name(const char *);
- static int scale_round(int, int, int);
- static
- Device *new_device(const char *name)
- {
- Device *dev;
- dev = XtNew(Device);
- dev->sizescale = 1;
- dev->res = 0;
- dev->unitwidth = 0;
- dev->fonts = 0;
- dev->X11 = 0;
- dev->paperlength = 0;
- dev->paperwidth = 0;
- dev->name = XtNewString(name);
- return dev;
- }
- void device_destroy(Device *dev)
- {
- DeviceFont *f;
-
- if (!dev)
- return;
- f = dev->fonts;
- while (f) {
- DeviceFont *tem = f;
- f = f->next;
- delete_font(tem);
- }
-
- XtFree(dev->name);
- XtFree((char *)dev);
- }
- Device *device_load(const char *name)
- {
- Device *dev;
- FILE *fp;
- int err = 0;
- char buf[256];
- fp = open_device_file(name, "DESC", ¤t_filename);
- if (!fp)
- return 0;
- dev = new_device(name);
- current_lineno = 0;
- while (fgets(buf, sizeof(buf), fp)) {
- char *p;
- current_lineno++;
- p = strtok(buf, WS);
- if (p) {
- int *np = 0;
- char *q;
- if (strcmp(p, "charset") == 0)
- break;
- if (strcmp(p, "X11") == 0)
- dev->X11 = 1;
- else if (strcmp(p, "sizescale") == 0)
- np = &dev->sizescale;
- else if (strcmp(p, "res") == 0)
- np = &dev->res;
- else if (strcmp(p, "unitwidth") == 0)
- np = &dev->unitwidth;
- else if (strcmp(p, "paperwidth") == 0)
- np = &dev->paperwidth;
- else if (strcmp(p, "paperlength") == 0)
- np = &dev->paperlength;
-
- if (np) {
- q = strtok((char *)0, WS);
- if (!q || sscanf(q, "%d", np) != 1 || *np <= 0) {
- error("bad argument");
- err = 1;
- break;
- }
- }
- }
- }
- fclose(fp);
- current_lineno = -1;
- if (!err) {
- if (dev->res == 0) {
- error("missing res line");
- err = 1;
- }
- else if (dev->unitwidth == 0) {
- error("missing unitwidth line");
- err = 1;
- }
- }
- if (dev->paperlength == 0)
- dev->paperlength = dev->res*11;
- if (dev->paperwidth == 0)
- dev->paperwidth = dev->res*8 + dev->res/2;
- if (err) {
- device_destroy(dev);
- dev = 0;
- }
- XtFree(current_filename);
- current_filename = 0;
- return dev;
- }
- DeviceFont *device_find_font(Device *dev, const char *name)
- {
- DeviceFont *f;
- if (!dev)
- return 0;
- for (f = dev->fonts; f; f = f->next)
- if (strcmp(f->name, name) == 0)
- return f;
- return load_font(dev, name);
- }
- static
- DeviceFont *load_font(Device *dev, const char *name)
- {
- FILE *fp;
- char buf[256];
- DeviceFont *f;
- int special = 0;
- fp = open_device_file(dev->name, name, ¤t_filename);
- if (!fp)
- return 0;
- current_lineno = 0;
- for (;;) {
- char *p;
- if (!fgets(buf, sizeof(buf), fp)) {
- error("no charset line");
- return 0;
- }
- current_lineno++;
- p = strtok(buf, WS);
- /* charset must be on a line by itself */
- if (p && strcmp(p, "charset") == 0 && strtok((char *)0, WS) == 0)
- break;
- if (p && strcmp(p, "special") == 0)
- special = 1;
- }
- f = new_font(name, dev);
- f->special = special;
- if (!read_charset_section(f, fp)) {
- delete_font(f);
- f = 0;
- }
- else {
- f->next = dev->fonts;
- dev->fonts = f;
- }
- fclose(fp);
- XtFree(current_filename);
- current_filename = 0;
- return f;
- }
- static
- DeviceFont *new_font(const char *name, Device *dev)
- {
- int i;
- DeviceFont *f;
- f = XtNew(DeviceFont);
- f->name = XtNewString(name);
- f->dev = dev;
- f->special = 0;
- f->next = 0;
- for (i = 0; i < CHAR_TABLE_SIZE; i++)
- f->char_table[i] = 0;
- for (i = 0; i < 256; i++)
- f->code_table[i] = 0;
- return f;
- }
- static
- void delete_font(DeviceFont *f)
- {
- int i;
- if (!f)
- return;
- XtFree(f->name);
- for (i = 0; i < CHAR_TABLE_SIZE; i++) {
- struct charinfo *ptr = f->char_table[i];
- while (ptr) {
- struct charinfo *tem = ptr;
- ptr = ptr->next;
- XtFree((char *)tem);
- }
- }
- XtFree((char *)f);
- }
- static
- unsigned hash_name(const char *name)
- {
- unsigned n = 0;
- /* XXX do better than this */
- while (*name)
- n = (n << 1) ^ *name++;
- return n;
- }
- static
- int scale_round(int n, int x, int y)
- {
- int y2;
- if (x == 0)
- return 0;
- y2 = y/2;
- if (n >= 0) {
- if (n <= (INT_MAX - y2)/x)
- return (n*x + y2)/y;
- return (int)(n*(double)x/(double)y + .5);
- }
- else {
- if (-(unsigned)n <= (-(unsigned)INT_MIN - y2)/x)
- return (n*x - y2)/y;
- return (int)(n*(double)x/(double)y + .5);
- }
- }
- static
- char *canonicalize_name(const char *s)
- {
- static char ch[2];
- if (s[0] == 'c' && s[1] == 'h' && s[2] == 'a' && s[3] == 'r') {
- const char *p;
- int n;
- for (p = s + 4; *p; p++)
- if (!isascii(*p) || !isdigit((unsigned char)*p))
- return (char *)s;
- n = atoi(s + 4);
- if (n >= 0 && n <= 0xff) {
- ch[0] = (char)n;
- return ch;
- }
- }
- return (char *)s;
- }
- /* Return 1 if the character is present in the font; widthp gets the
- width if non-null. */
- int device_char_width(DeviceFont *f, int ps, const char *name, int *widthp)
- {
- struct charinfo *p;
- name = canonicalize_name(name);
- for (p = f->char_table[hash_name(name) % CHAR_TABLE_SIZE];; p = p->next) {
- if (!p)
- return 0;
- if (strcmp(p->name, name) == 0)
- break;
- }
- *widthp = scale_round(p->width, ps, f->dev->unitwidth);
- return 1;
- }
- int device_code_width(DeviceFont *f, int ps, int code, int *widthp)
- {
- struct charinfo *p;
- for (p = f->code_table[code & 0xff];; p = p->code_next) {
- if (!p)
- return 0;
- if (p->code == code)
- break;
- }
- *widthp = scale_round(p->width, ps, f->dev->unitwidth);
- return 1;
- }
- char *device_name_for_code(DeviceFont *f, int code)
- {
- static struct charinfo *state = 0;
- if (f)
- state = f->code_table[code & 0xff];
- for (; state; state = state->code_next)
- if (state->code == code && state->name[0] != '\0') {
- char *name = state->name;
- state = state->code_next;
- return name;
- }
- return 0;
- }
- int device_font_special(DeviceFont *f)
- {
- return f->special;
- }
-
- static
- struct charinfo *add_char(DeviceFont *f, const char *name, int width, int code)
- {
- struct charinfo **pp;
- struct charinfo *ci;
-
- name = canonicalize_name(name);
- if (strcmp(name, "---") == 0)
- name = "";
- ci = (struct charinfo *)XtMalloc(XtOffsetOf(struct charinfo, name[0])
- + strlen(name) + 1);
-
- strcpy(ci->name, name);
- ci->width = width;
- ci->code = code;
-
- if (*name != '\0') {
- pp = &f->char_table[hash_name(name) % CHAR_TABLE_SIZE];
- ci->next = *pp;
- *pp = ci;
- }
- pp = &f->code_table[code & 0xff];
- ci->code_next = *pp;
- *pp = ci;
- return ci;
- }
- /* Return non-zero for success. */
- static
- int read_charset_section(DeviceFont *f, FILE *fp)
- {
- struct charinfo *last_charinfo = 0;
- char buf[256];
- while (fgets(buf, sizeof(buf), fp)) {
- char *name;
- int width;
- int code;
- char *p;
- current_lineno++;
- name = strtok(buf, WS);
- if (!name)
- continue; /* ignore blank lines */
- p = strtok((char *)0, WS);
- if (!p) /* end of charset section */
- break;
- if (strcmp(p, "\"") == 0) {
- if (!last_charinfo) {
- error("first line of charset section cannot use `\"'");
- return 0;
- }
- else
- (void)add_char(f, name,
- last_charinfo->width, last_charinfo->code);
- }
- else {
- char *q;
- if (sscanf(p, "%d", &width) != 1) {
- error("bad width field");
- return 0;
- }
- p = strtok((char *)0, WS);
- if (!p) {
- error("missing type field");
- return 0;
- }
- p = strtok((char *)0, WS);
- if (!p) {
- error("missing code field");
- return 0;
- }
- code = (int)strtol(p, &q, 0);
- if (q == p) {
- error("bad code field");
- return 0;
- }
- last_charinfo = add_char(f, name, width, code);
- }
- }
- return 1;
- }
- static
- FILE *find_file(const char *file, char **result)
- {
- char *buf = NULL;
- int bufsiz = 0;
- int flen;
- FILE *fp;
- char *path;
- char *env;
- env = getenv(FONTPATH_ENV_VAR);
- path = XtMalloc(((env && *env) ? strlen(env) + 1 : 0)
- + strlen(FONTPATH) + 1);
- *path = '\0';
- if (env && *env) {
- strcat(path, env);
- strcat(path, ":");
- }
- strcat(path, FONTPATH);
- *result = NULL;
-
- if (file == NULL)
- return NULL;
- if (*file == '\0')
- return NULL;
-
- if (*file == '/') {
- fp = fopen(file, "r");
- if (fp)
- *result = XtNewString(file);
- return fp;
- }
-
- flen = strlen(file);
-
- while (*path) {
- int len;
- char *start, *end;
-
- start = path;
- end = strchr(path, ':');
- if (end)
- path = end + 1;
- else
- path = end = strchr(path, '\0');
- if (start >= end)
- continue;
- if (end[-1] == '/')
- --end;
- len = (end - start) + 1 + flen + 1;
- if (len > bufsiz) {
- if (buf)
- buf = XtRealloc(buf, len);
- else
- buf = XtMalloc(len);
- bufsiz = len;
- }
- memcpy(buf, start, end - start);
- buf[end - start] = '/';
- strcpy(buf + (end - start) + 1, file);
- fp = fopen(buf, "r");
- if (fp) {
- *result = buf;
- return fp;
- }
- }
- XtFree(buf);
- return NULL;
- }
- static
- FILE *open_device_file(const char *device_name, const char *file_name,
- char **result)
- {
- char *buf;
- FILE *fp;
- buf = XtMalloc(3 + strlen(device_name) + 1 + strlen(file_name) + 1);
- sprintf(buf, "dev%s/%s", device_name, file_name);
- fp = find_file(buf, result);
- if (!fp) {
- fprintf(stderr, "can't find device file `%s'\n", file_name);
- fflush(stderr);
- }
- XtFree(buf);
- return fp;
- }
- static
- void error(const char *s)
- {
- if (current_filename) {
- fprintf(stderr, "%s:", current_filename);
- if (current_lineno > 0)
- fprintf(stderr, "%d:", current_lineno);
- putc(' ', stderr);
- }
- fputs(s, stderr);
- putc('\n', stderr);
- fflush(stderr);
- }
- /*
- Local Variables:
- c-indent-level: 4
- c-continued-statement-offset: 4
- c-brace-offset: -4
- c-argdecl-indent: 4
- c-label-offset: -4
- c-tab-always-indent: nil
- End:
- */