]>
Commit | Line | Data |
---|---|---|
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 | { | |
50 | FILE *fp; | |
51 | char bufchar; | |
52 | input_state_t input_state = IS_NORMAL; | |
53 | int exit_code = 0; | |
54 | int remove_whitespace = 0; | |
55 | int arg; | |
56 | ||
57 | if(argc < 2) | |
58 | usage(argv); | |
59 | for(arg=2; arg<argc; arg++) { | |
60 | switch(argv[arg][0]) { | |
61 | case 'r': | |
62 | remove_whitespace++; | |
63 | break; | |
64 | default: | |
65 | usage(argv); | |
66 | } | |
67 | } | |
68 | ||
69 | fp = fopen(argv[1], "r"); | |
70 | if(!fp) { | |
71 | fprintf(stderr, "Error opening %s\n", argv[1]); | |
72 | perror("fopen"); | |
73 | exit(1); | |
74 | } | |
75 | for(;;) { | |
76 | bufchar = getc_unlocked(fp); | |
77 | if (bufchar == EOF) | |
78 | break; | |
79 | ||
80 | switch(input_state) { | |
81 | ||
82 | case IS_NORMAL: | |
83 | if(bufchar == '/') { | |
84 | /* | |
85 | * Might be start of a comment. | |
86 | */ | |
87 | input_state = IS_SLASH; | |
88 | } | |
89 | else { | |
90 | if(!(remove_whitespace && isspace(bufchar))) { | |
91 | putchar_unlocked(bufchar); | |
92 | } | |
93 | } | |
94 | break; | |
95 | ||
96 | case IS_SLASH: | |
97 | switch(bufchar) { | |
98 | case '*': | |
99 | /* | |
100 | * Start of normal comment. | |
101 | */ | |
102 | input_state = IS_IN_COMMENT; | |
103 | break; | |
104 | ||
105 | case '/': | |
106 | /* | |
107 | * Start of 'to-end-of-line' comment. | |
108 | */ | |
109 | input_state = IS_IN_END_COMMENT; | |
110 | break; | |
111 | ||
112 | default: | |
113 | /* | |
114 | * Not the start of comment. Emit the '/' | |
115 | * we skipped last char in case we were | |
116 | * entering a comment this time, then the | |
117 | * current char. | |
118 | */ | |
119 | putchar_unlocked('/'); | |
120 | if(!(remove_whitespace && isspace(bufchar))) { | |
121 | putchar_unlocked(bufchar); | |
122 | } | |
123 | input_state = IS_NORMAL; | |
124 | break; | |
125 | } | |
126 | break; | |
127 | ||
128 | case IS_IN_COMMENT: | |
129 | if(bufchar == '*') { | |
130 | /* | |
131 | * Maybe ending comment... | |
132 | */ | |
133 | input_state = IS_STAR; | |
134 | } | |
135 | break; | |
136 | ||
137 | ||
138 | case IS_STAR: | |
139 | switch(bufchar) { | |
140 | case '/': | |
141 | /* | |
142 | * End of normal comment. | |
143 | */ | |
144 | input_state = IS_NORMAL; | |
145 | break; | |
146 | ||
147 | case '*': | |
148 | /* | |
149 | * Still could be one char away from end | |
150 | * of comment. | |
151 | */ | |
152 | break; | |
153 | ||
154 | default: | |
155 | /* | |
156 | * Still inside comment, no end in sight. | |
157 | */ | |
158 | input_state = IS_IN_COMMENT; | |
159 | break; | |
160 | } | |
161 | break; | |
162 | ||
163 | case IS_IN_END_COMMENT: | |
164 | if(bufchar == '\n') { | |
165 | /* | |
166 | * End of comment. Emit the newline if | |
167 | * appropriate. | |
168 | */ | |
169 | if(!remove_whitespace) { | |
170 | putchar_unlocked(bufchar); | |
171 | } | |
172 | input_state = IS_NORMAL; | |
173 | } | |
174 | break; | |
175 | ||
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 | { | |
187 | printf("usage: %s infile [r(emove whitespace)]\n", argv[0]); | |
188 | exit(1); | |
189 | } |