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 */
38typedef 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
46static void usage(char **argv);
47
48int 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
185static void usage(char **argv)
186{
187	printf("usage: %s infile [r(emove whitespace)]\n", argv[0]);
188	exit(1);
189}
190