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