#define _ERRORS_
#include "tok.h"

void warningprint(char* str, int line, int file);
WARNACT wact[WARNCOUNT] =
{
	warningprint, 1, warningprint, 1, warningprint, 1, warningprint, 1, warningprint, 1,
	warningprint, 1, warningprint, 1, warningprint, 1, warningprint, 1, warningprint, 1,
	warningprint, 1, warningprint, 1, warningprint, 1, warningprint, 1, warningprint, 1
};

int	maxerrors = 16; 				// number of errors to stop at

void warningprint(char* str, int line, int file);
unsigned char mapfile = FALSE;
FILE* hmap = NULL;

char shorterr[] = "SHORT jump distance too large";
char buferr[128];

/* ================== error messages start =========================== */

void FindStopTok()
{
	//	while(tok!=tk_eof&&itok2.type!=tp_stopper/*tok2!=tk_semicolon&&tok2!=tk_camma*/){
	do
	{
		nexttok();
	}
	while (tok != tk_eof && itok2.type != tp_stopper && itok.type != tp_stopper/*tok2!=tk_semicolon&&tok2!=tk_camma*/);

	//	}
}

void SkipBlock2()
{
	cha = cha2;
	inptr = inptr2;
	SkipBlock();
	cha2 = cha;
	inptr = inptr2;
	linenum2 = linenumber;
	FindStopTok();
}

void FindEndLex()
{
	while (tok2 != tk_semicolon && tok != tk_eof)
	{
		nexttok();
	}
}

void  preerror(char* str) /* error on currentline with line number and file name */
{
	preerror3(str, linenumber);
}

void  preerror3(char* str, unsigned int line, unsigned int file) //error message at a different than current line
{
	if (error < maxerrors)
	{
		error++;
		sprintf((char*)string3, "%s(%d)#%d> %s.\n", startfileinfo == NULL ? "" : (startfileinfo + file)->filename, line, error, str);
		printf((char*)string3);

		if (errfile.file == NULL)
		{
			errfile.file = fopen(errfile.name, "w+t");
		}

		if (errfile.file != NULL)
		{
			fprintf(errfile.file, (char*)string3);
		}
	}
	else
	{
		exit(e_toomanyerrors);
	}
}

void internalerror(char* str) // serious internal compiler error message
{
	char buf[200];
	sprintf(buf, "*** SERIOUS COMPILER INTERNAL ERROR ***\n>%s", str);
	preerror(buf);
	printf("STRING:%s\nIDNAME:%s\n", string, itok.name);
	printf("TOK:%d SEGM:%d POST:%d RM:%d number:%ld\n", tok, itok.segm, itok.post, itok.rm, itok.number);
	printf("STRING2:%s\nIDNAME2:%s\n", string2, itok2.name);
	printf("TOK2:%d SEGM2:%d POST2:%d RM2:%d number2:%ld\n", tok2, itok2.segm, itok2.post, itok2.rm, itok2.number);
	printf("Out position:%04X\n", outptr);
	exit(e_internalerror);
}

char* getnumoperand(int type, char* name)
{
	switch (type)
	{
	case 0:
		return "";

	case 1:
		strcpy(buferr, "1-st ");
		break;

	case 2:
		strcpy(buferr, "2-nd ");
		break;

	case 3:
		strcpy(buferr, "3-rd ");
		break;

	default:
		sprintf(buferr, "%d-th ", type % 256);
		break;
	}

	strcat(buferr, name);
	return buferr;
}

void  expected(char ch)
{
	char holdstr[80];
	sprintf(holdstr, "'%c' expected", ch);
	preerror(holdstr);
}

void numexpected(int type)
{
	char buf[40];
	sprintf(buf, "%snumber expected", getnumoperand(type, "operand "));
	preerror(buf);
}

void varexpected(int type)
{
	char buf[45];
	sprintf(buf, "%svariable expected", getnumoperand(type, "operand "));
	preerror(buf);
}

void stringexpected()
{
	preerror("string expected");
}

