#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <commdlg.h>
#include <richedit.h>
#include <stdio.h>

#include "qcc.h"
#include "gui.h"

#define Edit_Redo(hwndCtl)                      ((BOOL)(DWORD)SNDMSG((hwndCtl), EM_REDO, 0L, 0L))


#define MAIN_WINDOW_CLASS_NAME "FTEMAINWINDOW"
#define EDIT_WINDOW_CLASS_NAME "FTEEDITWINDOW"
#define OPTIONS_WINDOW_CLASS_NAME "FTEOPTIONSWINDOW"

#define EM_GETSCROLLPOS  (WM_USER + 221)
#define EM_SETSCROLLPOS  (WM_USER + 222)

static pbool fl_hexen2;
static pbool fl_nokeywords_coexist;
static pbool fl_autohighlight;
static pbool fl_compileonstart;
static pbool fl_autoprototype;

char parameters[16384];

char progssrcname[256];
char progssrcdir[256];


int GUIprintf(const char *msg, ...);
void GUIPrint(HWND wnd, char *msg);
char *QCC_ReadFile (char *fname, void *buffer, int len);
int QCC_FileSize (char *fname);
pbool QCC_WriteFile (char *name, void *data, int len);

void RunCompiler(char *args);

HINSTANCE ghInstance;
HMODULE richedit;



HWND mainwindow;
HWND outputbox;

struct{
	char *text;
	HWND hwnd;
	int washit;
} buttons[] = {
	{"Compile"},
	{"Edit"},
	{"Options"},
	{"Quit"}
};

#define ID_COMPILE	0
#define ID_EDIT	1
#define ID_OPTIONS 2
#define ID_QUIT	3

#define NUMBUTTONS sizeof(buttons)/sizeof(buttons[0])



enum {
	IDM_OPENDOCU=32,
	IDM_OPENNEW,
	IDM_GOTODEF,
	IDM_SAVE,
	IDM_FIND,
	IDM_QUIT,
	IDM_UNDO,
	IDM_REDO,
	IDM_ABOUT,
	IDM_HIGHTLIGHT,

	IDI_O_LEVEL0,
	IDI_O_LEVEL1,
	IDI_O_LEVEL2,
	IDI_O_LEVEL3,
	IDI_O_DEFAULT,
	IDI_O_DEBUG,
	IDI_CHANGE_PROGS_SRC
};


typedef struct editor_s {
	char filename[MAX_PATH];	//abs
	HWND window;
	HWND editpane;
	struct editor_s *next;
} editor_t;

editor_t *editors;

int EditorSave(editor_t *edit);
void EditFile(char *name, int line);
pbool EditorModified(editor_t *e);
int Rehighlight(editor_t *edit);

void QueryOpenFile(void)
{
	char filename[MAX_PATH];
	char oldpath[MAX_PATH+10];
	OPENFILENAME ofn;
	memset(&ofn, 0, sizeof(ofn));
	ofn.lStructSize = sizeof(ofn);
	ofn.hInstance = ghInstance;
	ofn.lpstrFile = filename;
	ofn.nMaxFile = sizeof(filename)-1;
	memset(filename, 0, sizeof(filename));
	GetCurrentDirectory(sizeof(oldpath)-1, oldpath);
	if (GetOpenFileName(&ofn))
		EditFile(filename, -1);
	SetCurrentDirectory(oldpath);
}

static LONG CALLBACK EditorWndProc(HWND hWnd,UINT message,
				     WPARAM wParam,LPARAM lParam)
{
	RECT rect;
	HDC hdc;
	PAINTSTRUCT ps;

	editor_t *editor;
	for (editor = editors; editor; editor = editor->next)
	{
		if (editor->window == hWnd)
			break;
	}
	if (!editor)
		return DefWindowProc(hWnd,message,wParam,lParam);

	switch (message)
	{
	case WM_CLOSE:
	case WM_QUIT:
		if (EditorModified(editor))
		{
			switch (MessageBox(hWnd, "Would you like to save?", editor->filename, MB_YESNOCANCEL))
			{
			case IDCANCEL:
				return false;
			case IDYES:
				if (!EditorSave(editor))
					return false;
			case IDNO:
			default:
				break;
			}
		}
		DestroyWindow(editor->window);
		break;
	case WM_DESTROY:
		{
			editor_t *e;
			if (editor == editors)
			{
				editors = editor->next;
				free(editor);
				return 0;
			}
			for (e = editors; e; e = e->next)
			{
				if (e->next == editor)
				{
					e->next = editor->next;
					free(editor);
					return 0;
				}
			}
			MessageBox(0, "Couldn't destroy file reference", "WARNING", 0);
		}
		break;
	case WM_SIZE:
		GetClientRect(editor->window, &rect);
		SetWindowPos(editor->editpane, NULL, 0, 0, rect.right-rect.left, rect.bottom-rect.top, 0);
		break;
	case WM_PAINT:
		hdc=BeginPaint(hWnd,(LPPAINTSTRUCT)&ps);

		EndPaint(hWnd,(LPPAINTSTRUCT)&ps);
		return TRUE;
		break;
	case WM_COMMAND:
		switch(LOWORD(wParam))
		{
		case IDM_OPENNEW:
			QueryOpenFile();
			break;
		case IDM_OPENDOCU:
			{
				char buffer[1024];
				int total;
				total = SendMessage(editor->editpane, EM_GETSELTEXT, (WPARAM)sizeof(buffer)-1, (LPARAM)buffer);
				buffer[total]='\0';
				if (!total)
				{
					MessageBox(NULL, "There is no name currently selected.", "Whoops", 0);
					break;
				}
				else
					EditFile(buffer, -1);
			}
			break;
		case IDM_SAVE:
			EditorSave(editor);
			break;
		case IDM_GOTODEF:
			{
				char buffer[1024];
				int total;
				total = SendMessage(editor->editpane, EM_GETSELTEXT, (WPARAM)sizeof(buffer)-1, (LPARAM)buffer);
				buffer[total]='\0';
				if (!total)
				{
					MessageBox(NULL, "There is no name currently selected.", "Whoops", 0);
					break;
				}
				else
					GoToDefinition(buffer);
			}
			break;
		case IDM_ABOUT:
			MessageBox(NULL, "FTE QuakeC Compiler\nWritten by Forethough Entertainment.\nBasically that means it was written by Spike.\n\nIt has a few cool features, like a useful IDE.\n\nSupports:\nPrecompiler (with macros)\nArrays\n+= / -= / *= / /= operations.\nSwitch statements\nfor loops\nLots of optimisations.", "About", 0);
			break;
		case IDM_HIGHTLIGHT:
			Rehighlight(editor);
			break;

		case IDM_UNDO:
			Edit_Undo(editor->editpane);
			break;
		case IDM_REDO:
			Edit_Redo(editor->editpane);
			break;
		}
		return DefWindowProc(hWnd,message,wParam,lParam);
	case WM_NOTIFY:
		{
		    NMHDR *nmhdr;
			SELCHANGE *sel;
			char message[2048];
			nmhdr = (NMHDR *)lParam;
			switch(nmhdr->code)
			{
			case EN_SELCHANGE:
				sel = (SELCHANGE *)nmhdr;
				sprintf(message, "%s:%i - FTEQCC Editor", editor->filename, 1+Edit_LineFromChar(editor->editpane, sel->chrg.cpMin));
				SetWindowText(editor->window, message);
				break;
			}
		}
		return DefWindowProc(hWnd,message,wParam,lParam);
	default:
		return DefWindowProc(hWnd,message,wParam,lParam);
	}
	return 0;
}

