1 | /*
|
---|
2 | * device.c -- cawf(1) output device support functions
|
---|
3 | */
|
---|
4 |
|
---|
5 | /*
|
---|
6 | * Copyright (c) 1991 Purdue University Research Foundation,
|
---|
7 | * West Lafayette, Indiana 47907. All rights reserved.
|
---|
8 | *
|
---|
9 | * Written by Victor A. Abell <abe@mace.cc.purdue.edu>, Purdue
|
---|
10 | * University Computing Center. Not derived from licensed software;
|
---|
11 | * derived from awf(1) by Henry Spencer of the University of Toronto.
|
---|
12 | *
|
---|
13 | * Permission is granted to anyone to use this software for any
|
---|
14 | * purpose on any computer system, and to alter it and redistribute
|
---|
15 | * it freely, subject to the following restrictions:
|
---|
16 | *
|
---|
17 | * 1. The author is not responsible for any consequences of use of
|
---|
18 | * this software, even if they arise from flaws in it.
|
---|
19 | *
|
---|
20 | * 2. The origin of this software must not be misrepresented, either
|
---|
21 | * by explicit claim or by omission. Credits must appear in the
|
---|
22 | * documentation.
|
---|
23 | *
|
---|
24 | * 3. Altered versions must be plainly marked as such, and must not
|
---|
25 | * be misrepresented as being the original software. Credits must
|
---|
26 | * appear in the documentation.
|
---|
27 | *
|
---|
28 | * 4. This notice may not be removed or altered.
|
---|
29 | */
|
---|
30 |
|
---|
31 | #include "cawf.h"
|
---|
32 | #include <ctype.h>
|
---|
33 |
|
---|
34 | _PROTOTYPE(static unsigned char *Convstr,(char *s, int *len));
|
---|
35 | _PROTOTYPE(static int Convfont,(char *nm, char *s, char **fn,
|
---|
36 | unsigned char **fi));
|
---|
37 |
|
---|
38 | #ifndef UNIX
|
---|
39 | #define strcasecmp strcmpi
|
---|
40 | #endif
|
---|
41 |
|
---|
42 |
|
---|
43 |
|
---|
44 | /*
|
---|
45 | * Convstr(s, len) - convert a string
|
---|
46 | */
|
---|
47 |
|
---|
48 | static unsigned char *
|
---|
49 | Convstr(s, len)
|
---|
50 | char *s; /* input string */
|
---|
51 | int *len; /* length of result */
|
---|
52 | {
|
---|
53 | int c; /* character assembly */
|
---|
54 | unsigned char *cp; /* temporary character pointer */
|
---|
55 | char *em; /* error message */
|
---|
56 | int i; /* temporary index */
|
---|
57 | int l; /* length */
|
---|
58 | unsigned char *r; /* result string */
|
---|
59 | /*
|
---|
60 | * Make space for the result.
|
---|
61 | */
|
---|
62 | if ((r = (unsigned char *)malloc(strlen((char *)s) + 1)) == NULL) {
|
---|
63 | (void) fprintf(stderr, "%s: out of string space at %s\n",
|
---|
64 | Pname, s);
|
---|
65 | return(NULL);
|
---|
66 | }
|
---|
67 | /*
|
---|
68 | * Copy the input string to the result, processing '\\' escapes.
|
---|
69 | */
|
---|
70 | for (cp = r, l = 0; *s;) {
|
---|
71 | switch (*s) {
|
---|
72 |
|
---|
73 | case '\\':
|
---|
74 | s++;
|
---|
75 | if (*s >= '0' && *s <= '7') {
|
---|
76 | /*
|
---|
77 | * '\xxx' -- octal form
|
---|
78 | */
|
---|
79 | for (c = i = 0; i < 3; i++, s++) {
|
---|
80 | if (*s < '0' || *s > '7') {
|
---|
81 | em = "non-octal char";
|
---|
82 | bad_string:
|
---|
83 | (void) fprintf(stderr,
|
---|
84 | "%s: %s : %s\n",
|
---|
85 | Pname, em, (char *)r);
|
---|
86 | return(NULL);
|
---|
87 | }
|
---|
88 | c = (c << 3) + *s - '0';
|
---|
89 | }
|
---|
90 | if (c > 0377) {
|
---|
91 | em = "octal char > 0377";
|
---|
92 | goto bad_string;
|
---|
93 | }
|
---|
94 | *cp++ = c;
|
---|
95 | l++;
|
---|
96 | } else if (*s == 'x') {
|
---|
97 | /*
|
---|
98 | * '\xyy' -- hexadecimal form
|
---|
99 | */
|
---|
100 | s++;
|
---|
101 | for (c = i = 0; i < 2; i++, s++) {
|
---|
102 | #if defined(__STDC__)
|
---|
103 | if ( ! isalpha(*s) && ! isdigit(*s))
|
---|
104 | #else
|
---|
105 | if ( ! isascii(*s) && ! isalpha(*s)
|
---|
106 | && ! isdigit(*s))
|
---|
107 | #endif
|
---|
108 | {
|
---|
109 | non_hex_char:
|
---|
110 | em = "non-hex char";
|
---|
111 | goto bad_string;
|
---|
112 | }
|
---|
113 | c = c << 4;
|
---|
114 | if (*s >= '0' && *s <= '9')
|
---|
115 | c += *s - '0';
|
---|
116 | else if ((*s >= 'a' && *s <= 'f')
|
---|
117 | || (*s >= 'A' && *s <= 'F'))
|
---|
118 | c += *s + 10 -
|
---|
119 | (isupper(*s) ? 'A' : 'a');
|
---|
120 | else
|
---|
121 | goto non_hex_char;
|
---|
122 | }
|
---|
123 | *cp++ = (unsigned char)c;
|
---|
124 | l++;
|
---|
125 | } else if (*s == 'E' || *s == 'e') {
|
---|
126 | /*
|
---|
127 | * '\E' or '\e' -- ESCape
|
---|
128 | */
|
---|
129 | *cp++ = ESC;
|
---|
130 | l++;
|
---|
131 | s++;
|
---|
132 | } else if (*s == '\0') {
|
---|
133 | em = "no char after \\";
|
---|
134 | goto bad_string;
|
---|
135 | } else {
|
---|
136 | /*
|
---|
137 | * escaped character (for some reason)
|
---|
138 | */
|
---|
139 | *cp++ = *s++;
|
---|
140 | l++;
|
---|
141 | }
|
---|
142 | break;
|
---|
143 | /*
|
---|
144 | * Copy a "normal" character.
|
---|
145 | */
|
---|
146 | default:
|
---|
147 | *cp++ = *s++;
|
---|
148 | l++;
|
---|
149 | }
|
---|
150 | }
|
---|
151 | *cp = '\0';
|
---|
152 | *len = l;
|
---|
153 | return(r);
|
---|
154 | }
|
---|
155 |
|
---|
156 |
|
---|
157 | /*
|
---|
158 | * Convfont(nm, s, fn, fi) - convert a font for a device
|
---|
159 | */
|
---|
160 |
|
---|
161 | static int
|
---|
162 | Convfont(nm, s, fn, fi)
|
---|
163 | char *nm; /* output device name */
|
---|
164 | char *s; /* font definition string */
|
---|
165 | char **fn; /* font name address */
|
---|
166 | unsigned char **fi; /* initialization string address */
|
---|
167 | {
|
---|
168 | char *cp; /* temporary character pointer */
|
---|
169 | int len; /* length */
|
---|
170 | /*
|
---|
171 | * Get the font name, allocate space for it and allocate space for
|
---|
172 | * a font structure.
|
---|
173 | */
|
---|
174 | if ((cp = strchr(s, '=')) == NULL) {
|
---|
175 | (void) fprintf(stderr, "%s: bad %s font line format: %s\n",
|
---|
176 | Pname, nm, s);
|
---|
177 | return(0);
|
---|
178 | }
|
---|
179 | if ((*fn = (char *)malloc(cp - s + 1)) == NULL) {
|
---|
180 | (void) fprintf(stderr, "%s: no space for %s font name %s\n",
|
---|
181 | Pname, nm, s);
|
---|
182 | return(0);
|
---|
183 | }
|
---|
184 | (void) strncpy(*fn, s, cp - s);
|
---|
185 | (*fn)[cp - s] = '\0';
|
---|
186 | /*
|
---|
187 | * Assmble the font initialization string.
|
---|
188 | */
|
---|
189 | if ((*fi = Convstr(cp + 1, &len)) == NULL)
|
---|
190 | return(0);
|
---|
191 | return(len);
|
---|
192 | }
|
---|
193 |
|
---|
194 |
|
---|
195 | /*
|
---|
196 | * Defdev() - define the output device
|
---|
197 | */
|
---|
198 |
|
---|
199 | int
|
---|
200 | Defdev()
|
---|
201 | {
|
---|
202 | unsigned char *fi = NULL; /* last font initialization string */
|
---|
203 | char *fn = NULL; /* font name */
|
---|
204 | int fd = 0; /* found-device flag */
|
---|
205 | FILE *fs; /* file stream */
|
---|
206 | int err = 0; /* errror count */
|
---|
207 | int i; /* temporary index */
|
---|
208 | int len; /* length */
|
---|
209 | char line[MAXLINE]; /* line buffer */
|
---|
210 | char *p; /* output device configuration file */
|
---|
211 | char *s; /* temporary string pointer */
|
---|
212 | /*
|
---|
213 | * Check for the built-in devices, ANSI, NONE or NORMAL (default).
|
---|
214 | */
|
---|
215 | Fstr.b = Fstr.i = Fstr.it = Fstr.r = NULL;
|
---|
216 | Fstr.bl = Fstr.il = Fstr.itl = Fstr.rl = 0;
|
---|
217 | if (Device == NULL || strcasecmp(Device, "normal") == 0) {
|
---|
218 | Fontctl = 0;
|
---|
219 | check_font:
|
---|
220 | if (Devfont) {
|
---|
221 | (void) fprintf(stderr,
|
---|
222 | "%s: font %s for device %s illegal\n",
|
---|
223 | Pname, Devfont, Device ? Device : "NORMAL");
|
---|
224 | return(1);
|
---|
225 | }
|
---|
226 | return(0);
|
---|
227 | }
|
---|
228 | Fontctl = 1;
|
---|
229 | if (strcasecmp(Device, "ansi") == 0) {
|
---|
230 | Fstr.b = Newstr((unsigned char *)"x[1m");
|
---|
231 | Fstr.it = Newstr((unsigned char *)"x[4m");
|
---|
232 | Fstr.r = Newstr((unsigned char *)"x[0m");
|
---|
233 | Fstr.b[0] = Fstr.it[0] = Fstr.r[0] = ESC;
|
---|
234 | Fstr.bl = Fstr.itl = Fstr.rl = 4;
|
---|
235 | goto check_font;
|
---|
236 | }
|
---|
237 | if (strcasecmp(Device, "none") == 0)
|
---|
238 | goto check_font;
|
---|
239 | /*
|
---|
240 | * If a device configuration file path is supplied, use it.
|
---|
241 | */
|
---|
242 | if (Devconf)
|
---|
243 | p = Devconf;
|
---|
244 | else {
|
---|
245 |
|
---|
246 | /*
|
---|
247 | * Use the CAWFLIB environment if it is defined.
|
---|
248 | */
|
---|
249 | if ((p = getenv("CAWFLIB")) == NULL)
|
---|
250 | p = CAWFLIB;
|
---|
251 | len = strlen(p) + 1 + strlen(DEVCONFIG) + 1;
|
---|
252 | if ((s = (char *)malloc(len)) == NULL) {
|
---|
253 | (void) fprintf(stderr, "%s: no space for %s name\n",
|
---|
254 | Pname, DEVCONFIG);
|
---|
255 | return(1);
|
---|
256 | }
|
---|
257 | (void) sprintf(s, "%s/%s", p, DEVCONFIG);
|
---|
258 | p = s;
|
---|
259 | }
|
---|
260 | /*
|
---|
261 | * Open the configuration file.
|
---|
262 | */
|
---|
263 | #ifdef UNIX
|
---|
264 | if ((fs = fopen(p, "r")) == NULL)
|
---|
265 | #else
|
---|
266 | if ((fs = fopen(p, "rt")) == NULL)
|
---|
267 | #endif
|
---|
268 | {
|
---|
269 | (void) fprintf(stderr, "%s: can't open config file: %s\n",
|
---|
270 | Pname, p);
|
---|
271 | return(1);
|
---|
272 | }
|
---|
273 | *line = ' ';
|
---|
274 | /*
|
---|
275 | * Look for a device definition line -- a line that begins with a name.
|
---|
276 | */
|
---|
277 | while ( ! feof(fs)) {
|
---|
278 | if (*line == '\t' || *line == '#' || *line == ' ') {
|
---|
279 | (void) fgets(line, MAXLINE, fs);
|
---|
280 | continue;
|
---|
281 | }
|
---|
282 | if ((s = strrchr(line, '\n')) != NULL)
|
---|
283 | *s = '\0';
|
---|
284 | else
|
---|
285 | line[MAXLINE-1] = '\0';
|
---|
286 | /*
|
---|
287 | * Match device name.
|
---|
288 | */
|
---|
289 | if (strcmp(Device, line) != 0) {
|
---|
290 | (void) fgets(line, MAXLINE, fs);
|
---|
291 | continue;
|
---|
292 | }
|
---|
293 | fd = 1;
|
---|
294 | /*
|
---|
295 | * Read the parameter lines for the device.
|
---|
296 | */
|
---|
297 | while (fgets(line, MAXLINE, fs) != NULL) {
|
---|
298 | if (*line == ' ') {
|
---|
299 | for (i = 1; line[i] == ' '; i++)
|
---|
300 | ;
|
---|
301 | } else if (*line == '\t')
|
---|
302 | i = 1;
|
---|
303 | else
|
---|
304 | break;
|
---|
305 | #if defined(__STDC__)
|
---|
306 | if ( ! isalpha(line[i])
|
---|
307 | #else
|
---|
308 | if ( ! isascii(line[i]) || ! isalpha(line[i])
|
---|
309 | #endif
|
---|
310 | || line[i+1] != '=')
|
---|
311 | break;
|
---|
312 | if ((s = strrchr(line, '\n')) != NULL)
|
---|
313 | *s = '\0';
|
---|
314 | else
|
---|
315 | line[MAXLINE-1] = '\0';
|
---|
316 | switch (line[i]) {
|
---|
317 | /*
|
---|
318 | * \tb=<bolding_string>
|
---|
319 | */
|
---|
320 | case 'b':
|
---|
321 | if (Fstr.b != NULL) {
|
---|
322 | (void) fprintf(stderr,
|
---|
323 | "%s: dup bold for %s in %s: %s\n",
|
---|
324 | Pname, Device, p, line);
|
---|
325 | (void) free(Fstr.b);
|
---|
326 | Fstr.b = NULL;
|
---|
327 | }
|
---|
328 | if ((Fstr.b = Convstr(&line[i+2], &Fstr.bl))
|
---|
329 | == NULL)
|
---|
330 | err++;
|
---|
331 | break;
|
---|
332 | /*
|
---|
333 | * \ti=<italicization_string>
|
---|
334 | */
|
---|
335 | case 'i':
|
---|
336 | if (Fstr.it != NULL) {
|
---|
337 | (void) fprintf(stderr,
|
---|
338 | "%s: dup italic for %s in %s: %s\n",
|
---|
339 | Pname, Device, p, line);
|
---|
340 | (void) free(Fstr.it);
|
---|
341 | Fstr.it = NULL;
|
---|
342 | }
|
---|
343 | if ((Fstr.it = Convstr(&line[i+2], &Fstr.itl))
|
---|
344 | == NULL)
|
---|
345 | err++;
|
---|
346 | break;
|
---|
347 | /*
|
---|
348 | * \tr=<return_to_Roman_string>
|
---|
349 | */
|
---|
350 | case 'r':
|
---|
351 | if (Fstr.r != NULL) {
|
---|
352 | (void) fprintf(stderr,
|
---|
353 | "%s: dup roman for %s in %s: %s\n",
|
---|
354 | Pname, Device, p, line);
|
---|
355 | (void) free(Fstr.r);
|
---|
356 | Fstr.r = NULL;
|
---|
357 | }
|
---|
358 | if ((Fstr.r = Convstr(&line[i+2], &Fstr.rl))
|
---|
359 | == NULL)
|
---|
360 | err++;
|
---|
361 | break;
|
---|
362 | /*
|
---|
363 | * \tf=<font_name>=<font_initialization_string>
|
---|
364 | */
|
---|
365 | case 'f':
|
---|
366 | if ( ! Devfont || Fstr.i)
|
---|
367 | break;
|
---|
368 | if ((i = Convfont(Device, &line[i+2], &fn, &fi))
|
---|
369 | < 0)
|
---|
370 | err++;
|
---|
371 | else if (fn && strcmp(Devfont, fn) == 0) {
|
---|
372 | Fstr.i = fi;
|
---|
373 | Fstr.il = i;
|
---|
374 | fi = NULL;
|
---|
375 | }
|
---|
376 | if (fn) {
|
---|
377 | (void) free(fn);
|
---|
378 | fn = NULL;
|
---|
379 | }
|
---|
380 | if (fi) {
|
---|
381 | (void) free((char *)fi);
|
---|
382 | fi = NULL;
|
---|
383 | }
|
---|
384 | break;
|
---|
385 | /*
|
---|
386 | * ????
|
---|
387 | */
|
---|
388 | default:
|
---|
389 | (void) fprintf(stderr,
|
---|
390 | "%s: unknown device %s line: %s\n",
|
---|
391 | Pname, Device, line);
|
---|
392 | err++;
|
---|
393 | }
|
---|
394 | }
|
---|
395 | break;
|
---|
396 | }
|
---|
397 | (void) fclose(fs);
|
---|
398 | if (err)
|
---|
399 | return(1);
|
---|
400 | /*
|
---|
401 | * See if the device stanza was located and the font exists.
|
---|
402 | */
|
---|
403 | if ( ! fd) {
|
---|
404 | (void) fprintf(stderr, "%s: can't find device %s in %s\n",
|
---|
405 | Pname, Device, p);
|
---|
406 | return(1);
|
---|
407 | }
|
---|
408 | if (Devfont && ! Fstr.i) {
|
---|
409 | (void) fprintf(stderr,
|
---|
410 | "%s: font %s for device %s not found in %s\n",
|
---|
411 | Pname, Devfont, Device, p);
|
---|
412 | return(1);
|
---|
413 | }
|
---|
414 | return(0);
|
---|
415 | }
|
---|