void valueexpected()
{
	preerror("value expected");
}

void wordvalexpected()
{
	preerror("word value expected");
}

void dwordvalexpected()
{
	preerror("dword value expected");
}

void qwordvalexpected()
{
	preerror("qword value expected");
}

void codeexpected()
{
	preerror("assembly opcode expected");
}

void operatorexpected()
{
	preerror("operator identifier expected");
}

void unexpectedeof()
{
	preerror("unexpected END OF FILE");
}

void swaperror()
{
	preerror("invalid or incompatable swap item");
}

void notexternfun()
{
	preerror("Do not insert extern function");
}

void idalreadydefined()
{
	char holdstr[80];
	sprintf(holdstr, "identifier '%s' already defined", itok.name);
	preerror(holdstr);
	FindStopTok();
	//	nexttok();
}

void  jumperror(unsigned int line, char* type)
{
	char smalltype[IDLENGTH];
	char buf[80];
	strcpy(smalltype, type);
	strlwr(smalltype);
	sprintf(buf, "'%s' jump distance too large, use '%s'", type, smalltype);
	preerror3(buf, line);
}

void unknowncompop()
{
	preerror("unknown comparison operator");
}

void maxoutputerror()
{
	preerror("maximum output code size exceeded");
	exit(e_outputtoobig);
}

void unableopenfile(char* name)
{
	char holdstr[256];
	sprintf(holdstr, "unable to open file '%s'", name);
	preerror(holdstr);
}

void shortjumptoolarge()
{
	preerror(shorterr);
}

void thisundefined(char* str, int next)
{
	char holdstr[80];
	sprintf(holdstr, "'%s' undefined", str);
	preerror(holdstr);

	if (next)
	{
		FindStopTok();
	}
}

void datatype_expected(int type)
{
	char buf[45];
	sprintf(buf, "%smemory variable expected", getnumoperand(type, "operand "));
	preerror(buf);
	FindStopTok();
}

void illegalfloat()
{
	preerror("illegal use of float point");
}

void tobigpost()
{
	preerror("maximum size of post variables exceeded");
	postsize = 0xFFFF;
}

void unuseableinput()
{
	preerror("unuseable input");
	FindStopTok();
}

void ManyLogicCompare()
{
	preerror("to many use logic compare");
}

void ZeroMassiv()
{
	preerror("size massiv unknown or zero");
}

void maxdataerror()
{
	preerror("maximum output data size exceeded");
	exit(e_outputtoobig);
}

void errorreadingfile(char* name)
{
	char buf[256];
	sprintf(buf, "error reading from file '%s'", name);
	preerror(buf);
}

void badinfile(char* name)
{
	char buf[256];
	sprintf(buf, "bad input file '%s'", name);
	preerror(buf);
}

void edpip(int num)
{
	char buf[64];
	//	preerror("error declare parameters in function");
	sprintf(buf, "error declare %sparameters in function", getnumoperand(num, ""));
	preerror(buf);
}

void CompareOr()
{
	preerror("compare logic OR or AND to big distance");
}

void dynamiclabelerror()
{
	preerror("global labels illegal within dynamic functions");
}

void OnlyComFile()
{
	preerror("this option only for COM output files");
}

void redeclare(char* name)
{
	char buf[120];
	sprintf(buf, "error redeclare function \"%s\"", name);
	preerror(buf);
}

void retvoid()
{
	preerror("function has return type of void");
}

void extraparam(char* name)
{
	char buf[120];
	sprintf(buf, "extra parameter in function %s", name);
	preerror(buf);
}

void blockerror()
{
	preerror("illegal syntax within [ ]");
}

void block16_32error()
{
	preerror("only one of 16 or 32 bit allowed within [ ]");
}

void notstructname()
{
	preerror("unique struct name expected");
}

void badtoken()
{
	char buf[80];

	if (displaytokerrors)
	{
		sprintf(buf, "tokenizer: bad character value - '%c'", cha);
		preerror(buf);
	}
}

