/*
 * load2.c -- a new load parser utilizing a state machine
 * For what its worth.
 *
 * Changes to note:  
 *	The C-like comments and Hash-line comments have equal precedence
 *	and are mutually exclusive.  It is not possible to start a C-like
 *	comment in the middle of a hash-line comment (this is the same as
 *	before), but it is not possible to start a hash-line comment in the
 *	middle of a C-like comment (this is different than before).
 *
 */

BUILT_IN_COMMAND(load2)
{
	char *		buffer;
	char *		buffer_end;
	char *		ptr;
	size_t		size;
	int		line;
	int		character;

	/*
	 * These are state variables
	 */
	int		new_line = 0;
	int		text_after_semicolon = 0;
	int		in_comment = 0;
	int		hash_comment = 0;
	int		lparens = 0;
	int		saw_star = 0;
	int		saw_slash = 0;
	char		last_char;

	size = slurp_file(buffer, args);
	buffer_end = buffer + size;

	for (ptr = buffer; ptr < buffer_end; last_char = *ptr, ptr++)
	{
		/*
		 * These are the various states of the machine.  
		 */

		/* 
		 * "C-like comment" state.  We ignore all characters up
		 * to the next sighting of a star followed by a slash.
		 */
		if (in_comment)
		{
			if (last_char == '*' && *ptr == '/')
				in_comment = 0;
			continue;
		}

		/*
		 * "Hash comment" state.  We ignore all characters up to
		 * the next newline.
		 */
		if (hash_comment)
		{
			if (*ptr == '\n')
				hash_comment = 0;
			continue;
		}

				continue;
			}
			else
				add_char('/');
			/* Fall through to the switch */
		}

		/*
		 * "New line" mode -- immediately after a newline is seen,
		 * we ignore all whitespace, and if the first character
		 * is a hash, we switch to "hash comment" mode.
		 */
		if (new_line)
		{
			if (my_isspace(*ptr))
				continue;

			if (*ptr == '#')
			{
				hash_comment = 1;
				continue;
			}

			new_line = 0;
			/* Fall through to the switch */
		}

	   /*
	    * Otherwise, we are in the "normal" state.
	    */
	   switch (*ptr)
	   {
		/*
		 * Newlines terminate a command, but only if the previous
		 * character was not an escape character, and as long as
		 * there are no outstanding unmatched lparens.
		 */
		case '\n':
		{
			if (last_char == '\\')
			{
				pop_char();
				break;
			}

			new_line = 1;	/* Switch to "New line" state */

			if (lparens > 0 && text_after_semicolon == 1)
			{
				text_after_semicolon = 0;
				push_char(';');
				break;
			}

			/* Dispatch the current command to parse_line */
			break;
		}

		/*
		 * lparens open up a new level of bracing that has to be
		 * matched.  Lparens always get added to the input.
		 */
		case '{':
		{
			new_line = 0;
			lparens++;

			push_char(*ptr);
			break;
		}

		/*
		 * rparens close a level of bracing that is waiting to be
		 * matched.  Rparens are always added to the input.
		 */
		case '}':
		{
			new_line = 0;
			if (lparens > 0)
				lparens--;

			push_char(*ptr);
			break;
		}

		/*
		 * Semicolons terminate a command inside of a larger
		 * command.  We are careful to not add extraneous semicolons
		 * unless text appears after a semicolon and before the end
		 * of the line.
		 */
		case ';':
		{
			new_line = 0;
			if (text_after_semicolon)
				push_char(*ptr);

			text_after_semicolon = 0;
			break;
		}

		/* 
		 * Whitespace is ignored if it is just after a 
		 * semicolon.  Otherwise it is added to the input.
		 */
		case ' ': '\t':
		{
			if (text_after_semicolon == 0)
				break;

			push_char(*ptr);
			break;
		}

		/*
		 * Hash marks, if they lead off a line, introduce comments.
		 * Otherwise they are added to the input.
		 */
		case '#':
		{
			if (new_line)
			{
				hash_comment = 1;
				break;
			}

			push_char(*ptr);
			break;
		}

		case '*':
		{
if (new_line || !get_int_var(COMMENT_HACK_VAR))
in_comment = 1;
			if (last_char == '/')
			{
				pop_char();
				in_comment = 1;
				break;
			}
			push_char(*ptr);
		}

		default: 
			text_after_semicolon = 1;
			new_line = 0;

			add_char(*ptr);
			break;


