ecf8930ed2
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@41 fc73d0e0-1445-4013-8a0c-d673dee63da5
1721 lines
37 KiB
C
1721 lines
37 KiB
C
#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;
|
|
}
|