void expectederror(char* str)
{
	char holdstr[80];

	if (displaytokerrors)
	{
		sprintf(holdstr, "%s expected", str);
		preerror(holdstr);
	}
}

void declareanonim()
{
	preerror("Error declare anonimus union");
}

void declareunion()
{
	preerror("Error declare union");
}
/*
void not_union_static()
{
	preerror("'static' not use in 'union'");
} */

void segoperror()
{
	preerror("only '=' or '><' operands valid with segment register");
}

void segbyteerror()
{
	preerror("segment registers can not be used in byte or char math");
}

void regmathoperror()
{
	preerror("invalid operation for non-AX register math");
}

void begmathoperror()
{
	preerror("invalid operation for non-AL register math");
}

void negregerror()
{
	preerror("negative non-constant invalid for non-AX register math");
}

void regbyteerror()
{
	preerror("byte or char operands invalid for non-AX register math");
}

void begworderror()
{
	preerror("specified 16 bit operand invalid for non-AL register math");
}

void regshifterror()
{
	preerror("only CL or 1 valid for non AX or AL register bit shifting");
}

void regmatherror()
{
	preerror("invalid operand for non-AX register math");
}

void DevideZero()
{
	preerror("impossible to divide into ZERO");
}

void wordnotoper()
{
	preerror("word or int operands invalid for non-EAX register math");
}

void regexpected(int type)
{
	char buf[50];
	sprintf(buf, "%sword register expected", getnumoperand(type, "operand "));
	preerror(buf);
}

void bytevalexpected(int type)
{
	char buf[50];
	sprintf(buf, "%sbyte value expected", getnumoperand(type, "operand "));
	preerror(buf);
}

void shortjumperror()
{
	preerror("invalid operand for SHORT jump");
}

void invalidfarjumpitem()
{
	preerror("invalid operand for FAR jump");
}

void invalidfarcallitem()
{
	preerror("invalid operand for FAR call");
}

void begexpected(int type)
{
	char buf[50];
	sprintf(buf, "%sbyte register expected", getnumoperand(type, "operand "));
	preerror(buf);
}

void reg32expected(int type)
{
	char buf[50];
	sprintf(buf, "%s32 bit register expected", getnumoperand(type, "operand "));
	preerror(buf);
}

void reg32regexpected(int type)
{
	char buf[50];
	sprintf(buf, "%s16 or 32 bit register expected", getnumoperand(type, "operand "));
	preerror(buf);
}

void regBXDISIBPexpected()
{
	preerror("use only one of BX, DI, SI or BP register");
}

void bytedxexpected()
{
	preerror("byte constant or DX expected");
}

void axalexpected()
{
	preerror("EAX, AX or AL expected");
}

void invalidoperand(int type)
{
	char buf[25];
	sprintf(buf, "%sinvalid", getnumoperand(type, "operand "));
	preerror(buf);
}

void mmxregexpected(int type)
{
	char buf[50];
	sprintf(buf, "%sMMX register expected", getnumoperand(type, "operand "));
	preerror(buf);
}

void xmmregexpected(int type)
{
	char buf[50];
	sprintf(buf, "%sXMM register expected", getnumoperand(type, "operand "));
	preerror(buf);
}

void xmmregorvarexpected(int type)
{
	char buf[60];
	sprintf(buf, "%sXMM register or memory varible expected", getnumoperand(type, "operand "));
	preerror(buf);
}

void mmxregordwordexpected(int type)
{
	char buf[60];
	sprintf(buf, "%sMMX register or memory varible expected", getnumoperand(type, "operand "));
	preerror(buf);
}

void clornumberexpected()
{
	preerror("CL or constant expected");
}

void fpuvarexpected(int type)
{
	char buf[70];
	sprintf(buf, "%sexpected FPU register|long|dword|float var", getnumoperand(type, "operand "));
	preerror(buf);
}

void fpustakexpected(int type)
{
	char buf[40];
	sprintf(buf, "%sexpected FPU register", getnumoperand(type, "operand "));
	preerror(buf);
}

