/***
****  QuBE --- Entity manipulation routines.
***/

#include "qube.h"
#include "entities.h"

/* Entitiesarray.  Maximum 2048 entities, which is fine for now, but again, it
   should be a linked list or someentity more expandable */

entity *entityarray[2048];
int nextentity = 0;
int curentity = 0;
long int linenum = 0;

long int readcount;
int putback = 0;
int lastread;
long int maxlen;

/*
**  EntList.  Prints out the entities, verbatim.
*/

void EntList(void)
{
	int c;

	if (header.id != 0x17)
		Error("Not a valid .BSP file");

	fseek(fi, header.entities, SEEK_SET);
	readcount = 0L;
	maxlen = header.entitieslen;
        while ((c = nextchar(fi)) != EOF) printf("%c", c);
}

/*
**  EntXtract.	Extracts out the entities, verbatim.
*/

void EntXtract(int argnum, char **argv)
{
	int c;
	FILE *fo;

	if (header.id != 0x17)
		Error("Not a valid .BSP file");

	fseek(fi, header.entities, SEEK_SET);
	readcount = 0L;

	maxlen = header.entitieslen;
        if ((fo = fopen(argv[argnum+1], "wt")) == NULL)
		Error("Unable to create output file.");

	while ((c = nextchar(fi)) != EOF) fprintf(fo, "%c", c);

	fclose(fo);
}

/*
**  EntReplace.  Replaces the entities in a .BSP file.
*/

void EntReplace(int argnum, char **argv)
{
	FILE *fo, *tf;
	char *tempstr, *tempstr2;
	long charswritten = 0L;
	char *temp;
	long int i, j, k;
	long int readsize;

	maxlen = 0x7FFFFFFF;

	if (header.id != 0x17)
		Error("Not a valid .BSP file");

	readcount = 0L;

	temp = Qmalloc(32768);

        if ((fo = fopen("$$$_temp.bsp", "wb")) == NULL)
		Error("Unable to create output file.");

	setvbuf(fo, NULL, _IOFBF, 32768);

	fseek(fi, 0, SEEK_SET);
	fseek(fo, 0, SEEK_SET);

	for (j = 0L; j < header.entities; j += 32768L) {
		if (header.entities - j >= 32768) k = 32768;
		else k = header.entities - j;
		readsize = fread(temp, sizeof(char), k, fi);
		fwrite(temp, sizeof(char), readsize, fo);
	}

	if ((tf = fopen(argv[argnum+1], "rt")) == NULL)
		Error("Unable to open entity file.");

	setvbuf(tf, NULL, _IOFBF, 32768);

	while (!feof(tf)) {
		skipspace(tf);
                if (!getopenbrace(tf))
			Error("Missing opening brace in entity file.");

		fprintf(fo, "{\n");

                do {
                        skipspace(tf);
                        if (nextchar(tf) == '}') break;
                        putback = 1;
			if (fileend())
				Error("Early end-of-file in entity file");
                        if ((tempstr = getstring(tf)) == NULL)
				Error("Syntax error (line %ld) in entity file; type needed", linenum);
                        skipspace(tf);
			if (fileend())
				Error("Early end-of-file in entity file");
                        if ((tempstr2 = getstring(tf)) == NULL)
				Error("Syntax error (line %ld) in entity file; entry needed", linenum);
                        fprintf(fo, "\"%s\" \"%s\"\n", tempstr, tempstr2);
			Qfree(tempstr);
			Qfree(tempstr2);
                        skipspace(tf);
	       } while (!feof(tf));

                skipspace(tf);

		fprintf(fo, "}\n");
        }
	fclose(tf);

	charswritten = ftell(fo) - header.entities;
	header.pictures += charswritten - header.entitieslen;
	fseek(fi, header.entities + header.entitieslen, SEEK_SET);

	while (!feof(fi)) {
		readsize = fread(temp, sizeof(char), 32768, fi);
		fwrite(temp, sizeof(char), readsize, fo);
	}

	fseek(fo, 0, SEEK_SET);
	header.entitieslen = charswritten;
	fwrite(&header, 4, 0x50, fo);

	Qfree(temp);

        fclose(fi);
	fclose(fo);

	unlink(argv[filenamearg]);
	rename("$$$_temp.bsp", argv[filenamearg]);
}

/*
**  getstring.	Reads in a "" delimited string, stripping the quotes.
*/

char *getstring(FILE *fp)
{
	char *temp = Qmalloc(32);
	int totallen = 32;
	int curlen = 0;
	int c;

	if (nextchar(fp) != '\"') {
		Qfree(temp);
		return(NULL);
        }

	do {
		c = nextchar(fp);

		if (curlen >= totallen) temp = Qrealloc(temp, curlen += 32);

		temp[curlen++] = c;
	} while (c != '\"' && c != '\n' && c != EOF);

	if (c != '\"') {
		Qfree(temp);
		return(NULL);
        }

	if (curlen) curlen--;
        temp[curlen] = '\0';

	return(temp);
}

/*
**  getopenbrace.  Reads in a left brace.
*/

int getopenbrace(FILE *fp)
{
	return(nextchar(fp) == '{');
}

/*
**  getclosebrace.  Reads in a right brace.
*/

int getclosebrace(FILE *fp)
{
	return(nextchar(fp) == '}');
}

/*
**  skipspace.	Skips over whitespace (space, tab, newline).
*/

void skipspace(FILE *fp)
{
	unsigned char c;

        do {
		c = nextchar(fp);
	} while (c <= 32);

	putback = 1;
}

/*
**  nextchar.  Reads in the next character, with putback.
*/

int nextchar(FILE *fp)
{
        if (putback) {
		putback = 0;
		return(lastread);
        }

	if (readcount < maxlen) {
                readcount++;
		lastread = fgetc(fp);
		if (lastread == '\n') linenum++;
                return(lastread);
        }
	else return(lastread = EOF);
}         

/*
**  fileend.  Returns whether we're at the file's end.
*/

int fileend(void)
{
	if (lastread == EOF) return(1);
	else return(0);
}

