//-------------------------------------------------------------------------
/*
Copyright (C) 1996, 2005 - 3D Realms Entertainment

This file is NOT part of Shadow Warrior version 1.2
However, it is either an older version of a file that is, or is
some test code written during the development of Shadow Warrior.
This file is provided purely for educational interest.

Shadow Warrior is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
*/
//-------------------------------------------------------------------------

// scriplib.c
#include "build.h"
#include "editor.h"
#include "cache1d.h"

#include "names2.h"
#include "game.h"

#include "parse.h"

#define PATHSEPERATOR   '\\'


//#define COMPUTE_TOTALS	1

/*
=============================================================================

						ABNORMAL TERMINATION

=============================================================================
*/
void Error (char *error, ...)
{
	va_list argptr;

	va_start (argptr,error);
	vprintf (error,argptr);
	va_end (argptr);
	printf ("\n");
	exit (1);
}



/*
=============================================================================

						PARSING STUFF

=============================================================================
*/

char    token[MAXTOKEN];
char    *scriptbuffer,*script_p,*scriptend_p;
int     grabbed;
int     scriptline;
BOOL    endofscript;
BOOL    tokenready;                     // only TRUE if UnGetToken was just called

/*
==============
=
= LoadScriptFile
=
==============
*/

BOOL LoadScriptFile (char *filename)
{
	int size;
	int fp;


	if((fp=kopen4load(filename,0)) == -1)
	{
		// If there's no script file, forget it.
		return FALSE;
	}

	size = kfilelength(fp);

	scriptbuffer = (char *)malloc(size);

	ASSERT(scriptbuffer != NULL);

	size = kread(fp, scriptbuffer, size);

	kclose(fp);


	// Convert filebuffer to all upper case
	//strupr(scriptbuffer);

	script_p = scriptbuffer;
	scriptend_p = script_p + size;
	scriptline = 1;
	endofscript = FALSE;
	tokenready = FALSE;
	return TRUE;
}


/*
==============
=
= UnGetToken
=
= Signals that the current token was not used, and should be reported
= for the next GetToken.  Note that

GetToken (TRUE);
UnGetToken ();
GetToken (FALSE);

= could cross a line boundary.
=
==============
*/

void UnGetToken (void)
{
	tokenready = TRUE;
}


/*
==============
=
= GetToken
=
==============
*/

void GetToken (BOOL crossline)
{
	char    *token_p;

	if (tokenready)                         // is a token already waiting?
	{
		tokenready = FALSE;
		return;
	}

	if (script_p >= scriptend_p)
	{
		if (!crossline)
			Error ("Line %i is incomplete\n",scriptline);
		endofscript = TRUE;
		return;
	}

//
// skip space
//
skipspace:
	while (*script_p <= 32)
	{
		if (script_p >= scriptend_p)
		{
			if (!crossline)
				Error ("Line %i is incomplete\n",scriptline);
			endofscript = TRUE;
			return;
		}
		if (*script_p++ == '\n')
		{
			if (!crossline)
				Error ("Line %i is incomplete\n",scriptline);
			scriptline++;
		}
	}

	if (script_p >= scriptend_p)
	{
		if (!crossline)
			Error ("Line %i is incomplete\n",scriptline);
		endofscript = TRUE;
		return;
	}

	if (*script_p == '#')   // # is comment field
	{
		if (!crossline)
			Error ("Line %i is incomplete\n",scriptline);
		while (*script_p++ != '\n')
			if (script_p >= scriptend_p)
			{
				endofscript = TRUE;
				return;
			}
		goto skipspace;
	}

//
// copy token
//
	token_p = token;

	while ( *script_p > 32 && *script_p != '#')
	{
		*token_p++ = *script_p++;
		if (script_p == scriptend_p)
			break;
		ASSERT (token_p != &token[MAXTOKEN]);
//			Error ("Token too large on line %i\n",scriptline);
	}

	*token_p = 0;
}


/*
==============
=
= TokenAvailable
=
= Returns true if there is another token on the line
=
==============
*/

BOOL TokenAvailable (void)
{
	char    *search_p;

	search_p = script_p;

	if (search_p >= scriptend_p)
		return FALSE;

	while ( *search_p <= 32)
	{
		if (*search_p == '\n')
			return FALSE;
		search_p++;
		if (search_p == scriptend_p)
			return FALSE;

	}

	if (*search_p == '#')
		return FALSE;

	return TRUE;
}

void DefaultExtension (char *path, char *extension)
{
	char    *src;
//
// if path doesn't have a .EXT, append extension
// (extension should include the .)
//
	src = path + strlen(path) - 1;

	while (*src != '\\' && src != path)
	{
		if (*src == '.')
			return;                 // it has an extension
		src--;
	}

	strcat (path, extension);
}