void fpu0expected()
{
	preerror("2-nd expected only st(0) fpu register");
}

void fpustdestroed()
{
	preerror("FPU register more 6 destroed");
}

void errstruct()
{
	preerror("illegal use of struct");
}

void tegnotfound()
{
	preerror("tag struct not found");
}

void ErrWrite()
{
	fprintf(stderr, "unable to write output file.\n");
}

void ErrReadStub()
{
	fprintf(stderr, "unable to read stubfile\n");
}

void InvOperComp()
{
	preerror("invalid operation for compare");
}

void mmxormem(int type)
{
	char buf[60];
	sprintf(buf, "%sexpected mmx register or memory variable", getnumoperand(type, "operand "));
	preerror(buf);
}

void reg32orword(int type)
{
	char buf[60];
	sprintf(buf, "%s32 bit register or word variable expected", getnumoperand(type, "operand "));
	preerror(buf);
}

void undefclass(char* name)
{
	char buf[30 + IDLENGTH];
	sprintf(buf, "Base class '%s' not defined", name);
	preerror(buf);
}

void unknowntype()
{
	preerror("unknown type");
}

void destrdestreg()
{
	preerror("destroyed destination register");
}

void unknownstruct(char* name, char* sname)
{
	char buf[IDLENGTH * 2 + 30];
	sprintf(buf, "unknown member '%s' in struct '%s'", name, sname);
	preerror(buf);
}

void unknowntagstruct(char* name)
{
	char buf[IDLENGTH + 16];
	sprintf(buf, "unknown tag '%s'", name);
	preerror(buf);
}

void unknownobj(char* name)
{
	char buf[IDLENGTH + 32];
	sprintf(buf, "unknown object for member '%s'", name);
	preerror(buf);
}

void unknownpragma(char* name)
{
	char buf[IDLENGTH + 32];
	sprintf(buf, "unknown parametr for #pragma %s", name);
	preerror(buf);
}

/*-----------------08.08.00 22:49-------------------
 Предупреждения
	--------------------------------------------------*/

void warningoptnum()
{
	if (wact[0].usewarn)
	{
		wact[0].fwarn("Optimize numerical expressions", linenumber, currentfileinfo);
	}
}

void  warningreg(char* str2)
{
	char buf[50];

	if (wact[1].usewarn)
	{
		sprintf(buf, "%s has been used by compiler", str2);
		wact[1].fwarn(buf, linenumber, currentfileinfo);
	}
}

void  warningjmp(char* str2, int line, int file)
{
	char buf[50];

	if (wact[2].usewarn)
	{
		sprintf(buf, "Short operator '%s' may be used", str2);
		wact[2].fwarn(buf, line, file);
	}
}

void warningstring()
{
	if (wact[3].usewarn)
	{
		sprintf((char*)string2, "String \"%s\" repeated", string3);
		wact[3].fwarn((char*)string2, linenumber, currentfileinfo);
	}
}

void warningexpand()
{
	if (wact[4].usewarn)
	{
		wact[4].fwarn("Expansion variable", linenumber, currentfileinfo);
	}
}

void warningretsign()
{
	if (wact[5].usewarn)
	{
		wact[5].fwarn("Signed value returned", linenumber, currentfileinfo);
	}
}

void warningprint(char* str, unsigned int line, unsigned int file)
{
	if (warning == TRUE)
	{
		if (wartype.name != NULL && wartype.file == stdout)
		{
			if ((wartype.file = fopen(wartype.name, "w+t")) == NULL)
			{
				wartype.file = stdout;
			}
		}

		fprintf(wartype.file, "%s(%d)> Warning! %s.\n", startfileinfo == NULL ? "" : (startfileinfo + file)->filename, line, str);
	}
}

void  warningdefined(char* name)
{
	char buf[IDLENGTH + 30];

	if (wact[6].usewarn)
	{
		sprintf(buf, "'%s' defined above, therefore skipped", name);
		wact[6].fwarn(buf, linenumber, currentfileinfo);
	}
}

