/***************************************************************************

    srcclean.c

    Basic source code cleanear.

    Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
    Visit http://mamedev.org for licensing and usage restrictions.

***************************************************************************/

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

#include "corestr.h"


/***************************************************************************
    CONSTANTS & DEFINES
***************************************************************************/

#define MAX_FILE_SIZE	(10 * 1024 * 1024)



/***************************************************************************
    GLOBAL VARIABLES
***************************************************************************/

static UINT8 original[MAX_FILE_SIZE];
static UINT8 modified[MAX_FILE_SIZE];



/***************************************************************************
    MAIN
***************************************************************************/

int main(int argc, char *argv[])
{
	int removed_tabs = 0, removed_spaces = 0, fixed_mac_style = 0, fixed_nix_style = 0;
	int src = 0, dst = 0, in_c_comment = 0, in_cpp_comment = 0;
	int hichars = 0;
	int is_c_file;
	const char *ext;
	FILE *file;
	int bytes;

	/* print usage info */
	if (argc != 2)
	{
		printf("Usage:\nsrcclean <file>\n");
		return 0;
 	}

	/* read the file */
	file = fopen(argv[1], "rb");
	if (file == NULL)
	{
		fprintf(stderr, "Can't open %s\n", argv[1]);
		return 1;
	}
	bytes = fread(original, 1, MAX_FILE_SIZE, file);
	fclose(file);

	/* determine if we are a C file */
	ext = strrchr(argv[1], '.');
	is_c_file = (ext && (core_stricmp(ext, ".c") == 0 || core_stricmp(ext, ".h") == 0 || core_stricmp(ext, ".cpp") == 0));

	/* rip through it */
	for (src = 0; src < bytes; )
	{
		UINT8 ch = original[src++];

		/* check for invalid upper-ASCII chars */
		if (ch != 13 && ch != 10 && ch != 9 && (ch > 127 || ch < 32))
		{
			ch = '?';
			hichars++;
		}

		/* track whether or not we are within a C-style comment */
		if (is_c_file && !in_cpp_comment)
		{
			if (ch == '/' && original[src] == '*')
				in_c_comment = 1;
			else if (ch == '*' && original[src] == '/')
				in_c_comment = 0;
		}

		/* track whether or not we are within a C++-style comment */
		if (is_c_file && !in_c_comment && ch == '/' && original[src] == '/')
			in_cpp_comment = 1;

		/* if we hit a LF without a CR, back up and act like we hit a CR */
		if (ch == 0x0a)
		{
			src--;
			ch = 0x0d;
			fixed_nix_style = 1;
		}

		/* if we hit a CR, clean up from there */
		if (ch == 0x0d)
		{
			/* remove all extra spaces/tabs at the end */
			while (dst > 0 && (modified[dst-1] == ' ' || modified[dst-1] == 0x09))
			{
				removed_spaces++;
				dst--;
			}

			/* insert a proper CR/LF */
			modified[dst++] = 0x0d;
			modified[dst++] = 0x0a;

			/* skip over any LF in the source file */
			if (original[src] == 0x0a)
				src++;
			else
				fixed_mac_style = 1;

			/* we are no longer in a C++-style comment */
			in_cpp_comment = 0;
		}

		/* if we hit a tab within a comment, expand it */
		else if (ch == 0x09 && (in_c_comment || in_cpp_comment))
		{
			int temp, col;

			/* scan backwards to find the start of line */
			for (temp = dst; temp >= 0; temp--)
				if (modified[temp] == 0x0a)
					break;

			/* scan forwards to compute the current column */
			for (temp++, col = 0; temp < dst; temp++)
				if (modified[temp] == 0x09)
					col += 4 - col % 4;
				else
					col++;

			/* compute how many spaces */
			col = 4 - col % 4;
			while (col--) modified[dst++] = ' ';
			removed_tabs++;
		}

		/* otherwise, copy the source character */
		else
			modified[dst++] = ch;
	}

	/* if we didn't find an end of comment, we screwed up */
	if (in_c_comment)
	{
		printf("Error: unmatched C-style comment (%s)!\n", argv[1]);
		return 1;
	}

	/* if the result == original, skip it */
	if (dst != bytes || memcmp(original, modified, bytes))
	{
		/* explain what we did */
		printf("Cleaned up %s:", argv[1]);
		if (removed_spaces) printf(" removed %d spaces", removed_spaces);
		if (removed_tabs) printf(" removed %d tabs", removed_tabs);
		if (hichars) printf(" fixed %d high-ASCII chars", hichars);
		if (fixed_nix_style) printf(" fixed *nix-style line-ends");
		if (fixed_mac_style) printf(" fixed Mac-style line-ends");
		printf("\n");

		/* write the file */
		file = fopen(argv[1], "wb");
		fwrite(modified, 1, dst, file);
		fclose(file);
	}

	return 0;
}
