xref: /xnu-8020.140.41/SETUP/decomment/decomment.c (revision 27b03b360a988dfd3dfdf34262bb0042026747cc)
1 /*
2  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3  *
4  * @APPLE_LICENSE_HEADER_START@
5  *
6  * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
7  * Reserved.  This file contains Original Code and/or Modifications of
8  * Original Code as defined in and that are subject to the Apple Public
9  * Source License Version 1.0 (the 'License').  You may not use this file
10  * except in compliance with the License.  Please obtain a copy of the
11  * License at http://www.apple.com/publicsource and read it before using
12  * this file.
13  *
14  * The Original Code and all software distributed under the License are
15  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
19  * License for the specific language governing rights and limitations
20  * under the License."
21  *
22  * @APPLE_LICENSE_HEADER_END@
23  */
24 /*
25  * decomment.c
26  *
27  * Removes all comments and (optionally) whitespace from an input file.
28  * Writes result on stdout.
29  */
30 
31 #include <stdio.h>
32 #include <ctype.h>      /* for isspace */
33 #include <libc.h>
34 
35 /*
36  * State of input scanner.
37  */
38 typedef enum {
39 	IS_NORMAL,
40 	IS_SLASH,               // encountered opening '/'
41 	IS_IN_COMMENT,          // within / * * / comment
42 	IS_STAR,                // encountered closing '*'
43 	IS_IN_END_COMMENT       // within / / comment
44 } input_state_t;
45 
46 static void usage(char **argv);
47 
48 int
main(int argc,char ** argv)49 main(int argc, char **argv)
50 {
51 	FILE *fp;
52 	char bufchar;
53 	input_state_t input_state = IS_NORMAL;
54 	int exit_code = 0;
55 	int remove_whitespace = 0;
56 	int arg;
57 
58 	if (argc < 2) {
59 		usage(argv);
60 	}
61 	for (arg = 2; arg < argc; arg++) {
62 		switch (argv[arg][0]) {
63 		case 'r':
64 			remove_whitespace++;
65 			break;
66 		default:
67 			usage(argv);
68 		}
69 	}
70 
71 	fp = fopen(argv[1], "r");
72 	if (!fp) {
73 		fprintf(stderr, "Error opening %s\n", argv[1]);
74 		perror("fopen");
75 		exit(1);
76 	}
77 	for (;;) {
78 		bufchar = getc_unlocked(fp);
79 		if (bufchar == EOF) {
80 			break;
81 		}
82 
83 		switch (input_state) {
84 		case IS_NORMAL:
85 			if (bufchar == '/') {
86 				/*
87 				 * Might be start of a comment.
88 				 */
89 				input_state = IS_SLASH;
90 			} else {
91 				if (!(remove_whitespace && isspace(bufchar))) {
92 					putchar_unlocked(bufchar);
93 				}
94 			}
95 			break;
96 
97 		case IS_SLASH:
98 			switch (bufchar) {
99 			case '*':
100 				/*
101 				 * Start of normal comment.
102 				 */
103 				input_state = IS_IN_COMMENT;
104 				break;
105 
106 			case '/':
107 				/*
108 				 * Start of 'to-end-of-line' comment.
109 				 */
110 				input_state = IS_IN_END_COMMENT;
111 				break;
112 
113 			default:
114 				/*
115 				 * Not the start of comment. Emit the '/'
116 				 * we skipped last char in case we were
117 				 * entering a comment this time, then the
118 				 * current char.
119 				 */
120 				putchar_unlocked('/');
121 				if (!(remove_whitespace && isspace(bufchar))) {
122 					putchar_unlocked(bufchar);
123 				}
124 				input_state = IS_NORMAL;
125 				break;
126 			}
127 			break;
128 
129 		case IS_IN_COMMENT:
130 			if (bufchar == '*') {
131 				/*
132 				 * Maybe ending comment...
133 				 */
134 				input_state = IS_STAR;
135 			}
136 			break;
137 
138 
139 		case IS_STAR:
140 			switch (bufchar) {
141 			case '/':
142 				/*
143 				 * End of normal comment.
144 				 */
145 				input_state = IS_NORMAL;
146 				break;
147 
148 			case '*':
149 				/*
150 				 * Still could be one char away from end
151 				 * of comment.
152 				 */
153 				break;
154 
155 			default:
156 				/*
157 				 * Still inside comment, no end in sight.
158 				 */
159 				input_state = IS_IN_COMMENT;
160 				break;
161 			}
162 			break;
163 
164 		case IS_IN_END_COMMENT:
165 			if (bufchar == '\n') {
166 				/*
167 				 * End of comment. Emit the newline if
168 				 * appropriate.
169 				 */
170 				if (!remove_whitespace) {
171 					putchar_unlocked(bufchar);
172 				}
173 				input_state = IS_NORMAL;
174 			}
175 			break;
176 		} /* switch input_state */
177 	}         /* main read loop */
178 
179 	/*
180 	 * Done.
181 	 */
182 	return exit_code;
183 }
184 
185 static void
usage(char ** argv)186 usage(char **argv)
187 {
188 	printf("usage: %s infile [r(emove whitespace)]\n", argv[0]);
189 	exit(1);
190 }
191