void warningnotused(char* name, int type)
{
	char buf[IDLENGTH + 40];
	char* typenames[] = {"Variable", "Structure", "Function", "Local variable",
						 "Parameter variable", "Local structure"
						};

	if (wact[7].usewarn)
	{
		sprintf(buf, "%s '%s' possible not used", (char*)typenames[type], name);
		wact[7].fwarn(buf, linenumber, currentfileinfo);
	}
}

void warningusenotintvar(char* name)
{
	char buf[IDLENGTH + 50];

	if (wact[8].usewarn)
	{
		sprintf(buf, "Non-initialized variable '%s' may have been used", name);
		wact[8].fwarn(buf, linenumber, currentfileinfo);
	}
}

void warningdestroyflags()
{
	if (wact[9].usewarn)
	{
		wact[9].fwarn("Return flag was destroyed", linenumber, currentfileinfo);
	}
}

void warningunreach()
{
	if (wact[10].usewarn)
	{
		wact[10].fwarn("Code may not be executable", linenumber, currentfileinfo);
	}
}

void warninline()
{
	if (wact[11].usewarn)
	{
		wact[11].fwarn("Don't use local/parametric values in inline functions", linenumber, currentfileinfo);
	}
}

void warnsize()
{
	if (wact[12].usewarn)
	{
		wact[12].fwarn("Sources size exceed destination size", linenumber, currentfileinfo);
	}
}

void waralreadinit(char* reg)
{
#ifdef BETTA
	char buf[IDLENGTH + 50];
	sprintf(buf, "Register %s already initialized", reg);
	warningprint(buf, linenumber, currentfileinfo);
#endif
}

void waralreadinitreg(char* reg, char* reg2)
{
#ifdef BETTA
	char buf[IDLENGTH + 50];
	sprintf(buf, "Register %s same as %s", reg, reg2);
	warningprint(buf, linenumber, currentfileinfo);
#endif
}

void warpragmapackpop()
{
	if (wact[13].usewarn)
	{
		wact[13].fwarn("Pragma pack pop with no matching pack push", linenumber, currentfileinfo);
	}
}

void missingpar(char* name)
{
	char buf[120];

	if (wact[14].usewarn)
	{
		sprintf(buf, "Missing parameter in function %s", name);
		wact[14].fwarn(buf, linenumber, currentfileinfo);
	}

	//	preerror(buf);
}

void warreplasevar(char* name)
{
	char buf[120];

	//	if(usewarn[14]){
	if (displaytokerrors)
	{
		sprintf(buf, "Variable %s is replased on constant", name);
		warningprint(buf, linenumber, currentfileinfo);
	}

	//	}
	//	preerror(buf);
}

void waralreadinitvar(char* name, unsigned int num)
{
	char buf[120];

	//	if(usewarn[14]){
	if (displaytokerrors)
	{
		sprintf(buf, "Variable %s already initialized by constant %d", name, num);
		warningprint(buf, linenumber, currentfileinfo);
	}

	//	}
	//	preerror(buf);
}

void warcompneqconst()
{
	warningprint("Comparison not equal constant. Skipped code", linenumber, currentfileinfo);
}

void warcompeqconst()
{
	warningprint("Comparison equal constant. Skipped compare", linenumber, currentfileinfo);
}

void warpointerstruct()
{
	warningprint("Compiler not support pointers on structure", linenumber, currentfileinfo);
}

void warESP()
{
	warningprint("ESP has ambiguous value", linenumber, currentfileinfo);
}

/* *****************   map file *************** */

void OpenMapFile()
{
	char buf[256];
	sprintf(buf, "%s.map", rawfilename);
	hmap = fopen(buf, "w+t");
}

