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