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