char* GetRetType(int type, int flag)
{
	char* retcode;

	if (flag & f_interrupt)
	{
		return "";
	}

	switch (type)
	{
	case tk_bytevar:
	case tk_byte:
		retcode = "byte ";
		break;

	case tk_charvar:
	case tk_char:
		retcode = "char ";
		break;

	case tk_wordvar:
	case tk_word:
		retcode = "word ";
		break;

	case tk_longvar:
	case tk_long:
		retcode = "long ";
		break;

	case tk_dwordvar:
	case tk_dword:
		retcode = "dword ";
		break;

	case tk_doublevar:
	case tk_double:
		retcode = "double ";
		break;

	case tk_fpust:
		retcode = "fpust ";
		break;

	case tk_floatvar:
	case tk_float:
		retcode = "float ";
		break;

	case tk_qwordvar:
	case tk_qword:
		retcode = "qword ";
		break;

	case tk_void:
		retcode = "void ";
		break;

	/*		case tk_intvar:
			case tk_int:
				retcode="int ";
				break;*/
	case tk_structvar:
		retcode = "struct";
		break;

	default:
		retcode = "int ";
		break;
	}

	return retcode;;
}

char* GetTypeProc(int flag)
{
	char* retcode;
	char* t;
	string2[0] = 0;

	if (flag & f_interrupt)
	{
		return "interrupt";
	}

	if (flag & f_far)
	{
		strcat((char*)string2, "far ");
	}

	if (flag & f_extern)
	{
		strcat((char*)string2, "extern ");
	}

	if (flag & f_export)
	{
		strcat((char*)string2, "_export ");
	}

	if (flag & f_inline)
	{
		strcat((char*)string2, "inline ");
	}

	if (flag & f_static)
	{
		strcat((char*)string2, "static ");
	}

	if (flag & f_retproc)
	{
		t = "";

		switch (((flag & f_retproc) >> 8) + tk_overflowflag - 1)
		{
		case tk_overflowflag:
			t = "OVERFLOW ";
			break;

		case tk_notoverflowflag:
			t = "NOTOVERFLOW ";
			break;

		case tk_carryflag:
			t = "CARRYFLAG ";
			break;

		case tk_notcarryflag:
			t = "NOTCARRYFLAG ";
			break;

		case tk_zeroflag:
			t = "ZEROFLAG ";
			break;

		case tk_notzeroflag:
			t = "NOTZEROFLAG ";
			break;

		case tk_minusflag:
			t = "MINUSFLAG ";
			break;

		case tk_plusflag:
			t = "PLUSFLAG ";
			break;
		}

		strcat((char*)string2, t);
	}

	switch (flag & f_typeproc)
	{
	case tp_pascal:
		t = "pascal ";
		break;

	case tp_cdecl:
		t = "cdecl ";
		break;

	case tp_stdcall:
		t = "stdcall ";
		break;

	case tp_fastcall:
		t = "fastcall ";
		break;
	}

	strcat((char*)string2, t);
	return (char*)string2;
}

char* GetFunParam(unsigned char c, unsigned char c2, unsigned char c3)
{
	switch (c)
	{
	case 'B':
		if (c2 >= 0x30 && c2 <= 0x37)
		{
			return begs[c2 - 0x30];
		}

		return "byte";

	case 'W':
		if (c2 >= 0x30 && c2 <= 0x37)
		{
			return regs[0][c2 - 0x30];
		}

		return "word";

	case 'D':
		if (c2 >= 0x30 && c2 <= 0x37)
		{
			return regs[1][c2 - 0x30];
		}

		return "dword";

	case 'C':
		return "char";

	case 'I':
		return "int";

	case 'L':
		return "long";

	case 'F':
		return "float";

	case 'A':
		return "...";

	case 'Q':
		if (c2 >= 0x30 && c2 <= 0x37)
		{
			sprintf((char*)string2, "%s:%s", regs[1][c2 - 0x30], regs[1][c3 - 0x30]);
			return (char*)string2;
		}

		return "qword";

	case 'E':
		return "double";

	case 'S':
		if (c2 >= 0x30 && c2 <= 0x37)
		{
			sprintf((char*)string2, "st(%c)", c2);
			return (char*)string2;
		}

		return "fpust";

	case 'T':
		return "struct";

	case 'U':
		return "void";
	}

	return "";;
}