static DWORD lastcolour;
int GUIEmitText(HWND wnd, int start, char *text, int len)
{
	int c, cr;
	DWORD colour;
	CHARFORMAT cf;

	if (!len)
		return start;

	c = text[len];
	text[len] = '\0';
	Edit_SetSel(wnd,start,start);
	Edit_ReplaceSel(wnd,text);

	if (!strcmp(text, "void"))
		colour = RGB(0, 0, 255);
	else if (!strcmp(text, "float"))
		colour = RGB(0, 0, 255);
	else if (!strcmp(text, "vector"))
		colour = RGB(0, 0, 255);
	else if (!strcmp(text, "entity"))
		colour = RGB(0, 0, 255);
	else if (!strcmp(text, "local"))
		colour = RGB(0, 0, 255);
	else if (!strcmp(text, "string"))
		colour = RGB(0, 0, 255);
	else if (!strcmp(text, "struct"))
		colour = RGB(0, 0, 255);
	else if (!strcmp(text, "class"))
		colour = RGB(0, 0, 255);
	else if (!strcmp(text, "union"))
		colour = RGB(0, 0, 255);
	else if (!strcmp(text, "const"))
		colour = RGB(0, 0, 255);
	else if (!strcmp(text, "var"))
		colour = RGB(0, 0, 255);
	else if (!strcmp(text, "nosave"))
		colour = RGB(0, 0, 255);

	else if (!strcmp(text, "goto"))
		colour = RGB(255, 0, 0);
	else if (!strcmp(text, "thinktime"))
		colour = RGB(0, 0, 255);
	else if (!strcmp(text, "if"))
		colour = RGB(0, 0, 255);
	else if (!strcmp(text, "else"))
		colour = RGB(0, 0, 255);
	else if (!strcmp(text, "switch"))
		colour = RGB(0, 0, 255);
	else if (!strcmp(text, "case"))
		colour = RGB(0, 0, 255);
	else if (!strcmp(text, "default"))
		colour = RGB(0, 0, 255);
	else if (!strcmp(text, "break"))
		colour = RGB(0, 0, 255);
	else if (!strcmp(text, "continue"))
		colour = RGB(0, 0, 255);
	else if (!strcmp(text, "do"))
		colour = RGB(0, 0, 255);
	else if (!strcmp(text, "while"))
		colour = RGB(0, 0, 255);
	else if (!strcmp(text, "for"))
		colour = RGB(0, 0, 255);
	else if (!strcmp(text, "return"))
		colour = RGB(0, 0, 255);

	else if (!strcmp(text, "self"))
		colour = RGB(0, 0, 127);
	else if (!strcmp(text, "this"))
		colour = RGB(0, 0, 127);
	else if (!strcmp(text, "other"))
		colour = RGB(0, 0, 127);
	else if (!strcmp(text, "world"))
		colour = RGB(0, 0, 127);
	else if (!strcmp(text, "time"))
		colour = RGB(0, 0, 127);


	else if (!strcmp(text, "#define"))
		colour = RGB(0, 128, 255);
	else if (!strcmp(text, "#ifdef"))
		colour = RGB(0, 128, 255);
	else if (!strcmp(text, "#ifndef"))
		colour = RGB(0, 128, 255);
	else if (!strcmp(text, "#else"))
		colour = RGB(0, 128, 255);
	else if (!strcmp(text, "#endif"))
		colour = RGB(0, 128, 255);
	else if (!strcmp(text, "#undef"))
		colour = RGB(0, 128, 255);
	else if (!strcmp(text, "#pragma"))
		colour = RGB(0, 128, 255);
	else if (!strcmp(text, "#includelist"))
		colour = RGB(0, 128, 255);
	else if (!strcmp(text, "#endlist"))
		colour = RGB(0, 128, 255);


	else if (*text == '\"')
		colour = RGB(128, 0, 0);

	else if (!strncmp(text, "//", 2))
		colour = RGB(0, 127, 0);
	else if (!strncmp(text, "/*", 2))
		colour = RGB(0, 127, 0);
	else
		colour = RGB(0, 0, 0);

	text[len] = c;

	cr = 0;
	for (c = 0; c < len; c++)
		if (text[c] == '\r')
			cr++;
	if (cr)
		len-=cr;

	if (colour == lastcolour)
		return start+len;

	lastcolour = colour;

	Edit_SetSel(wnd,start,start+len);
	memset(&cf, 0, sizeof(cf));
	cf.cbSize = sizeof(cf);
	cf.dwMask = CFM_COLOR;
	cf.crTextColor = colour;
	SendMessage(wnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
	Edit_SetSel(wnd,start+len,start+len);

	return start + len;
}
void GUIFormattingPrint(HWND wnd, char *msg)
{
	int len=Edit_GetTextLength(wnd);
	char *start;
	CHARRANGE chrg;
	lastcolour = RGB(0,0,0);
	SendMessage(wnd, WM_SETREDRAW, false, 0);
	chrg.cpMin = chrg.cpMax = 0;
	SendMessage(wnd, EM_EXSETSEL, 0, (LPARAM) &chrg);
	for(start = msg;;)
	{
		if (!*msg)
			break;
		else if (*msg == '/' && msg[1] == '/')
		{
			len = GUIEmitText(wnd, len, start, msg - start);
			start = msg;

			msg+=2;
			while(*msg && *msg != '\n' && *msg != '\r')
				msg++;
		}
		else if (*msg == '/' && msg[1] == '*')
		{
			len = GUIEmitText(wnd, len, start, msg - start);
			start = msg;
			msg+=2;
			while(*msg)
			{
				if (msg[0] == '*' && msg[1] == '/')
				{
					msg+=2;
					break;
				}
				msg++;
			}
		}
		else if (*msg == '#' || *msg == '_' || (*msg >= 'A' && *msg <= 'Z') || (*msg >= 'a' && *msg <= 'z'))
		{
			len = GUIEmitText(wnd, len, start, msg - start);
			start = msg;
			msg++;
			while (*msg == '_' || (*msg >= 'A' && *msg <= 'Z') || (*msg >= 'a' && *msg <= 'z' || *msg >= '0' && *msg <= '9'))
				msg++;
		}
		else if (*msg == '\"')
		{
			len = GUIEmitText(wnd, len, start, msg - start);
			start = msg;
			msg++;
			while(*msg)
			{
				if (*msg == '\\')
					msg++;
				else if (*msg == '\"')
				{
					msg++;
					break;
				}

				msg++;
			}
		}
/*		else if (*msg <= ' ')
		{
			while (*msg <= ' ' && *msg)
				msg++;
		}*/
		else
		{
			msg++;
			continue;
		}

		len = GUIEmitText(wnd, len, start, msg - start);
		start = msg;
	}
	len = GUIEmitText(wnd, len, start, msg - start);
	start = msg;
	SendMessage(wnd, WM_SETREDRAW, true, 0);
}

int Rehighlight(editor_t *edit)
{
	int len;
	char *file;

	CHARRANGE chrg;
	POINT scrollpos;

	SendMessage(edit->editpane, EM_SETEVENTMASK, 0, 0);

	SendMessage(edit->editpane, EM_GETSCROLLPOS, 0, (LPARAM)&scrollpos);
	SendMessage(edit->editpane, EM_EXGETSEL, 0, (LPARAM) &chrg);

	len = Edit_GetTextLength(edit->editpane);
	file = malloc(len+1);
	if (!file)
	{
		MessageBox(NULL, "Save failed - not enough mem", "Error", 0);
		return false;
	}
	Edit_GetText(edit->editpane, file, len);
	file[len] = '\0';

	SetWindowText(edit->editpane,"");

//	GUIPrint(edit->editpane, file);
	GUIFormattingPrint(edit->editpane, file);
	free(file);

//	Edit_SetSel(edit->editpane, Edit_LineIndex(neweditor->editpane, 0), Edit_LineIndex(neweditor->editpane, 0));

	SendMessage(edit->editpane, EM_SETEVENTMASK, 0, ENM_SELCHANGE);

	SendMessage(edit->editpane, EM_SETSCROLLPOS, 0, (LPARAM)&scrollpos);
	SendMessage(edit->editpane, EM_EXSETSEL, 0, (LPARAM) &chrg);

	InvalidateRect(edit->editpane, NULL, true);
	UpdateWindow(edit->editpane);

	return true;
}

void EditFile(char *name, int line)
{
	char title[1024];
	int flen;
	char *file;
	editor_t *neweditor;
	WNDCLASS wndclass;
	HMENU menu, menufile, menuhelp, menunavig;

	for (neweditor = editors; neweditor; neweditor = neweditor->next)
	{
		if (neweditor->window && !strcmp(neweditor->filename, name))
		{
			if (line >= 0)
			{
				Edit_SetSel(neweditor->editpane, Edit_LineIndex(neweditor->editpane, line), Edit_LineIndex(neweditor->editpane, line+1));
				Edit_ScrollCaret(neweditor->editpane);
			}
			SetFocus(neweditor->window);
			SetFocus(neweditor->editpane);
			return;
		}
	}

	flen = QCC_FileSize(name);
	if (flen == -1)
	{
		MessageBox(NULL, "File not found.", "Error", 0);
		return;
	}

	neweditor = malloc(sizeof(editor_t));
	if (!neweditor)
	{
		MessageBox(NULL, "Low memory", "Error", 0);
		return;
	}

	neweditor->next = editors;
	editors = neweditor;

	strncpy(neweditor->filename, name, sizeof(neweditor->filename)-1);

	menu = CreateMenu();
	menufile = CreateMenu();
	menuhelp = CreateMenu();
	menunavig = CreateMenu();
	AppendMenu(menu, MF_POPUP, (UINT)menufile,	"&File");
	AppendMenu(menu, MF_POPUP, (UINT)menunavig,	"&Navigation");
	AppendMenu(menu, MF_POPUP, (UINT)menuhelp,	"&Help");
	AppendMenu(menufile, 0, IDM_OPENNEW,	"Open &new file ");
	AppendMenu(menufile, 0, IDM_SAVE,		"&Save          ");
//	AppendMenu(menufile, 0, IDM_FIND,		"&Find");
	AppendMenu(menufile, 0, IDM_UNDO,		"&Undo          Ctrl+Z");
	AppendMenu(menufile, 0, IDM_REDO,		"&Redo          Ctrl+Y");
	AppendMenu(menunavig, 0, IDM_GOTODEF, "Go to definition");
	AppendMenu(menunavig, 0, IDM_OPENDOCU, "Open selected file");
	AppendMenu(menuhelp, 0, IDM_ABOUT, "About");
	AppendMenu(menu, 0, IDM_HIGHTLIGHT, "H&ighlight");



	
	wndclass.style      = 0;
    wndclass.lpfnWndProc   = (WNDPROC)EditorWndProc;
    wndclass.cbClsExtra    = 0;
    wndclass.cbWndExtra    = 0;
    wndclass.hInstance     = ghInstance;
    wndclass.hIcon         = 0;
    wndclass.hCursor       = LoadCursor (NULL,IDC_ARROW);
	wndclass.hbrBackground = (void *)COLOR_WINDOW;
    wndclass.lpszMenuName  = 0;
    wndclass.lpszClassName = EDIT_WINDOW_CLASS_NAME;
	RegisterClass(&wndclass);

	sprintf(title, "%s - FTEEditor", name);
	neweditor->window=CreateWindow(EDIT_WINDOW_CLASS_NAME, title, WS_OVERLAPPEDWINDOW,
		0, 0, 640, 480, NULL, NULL, ghInstance, NULL);

	SetMenu(neweditor->window, menu);

	if (!neweditor->window)
	{
		MessageBox(NULL, "Failed to create editor window", "Error", 0);
		return;
	}

	richedit = LoadLibrary("RICHED32.DLL");
	neweditor->editpane=CreateWindowEx(WS_EX_CLIENTEDGE,
		richedit?RICHEDIT_CLASS:"EDIT",
		"",
		WS_CHILD /*| ES_READONLY*/ | WS_VISIBLE | 
		WS_HSCROLL | WS_VSCROLL | ES_LEFT | ES_WANTRETURN |
		ES_MULTILINE | ES_AUTOVSCROLL,
		0, 0, 0, 0,
		neweditor->window,
		NULL,
		ghInstance,
		NULL);

	if (richedit)
	{
		SendMessage(neweditor->editpane, EM_EXLIMITTEXT, 0, 1<<20);

		SendMessage(neweditor->editpane, EM_SETUNDOLIMIT, 256, 256);
	}

	flen = QCC_FileSize(name);
	file = malloc(flen+1);
	QCC_ReadFile(name, file, flen);
	file[flen] = 0;

	SendMessage(neweditor->editpane, EM_SETEVENTMASK, 0, 0);

	if (!fl_autohighlight)
	{
		GUIPrint(neweditor->editpane, file);
	}
	else
	{
		GUIFormattingPrint(neweditor->editpane, file);
	}

	SendMessage(neweditor->editpane, EM_SETEVENTMASK, 0, ENM_SELCHANGE);

	if (line >= 0)
		Edit_SetSel(neweditor->editpane, Edit_LineIndex(neweditor->editpane, line), Edit_LineIndex(neweditor->editpane, line+1));
	else
		Edit_SetSel(neweditor->editpane, Edit_LineIndex(neweditor->editpane, 0), Edit_LineIndex(neweditor->editpane, 0));

	Edit_ScrollCaret(neweditor->editpane);

	ShowWindow(neweditor->window, SW_SHOWDEFAULT);
	SetFocus(neweditor->window);
	SetFocus(neweditor->editpane);
}

int EditorSave(editor_t *edit)
{
	int len;
	char *file;
	len = Edit_GetTextLength(edit->editpane);
	file = malloc(len+1);
	if (!file)
	{
		MessageBox(NULL, "Save failed - not enough mem", "Error", 0);
		return false;
	}
	Edit_GetText(edit->editpane, file, len);
	if (!QCC_WriteFile(edit->filename, file, len))
	{
		MessageBox(NULL, "Save failed\nCheck path and ReadOnly flags", "Failure", 0);
		return false;
	}
	free(file);

	return true;
}
void EditorsRun(void)
{
}


char *GUIReadFile(char *fname, void *buffer, int blen)
{
	editor_t *e;
	for (e = editors; e; e = e->next)
	{
		if (e->window && !strcmp(e->filename, fname))
		{
			int elen = Edit_GetTextLength(e->editpane);
			Edit_GetText(e->editpane, buffer, blen);
			return buffer;
		}
	}

	return QCC_ReadFile(fname, buffer, blen);
}

int GUIFileSize(char *fname)
{
	editor_t *e;
	for (e = editors; e; e = e->next)
	{
		if (e->window && !strcmp(e->filename, fname))
		{
			int len = Edit_GetTextLength(e->editpane);
			return len;
		}
	}
	return QCC_FileSize(fname);
}

pbool EditorModified(editor_t *e)
{
	char *buffer;
	int elen, flen;
	elen = Edit_GetTextLength(e->editpane);
	flen = QCC_FileSize(e->filename);

	if (elen != flen)
		return true;

	buffer = malloc(elen+flen);
	Edit_GetText(e->editpane, buffer, elen);
	QCC_ReadFile(e->filename, buffer+elen, flen);
	if (memcmp(buffer, buffer+elen, elen))
	{
		free(buffer);
		return true;
	}
	free(buffer);

	return false;
}













HWND optionsmenu;
HWND hexen2item;
HWND nokeywords_coexistitem;
HWND autoprototype_item;
HWND autohighlight_item;
HWND extraparmsitem;
static LONG CALLBACK OptionsWndProc(HWND hWnd,UINT message,
				     WPARAM wParam,LPARAM lParam)
{
	int i;
	switch (message)
	{
	case WM_DESTROY:
		optionsmenu = NULL;
		break;

	case WM_COMMAND:
		switch(wParam)
		{
		case IDRETRY:
		case IDOK:
			for (i = 0; optimisations[i].enabled; i++)
			{
				if (Button_GetCheck(optimisations[i].guiinfo))
					optimisations[i].flags |= 8;
				else
					optimisations[i].flags &= ~8;
			}
			fl_hexen2 = Button_GetCheck(hexen2item);
			fl_nokeywords_coexist = Button_GetCheck(nokeywords_coexistitem);
			fl_autohighlight = Button_GetCheck(autohighlight_item);
			fl_autoprototype = Button_GetCheck(autoprototype_item);
			Edit_GetText(extraparmsitem, parameters, sizeof(parameters)-1);

			if (wParam == IDRETRY)
				buttons[ID_COMPILE].washit = true;
			break;
		case IDI_CHANGE_PROGS_SRC:
			{
				char *s, *s2;
				char filename[MAX_PATH];
				char oldpath[MAX_PATH+10];
				OPENFILENAME ofn;
				memset(&ofn, 0, sizeof(ofn));
				ofn.lStructSize = sizeof(ofn);
				ofn.hInstance = ghInstance;
				ofn.lpstrFile = filename;
				ofn.lpstrTitle = "Please find progs.src";
				ofn.nMaxFile = sizeof(filename)-1;
				ofn.lpstrFilter = "QuakeC source\0*.src\0All files\0*.*\0";
				memset(filename, 0, sizeof(filename));
				GetCurrentDirectory(sizeof(oldpath)-1, oldpath);
				ofn.lpstrInitialDir = oldpath;
				if (GetOpenFileName(&ofn))
				{
					strcpy(progssrcdir, filename);
					for(s = progssrcdir; s; s = s2)
					{
						s2 = strchr(s+1, '\\');
						if (!s2)
							break;
						s = s2;
					}
					if (s)
					{
						*s = '\0';
						strcpy(progssrcname, s+1);
					}
					else
						strcpy(progssrcname, filename);

					SetCurrentDirectory(progssrcdir);
					*progssrcdir = '\0';
				}
			}
			break;
		case IDI_O_LEVEL0:
		case IDI_O_LEVEL1:
		case IDI_O_LEVEL2:
		case IDI_O_LEVEL3:
			for (i = 0; optimisations[i].enabled; i++)
			{
				if (optimisations[i].optimisationlevel<=(int)wParam-IDI_O_LEVEL0)
					Button_SetCheck(optimisations[i].guiinfo, 1);
				else
					Button_SetCheck(optimisations[i].guiinfo, 0);
			}
			break;
		case IDI_O_DEBUG:
			for (i = 0; optimisations[i].enabled; i++)
			{
				if (optimisations[i].flags&1)
					Button_SetCheck(optimisations[i].guiinfo, 0);
			}
			break;
		case IDI_O_DEFAULT:
			for (i = 0; optimisations[i].enabled; i++)
			{
				if (optimisations[i].flags & 2)
					Button_SetCheck(optimisations[i].guiinfo, 1);
				else
					Button_SetCheck(optimisations[i].guiinfo, 0);
			}
			break;
		}
		break;

	default:
		return DefWindowProc(hWnd,message,wParam,lParam);
	}
	return 0;
}
void OptionsDialog(void)
{
	HWND subsection;
	RECT r;
	WNDCLASS wndclass;
	HWND wnd;
	int i;

	int y;
	int height;

	if (optionsmenu)
	{
		BringWindowToTop(optionsmenu);
		return;
	}


	memset(&wndclass, 0, sizeof(wndclass));
	wndclass.style      = 0;
    wndclass.lpfnWndProc   = (WNDPROC)OptionsWndProc;
    wndclass.cbClsExtra    = 0;
    wndclass.cbWndExtra    = 0;
    wndclass.hInstance     = ghInstance;
    wndclass.hIcon         = 0;
    wndclass.hCursor       = LoadCursor (NULL,IDC_ARROW);
	wndclass.hbrBackground = (void *)COLOR_WINDOW;
    wndclass.lpszMenuName  = 0;
    wndclass.lpszClassName = OPTIONS_WINDOW_CLASS_NAME;
	RegisterClass(&wndclass);

	height = 0;
	for (i = 0; optimisations[i].enabled; i++)
		height++;

	height = ((height-1)/2)*16;

	height += 88+40;

	r.left = GetSystemMetrics(SM_CXSCREEN)/2-320;
	r.top = GetSystemMetrics(SM_CYSCREEN)/2-240;
	r.right  = r.left + 640;
	r.bottom = r.top + height;

	AdjustWindowRectEx (&r, WS_CAPTION|WS_SYSMENU, FALSE, 0);

	optionsmenu=CreateWindow(OPTIONS_WINDOW_CLASS_NAME, "Options - FTE QuakeC compiler", WS_CAPTION|WS_SYSMENU,
		r.left, r.top, r.right-r.left, r.bottom-r.top, NULL, NULL, ghInstance, NULL);

	subsection = CreateWindow("BUTTON", "Optimisations", WS_CHILD|WS_VISIBLE|BS_GROUPBOX,
		0, 0, 400, height-48, optionsmenu, NULL, ghInstance, NULL);

	for (i = 0; optimisations[i].enabled; i++)
	{
		optimisations[i].guiinfo = wnd = CreateWindow("BUTTON",optimisations[i].fullname,
			   WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
			   8+200*(i&1),16+16*(i/2),200-16,16,
			   subsection,
			   (HMENU)i,
			   ghInstance,
			   NULL);

		if (optimisations[i].flags&8)
			Button_SetCheck(wnd, 1);
		else
			Button_SetCheck(wnd, 0);
	}

	CreateWindow("BUTTON","O0",
		   WS_CHILD | WS_VISIBLE,
		   8,height-88,64,32,
		   optionsmenu,
		   (HMENU)IDI_O_LEVEL0,
		   ghInstance,
		   NULL);
	CreateWindow("BUTTON","O1",
		   WS_CHILD | WS_VISIBLE,
		   8+64,height-88,64,32,
		   optionsmenu,
		   (HMENU)IDI_O_LEVEL1,
		   ghInstance,
		   NULL);
	CreateWindow("BUTTON","O2",
		   WS_CHILD | WS_VISIBLE,
		   8+64*2,height-88,64,32,
		   optionsmenu,
		   (HMENU)IDI_O_LEVEL2,
		   ghInstance,
		   NULL);
	CreateWindow("BUTTON","O3",
		   WS_CHILD | WS_VISIBLE,
		   8+64*3,height-88,64,32,
		   optionsmenu,
		   (HMENU)IDI_O_LEVEL3,
		   ghInstance,
		   NULL);
	CreateWindow("BUTTON","Debug",
		   WS_CHILD | WS_VISIBLE,
		   8+64*4,height-88,64,32,
		   optionsmenu,
		   (HMENU)IDI_O_DEBUG,
		   ghInstance,
		   NULL);
	CreateWindow("BUTTON","Default",
		   WS_CHILD | WS_VISIBLE,
		   8+64*5,height-88,64,32,
		   optionsmenu,
		   (HMENU)IDI_O_DEFAULT,
		   ghInstance,
		   NULL);
	CreateWindow("BUTTON","Apply",
		   WS_CHILD | WS_VISIBLE,
		   8,height-40,64,32,
		   optionsmenu,
		   (HMENU)IDOK,
		   ghInstance,
		   NULL);
	CreateWindow("BUTTON","Use",
		   WS_CHILD | WS_VISIBLE,
		   8+64,height-40,64,32,
		   optionsmenu,
		   (HMENU)IDRETRY,
		   ghInstance,
		   NULL);
	CreateWindow("BUTTON","progs.src",
		   WS_CHILD | WS_VISIBLE,
		   8+64*2,height-40,64,32,
		   optionsmenu,
		   (HMENU)IDI_CHANGE_PROGS_SRC,
		   ghInstance,
		   NULL);



		y=4;
	hexen2item = wnd = CreateWindow("BUTTON","HexenC",
		   WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
		   408,y,200-16,16,
		   optionsmenu,
		   (HMENU)i,
		   ghInstance,
		   NULL);
	y+=16;
	if (fl_hexen2)
		Button_SetCheck(wnd, 1);
	else
		Button_SetCheck(wnd, 0);

	nokeywords_coexistitem = wnd = CreateWindow("BUTTON","Disable Keywords",
		   WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
		   408,y,200-16,16,
		   optionsmenu,
		   (HMENU)i,
		   ghInstance,
		   NULL);
	y+=16;
	if (fl_nokeywords_coexist)
		Button_SetCheck(wnd, 1);
	else
		Button_SetCheck(wnd, 0);

	autohighlight_item = wnd = CreateWindow("BUTTON","Syntax Highlighting",
		   WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
		   408,y,200-16,16,
		   optionsmenu,
		   (HMENU)i,
		   ghInstance,
		   NULL);
	y+=16;
	if (fl_autohighlight)
		Button_SetCheck(wnd, 1);
	else
		Button_SetCheck(wnd, 0);

	autoprototype_item = wnd = CreateWindow("BUTTON","Automate prototypes",
		   WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
		   408,y,200-16,16,
		   optionsmenu,
		   (HMENU)i,
		   ghInstance,
		   NULL);
	y+=16;
	if (fl_autoprototype)
		Button_SetCheck(wnd, 1);
	else
		Button_SetCheck(wnd, 0);

	CreateWindow("STATIC","Extra Parameters:",
		   WS_CHILD | WS_VISIBLE,
		   408,y,200-16,16,
		   optionsmenu,
		   (HMENU)IDOK,
		   ghInstance,
		   NULL);
	y+=16;
	extraparmsitem = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT",parameters,
		   WS_CHILD | WS_VISIBLE|ES_LEFT | ES_WANTRETURN |
		ES_MULTILINE | ES_AUTOVSCROLL,
		   408,y,240-16+16-12,height-y-4,
		   optionsmenu,
		   (HMENU)IDI_O_DEFAULT,
		   ghInstance,
		   NULL);

	ShowWindow(optionsmenu, SW_SHOWDEFAULT);
}











