#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include "asm_name.h"
#include "dir_name.h"
#include "id_name.h"
#include "res_name.h"
#include "res.h"

#define SORTSIZE 50

typedef uint16_t TABLEITEMTYPE;
const TABLEITEMTYPE tableitemnone = 0xFFFF;

typedef char OUTBUFITEMTYPE;

TABLEITEMTYPE table[53];
OUTBUFITEMTYPE* outbuf;
FILE* out;

void InitList(const char** keylist, int type);

void OpenFile(const char* name)
{
	if ((out = fopen(name, "wt")) == NULL)
	{
		puts("Not open output file");
		exit(1);
	}

	fputs("/* automatically generated by 'FASTLIST.EXE' */\n\n", out);
}

int main()
{
	int lastlit;
	int k, y, i;
	OUTBUFITEMTYPE* ii, *jj;

	InitList(Mnemonics, 0);
	OpenFile("asmnemon.h");
	fputs("short ofsmnem[26]={\n", out);

	for (i = 0;; i++)
	{
		if (table[i + 1] != tableitemnone)
		{
			lastlit = i + 1;
		}
		else if (table[i] != tableitemnone)
		{
			lastlit = i;
		}

		fprintf(out, "\t0x%04X,0x%04X", 0xFFFF & table[i], 0xFFFF & table[i + 1]);

		if (i == 24)
		{
			break;
		}

		fprintf(out, ",\t//%c %c\n", i + 'A', i + 1 + 'A');
		i++;
	}

	fputs("};\t//Y Z\n\nunsigned char asmMnem[]={\n", out);

	for (i = 0; i < 26; i++)
	{
		y = table[i];

		if (y != tableitemnone)
		{
			ii = outbuf + y;

			for (;; ii++)
			{
				k = *(TABLEITEMTYPE*)&*ii;

				if (k == tableitemnone)
				{
					fprintf(out, "\t0xFF,0xFF%s\t// end char \'%c\'\n", i == lastlit ? "" : ",", i + 'A');
					ii += 2;
					break;
				}

				fprintf(out, "\t0x%02X,0x%02X,", 0xFF & *ii, 0xFF & *(ii + 1));
				ii += 2;
				jj = ii;

				for (; *ii != 0; ii++)
				{
					fprintf(out, "0x%02X,", 0xFF & *ii);
				}

				fprintf(out, "0,\t// %c%s\n", i + 'A', jj);
			}
		}
	}

	fputs("};\n", out);
	free(outbuf);
	fclose(out);

	InitList(dirlist, 1);
	OpenFile("dirlist.h");
	fputs("short ofsdir[27]={\n", out);

	for (i = 0;; i++)
	{
		if (table[i + 1] != tableitemnone)
		{
			lastlit = i + 1;
		}
		else if (table[i] != tableitemnone)
		{
			lastlit = i;
		}

		fprintf(out, "\t0x%04X,0x%04X", 0xFFFF & table[i], 0xFFFF & table[i + 1]);

		if (i == 24)
		{
			break;
		}

		fprintf(out, ",\t//%c %c\n", i == 0 ? 'D' : i + 0x60, i + 'a');
		i++;
	}

	fprintf(out, ",\t//x y\n\t0x%04X};\t//z \n\nunsigned char dirlist[]={\n", table[26]);

	for (i = 0; i < 27; i++)
	{
		y = table[i];

		if (y != tableitemnone)
		{
			ii = outbuf + y;

			for (;; ii++)
			{
				k = *(TABLEITEMTYPE*)&*ii;

				if (k == tableitemnone)
				{
					fprintf(out, "\t0xFF,0xFF%s\t// end char \'%c\'\n", i == lastlit ? "" : ",", i == 0 ? 'D' : i + 0x60);
					ii += 2;
					break;
				}

				fprintf(out, "\t0x%02X,0x%02X,", 0xFF & *ii, 0xFF & *(ii + 1));
				ii += 2;
				jj = ii;

				for (; *ii != 0; ii++)
				{
					fprintf(out, "0x%02X,", 0xFF & *ii);
				}

				fprintf(out, "0,\t// %c%s\n", i == 0 ? 'D' : i + 0x60, jj);
			}
		}
	}

	fputs("};\n", out);
	free(outbuf);
	fclose(out);

	InitList(ID, 2);
	OpenFile("id.h");
	fputs("short idofs[53]={\n", out);

	for (i = 0;; i++)
	{
		if (table[i + 1] != tableitemnone)
		{
			lastlit = i + 1;
		}
		else if (table[i] != tableitemnone)
		{
			lastlit = i;
		}

		fprintf(out, "\t0x%04X,0x%04X", 0xFFFF & table[i], 0xFFFF & table[i + 1]);

		if (i == 50)
		{
			break;
		}

		fprintf(out, ",\t//%c %c\n", i >= 26 ? (i == 26 ? '_' : i + 'a' - 27) : i + 'A',
				i >= 26 ? i + 'a' - 26 : i + 'B');
		i++;
	}

	fprintf(out, ",\t//x y\n\t0x%04X};\t//z \n\nunsigned char id[]={\n", table[52]);

	for (i = 0; i < 53; i++)
	{
		y = table[i];

		if (y != tableitemnone)
		{
			ii = outbuf + y;

			for (;; ii++)
			{
				k = *(TABLEITEMTYPE*)&*ii;

				if (k == tableitemnone)
				{
					fprintf(out, "\t0xFF,0xFF%s\t// end char \'%c\'\n", i == lastlit ? "" : ",", i >= 26 ? (i == 26 ? '_' : i + 'a' - 27) : i + 'A');
					ii += 2;
					break;
				}

				fprintf(out, "\t0x%02X,0x%02X,", 0xFF & *ii, 0xFF & *(ii + 1));
				ii += 2;
				jj = ii;

				for (; *ii != 0; ii++)
				{
					fprintf(out, "0x%02X,", 0xFF & *ii);
				}

				fprintf(out, "0,\t// %c%s\n", i >= 26 ? (i == 26 ? '_' : i + 'a' - 27) : i + 'A', jj);
			}
		}
	}

	fputs("};\n", out);
	free(outbuf);
	fclose(out);

	InitList(res_name, 3);
	OpenFile("resname.h");
	fputs("short ofsres[26]={\n", out);

	for (i = 0;; i++)
	{
		if (table[i + 1] != tableitemnone)
		{
			lastlit = i + 1;
		}
		else if (table[i] != tableitemnone)
		{
			lastlit = i;
		}

		fprintf(out, "\t0x%04X,0x%04X", 0xFFFF & table[i], 0xFFFF & table[i + 1]);

		if (i == 24)
		{
			break;
		}

		fprintf(out, ",\t//%c %c\n", i + 'a', i + 1 + 'a');
		i++;
	}

	fputs("};\t//y z\n\nunsigned char resMnem[]={\n", out);

	for (i = 0; i < 26; i++)
	{
		y = table[i];

		if (y != tableitemnone)
		{
			ii = outbuf + y;

			for (;; ii++)
			{
				k = *(TABLEITEMTYPE*)&*ii;

				if (k == tableitemnone)
				{
					fprintf(out, "\t0xFF,0xFF%s\t// end char \'%c\'\n", i == lastlit ? "" : ",", i + 'a');
					ii += 2;
					break;
				}

				fprintf(out, "\t0x%02X,0x%02X,", 0xFF & *ii, 0xFF & *(ii + 1));
				ii += 2;
				jj = ii;

				for (; *ii != 0; ii++)
				{
					fprintf(out, "0x%02X,", 0xFF & *ii);
				}

				fprintf(out, "0,\t// %c%s\n", i + 'a', jj);
			}
		}
	}

	fputs("};\n", out);
	free(outbuf);
	fclose(out);

	return 0;
}

