/* Mike Sullivan */

/* Write a program to remove all comments from a C program. Don't
 * forget to handle quoted strings and character constants properly. C
 * comments do not nest */

/* This is based on a program I wrote for one of the examples in The C
 * Programming Language. It's been improved a little. It's not
 * perfect, but it works. It sometimes leaves extra whitespace, but
 * life goes on. It also supports C++ comments. */ 

#include <stdio.h>
#include <string.h>
#include <errno.h>

int decomment(FILE *f);

int main(int argc, char *argv[])
{
	FILE *f;

	if (argc < 2 || strcmp(argv[1], "-") == 0)
		f = stdin;
	else
		if (!(f = fopen(argv[1], "r"))) {
			fprintf(stderr, "%s: %s: %s\n", argv[0], argv[1],
				strerror(errno));
			return 1;
		}



	decomment(f);
	return 0;
}

int decomment(FILE *f)
{
	int escape; /* escape char is up */
	int in_comment; /* whether it is currently inside a comment */
	int in_cpp_comment; /* whether it is currently inside a c++ comment */
	int in_quote; /* whether it is currently inside quotes */
	char quote_type; /* whether it's a double or single quote */
	int c, tmp;

	c = escape = quote_type = in_quote = in_comment = in_cpp_comment = 0;
	while ((c = getc(f)) != EOF) {
		if (in_cpp_comment && c != '\n')
			continue;
		if (in_cpp_comment && c == '\n')
			in_cpp_comment = 0;
		
		if (!in_quote && !in_cpp_comment && c == '/') {
			if ((tmp = getc(f)) == '/') {
				in_cpp_comment = 1;
				continue;
			} else {
				ungetc(tmp, f);
			}
		}

		if (!in_quote && c == '/') {
			if ((tmp = getc(f)) == '*')
				in_comment = 1;
			else
				ungetc(tmp, f);
		}

		if (in_comment && c == '*') {
			if ((tmp = getc(f)) == '/') {
				in_comment = 0;
				continue;
			} else
				ungetc(tmp, f);
		}


		if (in_quote && !escape && c == quote_type)
			quote_type = in_quote = 0;
		else if (!in_quote && !in_comment && (c == '\'' || c == '"')) {
			in_quote = 1;
			quote_type = c;
		}

		if (in_quote && c == '\\' && !escape)
			escape = 1;
		else
			escape = 0;

		if (!in_comment)
			putchar(c);
	}
	return 0;
}
