/****************************************************************************************/
/*  PARSE_INPUT.C                                                                       */
/*                                                                                      */
/*  Author: Timothy Roff	                                                            */
/*  Description:  Input stuffs for the parsing engine                                   */
/*                                                                                      */
/*  The contents of this file are subject to the Jet3D Public License                   */
/*  Version 1.02 (the "License"); you may not use this file except in                   */
/*  compliance with the License. You may obtain a copy of the License at                */
/*  http://www.jet3d.com                                                                */
/*                                                                                      */
/*  Software distributed under the License is distributed on an "AS IS"                 */
/*  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See                */
/*  the License for the specific language governing rights and limitations              */
/*  under the License.                                                                  */
/*                                                                                      */
/*  This file was NOT part of the original Jet3D, released December 12, 1999.           */
/*                                                                                      */
/****************************************************************************************/

#include "jeParse.h"
#include "jeParse_h.h"

//=====================================================================================
//	jeParse_Input
//=====================================================================================
int jeParse_Input(scriptData *info)
{
   int cin;
   	assert(info != NULL);

   if (info->uninputted) {
      cin = info->uninput_cin;
      info->uninputted = JE_FALSE;
   }
   else {
      cin = jeParse_GetInput(info);
   }

   if (cin == '\n') {
      info->next_line_count++;
   }

   return cin;
}

//=====================================================================================
//	jeParse_InputUnget
//=====================================================================================
void jeParse_InputUnget(int cin, scriptData *info)
{
	assert(info != NULL);

   info->uninput_cin = cin;
   info->uninputted  = JE_TRUE;
}


//=====================================================================================
//	jeParse_GetInput
//=====================================================================================
int jeParse_GetInput(scriptData *info)
{
	assert(info != NULL);

	return getc(info->shader_file);
}

//=====================================================================================
//	jeParse_SetInput
//=====================================================================================
jeBoolean jeParse_SetInput(FILE* f, scriptData *info)
{
	assert(info != NULL);
	info->shader_file = f;

	return JE_TRUE;

}



//=====================================================================================
//	jeParse_BeginScan
//=====================================================================================
void jeParse_BeginScan(scriptData *info)
{
	assert(info != NULL);

   info->brace_count     = 0;
   info->jet_parse_line_count  = 1;
   info->next_line_count = 1;
}


//=====================================================================================
//	jeParse_EndScan
//=====================================================================================
void jeParse_EndScan(scriptData *info)
{
	assert(info != NULL);

   info->brace_count      = 0;
   info->jet_parse_line_count   = 0;
   info->next_line_count  = 0;
}


void parse_end_of_input(scriptData *info)
{
	assert(info != NULL);

   strncpy(info->token.string, "<EOF>", JE_PARSE_TOKEN_LEN);

   if (info->brace_count > 0) {
	   jeParse_Error("%d extra opening brace%s detected in file", (info->brace_count > 1)?("s "):(" "), info->brace_count);

   }
   else if (info->brace_count < 0) {
      jeParse_Error("%d extra closing brace%s detected in file", (info->brace_count < -1)?("s "):(" "), -info->brace_count);
   }
}


//=====================================================================================
//	jeParse_Scan
//=====================================================================================
JE_PARSE_TOKEN jeParse_Scan(scriptData *info)
{
	int cin;

   	assert(info != NULL);

   info->token.string[0]  = '\0';
   info->token.is_newline = JE_FALSE;

   info->jet_parse_line_count = info->next_line_count;

   for (;;) {
      do {
         cin = jeParse_Input(info);

         if (cin == '\n') info->token.is_newline = JE_TRUE;

      } while (isspace(cin));

      if (cin == '/') {
         cin = jeParse_Input(info);

         if (cin == '/') {
            do {
               cin = jeParse_Input(info);
            } while ((cin != '\n') && (cin != EOF));

            if (cin == '\n') info->token.is_newline = JE_TRUE;

            if (cin == EOF) {
               parse_end_of_input(info);
               return JE_PARSE_TOKEN_EOF;
            }
         }
         else {
            jeParse_InputUnget(cin, info);
            break;
         }
      }
      else {
         break;
      }
   }

   if (cin != EOF) {
      int pos = 0;

      do {
         info->token.string[pos] = (char)cin;
         cin = jeParse_Input(info);

         // If the token is too big then it will be truncated to a size
         // one larger than is allowable.  The overflow can then be
         // detected and reported by the consumer of the token.
         if (pos < JE_PARSE_TOKEN_LEN) pos++;
      } while (!isspace(cin) && (cin != EOF));

      jeParse_InputUnget(cin, info);

      info->token.string[pos] = '\0';

      if (strcmp("{", info->token.string) == 0) {
         info->brace_count++;

         if (info->brace_count > 2) jeParse_Error("'{' (opening braces) should never be nested more than 2 deep");

         return '{';
      }
      else if (strcmp("}", info->token.string) == 0) {
         info->brace_count--;

         if (info->brace_count < 0) jeParse_Error("extra '}' (closing brace) detected");

         return '}';
      }
	  else {
         return JE_PARSE_TOKEN_STRING;
      }
   }
   else {
      parse_end_of_input(info);
      return JE_PARSE_TOKEN_EOF;
   }
}

//=====================================================================================
//	jeParse_Skip
//=====================================================================================
jeBoolean jeParse_Skip(scriptData *info)
{
	assert(info != NULL);

   while (info->brace_count == 0) {
      if (jeParse_Scan(info) == JE_PARSE_TOKEN_EOF) return JE_TRUE;
   }

   while (info->brace_count != 0) {
      if (jeParse_Scan(info) == JE_PARSE_TOKEN_EOF) return JE_TRUE;
   }

   return JE_TRUE;
}


//EOF