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 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* Copyright (c) 1982 Regents of the University of California */ 31 32 #pragma ident "%Z%%M% %I% %E% SMI" 33 34 /* 35 * unifdef - remove ifdef'ed lines 36 */ 37 38 #include <stdio.h> 39 #include <ctype.h> 40 #include <locale.h> 41 #define BSS 42 FILE *input; 43 #ifndef YES 44 #define YES 1 45 #define NO 0 46 #endif 47 48 char *progname BSS; 49 char *filename BSS; 50 char text BSS; /* -t option in effect: this is a text file */ 51 char lnblank BSS; /* -l option in effect: blank deleted lines */ 52 char complement BSS; /* -c option in effect: complement the operation */ 53 #define MAXSYMS 100 54 char true[MAXSYMS] BSS; 55 char ignore[MAXSYMS] BSS; 56 char *sym[MAXSYMS] BSS; 57 signed char insym[MAXSYMS] BSS; 58 #define KWSIZE 8 59 char buf[KWSIZE]; 60 char nsyms BSS; 61 char incomment BSS; 62 #define QUOTE1 0 63 #define QUOTE2 1 64 char inquote[2] BSS; 65 int exitstat BSS; 66 char *skipcomment (); 67 char *skipquote (); 68 char *nextsym(); 69 70 #ifdef i386 71 #define gettext(s) s 72 #endif 73 74 main (argc, argv) 75 int argc; 76 char **argv; 77 { 78 char **curarg; 79 register char *cp; 80 register char *cp1; 81 char ignorethis; 82 83 (void) setlocale (LC_ALL, ""); 84 85 /* i386 doesn't handle this yet */ 86 #ifndef i386 87 88 #if !defined(TEXT_DOMAIN) 89 #define TEXT_DOMAIN "SYS_TEST" 90 #endif 91 (void) textdomain(TEXT_DOMAIN); 92 93 #endif 94 95 progname = argv[0][0] ? argv[0] : "unifdef"; 96 97 for (curarg = &argv[1]; --argc > 0; curarg++) { 98 if (*(cp1 = cp = *curarg) != '-') 99 break; 100 if (*++cp1 == 'i') { 101 ignorethis = YES; 102 cp1++; 103 } 104 else 105 ignorethis = NO; 106 if ( ( *cp1 == 'D' 107 || *cp1 == 'U' 108 ) 109 && cp1[1] != '\0' 110 ) { 111 if (nsyms >= MAXSYMS) { 112 prname (); 113 fprintf (stderr, gettext("too many symbols.\n")); 114 exit (2); 115 } 116 ignore[nsyms] = ignorethis; 117 true[nsyms] = *cp1 == 'D' ? YES : NO; 118 sym[nsyms++] = &cp1[1]; 119 } 120 else if (ignorethis) 121 goto unrec; 122 else if (strcmp (&cp[1], "t") == 0) 123 text = YES; 124 else if (strcmp (&cp[1], "l") == 0) 125 lnblank = YES; 126 else if (strcmp (&cp[1], "c") == 0) 127 complement = YES; 128 else { 129 unrec: 130 prname (); 131 fprintf (stderr, gettext("unrecognized option: %s\n"), cp); 132 goto usage; 133 } 134 } 135 if (nsyms == 0) { 136 usage: 137 fprintf (stderr, gettext("\ 138 Usage: %s [-l] [-t] [-c] [[-Dsym] [-Usym] [-idsym] [-iusym]]... [file]\n\ 139 At least one arg from [-D -U -id -iu] is required\n"), progname); 140 exit (2); 141 } 142 143 if (argc > 1) { 144 prname (); 145 fprintf (stderr, gettext("can only do one file.\n")); 146 } 147 else if (argc == 1) { 148 filename = *curarg; 149 if ((input = fopen (filename, "r")) != NULL) { 150 pfile(); 151 fclose (input); 152 } 153 else { 154 prname (); 155 perror(*curarg); 156 } 157 } 158 else { 159 filename = "[stdin]"; 160 input = stdin; 161 pfile(); 162 } 163 164 fflush (stdout); 165 exit (exitstat); 166 /* NOTREACHED */ 167 } 168 169 /* types of input lines: */ 170 #define PLAIN 0 /* ordinary line */ 171 #define TRUE 1 /* a true #ifdef of a symbol known to us */ 172 #define FALSE 2 /* a false #ifdef of a symbol known to us */ 173 #define OTHER 3 /* an #ifdef of a symbol not known to us */ 174 #define ELSE 4 /* #else */ 175 #define ENDIF 5 /* #endif */ 176 #define LEOF 6 /* end of file */ 177 178 /* should be int declaration, was char */ 179 int reject BSS; /* 0 or 1: pass thru; 1 or 2: ignore comments */ 180 int linenum BSS; /* current line number */ 181 int stqcline BSS; /* start of current coment or quote */ 182 char *errs[] = { 183 #define NO_ERR 0 184 "", 185 #define END_ERR 1 186 "", 187 #define ELSE_ERR 2 188 "Inappropriate else", 189 #define ENDIF_ERR 3 190 "Inappropriate endif", 191 #define IEOF_ERR 4 192 "Premature EOF in ifdef", 193 #define CEOF_ERR 5 194 "Premature EOF in comment", 195 #define Q1EOF_ERR 6 196 "Premature EOF in quoted character", 197 #define Q2EOF_ERR 7 198 "Premature EOF in quoted string" 199 }; 200 201 pfile () 202 { 203 reject = 0; 204 doif (-1, NO, reject, 0); 205 return; 206 } 207 208 doif (thissym, inif, prevreject, depth) 209 register int thissym; /* index of the symbol who was last ifdef'ed */ 210 int inif; /* YES or NO we are inside an ifdef */ 211 int prevreject; /* previous value of reject */ 212 int depth; /* depth of ifdef's */ 213 { 214 register int lineval; 215 register int thisreject; 216 int doret; /* tmp return value of doif */ 217 int cursym; /* index of the symbol returned by checkline */ 218 int stline; /* line number when called this time */ 219 220 stline = linenum; 221 for (;;) { 222 switch (lineval = checkline (&cursym)) { 223 case PLAIN: 224 flushline (YES); 225 break; 226 227 case TRUE: 228 case FALSE: 229 thisreject = reject; 230 if (lineval == TRUE) 231 insym[cursym] = 1; 232 else { 233 if (reject < 2) 234 reject = ignore[cursym] ? 1 : 2; 235 insym[cursym] = -1; 236 } 237 if (ignore[cursym]) 238 flushline (YES); 239 else { 240 exitstat = 0; 241 flushline (NO); 242 } 243 if ((doret = doif (cursym, YES, thisreject, depth + 1)) != NO_ERR) 244 return error (doret, stline, depth); 245 break; 246 247 case OTHER: 248 flushline (YES); 249 if ((doret = doif (-1, YES, reject, depth + 1)) != NO_ERR) 250 return error (doret, stline, depth); 251 break; 252 253 case ELSE: 254 if (inif != 1) 255 return error (ELSE_ERR, linenum, depth); 256 inif = 2; 257 if (thissym >= 0) { 258 if ((insym[thissym] = -insym[thissym]) < 0) 259 reject = ignore[thissym] ? 1 : 2; 260 else 261 reject = prevreject; 262 if (!ignore[thissym]) { 263 flushline (NO); 264 break; 265 } 266 } 267 flushline (YES); 268 break; 269 270 case ENDIF: 271 if (inif == 0) 272 return error (ENDIF_ERR, linenum, depth); 273 if (thissym >= 0) { 274 insym[thissym] = 0; 275 reject = prevreject; 276 if (!ignore[thissym]) { 277 flushline (NO); 278 return NO_ERR; 279 } 280 } 281 flushline (YES); 282 return NO_ERR; 283 284 case LEOF: { 285 int err; 286 err = incomment 287 ? CEOF_ERR 288 : inquote[QUOTE1] 289 ? Q1EOF_ERR 290 : inquote[QUOTE2] 291 ? Q2EOF_ERR 292 : NO_ERR; 293 if (inif) { 294 if (err != NO_ERR) 295 error (err, stqcline, depth); 296 return error (IEOF_ERR, stline, depth); 297 } 298 else if (err != NO_ERR) 299 return error (err, stqcline, depth); 300 else 301 return NO_ERR; 302 } 303 } 304 } 305 } 306 307 #define endsym(c) (!isalpha (c) && !isdigit (c) && c != '_') 308 309 #define MAXLINE 256 310 char tline[MAXLINE] BSS; 311 312 checkline (cursym) 313 int *cursym; 314 { 315 register char *cp; 316 register char *symp; 317 register char chr; 318 char *scp; 319 int retval; 320 int symind; 321 char keyword[KWSIZE]; 322 323 linenum++; 324 if (getlin (tline, sizeof tline, input, NO) == EOF) 325 return LEOF; 326 327 retval = PLAIN; 328 if ( *(cp = tline) != '#' 329 || incomment 330 || inquote[QUOTE1] 331 || inquote[QUOTE2] 332 ) 333 goto eol; 334 335 cp = skipcomment (++cp); 336 symp = keyword; 337 while (!endsym (*cp)) { 338 *symp = *cp++; 339 if (++symp >= &keyword[KWSIZE]) 340 goto eol; 341 } 342 *symp = '\0'; 343 344 if (strcmp (keyword, "ifdef") == 0) { 345 retval = YES; 346 goto ifdef; 347 } 348 else if (strcmp (keyword, "if") == 0) { 349 cp = skipcomment(++cp); 350 if (strcmp (nextsym(cp), "defined") == 0) { 351 cp += strlen("defined") + 1; 352 /* skip to identifier */ 353 while (endsym(*cp)) 354 ++cp; 355 retval = YES; 356 goto ifdef; 357 } 358 else { 359 retval = OTHER; 360 goto eol; 361 } 362 } 363 else if (strcmp (keyword, "ifndef") == 0) { 364 retval = NO; 365 ifdef: 366 scp = cp = skipcomment (cp); 367 if (incomment) { 368 retval = PLAIN; 369 goto eol; 370 } 371 for (symind = 0; ; ) { 372 if (insym[symind] == 0) { 373 for ( symp = sym[symind], cp = scp 374 ; *symp && *cp == *symp 375 ; cp++, symp++ 376 ) 377 {} 378 chr = *cp; 379 if (*symp == '\0' && endsym (chr)) { 380 *cursym = symind; 381 retval = (retval ^ true[symind]) ? FALSE : TRUE; 382 break; 383 } 384 } 385 if (++symind >= nsyms) { 386 retval = OTHER; 387 break; 388 } 389 } 390 } 391 else if (strcmp (keyword, "else") == 0) 392 retval = ELSE; 393 else if (strcmp (keyword, "endif") == 0) 394 retval = ENDIF; 395 396 eol: 397 if (!text && !reject) 398 for (; *cp; ) { 399 if (incomment) 400 cp = skipcomment (cp); 401 else if (inquote[QUOTE1]) 402 cp = skipquote (cp, QUOTE1); 403 else if (inquote[QUOTE2]) 404 cp = skipquote (cp, QUOTE2); 405 else if (*cp == '/' && cp[1] == '*') 406 cp = skipcomment (cp); 407 else if (*cp == '\'') 408 cp = skipquote (cp, QUOTE1); 409 else if (*cp == '"') 410 cp = skipquote (cp, QUOTE2); 411 else 412 cp++; 413 } 414 return retval; 415 } 416 417 /* Skip over comments and stop at the next character 418 * position that is not whitespace. 419 */ 420 char * 421 skipcomment (cp) 422 register char *cp; 423 { 424 if (incomment) 425 goto inside; 426 for (;; cp++) { 427 while (*cp == ' ' || *cp == '\t') 428 cp++; 429 if (text) 430 return cp; 431 if ( cp[0] != '/' 432 || cp[1] != '*' 433 ) 434 return cp; 435 cp += 2; 436 if (!incomment) { 437 incomment = YES; 438 stqcline = linenum; 439 } 440 inside: 441 for (;;) { 442 for (; *cp != '*'; cp++) 443 if (*cp == '\0') 444 return cp; 445 if (*++cp == '/') 446 break; 447 } 448 incomment = NO; 449 } 450 } 451 452 /* Skip over a quoted string or character and stop at the next charaacter 453 * position that is not whitespace. 454 */ 455 char * 456 skipquote (cp, type) 457 register char *cp; 458 register int type; 459 { 460 register char qchar; 461 462 qchar = type == QUOTE1 ? '\'' : '"'; 463 464 if (inquote[type]) 465 goto inside; 466 for (;; cp++) { 467 if (*cp != qchar) 468 return cp; 469 cp++; 470 if (!inquote[type]) { 471 inquote[type] = YES; 472 stqcline = linenum; 473 } 474 inside: 475 for (; ; cp++) { 476 if (*cp == qchar) 477 break; 478 if ( *cp == '\0' 479 || *cp == '\\' 480 && *++cp == '\0' 481 ) 482 return cp; 483 } 484 inquote[type] = NO; 485 } 486 } 487 488 /* 489 * special getlin - treats form-feed as an end-of-line 490 * and expands tabs if asked for 491 * 492 */ 493 getlin (line, maxline, inp, expandtabs) 494 register char *line; 495 int maxline; 496 FILE *inp; 497 int expandtabs; 498 { 499 int tmp; 500 register int num; 501 register int chr; 502 #ifdef FFSPECIAL 503 static char havechar = NO; /* have leftover char from last time */ 504 static char svchar BSS; 505 #endif 506 507 num = 0; 508 #ifdef FFSPECIAL 509 if (havechar) { 510 havechar = NO; 511 chr = svchar; 512 goto ent; 513 } 514 #endif 515 while (num + 8 < maxline) { /* leave room for tab */ 516 chr = getc (inp); 517 if (isprint (chr)) { 518 #ifdef FFSPECIAL 519 ent: 520 #endif 521 *line++ = chr; 522 num++; 523 } 524 else 525 switch (chr) { 526 case EOF: 527 return EOF; 528 529 case '\t': 530 if (expandtabs) { 531 num += tmp = 8 - (num & 7); 532 do 533 *line++ = ' '; 534 while (--tmp); 535 break; 536 } 537 default: 538 *line++ = chr; 539 num++; 540 break; 541 542 case '\n': 543 *line = '\n'; 544 num++; 545 goto end; 546 547 #ifdef FFSPECIAL 548 case '\f': 549 if (++num == 1) 550 *line = '\f'; 551 else { 552 *line = '\n'; 553 havechar = YES; 554 svchar = chr; 555 } 556 goto end; 557 #endif 558 } 559 } 560 end: 561 *++line = '\0'; 562 return num; 563 } 564 565 flushline (keep) 566 { 567 if ((keep && reject < 2) ^ complement) 568 putlin (tline, stdout); 569 else if (lnblank) 570 putlin ("\n", stdout); 571 return; 572 } 573 574 /* 575 * putlin - for tools 576 * 577 */ 578 putlin (line, fio) 579 register char *line; 580 register FILE *fio; 581 { 582 register char chr; 583 584 while (chr = *line++) 585 putc (chr, fio); 586 return; 587 } 588 589 prname () 590 { 591 fprintf (stderr, "%s: ", progname); 592 return; 593 } 594 595 596 error (err, line, depth) 597 { 598 if (err == END_ERR) 599 return err; 600 601 prname (); 602 603 #ifndef TESTING 604 fprintf (stderr, gettext("Error in %s line %d: %s.\n"), 605 filename, line, gettext(errs[err])); 606 #endif 607 608 #ifdef TESTING 609 fprintf (stderr, gettext("Error in %s line %d: %s. "), 610 filename, line, errs[err]); 611 fprintf (stderr, gettext("ifdef depth: %d\n"), depth); 612 #endif 613 614 exitstat = 1; 615 return depth > 1 ? IEOF_ERR : END_ERR; 616 } 617 618 /* return the next token in the line buffer */ 619 char * 620 nextsym(p) 621 char *p; 622 { 623 register char *key; 624 register int i = KWSIZE; 625 626 key = buf; 627 while (!endsym(*p) && --i) 628 *key++ = *p++; 629 *key = '\0'; 630 631 return (buf); 632 } 633