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) 1996, by Sun Microsystems, Inc.
24 * All rights reserved.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 /*
30 * ticscan.c Terminal Information Compiler
31 *
32 * Copyright 1990, 1992 by Mortice Kern Systems Inc. All rights reserved.
33 *
34 * Portions of this code Copyright 1982 by Pavel Curtis.
35 *
36 */
37
38 #ifdef M_RCSID
39 #ifndef lint
40 static char rcsID[] = "$Header: /rd/src/tic/rcs/ticscan.c 1.13 1994/02/08 20:19:29 rog Exp $";
41 #endif
42 #endif
43
44 #include "tic.h"
45 #include <limits.h>
46 #include <ctype.h>
47
48 #define iswhite(ch) (ch == ' ' || ch == '\t')
49
50
51 token curr_token;
52 long curr_file_pos;
53 int curr_column = -1;
54 char line[LINE_MAX+1];
55 static int first_column; /* See 'next_char()' below */
56
57 STATIC int next_char ANSI((void));
58 STATIC int trans_string ANSI((char *));
59 STATIC int escape ANSI((int));
60 STATIC void backspace ANSI((void));
61
62 char early_eof[] = m_textstr(3122, "Premature EOF", "E");
63 char nl_middle[] = m_textstr(3123, "Newline in middle of terminal name", "E");
64 char ill_char[] = m_textstr(3124, "Illegal character - '%c'", "E char");
65 char ill_ctrl[] = m_textstr(3125, "Illegal control character - '%c'", "E char");
66 char off_beg[] = m_textstr(3126, "Backspaced off beginning of line", "E");
67 char no_comma[] = m_textstr(3127, "Missing comma", "E");
68 char very_long[] = m_textstr(3128, "Very long string found. Missing comma?", "E");
69 char token_msg[] = m_textstr(3129, "Token: ", "I");
70 char bool_msg[] = m_textstr(3130, "Boolean; name='%s'\n", "I string");
71 char num_msg[] = m_textstr(3131, "Number; name='%s', value=%d\n", "I name value");
72 char str_msg[] = m_textstr(3132, "String; name='%s', value='%s'\n", "I name value");
73 char cancel[] = m_textstr(3133, "Cancel; name='%s'\n", "I name");
74 char names[] = m_textstr(3134, "Names; value='%s'\n", "I value");
75 char eof_msg[] = m_textstr(3135, "End of file.\n", "I");
76 char bad_token[] = m_textstr(3136, "Bad token type", "E");
77
78
79 /*f
80 * Scans the input for the next token, storing the specifics in the
81 * global structure 'curr_token' and returning one of the following:
82 *
83 * NAMES A line beginning in column 1. 'name'
84 * will be set to point to everything up to
85 * but not including the first comma on the line.
86 * BOOLEAN An entry consisting of a name followed by
87 * a comma. 'name' will be set to point to the
88 * name of the capability.
89 * NUMBER An entry of the form
90 * name#digits,
91 * 'name' will be set to point to the capability
92 * name and 'valnumber' to the number given.
93 * STRING An entry of the form
94 * name=characters,
95 * 'name' is set to the capability name and
96 * 'valstring' to the string of characters, with
97 * input translations done.
98 * CANCEL An entry of the form
99 * name@,
100 * 'name' is set to the capability name and
101 * 'valnumber' to -1.
102 * EOF The end of the file has been reached.
103 */
104 int
get_token()105 get_token()
106 {
107 long number;
108 int type;
109 int ch;
110 static char buffer[1024];
111 register char *ptr;
112 int dot_flag = 0;
113
114 while ((ch = next_char()) == '\n' || iswhite(ch)) {
115 ;
116 }
117
118 if (ch == EOF)
119 type = EOF;
120 else
121 {
122 if (ch == '.')
123 {
124 dot_flag = 1;
125
126 while ((ch = next_char()) == ' ' || ch == '\t')
127 ;
128 }
129
130 if (! isalnum(ch)) {
131 warning(m_strmsg(ill_char), ch);
132 panic_mode(',');
133 }
134
135 ptr = buffer;
136 *(ptr++) = ch;
137
138 if (first_column)
139 {
140 while ((ch = next_char()) != ',' && ch != '\n' && ch != EOF)
141 *(ptr++) = ch;
142
143 if (ch == EOF)
144 err_abort(m_strmsg(early_eof));
145 else if (ch == '\n') {
146 warning(m_strmsg(nl_middle));
147 panic_mode(',');
148 }
149
150 *ptr = '\0';
151 curr_token.tk_name = buffer;
152 type = NAMES;
153 }
154 else
155 {
156 ch = next_char();
157 while (isalnum(ch))
158 {
159 *(ptr++) = ch;
160 ch = next_char();
161 }
162
163 *ptr++ = '\0';
164 switch (ch)
165 {
166 case ',':
167 curr_token.tk_name = buffer;
168 type = BOOLEAN;
169 break;
170
171 case '@':
172 if (next_char() != ',')
173 warning(m_strmsg(no_comma));
174 curr_token.tk_name = buffer;
175 type = CANCEL;
176 break;
177
178 case '#':
179 number = 0;
180 while (isdigit(ch = next_char()))
181 number = number * 10 + ch - '0';
182 if (ch != ',')
183 warning(m_strmsg(no_comma));
184 curr_token.tk_name = buffer;
185 curr_token.tk_valnumber = number;
186 type = NUMBER;
187 break;
188
189 case '=':
190 ch = trans_string(ptr);
191 if (ch != ',')
192 warning(m_strmsg(no_comma));
193 curr_token.tk_name = buffer;
194 curr_token.tk_valstring = ptr;
195 type = STRING;
196 break;
197
198 default:
199 warning(m_strmsg(ill_char), ch);
200 }
201 } /* end else (first_column == 0) */
202 } /* end else (ch != EOF) */
203
204 if (dot_flag == 1)
205 DEBUG(8, "Commented out ", "");
206
207 if (debug_level >= 8)
208 {
209 fprintf(stderr, m_strmsg(token_msg));
210 switch (type)
211 {
212 case BOOLEAN:
213 fprintf(stderr, m_strmsg(bool_msg), curr_token.tk_name);
214 break;
215
216 case NUMBER:
217 fprintf(
218 stderr, m_strmsg(num_msg),
219 curr_token.tk_name, curr_token.tk_valnumber
220 );
221 break;
222
223 case STRING:
224 fprintf(
225 stderr, m_strmsg(str_msg),
226 curr_token.tk_name, curr_token.tk_valstring
227 );
228 break;
229
230 case CANCEL:
231 fprintf(stderr, m_strmsg(cancel), curr_token.tk_name);
232 break;
233
234 case NAMES:
235 fprintf(stderr, m_strmsg(names), curr_token.tk_name);
236 break;
237
238 case EOF:
239 fprintf(stderr, m_strmsg(eof_msg));
240 break;
241
242 default:
243 warning(m_strmsg(bad_token));
244 }
245 }
246
247 if (dot_flag == 1) /* if commented out, use the next one */
248 type = get_token();
249
250 return(type);
251 }
252
253
254 /*f
255 * Returns the next character in the input stream. Comments and leading
256 * white space are stripped. The global state variable 'firstcolumn' is
257 * set TRUE if the character returned is from the first column of the input
258 * line. The global variable curr_line is incremented for each new line.
259 * The global variable curr_file_pos is set to the file offset of the
260 * beginning of each line.
261 */
262 STATIC int
next_char()263 next_char()
264 {
265 char *rtn_value;
266
267 if (curr_column < 0 || LINE_MAX < curr_column
268 || line[curr_column] == '\0') {
269 do {
270 curr_file_pos = ftell(stdin);
271 if ((rtn_value = fgets(line, LINE_MAX, stdin)) != NULL)
272 curr_line++;
273 } while (rtn_value != NULL && line[0] == '#');
274
275 if (rtn_value == NULL)
276 return (EOF);
277
278 curr_column = 0;
279 while (iswhite(line[curr_column]))
280 curr_column++;
281 }
282 first_column = curr_column == 0 && *line != '\n';
283 return (line[curr_column++]);
284 }
285
286
287 /*f
288 * go back one character
289 */
290 STATIC void
backspace()291 backspace()
292 {
293 curr_column--;
294
295 if (curr_column < 0)
296 syserr_abort(m_strmsg(off_beg));
297 }
298
299
300 /*f
301 * Resets the input-reading routines. Used after a seek has been done.
302 */
303 void
reset_input()304 reset_input()
305 {
306 curr_column = -1;
307 }
308
309 /*f
310 * Reads characters using next_char() until encountering a comma, newline
311 * or end-of-file. The returned value is the character which caused
312 * reading to stop. The following translations are done on the input:
313 *
314 * ^X goes to ctrl-X (i.e. X & 037)
315 * {backslash-E,backslash-n,backslash-r,backslash-b,
316 * backslash-t,backslash-f} go to
317 * {ESCAPE,newline,carriage-return,backspace,tab,formfeed}
318 * {backslash-^,backslash-backslash} go to {carat,backslash}
319 * backslash-ddd (for ddd = up to three octal digits) goes to
320 * the character ddd
321 *
322 * backslash-e == backslash-E
323 * backslash-0 == backslash-200
324 */
325 STATIC int
trans_string(ptr)326 trans_string(ptr)
327 char *ptr;
328 {
329 int i, number, ch;
330 register int count = 0;
331
332 while ((ch = next_char()) != ',' && ch != EOF) {
333 if (ch == '^') {
334 ch = next_char();
335 if (ch == EOF)
336 err_abort(m_strmsg(early_eof));
337 if (!isprint(ch))
338 warning(m_strmsg(ill_ctrl), ch);
339 *(ptr++) = ch & 037;
340 } else if (ch == '\\') {
341 /* Try to read a three character octal number. */
342 for (number = i = 0; i < 3; ++i) {
343 ch = next_char();
344 if (ch == EOF)
345 err_abort(m_strmsg(early_eof));
346 if (ch < '0' || '7' < ch) {
347 backspace();
348 break;
349 }
350 number = number * 8 + ch - '0';
351 }
352 if (0 < i) {
353 /* Read an octal number. */
354 *ptr++ = number == 0 ? 0200 : (char) number;
355 } else {
356 /* Escape mapping translation. */
357 ch = escape(next_char());
358 *ptr++ = ch;
359 }
360 } else {
361 *(ptr++) = ch;
362 }
363 if (500 < ++count)
364 warning(m_strmsg(very_long));
365 }
366 *ptr = '\0';
367 return (ch);
368 }
369
370 /*f
371 * Panic mode error recovery - skip everything until a "ch" is found.
372 */
373 void
panic_mode(ch)374 panic_mode(ch)
375 char ch;
376 {
377 int c;
378 for (;;) {
379 c = next_char();
380 if (c == ch)
381 return;
382 if (c == EOF);
383 return;
384 }
385 }
386
387 /*f
388 * This routine is a codeset independent method of specifying a translation
389 * from an unambiguous printable form, to an internal binary value.
390 * This mapping is defined by Table 2-13 in section 2-12 of POSIX.2.
391 *
392 * This table has been extended to account for tic/infocmp specification
393 * of additional characters: <escape>, <space>, <colon>, <caret>, <comma>
394 *
395 * Assume that the escape lead-in character has been processed and
396 * any escaped octal sequence.
397 */
398 STATIC int
escape(c)399 escape(c)
400 int c;
401 {
402 int i;
403 static int cntl_code[] = {
404 '\0', '\\', M_ALERT, '\b', '\f', '\n', '\r', '\t',
405 M_VTAB, M_ESCAPE, M_ESCAPE, ' ', ':', '^', ',',
406 -1
407 };
408 static int escape_char[] = {
409 '\0', '\\', 'a', 'b', 'f', 'n', 'r', 't',
410 'v', 'E', 'e', 's', ':', '^', ',',
411 -1
412 };
413 for (i = 0; escape_char[i] != -1; ++i)
414 if (c == escape_char[i])
415 return (cntl_code[i]);
416 return (c);
417 }
418