ifdef.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. /* (C) 1992,1996,1998-9 R de Bath */
  2. #include <stdio.h>
  3. #include <ctype.h>
  4. #include <string.h>
  5. #ifdef __STDC__ /* == Not braindead compiler (hopefully!) */
  6. #include <stdlib.h>
  7. #define P(x) x
  8. #else
  9. #define P(x) ()
  10. #define void char
  11. #endif
  12. /*
  13. * Linked list of variables, the only source for these is the command line
  14. * and the (optional) manifest constants.
  15. */
  16. struct varrec
  17. {
  18. struct varrec * next;
  19. int state;
  20. char name[1];
  21. }
  22. *varlist = 0;
  23. int cuttype = 0; /* 0 = use blank lines */
  24. /* 1 = use #lines */
  25. /* 2 = use '# 'oldtext */
  26. /* 3 = delete unused lines */
  27. int striphash = 0;
  28. int stripcomment = 0;
  29. char linebuf[2048];
  30. char * filename;
  31. int lineno;
  32. int prline;
  33. FILE * fd;
  34. int iflevel = 0;
  35. int keeptext = 1;
  36. int unknown_stat = 0;
  37. char * commentstr = "#";
  38. char names[16][32];
  39. char state[16];
  40. int main P((int argc, char ** argv));
  41. void Usage P((char * prog));
  42. void save_name P((char * varname, int state));
  43. void do_file P((char * fname));
  44. void set_line P((int lineno));
  45. int do_hashcom P((void));
  46. int do_ifdef P((char * p, int which));
  47. void check_name P((char * nm));
  48. void fatal P((char * msg));
  49. void manifest_constant P((void));
  50. int
  51. main(argc, argv)
  52. int argc;
  53. char ** argv;
  54. {
  55. int ar;
  56. char * ptr;
  57. if( argc <= 1 ) Usage(argv[0]);
  58. for(ar=1; ar<argc; ar++) if( argv[ar][0] == '-' )
  59. {
  60. if( argv[ar][1] == 'D' || argv[ar][1] == 'U' )
  61. {
  62. if( argv[ar][2] )
  63. save_name(argv[ar]+2, argv[ar][1]);
  64. else
  65. unknown_stat = argv[ar][1];
  66. }
  67. else if( argv[ar][1] == 'C' )
  68. {
  69. cuttype = 2;
  70. if( argv[ar][2] ) commentstr = argv[ar]+2;
  71. }
  72. else for(ptr=argv[ar]+1; *ptr; ptr++) switch(*ptr)
  73. {
  74. case 'b': cuttype = 0; break;
  75. case 'l': cuttype = 1; break;
  76. case 'C':
  77. case 'c': cuttype = 2; break;
  78. case 'r': cuttype = 3; break;
  79. case 'h': striphash=1; break;
  80. case 'M': manifest_constant(); break;
  81. case 'D': unknown_stat = 'D'; break;
  82. case 'U': unknown_stat = 'U'; break;
  83. default: Usage(argv[0]);
  84. }
  85. }
  86. else
  87. {
  88. do_file(argv[ar]);
  89. }
  90. exit(0);
  91. }
  92. void Usage(prog)
  93. char * prog;
  94. {
  95. fprintf(stderr, "Usage: %s [-DFLAG] [-UFLAG] [-blcrhMDU] [-C##] files\n",
  96. prog);
  97. fprintf(stderr, "\t-DFLAG\tDefine flag.\n");
  98. fprintf(stderr, "\t-UFLAG\tUndefine flag.\n");
  99. fprintf(stderr, "\t-C##\tComment out liines with '##'\n");
  100. fprintf(stderr, "\t-b\tRemove contents of lines leaving empty lines\n");
  101. fprintf(stderr, "\t-l\tUse #line lines.\n");
  102. fprintf(stderr, "\t-c\tComment out with '# '\n");
  103. fprintf(stderr, "\t-r\tRemove undefined lines completely.\n");
  104. fprintf(stderr, "\t-h\tRemove any line beginning with a '#'\n");
  105. fprintf(stderr, "\t-M\tInclude manifest constants.\n");
  106. fprintf(stderr, "\t-D\tAssume any unknown names are defined.\n");
  107. fprintf(stderr, "\t-U\tAssume any unknown names are undefined.\n");
  108. exit(1);
  109. }
  110. void
  111. save_name(varname, state)
  112. char * varname;
  113. int state;
  114. {
  115. struct varrec * curr;
  116. struct varrec * prev = 0;
  117. for(curr=varlist;
  118. curr && strcmp(curr->name, varname) != 0;
  119. prev=curr, curr=curr->next)
  120. ;
  121. if( curr == 0 )
  122. {
  123. curr = (struct varrec*) malloc(sizeof(struct varrec)+strlen(varname));
  124. if( curr == 0 )
  125. fatal("Out of memory error");
  126. if( prev ) prev->next = curr;
  127. else varlist = curr;
  128. curr->next = 0;
  129. strcpy(curr->name, varname);
  130. }
  131. curr->state = state;
  132. }
  133. void
  134. do_file(fname)
  135. char * fname;
  136. {
  137. filename = fname;
  138. prline = lineno = 0;
  139. fd = fopen(fname, "r");
  140. if( fd == 0 )
  141. fatal("Cannot open file");
  142. if( cuttype == 1 )
  143. printf("#line 1 \"%s\"\n", filename);
  144. /* NB: limited line length */
  145. while( fgets(linebuf, sizeof(linebuf), fd) != 0 )
  146. {
  147. int f = 1;
  148. char * p = linebuf;
  149. lineno++;
  150. while(isspace(*p)) p++;
  151. if( *p == '#' )
  152. f = do_hashcom();
  153. if(f)
  154. {
  155. if( keeptext )
  156. {
  157. if( cuttype == 1 ) set_line(lineno);
  158. printf("%s", linebuf);
  159. }
  160. else
  161. {
  162. if( cuttype == 0 ) printf("\n");
  163. if( cuttype == 2 ) printf("%s %s", commentstr, linebuf);
  164. }
  165. }
  166. }
  167. fclose(fd);
  168. if( iflevel != 0 ) fatal("Not enough endif's");
  169. }
  170. void
  171. set_line(lineno)
  172. int lineno;
  173. {
  174. if( prline+2 == lineno )
  175. printf("\n");
  176. else if( prline+1 != lineno )
  177. printf("#line %d \"%s\"\n", lineno, filename);
  178. prline = lineno;
  179. }
  180. int
  181. do_hashcom()
  182. {
  183. char * p = linebuf;
  184. int flg = -1;
  185. while(isspace(*p)) p++;
  186. if( *p == '#' ) p++;
  187. while(isspace(*p)) p++;
  188. if(strncmp(p, "ifdef", 5) == 0)
  189. {
  190. do_ifdef(p+5, 'D');
  191. }
  192. else
  193. if(strncmp(p, "ifndef", 6) == 0)
  194. {
  195. do_ifdef(p+6, 'U');
  196. }
  197. else
  198. if(strncmp(p, "if", 2) == 0 && isspace(p[2]) )
  199. {
  200. state[iflevel++] = keeptext;
  201. keeptext |= 2;
  202. }
  203. else
  204. if(strncmp(p, "else", 4) == 0)
  205. {
  206. if( iflevel == 0 ) fatal("#else at top level");
  207. if( iflevel && state[iflevel-1]) keeptext ^= 1;
  208. }
  209. else
  210. if(strncmp(p, "endif", 5) == 0)
  211. {
  212. flg = (keeptext&2);
  213. if( iflevel == 0 ) fatal("Too many endif's");
  214. iflevel--;
  215. keeptext = state[iflevel];
  216. }
  217. else if( !striphash ) return 1;
  218. if( flg < 0 ) flg = (keeptext&2);
  219. if( flg ) return 1;
  220. if( cuttype == 0 ) printf("\n");
  221. if( cuttype == 2 ) printf("%s %s", commentstr, linebuf);
  222. return 0;
  223. }
  224. int
  225. do_ifdef(p, which)
  226. char * p;
  227. int which;
  228. {
  229. char * nm;
  230. char * s;
  231. struct varrec * curr;
  232. while( *p == ' ' || *p == '\t') p++;
  233. nm = p;
  234. for(curr=varlist; curr ; curr = curr->next)
  235. {
  236. s = curr->name;
  237. p = nm;
  238. while( *p == *s ) { p++; s++; }
  239. if( *s == '\0' && *p <= ' ' ) /* FIXME alphanum */
  240. break;
  241. }
  242. state[iflevel] = keeptext;
  243. iflevel++;
  244. p=nm;
  245. s=names[iflevel];
  246. while(*p > ' ') *s++ = *p++;
  247. *s = '\0';
  248. if( curr == 0 )
  249. {
  250. if( unknown_stat == 0 )
  251. {
  252. if( keeptext ) keeptext |= 2;
  253. return 0;
  254. }
  255. if( keeptext )
  256. keeptext = (unknown_stat == which);
  257. return 1;
  258. }
  259. if( keeptext )
  260. keeptext = (curr->state == which);
  261. return 1;
  262. }
  263. #if 0
  264. do_if(p)
  265. char * p;
  266. {
  267. /*
  268. * Look for:
  269. * defined Label
  270. * one sort of || &&
  271. * 0
  272. * 1
  273. *
  274. * Skip characters: WS, (, )
  275. *
  276. * Give up on unknown characters and labels without a defined or assumed
  277. * state. BUT note that if there is another label that forces the state
  278. * of the result irrespective of an unknown label the state should be set.
  279. *
  280. */
  281. static char wbuf[256];
  282. int combiner = 0;
  283. int true_defs = 0;
  284. int false_defs = 0;
  285. int unkn_defs = 0;
  286. int state = 0;
  287. char * d;
  288. for(;;)
  289. {
  290. d=wbuf;
  291. do
  292. {
  293. while( isspace(*p) || (d==wbuf && (*p == '(' || *p == ')' ))) p++;
  294. if( d!=wbuf && (*p == '(' || *p == ')' )) break;
  295. while( !(isspace(*p) || *p == '(' || *p == ')' ))
  296. if( d<wbuf+sizeof(wbuf)-2) *d++ = *p++;
  297. else p++;
  298. *d= 0;
  299. }
  300. while( strcmp(wbuf, "!") == 0 );
  301. if( state == 0 )
  302. {
  303. if( strcmp(wbuf, "defined" ) == 0 )
  304. {
  305. state = 1;
  306. continue;
  307. }
  308. if( strcmp(wbuf, "!defined" ) == 0 )
  309. {
  310. state = 2;
  311. continue;
  312. }
  313. if( strcmp(wbuf, "||" ) == 0 || strcmp(wbuf, "&&") == 0 )
  314. {
  315. if( combiner == 0 ) combiner = wbuf[0];
  316. if( combiner != wbuf[0] ) combiner = '@';
  317. continue;
  318. }
  319. /* Something we're not ready for ... */
  320. goto Dont_know;
  321. }
  322. }
  323. }
  324. #endif
  325. void
  326. check_name(nm)
  327. char * nm;
  328. {
  329. char * p;
  330. char * s;
  331. while(*nm == ' ' || *nm == '\t' ) nm++;
  332. s = nm;
  333. if( *s == '\n' || *s == '\r' || *s == '\0' ) return;
  334. p = names[iflevel];
  335. while(*p)
  336. {
  337. if( *p++ != *s++ )
  338. goto x_error;
  339. }
  340. if( *s <= ' ' ) return;
  341. x_error:
  342. fprintf(stderr, "Ifdef mis-nesting Line %d Expect '%s' Got '",
  343. lineno,
  344. names[iflevel]);
  345. while(*nm > ' ' )
  346. fputc(*nm++, stderr);
  347. fputc('\'', stderr);
  348. fputc('\n', stderr);
  349. }
  350. void
  351. fatal(msg)
  352. char * msg;
  353. {
  354. fprintf(stderr, "Fatal error:%s\n", msg);
  355. exit(1);
  356. }
  357. /* This places manifest constants defined by the C compiler into ifdef
  358. *
  359. * Unfortunatly I can find no way of discovering the variables automatically
  360. */
  361. void
  362. manifest_constant()
  363. {
  364. /* General */
  365. #ifdef __STDC__
  366. save_name("__STDC__", 'D');
  367. #endif
  368. #ifdef __GNUC__
  369. save_name("__GNUC__", 'D');
  370. #endif
  371. #ifdef GNUMAKE
  372. save_name("GNUMAKE", 'D');
  373. #endif
  374. if( sizeof(int) < 4 )
  375. save_name("__SMALL_INTS__", 'D');
  376. if( sizeof(char *) <= 2 )
  377. save_name("__SMALL_MEMORY__", 'D');
  378. if( sizeof(long) == 4 )
  379. save_name("__LONG_32_BIT__", 'D');
  380. if( sizeof(long) == 8 )
  381. save_name("__LONG_64_BIT__", 'D');
  382. /* MSDOS */
  383. #ifdef MSDOS
  384. save_name("MSDOS", 'D');
  385. #endif
  386. #ifdef __MSDOS__
  387. save_name("__MSDOS__", 'D');
  388. #endif
  389. /* Linux/unix */
  390. #ifdef __linux__
  391. save_name("__linux__", 'D');
  392. #ifdef __i386__
  393. save_name("__elksemu_works__", 'D');
  394. #endif
  395. #endif
  396. #ifdef __unix__
  397. save_name("__unix__", 'D');
  398. #endif
  399. #ifdef __GNUC__
  400. save_name("__GNUC__", 'D');
  401. #endif
  402. #ifdef __ELF__
  403. save_name("__ELF__", 'D');
  404. #endif
  405. #ifdef __i386__
  406. save_name("__i386__", 'D');
  407. #endif
  408. #ifdef __i486__
  409. save_name("__i486__", 'D');
  410. #endif
  411. #ifdef i386
  412. save_name("i386", 'D');
  413. #endif
  414. #ifdef linux
  415. save_name("linux", 'D');
  416. #endif
  417. #ifdef unix
  418. save_name("unix", 'D');
  419. #endif
  420. /* BCC */
  421. #ifdef __BCC__
  422. save_name("__BCC__", 'D');
  423. #endif
  424. #ifdef __AS386_16__
  425. save_name("__AS386_16__", 'D');
  426. #endif
  427. #ifdef __AS386_32__
  428. save_name("__AS386_32__", 'D');
  429. #endif
  430. /* AIX, RS6000 */
  431. #ifdef _IBMR2
  432. save_name("_IBMR2", 'D');
  433. #endif
  434. #ifdef _AIX
  435. save_name("_AIX", 'D');
  436. #endif
  437. #ifdef _AIX32
  438. save_name("_AIX32", 'D');
  439. #endif
  440. /* Ugh! Minix is actually _very_ nasty */
  441. #ifdef __minix
  442. save_name("__minix", 'D');
  443. #endif
  444. /* This isn't much nicer */
  445. #ifdef __CYGWIN__
  446. save_name("__CYGWIN__", 'D');
  447. #endif
  448. #ifdef __APPLE__
  449. save_name("__APPLE__", 'D');
  450. #endif
  451. }