void DefaultPath (char *path, char *basepath)
{
	char    temp[128];

	if (path[0] == '\\')
		return;                                                 // absolute path location
	strcpy (temp,path);
	strcpy (path,basepath);
	strcat (path,temp);
}


void    StripFilename (char *path)
{
	int             length;

	length = (int)strlen(path)-1;
	while (length > 0 && path[length] != PATHSEPERATOR)
		length--;
	path[length] = 0;
}


void ExtractFileBase (char *path, char *dest)
{
	char    *src;
	int             length;

	src = path + strlen(path) - 1;

//
// back up until a \ or the start
//
	while (src != path && *(src-1) != '\\')
		src--;

//
// copy up to eight characters
//
	memset (dest,0,8);
	length = 0;
	while (*src && *src != '.')
	{
		if (++length == 9)
			Error ("Filename base of %s >8 chars",path);
		*dest++ = toupper(*src++);
	}
}


/*
==============
=
= ParseNum / ParseHex
=
==============
*/

int ParseHex (char *hex)
{
	char    *str;
	int    num;

	num = 0;
	str = hex;

	while (*str)
	{
		num <<= 4;
		if (*str >= '0' && *str <= '9')
			num += *str-'0';
		else if (*str >= 'a' && *str <= 'f')
			num += 10 + *str-'a';
		else if (*str >= 'A' && *str <= 'F')
			num += 10 + *str-'A';
		else
			Error ("Bad hex number: %s",hex);
		str++;
	}

	return num;
}


int ParseNum (char *str)
{
	if (str[0] == '$')
		return ParseHex (str+1);
	if (str[0] == '0' && str[1] == 'x')
		return ParseHex (str+2);
	return atoi (str);
}




// voxelarray format is:
//  	spritenumber, voxelnumber
int aVoxelArray[MAXTILES];

extern int nextvoxid;

// Load all the voxel files using swvoxfil.txt script file
// Script file format:

//			# - Comment
//			spritenumber (in artfile), voxel number, filename
//			Ex. 1803 0 medkit2.kvx
//			    1804 1 shotgun.kvx
//				etc....

void LoadKVXFromScript( char *filename )
{
	int lNumber=0,lTile=0;	// lNumber is the voxel no. and lTile is the editart tile being
							// replaced.
	char *sName;			// KVS file being loaded in.

	int grabbed=0;			// Number of lines parsed

	sName = (char *)malloc(256);	// Up to 256 bytes for path
	ASSERT(sName != NULL);

	// zero out the array memory with -1's for pics not being voxelized
	memset(aVoxelArray,-1,sizeof(aVoxelArray));

	// Load the file
	if (!LoadScriptFile(filename)) return;

	do {
		GetToken (TRUE);	// Crossing a line boundary on the end of line to first token
							// of a new line is permitted (and expected)
		if (endofscript)
			break;

		lTile = atoi(token);

		GetToken(FALSE);
		lNumber = atoi(token);

		GetToken(FALSE);
		strcpy(sName,token);			// Copy the whole token as a file name and path

		// Load the voxel file into memory
		if (!qloadkvx(lNumber,sName)) {
			// Store the sprite and voxel numbers for later use
			aVoxelArray[lTile] = lNumber;	// Voxel num
		}

		if (lNumber >= nextvoxid)	// JBF: so voxels in the def file append to the list
			nextvoxid = lNumber + 1;

		grabbed++;
		ASSERT(grabbed < MAXSPRITES);

	} while (script_p < scriptend_p);

	free(scriptbuffer);
	script_p = NULL;
}


/// MISC ////////////////////////////////////////////////////////////////////

