xref: /minix/minix/commands/ifdef/ifdef.c (revision 7f5f010b)
1 /* ifdef - remove #ifdefs		Author: Warren Toomey */
2 
3 /* Copyright 1989 by Warren Toomey	wkt@cs.adfa.oz.au[@uunet.uu.net]
4  *
5  * You may freely copy or distribute this code as long as this notice
6  * remains intact.
7  *
8  * You may modify this code, as long as this notice remains intact, and
9  * you add another notice indicating that the code has been modified.
10  *
11  * You may NOT sell this code or in any way profit from this code without
12  * prior agreement from the author.
13  */
14 
15 #include <sys/types.h>
16 #include <string.h>
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <unistd.h>
20 
21 /* Definition of structures and constants used in ifdef.c  */
22 
23 /* Types of symbols */
24 #define DEF	  1		/* Symbol is defined    */
25 #define UNDEF	  2		/* Symbol isn't defined */
26 #define IGN	  3		/* Ignore this symbol unless defined */
27 
28 /* Redef mode values */
29 #define MUTABLE   1		/* Symbol can change defined <-> undefined */
30 #define IMMUTABLE 2		/* Symbol can't change as above            */
31 
32 /* Processing modes */
33 #define NO	0		/* Don't process */
34 #define YES	1		/* Process */
35 
36 /* Ignore (IGN), ignore but process */
37 struct DEFINE {
38   char *symbol;			/* SLL of defined symbols. The redef  */
39   char type;			/* field indicates if this symbol can */
40   char redef;			/* change from defined <-> undefined. */
41   struct DEFINE *next;		/* Type is DEF or UNDEF.	      */
42 };
43 
44 /* Global variables & structures */
45 FILE *zin;			/* Input file for processing  */
46 struct DEFINE *defptr;		/* Defined symbols SLL        */
47 struct DEFINE *defend;		/* Ptr to last node in defptr */
48 struct DEFINE *deftemp;		/* Ptr to last found node     */
49 int line = 1;			/* Current line number        */
50 int table = 0;			/* Don't normally want a table */
51 
52 extern int optind;
53 extern char *optarg;
54 
55 /* Prototypes. */
56 int main(int argc, char **argv);
57 char fgetarg(FILE *stream, char *cbuf);
58 int find(char *symd);
59 void defit(char *sym, int redef, int typed);
60 void stop(void);
61 void gotoeoln(void);
62 void prteoln(void);
63 void printtable(void);
64 char getendif(void);
65 void gettable(void);
66 void parse(void);
67 void usage(void);
68 
69 #ifdef __STDC__
70 char fgetarg ( FILE *stream , char *cbuf )
71 #else
72 char fgetarg(stream, cbuf)	/* Get next arg from file into cbuf, */
73 FILE *stream;			/* returning the character that      */
74 char *cbuf;			/* terminated it. Cbuf returns 0     */
75 #endif
76 {				/* if no arg. EOF is returned if no  */
77   int ch;			/* args left in file.                */
78   int i;
79 
80   i = 0;
81   cbuf[i] = 0;
82 
83   while (((ch = fgetc(stream)) == ' ') || (ch == '\t') || (ch == '\n'))
84 	if (ch == '\n') return(ch);	/* Bypass leading */
85 					/* Whitespace     */
86   if (feof(stream)) return(EOF);
87 
88   cbuf[i++] = ch;
89 
90   while (((ch = fgetc(stream)) != ' ') && (ch != '\t') && (ch != '\n'))
91 	cbuf[i++] = ch;			/* Get the argument */
92 
93   cbuf[i] = 0;
94   return(ch);
95 }
96 
97 
98 #ifdef __STDC__
99 int find ( char *sym )
100 #else
101 int find(sym)
102 char *sym;
103 #endif
104 {				/* Return DEF if defined else UNDEF */
105 
106   deftemp = defptr;
107   while (deftemp) {			/* Search for the symbol */
108 	if (!strcmp(deftemp->symbol, sym))
109 		return(deftemp->type);	/* Setting up the type */
110 	deftemp = deftemp->next;
111   }
112   return(0);
113 }
114 
115 
116 
117 #define Define(x,y)	defit(x,y,DEF)
118 #define Undefine(x,y)	defit(x,y,UNDEF)
119 #define Ignore(x,y)	defit(x,y,IGN)
120 
121 #ifdef __STDC__
122 void defit ( char *sym , int redef , int type )
123 #else
124 void defit(sym, redef, type)	/* Add symbol to the define list */
125 char *sym;
126 char redef;			/* Mode: MUTABLE etc      */
127 char type;			/* Type: DEF, UNDEF, IGN  */
128 #endif
129 {
130   struct DEFINE *temp;
131   char c;
132 
133   c = find(sym);		/* First try finding the symbol */
134   if (type == c) return;	/* Return if already declared */
135   if (c) {			/* We have to move if from DEF <-> UNDEF */
136 	if (deftemp->redef == IMMUTABLE)
137 		return;
138 	else {
139 		deftemp->type = type;
140 		deftemp->redef = redef;
141 	}
142   } else {			/* We must create a struct & add it */
143 				/* Malloc room for the struct */
144 	if ((temp = (struct DEFINE *)malloc(sizeof(struct DEFINE))) == NULL) {
145 		(void)fprintf(stderr, "ifdef: could not malloc\n");
146 		exit(1);
147 	}
148 
149 					/* Malloc room for symbol */
150 	if ((temp->symbol = (char *)malloc(strlen(sym) + 1)) == NULL) {
151 		(void)fprintf(stderr, "ifdef: could not malloc\n");
152 		exit(1);
153 	}
154 	(void)strcpy(temp->symbol, sym); /* Copy symbol into struct      */
155 	temp->redef = redef;		/* and set its redef mode too   */
156 	temp->type = type;		/* as well as making it defined */
157 
158 
159 					/* Now add to the SLL */
160 	if (defptr == NULL)		/* If first node set  */
161 		defptr = temp;		/* the pointers to it */
162 	else
163 		defend->next = temp;	/* else add it to the */
164 	defend = temp;			/* end of the list.   */
165   }
166 }
167 
168 
169 
170 #ifdef __STDC__
171 void stop ( void )
172 #else
173 void stop()
174 #endif
175 {				/* Stop: Tidy up at EOF */
176   if (table) printtable();
177   (void)fclose(zin);
178   exit(0);
179 }
180 
181 #define Goto	{ line++; if (ch!='\n') gotoeoln(); }
182 #define Print	{ line++; if (ch!='\n') prteoln();  }
183 
184 #ifdef __STDC__
185 void gotoeoln ( void )
186 #else
187 void gotoeoln()			/* Go to the end of the line */
188 #endif
189 {
190   int ch;
191   while ((ch = fgetc(zin)) != '\n')
192 	if (ch == EOF) stop();
193 }
194 
195 
196 #ifdef __STDC__
197 void prteoln ( void )
198 #else
199 void prteoln()			/* Print to the end of the line */
200 #endif
201 {
202   int ch;
203   while ((ch = fgetc(zin)) != '\n')
204 	if (ch == EOF)
205 		stop();
206 	else
207 		(void)putchar(ch);
208   (void)putchar('\n');
209 }
210 
211 
212 #ifdef __STDC__
213 void printtable ( void )
214 #else
215 void printtable()		/* Print the defines in the SLL */
216 #endif
217 {
218   struct DEFINE *temp;
219 
220   (void)printf("Defined\n\n");
221 
222   temp = defptr;
223   while (temp) {
224 	if (temp->type == DEF) (void)printf("%s\n", temp->symbol);
225 	temp = temp->next;
226   }
227 
228   (void)printf("\n\nUndefined\n\n");
229 
230   temp = defptr;
231   while (temp) {
232 	if (temp->type == UNDEF) (void)printf("%s\n", temp->symbol);
233 	temp = temp->next;
234   }
235 }
236 
237 #ifdef __STDC__
238 char getendif ( void )
239 #else
240 char getendif()
241 #endif
242 {				/* Find matching endif when ignoring */
243   char word[80];		/* Buffer for symbols */
244   int ch;
245   int skip;			/* Number of skipped #ifdefs */
246 
247   skip = 1;
248 
249   while (1) {
250 			/* Scan through the file looking for starting lines */
251 	if ((ch = fgetc(zin)) == EOF)
252 		stop();		/* Get first char on the line */
253 	if (ch != '#') {	/* If not a # ignore line     */
254 		(void)putchar(ch);
255 		Print;
256 		continue;
257 	}
258 	ch = fgetarg(zin, word);	/* Get the word after the # */
259 
260 	if (!strcmp(word, "ifdef") || !strcmp(word, "ifndef")) skip++;
261 						/* Keep track of ifdefs & */
262 	if (!strcmp(word, "endif")) skip--;	/* endifs		  */
263 
264 	(void)printf("#%s%c", word, ch);	/* Print the line out 	  */
265 	Print;
266 	if (!skip) return('\n');	/* If matching endif, return */
267   }
268 }
269 
270 
271 #ifdef __STDC__
272 void gettable ( void )
273 #else
274 void gettable()			/* Get & print a table of defines etc.  */
275 #endif
276 {
277 
278   char word[80];		/* Buffer for symbols */
279   int ch;
280 
281   while (1) {
282 			/* Scan through the file looking for starting lines */
283 	if ((ch = fgetc(zin)) == EOF)
284 		stop();		/* Get first char on the line */
285 	if (ch != '#') {	/* If not a # ignore line     */
286 		Goto;
287 		continue;
288 	}
289 	ch = fgetarg(zin, word);	/* Get the word after the # */
290 
291 	if (!strcmp(word, "define")) {		/* Define: Define the */
292 		ch = fgetarg(zin, word);	/* symbol, and goto   */
293 		Define(word, MUTABLE);		/* the end of line    */
294 		Goto;
295 		continue;
296 	}
297 	if (!strcmp(word, "undef")) {		/* Undef: Undefine the */
298 		ch = fgetarg(zin, word);	/* symbol, and goto    */
299 		Undefine(word, MUTABLE);	/* the end of line     */
300 		Goto;
301 		continue;
302 	}					/* Ifdef:            */
303 	if (!strcmp(word, "ifdef") || !strcmp(word, "ifndef")) {
304 		ch = fgetarg(zin, word);	/* Get the symbol */
305 		if (find(word) != DEF)
306 			Undefine(word, MUTABLE);	/* undefine it */
307 		Goto;
308 		continue;
309 	}
310 	Goto;				/* else ignore the line */
311   }
312 }
313 
314 
315 
316 #ifdef __STDC__
317 void parse ( void )
318 #else
319 void parse()
320 #endif
321 {				/* Parse & remove ifdefs from C source */
322   char word[80];		/* Buffer for symbols */
323   int ch;
324   int proc;			/* Should we be processing this bit?    */
325   int skip;			/* Number of skipped #ifdefs		 */
326 
327   proc = 1;
328   skip = 0;
329 
330   while (1) {
331 			/* Scan through the file looking for starting lines */
332 	if ((ch = fgetc(zin)) == EOF)
333 		stop();		/* Get first char on the line */
334 	if (ch != '#')
335 		if (proc) {	/* If not # and  we're processing */
336 			(void)putchar(ch); /* then print the line */
337 			Print;
338 			continue;
339 		} else {
340 			Goto;	/* else just skip the line  */
341 			continue;
342 		}
343 
344 	ch = fgetarg(zin, word);	/* Get the word after the # */
345 
346 	if (!strcmp(word, "define") && proc) {	/* Define: Define the */
347 		ch = fgetarg(zin, word);	/* symbol, and goto   */
348 		Define(word, MUTABLE);		/* the end of line    */
349 		(void)printf("#define %s%c", word, ch);
350 		Print;
351 		continue;
352 	}
353 	if (!strcmp(word, "undef") && proc) {	/* Undef: Undefine the */
354 		ch = fgetarg(zin, word);	/* symbol, and goto    */
355 		Undefine(word, MUTABLE);	/* the end of line     */
356 		(void)printf("#undef %s%c", word, ch);
357 		Print;
358 		continue;
359 	}
360 	if (!strcmp(word, "if")) {	/* If: we cannot handle these */
361 		if (!proc)		/* at the moment, so just */
362 			skip++;		/* treat them as an ignored */
363 		else {			/* definition */
364 			(void)printf("#%s%c",word,ch);
365 			Print;
366 			ch = getendif();	/* Get matching endif */
367 			continue;
368 		     	}
369 	}
370 	if (!strcmp(word, "ifdef")) {	/* Ifdef:	     */
371 		if (!proc)		/* If not processing */
372 			skip++;		/* skip it           */
373 		else {
374 			ch = fgetarg(zin, word); /* Get the symbol */
375 			switch (find(word)) {
376 			    case DEF:
377 				break;
378 			    case IGN:
379 				(void)printf("#ifdef %s%c", word, ch);
380 				Print;
381 				ch = getendif(); /* Get matching endif */
382 				break;
383 						/* If symbol undefined */
384 			    default:
385 				Undefine(word, MUTABLE); /* undefine it */
386 				proc = 0;	/* & stop processing */
387 			}
388 		}
389 		Goto;
390 		continue;
391 	}
392 	if (!strcmp(word, "ifndef")) {
393 		/* Ifndef: */
394 		if (!proc)	/* If not processing */
395 			skip++;	/* skip the line     */
396 		else {
397 			ch = fgetarg(zin, word); /* Get the symbol */
398 			switch (find(word)) {	/* If defined, stop */
399 			    case DEF:
400 				proc = 0;	/* processing       */
401 				break;
402 			    case IGN:
403 				(void)printf("#ifdef %s%c", word, ch);
404 				Print;
405 				ch = getendif(); /* Get matching endif */
406 				break;
407 			}
408 		}
409 		Goto;
410 		continue;
411 	}
412 	if (!strcmp(word, "else") && !skip) {	/* Else: Flip processing */
413 		proc = !proc;
414 		Goto;
415 		continue;
416 	}
417 	if (!strcmp(word, "endif")) {	/* Endif: If no skipped   */
418 					/* ifdefs turn processing */
419 		if (!skip)		/* on, else decrement the */
420 			proc = 1;	/* number of skips        */
421 		else
422 			skip--;
423 		Goto;
424 		continue;
425 	}
426 		/* The word fails all of the above tests, so if we're */
427 		/* processing, print the line. */
428 	if (proc) {
429 		(void)printf("#%s%c", word, ch);
430 		Print;
431 	} else
432 		Goto;
433   }
434 }
435 
436 
437 #ifdef __STDC__
438 void usage ( void )
439 #else
440 void usage()
441 #endif
442 {
443   (void)fprintf(stderr, "Usage: ifdef [-t] [-Dsymbol] [-dsymbol] [-Usymbol] [-Isymbol] <file>\n");
444   exit(0);
445 }
446 
447 
448 #ifdef __STDC__
449 int main(int argc , char *argv [])
450 #else
451 int main(argc, argv)
452 int argc;
453 char *argv[];
454 #endif
455 {
456   char sym[80];			/* Temp symbol storage */
457   int c;
458 
459   if (argc == 1) usage();	/* Catch the curious user	 */
460   while ((c = getopt(argc, argv, "tD:d:U:I:")) != EOF) {
461 	switch (c) {
462 	    case 't':
463 		table = 1;	/* Get the various options */
464 		break;
465 
466 	    case 'd':
467 		(void)strcpy(sym, optarg);
468 		Define(sym, MUTABLE);
469 		break;
470 
471 	    case 'D':
472 		(void)strcpy(sym, optarg);
473 		Define(sym, IMMUTABLE);
474 		break;
475 
476 	    case 'U':
477 		(void)strcpy(sym, optarg);
478 		Undefine(sym, IMMUTABLE);
479 		break;
480 
481 	    case 'I':
482 		(void)strcpy(sym, optarg);
483 		Ignore(sym, IMMUTABLE);
484 		break;
485 
486 	    default:	usage();
487 	}
488   }
489 
490   zin = stdin;		/* If a C file is named */
491 			/* Open stdin with it */
492   if (*argv[argc - 1] != '-') {
493 	(void)fclose(zin);
494 	if ((zin = fopen(argv[argc - 1], "r")) == NULL) {
495 		perror("ifdef");
496 		exit(1);
497 	}
498   }
499   if (table)
500 	gettable();		/* Either generate a table or    */
501   else
502 	parse();		/* parse & replace with the file */
503   return(0);
504 }
505