xref: /titanic_51/usr/src/cmd/tic/tic_scan.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright (c) 1999 by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 /*	Copyright (c) 1988 AT&T	*/
27 /*	  All Rights Reserved  	*/
28 
29 
30 /*
31  * University Copyright- Copyright (c) 1982, 1986, 1988
32  * The Regents of the University of California
33  * All Rights Reserved
34  *
35  * University Acknowledgment- Portions of this document are derived from
36  * software developed by the University of California, Berkeley, and its
37  * contributors.
38  */
39 
40 #pragma ident	"%Z%%M%	%I%	%E% SMI"
41 
42 /*
43  *			COPYRIGHT NOTICE
44  *
45  *	This software is copyright(C) 1982 by Pavel Curtis
46  *
47  *	Permission is granted to reproduce and distribute
48  *	this file by any means so long as no fee is charged
49  *	above a nominal handling fee and so long as this
50  *	notice is always included in the copies.
51  *
52  *	Other rights are reserved except as explicitly granted
53  *	by written permission of the author.
54  *		Pavel Curtis
55  *		Computer Science Dept.
56  *		405 Upson Hall
57  *		Cornell University
58  *		Ithaca, NY 14853
59  *
60  *		Ph- (607) 256-4934
61  *
62  *		Pavel.Cornell@Udel-Relay(ARPAnet)
63  *		decvax!cornell!pavel(UUCPnet)
64  */
65 
66 /*
67  *	comp_scan.c --- Lexical scanner for terminfo compiler.
68  *
69  *   $Log:	RCS/comp_scan.v $
70  * Revision 2.1  82/10/25  14:45:55  pavel
71  * Added Copyright Notice
72  *
73  * Revision 2.0  82/10/24  15:17:12  pavel
74  * Beta-one Test Release
75  *
76  * Revision 1.3  82/08/23  22:30:03  pavel
77  * The REAL Alpha-one Release Version
78  *
79  * Revision 1.2  82/08/19  19:10:06  pavel
80  * Alpha Test Release One
81  *
82  * Revision 1.1  82/08/12  18:37:46  pavel
83  * Initial revision
84  *
85  *
86  */
87 
88 
89 #include <stdio.h>
90 #include <ctype.h>
91 #include "compiler.h"
92 
93 #define	iswhite(ch)	(ch == ' ' || ch == '\t')
94 
95 
96 static int	first_column;		/* See 'next_char()' below */
97 
98 
99 
100 /*
101  *	int
102  *	get_token()
103  *
104  *	Scans the input for the next token, storing the specifics in the
105  *	global structure 'curr_token' and returning one of the following:
106  *
107  *		NAMES		A line beginning in column 1.  'name'
108  *				will be set to point to everything up to
109  *				but not including the first comma on the line.
110  *		BOOLEAN		An entry consisting of a name followed by
111  *				a comma.  'name' will be set to point to the
112  *				name of the capability.
113  *		NUMBER		An entry of the form
114  *					name#digits,
115  *				'name' will be set to point to the capability
116  *				name and 'valnumber' to the number given.
117  *		STRING		An entry of the form
118  *					name=characters,
119  *				'name' is set to the capability name and
120  *				'valstring' to the string of characters, with
121  *				input translations done.
122  *		CANCEL		An entry of the form
123  *					name@,
124  *				'name' is set to the capability name and
125  *				'valnumber' to -1.
126  *		EOF		The end of the file has been reached.
127  *
128  */
129 
130 int
131 get_token()
132 {
133 	long		number;
134 	int		type;
135 	register int	ch;
136 	static char	buffer[1024];
137 	register char	*ptr;
138 	int		dot_flag = FALSE;
139 
140 	while ((ch = next_char()) == '\n' || (isascii(ch) && iswhite(ch)));
141 
142 	if (ch == EOF)
143 	    type = EOF;
144 	else {
145 	    if (ch == '.') {
146 		dot_flag = TRUE;
147 
148 		while ((ch = next_char()) == ' ' || ch == '\t');
149 	    }
150 
151 	    if (! isascii(ch) || ! isalnum(ch)) {
152 		warning("Illegal character - '%c'", ch);
153 		panic_mode(',');
154 	    }
155 
156 	    ptr = buffer;
157 	    if (ch != '\n') *(ptr++) = ch;
158 
159 	    if (first_column) {
160 		while ((ch = next_char()) != ',' && ch != '\n' && ch != EOF)
161 		    *(ptr++) = ch;
162 
163 		if (ch == EOF)
164 		    err_abort("Premature EOF");
165 		else if (ch == '\n') {
166 		    warning("Newline in middle of terminal name");
167 		    panic_mode(',');
168 		}
169 
170 		*ptr = '\0';
171 		curr_token.tk_name = buffer;
172 		type = NAMES;
173 	    } else {
174 		ch = next_char();
175 		while (isascii(ch) && isalnum(ch)) {
176 		    *(ptr++) = ch;
177 		    ch = next_char();
178 		}
179 
180 		*ptr++ = '\0';
181 		switch (ch) {
182 		    case ',':
183 			curr_token.tk_name = buffer;
184 			type = BOOLEAN;
185 			break;
186 
187 		    case '@':
188 			if (next_char() != ',')
189 			    warning("Missing comma");
190 			curr_token.tk_name = buffer;
191 			type = CANCEL;
192 			break;
193 
194 		    case '#':
195 			number = 0;
196 			if ((ch = next_char()) == ',')
197 				warning("Missing numeric value");
198 			backspace();
199 			if ((ch = next_char()) == '0') {
200 			    if ((ch = next_char()) == 'x' || ch == 'X') {
201 				while (isascii(ch = next_char()) &&
202 				    isxdigit(ch)) {
203 				    number *= 16;
204 				    if (isdigit(ch))
205 					number += ch - '0';
206 				    else if (ch >= 'a' && ch <= 'f')
207 					number += 10 + ch - 'a';
208 				    else
209 					number += 10 + ch - 'A';
210 				}
211 			    } else {
212 				backspace();
213 				while ((ch = next_char()) >= '0' &&
214 				    ch <= '7')
215 				    number = number * 8 + ch - '0';
216 				}
217 			    } else {
218 				    backspace();
219 				    while (isascii(ch = next_char()) &&
220 					isdigit(ch))
221 					number = number * 10 + ch - '0';
222 			    }
223 			if (ch != ',')
224 			    warning("Missing comma");
225 			curr_token.tk_name = buffer;
226 			curr_token.tk_valnumber = number;
227 			type = NUMBER;
228 			break;
229 
230 		    case '=':
231 			ch = trans_string(ptr);
232 			if (ch != NULL && ch != ',')
233 			    warning("Missing comma");
234 			if (ch == NULL)
235 				warning("NULL string value");
236 			curr_token.tk_name = buffer;
237 			curr_token.tk_valstring = ptr;
238 			type = STRING;
239 			break;
240 
241 		    default:
242 			warning("Illegal character - '%c'", ch);
243 		}
244 	    } /* end else (first_column == FALSE) */
245 	} /* end else (ch != EOF) */
246 
247 	if (dot_flag == TRUE)
248 	    DEBUG(8, "Commented out ", "");
249 
250 	if (debug_level >= 8) {
251 	    fprintf(stderr, "Token: ");
252 	    switch (type) {
253 		case BOOLEAN:
254 			fprintf(stderr, "Boolean;  name='%s'\n",
255 			    curr_token.tk_name);
256 			break;
257 
258 		case NUMBER:
259 			fprintf(stderr, "Number; name = '%s', value = %d\n",
260 			    curr_token.tk_name, curr_token.tk_valnumber);
261 			break;
262 
263 		case STRING:
264 			fprintf(stderr, "String; name = '%s', value = '%s'\n",
265 			    curr_token.tk_name, curr_token.tk_valstring);
266 			break;
267 
268 		case CANCEL:
269 			fprintf(stderr, "Cancel; name = '%s'\n",
270 			    curr_token.tk_name);
271 		    break;
272 
273 		case NAMES:
274 			fprintf(stderr, "Names; value = '%s'\n",
275 			    curr_token.tk_name);
276 			break;
277 
278 		case EOF:
279 			fprintf(stderr, "End of file\n");
280 			break;
281 
282 		default:
283 			warning("Bad token type");
284 	    }
285 	}
286 
287 	if (dot_flag == TRUE)	/* if commented out, use the next one */
288 	    type = get_token();
289 
290 	return (type);
291 }
292 
293 
294 
295 /*
296  *	int
297  *	next_char()
298  *
299  *	Returns the next character in the input stream.  Comments and leading
300  *	white space are stripped.  The global state variable 'firstcolumn' is
301  *	set TRUE if the character returned is from the first column of the
302  * 	inputline.  The global variable curr_line is incremented for each new.
303  *	line. The global variable curr_file_pos is set to the file offset
304  *	of the beginning of each line.
305  *
306  */
307 
308 int	curr_column = -1;
309 char	line[1024];
310 
311 int
312 next_char()
313 {
314 	char	*rtn_value;
315 	long	ftell();
316 	char	*p;
317 
318 	if (curr_column < 0 || curr_column > 1023 ||
319 	    line[curr_column] == '\0') {
320 	    do {
321 			curr_file_pos = ftell(stdin);
322 
323 			if ((rtn_value = fgets(line, 1024, stdin)) == NULL)
324 				return (EOF);
325 			curr_line++;
326 			p = &line[0];
327 			while (*p && iswhite(*p)) {
328 				p++;
329 			}
330 	    } while (*p == '#');
331 
332 	    curr_column = 0;
333 	    while (isascii(line[curr_column]) && iswhite(line[curr_column]))
334 		curr_column++;
335 	}
336 
337 	if (curr_column == 0 && line[0] != '\n')
338 	    first_column = TRUE;
339 	else
340 	    first_column = FALSE;
341 
342 	return (line[curr_column++]);
343 }
344 
345 
346 backspace()
347 {
348 	curr_column--;
349 
350 	if (curr_column < 0)
351 	    syserr_abort("Backspaced off beginning of line");
352 }
353 
354 
355 
356 /*
357  *	reset_input()
358  *
359  *	Resets the input-reading routines.  Used after a seek has been done.
360  *
361  */
362 
363 reset_input()
364 {
365 	curr_column = -1;
366 }
367 
368 
369 
370 /*
371  *	int
372  *	trans_string(ptr)
373  *
374  *	Reads characters using next_char() until encountering a comma, a new
375  *	entry, or end-of-file.  The returned value is the character which
376  *	caused reading to stop.  The following translations are done on the
377  *	input:
378  *
379  *		^X  goes to  ctrl-X (i.e. X & 037)
380  *		{\E,\n,\r,\b,\t,\f}  go to
381  *			{ESCAPE,newline,carriage-return,backspace,tab,formfeed}
382  *		{\^,\\}  go to  {carat,backslash}
383  *		\ddd (for ddd = up to three octal digits)  goes to
384  *							the character ddd
385  *
386  *		\e == \E
387  *		\0 == \200
388  *
389  */
390 
391 int
392 trans_string(char *ptr)
393 {
394 	register int	count = 0;
395 	int		number;
396 	register int	i;
397 	register int	ch;
398 
399 	while ((ch = next_char()) != ',' && ch != EOF && !first_column) {
400 	    if (ch == '^') {
401 		ch = next_char();
402 		if (ch == EOF)
403 		    err_abort("Premature EOF");
404 
405 		if (!isascii(ch) || ! isprint(ch)) {
406 		    warning("Illegal ^ character - '%c'", ch);
407 		}
408 
409 		if (ch == '@')
410 		    *(ptr++) = 0200;
411 		else
412 		    *(ptr++) = ch & 037;
413 	    } else if (ch == '\\') {
414 		ch = next_char();
415 		if (ch == EOF)
416 		    err_abort("Premature EOF");
417 
418 		if (ch >= '0' && ch <= '7') {
419 		    number = ch - '0';
420 		    for (i = 0; i < 2; i++) {
421 			ch = next_char();
422 			if (ch == EOF)
423 			    err_abort("Premature EOF");
424 
425 			if (ch < '0' || ch > '7') {
426 			    backspace();
427 			    break;
428 			}
429 
430 			number = number * 8 + ch - '0';
431 		    }
432 
433 		    if (number == 0)
434 			number = 0200;
435 		    *(ptr++) = (char)number;
436 		} else {
437 		    switch (ch) {
438 			case 'E':
439 			case 'e':	*(ptr++) = '\033';	break;
440 
441 			case 'l':
442 			case 'n':	*(ptr++) = '\n';	break;
443 
444 			case 'r':	*(ptr++) = '\r';	break;
445 
446 			case 'b':	*(ptr++) = '\010';	break;
447 
448 			case 's':	*(ptr++) = ' ';		break;
449 
450 			case 'f':	*(ptr++) = '\014';	break;
451 
452 			case 't':	*(ptr++) = '\t';	break;
453 
454 			case '\\':	*(ptr++) = '\\';	break;
455 
456 			case '^':	*(ptr++) = '^';		break;
457 
458 			case ',':	*(ptr++) = ',';		break;
459 
460 			case ':':	*(ptr++) = ':';		break;
461 
462 			default:
463 			    warning("Illegal character in \\ sequence - '%c'",
464 				ch);
465 			    *(ptr++) = ch;
466 		    } /* endswitch (ch) */
467 		} /* endelse (ch < '0' ||  ch > '7') */
468 	    } /* end else if (ch == '\\') */
469 	    else {
470 		if (ch != '\n') *(ptr++) = ch;
471 	    }
472 
473 	    count ++;
474 
475 	    if (count > 1000)
476 		warning("Very long string found.  Missing comma?");
477 	} /* end while */
478 
479 	if (ch == EOF)
480 	    warning("Premature EOF - missing comma?");
481 	/* start of new description */
482 	else if (first_column) {
483 	    backspace();
484 	    warning("Missing comma?");
485 	    /* pretend we did get a comma */
486 	    ch = ',';
487 	}
488 
489 	*ptr = '\0';
490 
491 	if (count == 0)
492 		return (NULL);
493 	return (ch);
494 }
495 
496 /*
497  * Panic mode error recovery - skip everything until a "ch" is found.
498  */
499 panic_mode(int ch)
500 {
501 	register int c;
502 
503 	for (;;) {
504 		c = next_char();
505 		if (c == ch)
506 			return;
507 		if (c == EOF)
508 			return;
509 	}
510 }
511