~ubuntu-branches/ubuntu/dapper/groff/dapper

« back to all changes in this revision

Viewing changes to src/xditview/device.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson
  • Date: 2002-03-17 04:11:50 UTC
  • Revision ID: james.westby@ubuntu.com-20020317041150-wkgfawjc3gxlk0o5
Tags: upstream-1.17.2
ImportĀ upstreamĀ versionĀ 1.17.2

Show diffs side-by-side

added added

removed removed

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