/*
extern int idleclock,slackerclock;

// Watch dog function.  Tracks user's work times.
void LogUserTime( BOOL bIsLoggingIn )
{
	int size, readsize;
	time_t time_of_day;
    char serialid[20],filename[100],fbase[20],buf[26],filetemp[100];
    FILE *fp;
	int tothours, totmins, totsecs, gtotalclock=0,gidleclock=0;
	ldiv_t mins_secs;
	ldiv_t hrs_mins;
	int i;

	char path[] = "o:\\user\\jimn\\logs\\";
//	char path[] = "c:\\jim\\sw\\";

	memset(filename,0,sizeof(filename));
	memset(fbase,0,sizeof(fbase));
	memset(serialid,0,sizeof(serialid));
	memset(buf,0,sizeof(buf));
	memset(filetemp,0,sizeof(filetemp));

	// Get the time of day user logged in to build
    time_of_day = time( NULL );

	// Get the serial number from the user's disk drive "it's unique!"
	system("dir > serid.bld");
	LoadScriptFile("serid.bld");

	// Go to the serial number
	for (i=0; i<11; i++)
	{
		GetToken (TRUE);
		if (endofscript)
			return;
	}

	// Copy the token to serialid
	strcpy(serialid,token);

	// Free the script memory when done
	free(scriptbuffer);
	script_p = NULL;

	// Build a file name using serial id.
	strcpy(filename,path);
	strncpy(fbase,serialid,8);
	strcat(fbase,".bld");
	strcat(filename,fbase);

	// Delete the temp file
	system("erase serid.bld");

	// Unhide the file so it can be opened
	_dos_setfileattr(filename,_A_NORMAL);


	// Open the file
	fp = fopen( filename, "a+" );

	// Opening on the network failed, try putting it on the current disk drive
	if(fp == NULL)
	{
		// Unhide the file so it can be opened/this works if file was created before!
		_dos_setfileattr(fbase,_A_NORMAL);
		fp = fopen( fbase, "a+" );
		strcpy(filetemp,fbase);
	} else
		strcpy(filetemp,filename);


  	if( fp == NULL)
   		return;
	else
    {
		if(bIsLoggingIn)
		{
			fprintf(fp, "//////////////////////////////\n");
		    fprintf(fp, "User logged into build at: %s", _ctime( &time_of_day, buf ) );
		}else
		{
			totsecs = totalclock/120;	// Convert totalclock to seconds.

			mins_secs = ldiv( totsecs, 60L );
			totmins = mins_secs.quot;
			totsecs = mins_secs.rem;

			hrs_mins = ldiv( totmins, 60L);
			tothours = hrs_mins.quot;
			totmins = hrs_mins.rem;

			fprintf(fp, "TotalClock: %ld\n",totalclock);
#ifdef COMPUTE_TOTALS
			fprintf(fp, "IdleClock: %ld\n",slackerclock);
#endif
			fprintf(fp, "Time this session: %ld Hours %ld Mins %ld Secs\n",tothours,totmins,totsecs);
#ifdef COMPUTE_TOTALS
			totsecs = (totalclock-slackerclock)/120;	// Convert totalclock to seconds.
			if(totsecs<=0) totsecs = 0;

			mins_secs = ldiv( totsecs, 60L );
			totmins = mins_secs.quot;
			totsecs = mins_secs.rem;

			hrs_mins = ldiv( totmins, 60L);
			tothours = hrs_mins.quot;
			totmins = hrs_mins.rem;
			fprintf(fp, "Time - idleclock : %ld Hours %ld Mins %ld Secs\n",tothours,totmins,totsecs);
#endif
		}

	    fclose( fp );
	}

#if 1
	if(!bIsLoggingIn)
	{
		// Compute total time for file
		LoadScriptFile(filetemp);

		do {
			GetToken (TRUE);

			if (endofscript)
				break;

			if(!strcmpi(token,"totalclock:"))
			{
				GetToken(TRUE);
				gtotalclock += atol(token);
			}
#if 0
			if(!strcmpi(token,"idleclock:"))
			{
				GetToken(TRUE);
				gidleclock += atol(token);
			}
#endif

		} while (script_p < scriptend_p);

		// Free the script memory when done
		free(scriptbuffer);
		script_p = NULL;

		// Open the file
		fp = fopen( filetemp, "a+" );

		// Now compute the grand total
		if(fp != NULL)
		{
			totsecs = gtotalclock/120;	// Convert totalclock to seconds.

			mins_secs = ldiv( totsecs, 60L );
			totmins = mins_secs.quot;
			totsecs = mins_secs.rem;

			hrs_mins = ldiv( totmins, 60L);
			tothours = hrs_mins.quot;
			totmins = hrs_mins.rem;

			fprintf(fp, "\nTotal time so far  : %ld Hours %ld Mins %ld Secs\n",tothours,totmins,totsecs);

#if 0
			totsecs = (gtotalclock-gidleclock)/120;	// Convert totalclock to seconds.
			if(totsecs<=0) totsecs = 0;

			mins_secs = ldiv( totsecs, 60L );
			totmins = mins_secs.quot;
			totsecs = mins_secs.rem;

			hrs_mins = ldiv( totmins, 60L);
			tothours = hrs_mins.quot;
			totmins = hrs_mins.rem;

			fprintf(fp, "\nTotal actual time  : %ld Hours %ld Mins %ld Secs\n",tothours,totmins,totsecs);
#endif

			fclose(fp);
		}
	}
#endif

	_dos_setfileattr(filename,_A_HIDDEN);


}
*/
