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
34#ifndef __linux__
35#include <libc.h>
36#else
37#include <string.h>
38#include <stdlib.h>
39#include <stdarg.h>
40#include <unistd.h>
41#endif
42
43/*
44 * State of input scanner.
45 */
46typedef enum {
47	IS_NORMAL,
48	IS_SLASH,		// encountered opening '/'
49	IS_IN_COMMENT,		// within / * * / comment
50	IS_STAR,		// encountered closing '*'
51	IS_IN_END_COMMENT	// within / / comment
52} input_state_t;
53
54static void usage(char **argv);
55
56int main(int argc, char **argv)
57{
58	FILE *fp;
59	char bufchar;
60	input_state_t input_state = IS_NORMAL;
61	int exit_code = 0;
62	int remove_whitespace = 0;
63	int arg;
64
65	if(argc < 2)
66		usage(argv);
67	for(arg=2; arg<argc; arg++) {
68		switch(argv[arg][0]) {
69		    case 'r':
70		    	remove_whitespace++;
71			break;
72		    default:
73		    	usage(argv);
74		}
75	}
76
77	fp = fopen(argv[1], "r");
78	if(!fp) {
79		fprintf(stderr, "Error opening %s\n", argv[1]);
80		perror("fopen");
81		exit(1);
82	}
83	for(;;) {
84		bufchar = getc_unlocked(fp);
85		if (bufchar == EOF)
86			break;
87
88		switch(input_state) {
89
90		    case IS_NORMAL:
91		    	if(bufchar == '/') {
92			   	/*
93				 * Might be start of a comment.
94				 */
95				input_state = IS_SLASH;
96			}
97			else {
98				if(!(remove_whitespace && isspace(bufchar))) {
99					putchar_unlocked(bufchar);
100				}
101			}
102			break;
103
104		    case IS_SLASH:
105		    	switch(bufchar) {
106			    case '*':
107			    	/*
108				 * Start of normal comment.
109				 */
110				input_state = IS_IN_COMMENT;
111				break;
112
113			    case '/':
114			    	/*
115				 * Start of 'to-end-of-line' comment.
116				 */
117				input_state = IS_IN_END_COMMENT;
118				break;
119
120			    default:
121			    	/*
122				 * Not the start of comment. Emit the '/'
123				 * we skipped last char in case we were
124				 * entering a comment this time, then the
125				 * current char.
126				 */
127				putchar_unlocked('/');
128				if(!(remove_whitespace && isspace(bufchar))) {
129					putchar_unlocked(bufchar);
130				}
131				input_state = IS_NORMAL;
132				break;
133			}
134			break;
135
136		    case IS_IN_COMMENT:
137		    	if(bufchar == '*') {
138			    	/*
139				 * Maybe ending comment...
140				 */
141			    	input_state = IS_STAR;
142			}
143		    	break;
144
145
146		    case IS_STAR:
147		    	switch(bufchar) {
148			    case '/':
149				/*
150				 * End of normal comment.
151				 */
152				input_state = IS_NORMAL;
153				break;
154
155			    case '*':
156			    	/*
157				 * Still could be one char away from end
158				 * of comment.
159				 */
160				break;
161
162			    default:
163			    	/*
164				 * Still inside comment, no end in sight.
165				 */
166				input_state = IS_IN_COMMENT;
167				break;
168			}
169			break;
170
171		    case IS_IN_END_COMMENT:
172		    	if(bufchar == '\n') {
173				/*
174				 * End of comment. Emit the newline if
175				 * appropriate.
176				 */
177				if(!remove_whitespace) {
178					putchar_unlocked(bufchar);
179				}
180				input_state = IS_NORMAL;
181			}
182			break;
183
184		} /* switch input_state */
185	} 	  /* main read loop */
186
187	/*
188	 * Done.
189	 */
190	return(exit_code);
191}
192
193static void usage(char **argv)
194{
195	printf("usage: %s infile [r(emove whitespace)]\n", argv[0]);
196	exit(1);
197}
198