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