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