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 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 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 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 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 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 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 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