void InitList(const char** keylist, int type)
/*-----------------22.11.99 19:35-------------------
 type: 0 - 26 больших букв с возможностью пропуска - строка "-" 2-байтовый идентификатор
			 1 - 26 маленьких букв и 'D'
			 2 - 26 маленьких и больших букв и символ '_' 2-юайтовый идентификатор
	--------------------------------------------------*/
{
	OUTBUFITEMTYPE* i;
	size_t j;
	size_t num = 0;

	if ((outbuf = (OUTBUFITEMTYPE*)malloc(SORTSIZE * 1024)) == NULL)
	{
		puts("Not enough memory for the compiler's buffers.");
		exit(1);
	}

	for (j = 0; keylist[j] != NULL; j++)
	{
		i = outbuf + num * SORTSIZE;

		if (strcmp(keylist[j], "-") == 0)
		{
			continue;
		}

		*(TABLEITEMTYPE*)&*i = (type == 2 ? IDvalue[j] : j);
		i += 2;
		int k = 0;
		char firstchar = keylist[j][k];
		char c;

		do
		{
			c = keylist[j][k++];

			if (c == '/')
			{
				*i = 0;
				num++;
				i = outbuf + num * SORTSIZE;
				*(TABLEITEMTYPE*)&*i = (type == 2 ? IDvalue[j] : j);
				i += 2;
				c = firstchar;
			}

			*i++ = c;
		}
		while (c != 0);

		num++;
	}

	//сортировка
	for (j = 0; j < num; j++)
	{
		i = outbuf + j * SORTSIZE;

		for (size_t k = j + 1; k < num; k++)
		{
			OUTBUFITEMTYPE* ii = outbuf + k * SORTSIZE;

			if (strcmp((char*)&i[2], (char*)&ii[2]) > 0)
			{
				OUTBUFITEMTYPE buf[SORTSIZE];
				memcpy(buf, i, SORTSIZE);
				memcpy(i, ii, SORTSIZE);
				memcpy(ii, buf, SORTSIZE);
			}
		}
	}

	for (j = 0; j < sizeof(table) / sizeof(table[0]); j++)
	{
		table[j] = tableitemnone;
	}

	//конечная таблица
	i = outbuf;
	char cc = 0;

	for (j = 0; j < num; j++)
	{
		OUTBUFITEMTYPE* ii = outbuf + SORTSIZE * j;

		if (ii[2] != cc) 	//новая буква
		{
			if (cc != 0) 	//не начало таблицы
			{
				*(TABLEITEMTYPE*)&*i = tableitemnone;	//признак конца буквы
				i += 2;
			}

			cc = ii[2];

			switch (type)
			{
			case 0:
				table[cc - 'A'] = i - outbuf;
				break;

			case 1:
				if (cc == 'D')
				{
					table[0] = i - outbuf;
				}
				else
				{
					table[cc - 0x60] = i - outbuf;
				}

				break;

			case 2:
				if (cc == '_')
				{
					table[26] = i - outbuf;
				}
				else if (cc >= 'A' && cc <= 'Z')
				{
					table[cc - 'A'] = i - outbuf;
				}
				else
				{
					table[cc - 'a' + 27] = i - outbuf;
				}

				break;

			case 3:
				table[cc - 'a'] = i - outbuf;
				break;
			}
		}

		*(TABLEITEMTYPE*)&*i = *(TABLEITEMTYPE*)&*ii;
		i += 2;
		ii += 3;

		char c;

		do
		{
			c = *ii++;
			*i++ = c;
		}
		while (c != 0);
	}

	*(TABLEITEMTYPE*)&*i = tableitemnone;
}