#undef printf



static LONG CALLBACK MainWndProc(HWND hWnd,UINT message,
				     WPARAM wParam,LPARAM lParam)
{
	int width;
	int i;
	RECT rect;
	HDC hdc;
	PAINTSTRUCT ps;
	switch (message)
	{
	case WM_DESTROY:
		mainwindow = NULL;
		break;

	case WM_SIZE:
		GetClientRect(mainwindow, &rect);
		SetWindowPos(outputbox, NULL, 0, 0, rect.right-rect.left, rect.bottom-rect.top - 32, 0);
		width = (rect.right-rect.left);
		width/=NUMBUTTONS;
		for (i = 0; i < NUMBUTTONS; i++)
		{
			SetWindowPos(buttons[i].hwnd, NULL, width*i, rect.bottom-rect.top - 32, width, 32, 0);
		}
		break;
	case WM_PAINT:
		hdc=BeginPaint(hWnd,(LPPAINTSTRUCT)&ps);

		EndPaint(hWnd,(LPPAINTSTRUCT)&ps);
		return TRUE;
		break;
	case WM_COMMAND:
		if (LOWORD(wParam))
			buttons[LOWORD(wParam)-1].washit = 1;
		break;
	default:
		return DefWindowProc(hWnd,message,wParam,lParam);
	}
	return 0;
}