char* GetName(char* name, int flag)
{
	char* tn;
	char iname[IDLENGTH];
	strcpy(iname, name);

	if ((tn = strchr(iname, '@')) != NULL)
	{
		*tn = 0;
	}

	if (flag & fs_constructor)
	{
		sprintf((char*)string3, "%s::%s", iname, iname);
	}
	else if (flag & fs_destructor)
	{
		sprintf((char*)string3, "%s::~%s", iname, iname);
	}
	else if (flag & f_classproc)
	{
		sprintf((char*)string3, "%s::%s", searchteg->name, iname);
	}
	else
	{
		strcpy((char*)string3, iname);
	}

	return (char*)string3;
}

char* GetSizeVar(int type, int adr)
{
	char* reg;
	char* sign;

	if (type == tp_postvar || type == tp_gvar)
	{
		return "DS:???";
	}

	if (am32)
	{
		if (ESPloc)
		{
			reg = "ESP";
		}
		else
		{
			reg = "EBP";
		}
	}
	else
	{
		reg = "BP";
	}

	if (adr < 0)
	{
		sign = "";
	}
	else
	{
		sign = "+";
	}

	sprintf((char*)string2, "%s%s%d", reg, sign, adr);
	return (char*)string2;
}

void GetRangeUsed(char* buf, localinfo* ptr)
{
	if (ptr->count == 0)
	{
		buf[0] = 0;
	}
	else if (ptr->count == 1)
	{
		sprintf(buf, "%d", ptr->usedfirst);
	}
	else
	{
		sprintf(buf, "%d-%d", ptr->usedfirst, ptr->usedlast);
	}
}

void mapfun(int line)
{
	treelocalrec* ftlr;
	struct localrec* ptr;
	int i, fheader;
	char buf[32];

	if (hmap == NULL)
	{
		OpenMapFile();
	}

	if (hmap)
	{
		fprintf(hmap, "\n%s%s%s(", GetTypeProc(itok.flag), GetRetType(itok.rm, itok.flag), GetName(itok.name, itok.flag));

		for (i = 0;; i++)
		{
			unsigned char c = string[i];

			if (c == 0)
			{
				break;
			}

			if (c >= 0x30 && c <= 0x37)
			{
				continue;
			}

			if (i)
			{
				fputc(',', hmap);
			}

			unsigned char c2 = string[i + 1];
			unsigned char c3 = string[i + 2];
			fputs(GetFunParam(c, c2, c3), hmap);
		}

		fputc(')', hmap);
		fprintf(hmap, "\nlocation: line %d-%d file %s", line, linenumber, startfileinfo == NULL ? "" : (startfileinfo + currentfileinfo)->filename);
		fprintf(hmap, "\noffset=0x%X(%d)\tsize=0x%X(%d)", itok.number, itok.number, itok.size, itok.size);
	}

	fheader = 0;

	for (ftlr = btlr; ftlr != NULL; ftlr = ftlr->next)
	{
		for (ptr = ftlr->lrec; ptr != NULL; ptr = ptr->rec.next)
		{
			i = ptr->rec.type;

			if (i == tp_postvar || i == tp_gvar || i == tp_localvar || i == tp_paramvar)
			{
				if (!fheader)
				{
					fputs("\nType    Address   Used     Count  Size    Name", hmap);
					fputs("\n----------------------------------------------", hmap);
					fheader = TRUE;
				}

				GetRangeUsed(buf, &ptr->li);
				fprintf(hmap, "\n%-8s%-10s%-12s%-4d%-8d", GetRetType(ptr->rec.rectok, 0), GetSizeVar(ptr->rec.type, ptr->rec.recnumber), buf, ptr->li.count, ptr->rec.recsize);

				if (ptr->rec.npointr)for (i = ptr->rec.npointr; i > 0; i--)
					{
						fputc('*', hmap);
					}

				fputs(ptr->rec.recid, hmap);
			}
		}
	}

	fputs("\n", hmap);
}