void GUIPrint(HWND wnd, char *msg)
{
	MSG        wmsg;
	int len;
	static int writing;

	if (writing)
		return;
	if (!mainwindow)
	{
		printf("%s", msg);
		return;
	}
	writing=true;
	len=Edit_GetTextLength(wnd);
/*	if ((unsigned)len>(32767-strlen(msg)))
		Edit_SetSel(wnd,0,len);
	else*/
		Edit_SetSel(wnd,len,len);
	Edit_ReplaceSel(wnd,msg);

	while (PeekMessage (&wmsg, NULL, 0, 0, PM_NOREMOVE))
	{
		if (!GetMessage (&wmsg, NULL, 0, 0))
			break;
		TranslateMessage (&wmsg);
		DispatchMessage (&wmsg);
	}
	writing=false;
}
int GUIEmitOutputText(HWND wnd, int start, char *text, int len, DWORD colour)
{
	int c, cr;
	CHARFORMAT cf;

	if (!len)
		return start;

	c = text[len];
	text[len] = '\0';
	Edit_SetSel(wnd,start,start);
	Edit_ReplaceSel(wnd,text);

	text[len] = c;

	cr = 0;
	for (c = 0; c < len; c++)
		if (text[c] == '\r')
			cr++;
	if (cr)
		len-=cr;

	Edit_SetSel(wnd,start,start+len);
	memset(&cf, 0, sizeof(cf));
	cf.cbSize = sizeof(cf);
	cf.dwMask = CFM_COLOR;
	cf.crTextColor = colour;
	SendMessage(wnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
	Edit_SetSel(wnd,start+len,start+len);

	return start + len;
}
int outlen;
int GUIprintf(const char *msg, ...)
{
	va_list		argptr;
	char		buf[1024];
	char rn[3] = "\n";
	char *st, *s;
	int args;
	MSG        wmsg;

	DWORD col;

	va_start (argptr,msg);
	args = QC_vsnprintf (buf,sizeof(buf)-1, msg,argptr);
	va_end (argptr);

	if (!*buf)
	{
		SetWindowText(outputbox,"");
		outlen = 0;
		return 0;
	}

	if (strstr(buf, "warning: "))
		col = RGB(128, 128, 0);
	else if (strstr(buf, "error: "))
		col = RGB(255, 0, 0);
	else
		col = RGB(0, 0, 0);

	s = st = buf;
	while(*s)
	{
		if (*s == '\n')
		{
			*s = '\0';
			if (*st)
				outlen = GUIEmitOutputText(outputbox, outlen, st, strlen(st), col);
			outlen = GUIEmitOutputText(outputbox, outlen, rn, 1, col);
			st = s+1;
		}

		s++;
	}
	if (*st)
		outlen = GUIEmitOutputText(outputbox, outlen, st, strlen(st), col);

	while (PeekMessage (&wmsg, NULL, 0, 0, PM_NOREMOVE))
	{
		if (!GetMessage (&wmsg, NULL, 0, 0))
			break;
		TranslateMessage (&wmsg);
		DispatchMessage (&wmsg);
	}
/*
	s = st = buf;
	while(*s)
	{
		if (*s == '\n')
		{
			*s = '\0';
			if (*st)
				GUIPrint(outputbox, st);
			GUIPrint(outputbox, "\r\n");
			st = s+1;
		}

		s++;
	}
	if (*st)
		GUIPrint(outputbox, st);
*/
	return args;
}

#undef Sys_Error
void Sys_Error(const char *text, ...);
void RunCompiler(char *args)
{
	int i;
	char *argv[64];
	char param[2048];
	char *next;
	int paramlen = 0;
	int argc;
	progexterns_t ext;
	progfuncs_t funcs;
	memset(&funcs, 0, sizeof(funcs));
	funcs.parms = &ext;
	memset(&ext, 0, sizeof(ext));
	funcs.parms->ReadFile = GUIReadFile;
	funcs.parms->FileSize = GUIFileSize;
	funcs.parms->WriteFile = QCC_WriteFile;
	funcs.parms->printf = GUIprintf;
	funcs.parms->Sys_Error = Sys_Error;
	GUIprintf("");
	

	argc = 1;
	argv[0] = "fteqcc";

	while(*args)
	{
		while (*args <= ' '&& *args)
			args++;

		for (next = args; *next>' '; next++)
			;
		strncpy(param+paramlen, args, next-args);
		param[paramlen+next-args] = '\0';
		argv[argc++] = param+paramlen;
		paramlen += strlen(param+paramlen)+1;

		args=next;
	}

	if (fl_hexen2)
	{
		strcpy(param+paramlen, "-Th2");
		argv[argc++] = param+paramlen;
		paramlen += strlen(param+paramlen)+1;
	}
	if (fl_nokeywords_coexist)
	{
		strcpy(param+paramlen, "-Fno-kce");
		argv[argc++] = param+paramlen;
		paramlen += strlen(param+paramlen)+1;
	}
	if (fl_autoprototype)
	{
		strcpy(param+paramlen, "-Fautoproto");
		argv[argc++] = param+paramlen;
		paramlen += strlen(param+paramlen)+1;
	}


	for (i = 0; optimisations[i].enabled; i++)	//enabled is a pointer
	{
		if (optimisations[i].flags & 8)
			sprintf(param+paramlen, "-O%s", optimisations[i].abbrev);
		else
			sprintf(param+paramlen, "-Ono-%s", optimisations[i].abbrev);
		argv[argc++] = param+paramlen;
		paramlen += strlen(param+paramlen)+1;
	}


/*	while(*args)
	{
		while (*args <= ' '&& *args)
			args++;

		for (next = args; *next>' '; next++)
			;
		strncpy(param+paramlen, args, next-args);
		param[paramlen+next-args] = '\0';
		argv[argc++] = param+paramlen;
		paramlen += strlen(param+paramlen)+1;
		args=next;
	}*/

	if (*progssrcname)
	{
		argv[argc++] = "-srcfile";
		argv[argc++] = progssrcname;
	}
	if (*progssrcdir)
	{
		argv[argc++] = "-src";
		argv[argc++] = progssrcdir;
	}

	CompileParams(&funcs, true, argc, argv);
}


//this function takes the windows specified commandline and strips out all the options menu items.
void GuiParseCommandLine(char *args)
{
	int paramlen=0;
	int l, p;
	char *next;
	while(*args)
	{
		while (*args <= ' ' && *args)
			args++;

		for (next = args; *next>' '; next++)
			;

		strncpy(parameters+paramlen, args, next-args);
		parameters[paramlen+next-args] = '\0';
		l = strlen(parameters+paramlen)+1;

		if (!strnicmp(parameters+paramlen, "-O", 2) || !strnicmp(parameters+paramlen, "/O", 2))
		{	//strip out all -O
			if (parameters[paramlen+2] >= '0' && parameters[paramlen+2] <= '3')
			{
				p = parameters[paramlen+2]-'0';
				for (l = 0; optimisations[l].enabled; l++)
				{
					if (optimisations[l].optimisationlevel<=p)
						optimisations[l].flags |= 8;
					else
						optimisations[l].flags &= ~8;
				}
				p=0;
			}
			else if (!strncmp(parameters+paramlen+2, "no-", 3))
			{
				if (parameters[paramlen+5])
					for (p = 0; optimisations[p].enabled; p++)
						if ((*optimisations[p].abbrev && !strcmp(parameters+paramlen+5, optimisations[p].abbrev)) || !strcmp(parameters+paramlen+5, optimisations[p].fullname))
						{
							optimisations[p].flags &= ~8;
							break;
						}
			}
			else
			{
				if (parameters[paramlen+2])
					for (p = 0; optimisations[p].enabled; p++)
						if ((*optimisations[p].abbrev && !strcmp(parameters+paramlen+2, optimisations[p].abbrev)) || !strcmp(parameters+paramlen+2, optimisations[p].fullname))
						{
							optimisations[p].flags |= 8;
							break;
						}
			}

			if (!optimisations[p].enabled)
			{
				parameters[paramlen+next-args] = ' ';
				paramlen += l;
			}
		}
		else if (!strnicmp(parameters+paramlen, "-Fno-kce", 8) || !strnicmp(parameters+paramlen, "/Fno-kce", 8))	//keywords stuph
		{
			fl_nokeywords_coexist = true;
		}
		else if (!strnicmp(parameters+paramlen, "-Fkce", 5) || !strnicmp(parameters+paramlen, "/Fkce", 5))
		{
			fl_nokeywords_coexist = false;
		}
		else if (!strnicmp(parameters+paramlen, "-sh", 3) || !strnicmp(parameters+paramlen, "/sh", 3))
		{
			fl_autohighlight = true;
		}
		else if (!strnicmp(parameters+paramlen, "-autoproto", 10) || !strnicmp(parameters+paramlen, "/autoproto", 10))
		{
			fl_autoprototype = true;
		}
		else if (!strnicmp(parameters+paramlen, "-ac", 3) || !strnicmp(parameters+paramlen, "/ac", 3))
		{
			fl_compileonstart = true;
		}
		else if (!strnicmp(parameters+paramlen, "-T", 2) || !strnicmp(parameters+paramlen, "/T", 2))	//the target
		{
			if (!strnicmp(parameters+paramlen+2, "h2", 2))
			{
				fl_hexen2 = true;
			}
			else
			{
				fl_hexen2 = false;
				parameters[paramlen+next-args] = ' ';
				paramlen += l;
			}
		}
		else
		{
			parameters[paramlen+next-args] = ' ';
			paramlen += l;
		}

		args=next;
	}
	if (paramlen)
		parameters[paramlen-1] = '\0';
	else
		*parameters = '\0';
}

void SetDefaultOpts(void)
{
	int i;
	for (i = 0; optimisations[i].enabled; i++)	//enabled is a pointer
	{
		if (optimisations[i].flags & 2)
			optimisations[i].flags |= 8;
		else
			optimisations[i].flags &= ~8;
	}
}

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	unsigned int i;
	WNDCLASS wndclass;
	ghInstance= hInstance;

	SetDefaultOpts();

	if(strstr(lpCmdLine, "-stdout"))
	{
		RunCompiler(lpCmdLine);
		return 0;
	}

	GuiParseCommandLine(lpCmdLine);

	if (!*progssrcname)
	{
		strcpy(progssrcname, "preprogs.src");
		if (QCC_FileSize(progssrcname)==-1)
			strcpy(progssrcname, "progs.src");
		if (QCC_FileSize(progssrcname)==-1)
		{
			char *s, *s2;
			char filename[MAX_PATH];
			char oldpath[MAX_PATH+10];
			OPENFILENAME ofn;
			memset(&ofn, 0, sizeof(ofn));
			ofn.lStructSize = sizeof(ofn);
			ofn.hInstance = ghInstance;
			ofn.lpstrFile = filename;
			ofn.lpstrTitle = "Please find progs.src";
			ofn.nMaxFile = sizeof(filename)-1;
			ofn.lpstrFilter = "QuakeC source\0*.src\0All files\0*.*\0";
			memset(filename, 0, sizeof(filename));
			GetCurrentDirectory(sizeof(oldpath)-1, oldpath);
			ofn.lpstrInitialDir = oldpath;
			if (GetOpenFileName(&ofn))
			{
				strcpy(progssrcdir, filename);
				for(s = progssrcdir; s; s = s2)
				{
					s2 = strchr(s+1, '\\');
					if (!s2)
						break;
					s = s2;
				}
				if (s)
				{
					*s = '\0';
					strcpy(progssrcname, s+1);
				}
				else
					strcpy(progssrcname, filename);
			}
			else
			{
				MessageBox(NULL, "You didn't select a file", "Error", 0);
				return 0;
			}
			SetCurrentDirectory(progssrcdir);
			*progssrcdir = '\0';
		}
	}

    wndclass.style      = 0;
    wndclass.lpfnWndProc   = (WNDPROC)MainWndProc;
    wndclass.cbClsExtra    = 0;
    wndclass.cbWndExtra    = 0;
    wndclass.hInstance     = ghInstance;
    wndclass.hIcon         = 0;
    wndclass.hCursor       = LoadCursor (NULL,IDC_ARROW);
	wndclass.hbrBackground = (void *)COLOR_WINDOW;
    wndclass.lpszMenuName  = 0;
    wndclass.lpszClassName = MAIN_WINDOW_CLASS_NAME;
	RegisterClass(&wndclass);

	mainwindow=CreateWindow(MAIN_WINDOW_CLASS_NAME, "FTE QuakeC compiler", WS_OVERLAPPEDWINDOW,
		0, 0, 640, 480, NULL, NULL, ghInstance, NULL);

	if (!mainwindow)
	{
		MessageBox(NULL, "Failed to create main window", "Error", 0);
		return 0;
	}

	InitCommonControls();
/*
	outputbox=CreateWindowEx(WS_EX_CLIENTEDGE,
		"EDIT",
		"",
		WS_CHILD | ES_READONLY | WS_VISIBLE | 
		WS_VSCROLL | ES_LEFT | ES_WANTRETURN |
		ES_MULTILINE | ES_AUTOVSCROLL,
		0, 0, 0, 0,
		mainwindow,
		NULL,
		ghInstance,
		NULL);
*/
	richedit = LoadLibrary("RICHED32.DLL");
	outputbox=CreateWindowEx(WS_EX_CLIENTEDGE,
		richedit?RICHEDIT_CLASS:"EDIT",
		"",
		WS_CHILD /*| ES_READONLY*/ | WS_VISIBLE | 
		WS_HSCROLL | WS_VSCROLL | ES_LEFT | ES_WANTRETURN |
		ES_MULTILINE | ES_AUTOVSCROLL,
		0, 0, 0, 0,
		mainwindow,
		NULL,
		ghInstance,
		NULL);

	if (richedit)
	{
		SendMessage(outputbox, EM_EXLIMITTEXT, 0, 1<<20);
	}


	for (i = 0; i < NUMBUTTONS; i++)
	{
		buttons[i].hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,
			"BUTTON",
			buttons[i].text,
			WS_CHILD | WS_VISIBLE,
			0, 0, 5, 5,
			mainwindow,
			(HMENU)(i+1),
			ghInstance,
			NULL); 
	}

	ShowWindow(mainwindow, SW_SHOWDEFAULT);

	if (fl_compileonstart)
	{
		RunCompiler(lpCmdLine);
	}
	else
	{
		GUIprintf("Welcome to FTE QCC\n");
		GUIprintf("Source file: ");
		GUIprintf(progssrcname);
		GUIprintf("\n");

		RunCompiler("-?");
	}

	while(mainwindow || editors)
	{
		MSG        msg;

		EditorsRun();

		while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
		{
			if (!GetMessage (&msg, NULL, 0, 0))
				break;
			TranslateMessage (&msg);
			DispatchMessage (&msg);
		}

		if (mainwindow)
		{
			i = Edit_GetSel(outputbox);
			if ((i>>16) != (i&0xffff) && i != -1)	//some text is selected.
			{
				int bytes;
				char line[1024];
				char *colon1, *colon2 = NULL;

				int l1;
				int l2;

				l1 = Edit_LineFromChar(outputbox, i&0xffff);
				l2 = Edit_LineFromChar(outputbox, (i>>16)&0xffff);
				if (l1 == l2)
				{
					bytes = Edit_GetLine(outputbox, Edit_LineFromChar(outputbox, i&0xffff), line, sizeof(line)-1);
					line[bytes] = 0;

					for (colon1 = line+strlen(line)-1; *colon1 <= ' ' && colon1>=line; colon1--)
						*colon1 = '\0';
					if (!strncmp(line, "warning: ", 9))
						memmove(line, line+9, sizeof(line));
					colon1=line;
					do
					{
						colon1 = strchr(colon1+1, ':');
					} while (colon1 && colon1[1] == '\\');

					if (colon1)
					{
						colon2 = strchr(colon1+1, ':');
						while (colon2 && colon2[1] == '\\')
						{
							colon2 = strchr(colon2+1, ':');
						}
						if (colon2)
						{
							*colon1 = '\0';
							*colon2 = '\0';
							EditFile(line, atoi(colon1+1)-1);
						}
						else if (!strncmp(line, "Source file: ", 13))
							EditFile(line+13, -1);
						else if (!strncmp(line, "Including: ", 11))
							EditFile(line+11, -1);
					}
					else if (!strncmp(line, "compiling ", 10))
						EditFile(line+10, -1);
					Edit_SetSel(outputbox, i&0xffff, i&0xffff);	//deselect it.
				}
			}

			if (buttons[ID_COMPILE].washit)
			{
				RunCompiler(parameters);

				buttons[ID_COMPILE].washit = false;
			}
			if (buttons[ID_EDIT].washit)
			{
				buttons[ID_EDIT].washit = false;
				EditFile(progssrcname, -1);
			}
			if (buttons[ID_OPTIONS].washit)
			{
				buttons[ID_OPTIONS].washit = false;
				OptionsDialog();
			}
			if (buttons[ID_QUIT].washit)
			{
				buttons[ID_QUIT].washit = false;
				DestroyWindow(mainwindow);
			}
		}

		Sleep(10);
	}

	return 0;
}
