See More

// ChatScriptIDE.cpp : Defines the entry point for the application. // #include "stdafx.h" #include "ChatScriptIDE.h" #include #include #include "../SRC/common.h" using namespace std; /* entry points: DebugCall DebugAction DebugVar DebugMessage DebugMark */ typedef struct WINDOWSTRUCT { HWND window; int linesPerPage; int charsPerPage; int maxLines; int maxChars; RECT rect; SIZE metrics; int xposition; int yposition; } WINDOWSTRUCT; WINDOWSTRUCT scriptData, statData, varData, sentenceData, stackData, inputData, outputData; #define NO_BREAK 0 #define BREAK_CALL 1 #define BREAK_ACTION 2 #define BREAK_VAR 3 #define BREAK_MSG 4 typedef struct MAPDATA { uint64 botid; // restriction if any MAPDATA* next; // maps are kept in order start to finish of a file, char* filename; int fileline; char* name; } MAPDATA; typedef struct LINEDATA { LINEDATA* next; LINEDATA* prior; MAPDATA* mapentry; char text[1]; // actually it can be any size } LINEDATA; typedef struct FILEDATA { FILEDATA* next; char* filename; LINEDATA* filelines; // actually, char*, char*, linecharacters MAPDATA* map; // start of map info on this file char* status; int charsize; int lineCount; } FILEDATA; typedef struct CLICKLIST { FILEDATA* file; CLICKLIST* next; int yposition; int mousey; } CLICKLIST; static void UpdateWindowMetrics(WINDOWSTRUCT& data, bool font = false); CLICKLIST* clickList = NULL; static void AddTab(char* name); FILEDATA* currentFileData = NULL; static int offsetCode = -1; int breakType = NO_BREAK; static bool WhereAmI(int depth); static char breakAt[400][40]; static int rulesInMap = 0; static int rulesExecuted = 0; static int breakIndex = 0; int sentenceMode = 0; static bool sysfail = false; static int nextdepth = -1; static int nextlevel = -1; static int idedepth = -1; static int ideoutputlevel = -1; static char* fnvars = NULL; static int fnlevel = -1; static void ClearStops(); static uintptr_t csThread = 0; static MAPDATA* lastItem = NULL; static char filenames[1000]; static char varnames[1000]; static char varbreaknames[1000]; static MAPDATA* firstMap = NULL; static MAPDATA* priorMapLine = NULL; static char* DebugInput(char* input); static void MakeCurrentFile(char* name, uint64 botid); static char windowTitle[MAX_WORD_SIZE]; static int breakpointCount = 0; static FILEDATA* fileList = NULL; static char varAt[100][40]; static int varIndex = 0; LINEDATA* firstline = NULL; LINEDATA* priorline = NULL; LINEDATA* line = NULL; int outlevel = 0; #define MAX_LOADSTRING 100 #define ID_EDITCHILD 100 // output #define ID_EDITCHILD1 101 // input HWND hParent = NULL; static void RemoveBreak(char* name); HWND hGoButton, hStopButton, hClearButton, hNextButton, hInButton, hOutButton; HWND hLocalsButton, hBackButton, hBreakMessageButton; HWND hFontButton, hFailButton; HWND hDialog; int fontsize = 30; size_t editLen = 0; bool changingEdit = false; SCROLLINFO si; static int ProcessBreak(char* input, int flags); HFONT hFont, hFontBigger, hButtonFont; HPEN hPen; HBRUSH hBrush; HBRUSH hBrushBlue; HBRUSH hBrushOrange; int mouseLine = -1; int codeLine = -1; // where are we FILEDATA* codeFile = NULL; int codeOffset = -1; char* codePtr = NULL; int mouseCharacter = -1; char transientBreak[200]; RECT titlerect; RECT numrect; RECT tagrect; static char* DebugVar(char* name, char* value); static char* DebugMark(char* name, char* value); int outdepth = -1; static char* DebugOutput(char* output); // Global Variables: HINSTANCE hInst; // current instance char szTitle[MAX_LOADSTRING]; // The title bar text char szWindowClass[MAX_LOADSTRING]; // the main scriptData.window class name char* DoneCallback(char* buffer); // Forward declarations of functions included in this code module: ATOM MyRegisterClass(HINSTANCE hInstance, LPCSTR szWindowClass); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); static FILEDATA* GetFile(char* name, uint64 botid); int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); if (!SetCurrentDirectory((LPCSTR)"..")) { printf("no change dir"); } // TODO: Place code here. // Initialize global strings LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadString(hInstance, IDC_CHATSCRIPTIDE, szWindowClass, MAX_LOADSTRING); ATOM j = MyRegisterClass(hInstance, (LPCSTR)szWindowClass); // Perform application initialization: if (!InitInstance(hInstance, nCmdShow)) { return FALSE; } HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_CHATSCRIPTIDE)); MSG msg; // Main message loop: while (GetMessage(&msg, nullptr, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return (int)msg.wParam; } static MAPDATA* FindFileMap(char* filename, uint64 botid) { MAPDATA* at = firstMap; while (at) { // map has link, file, line, name // we match either full path or tail naming only if ((at->botid == botid || at->botid & botid) && (!stricmp(at->name, filename) || !stricmp(at->filename, filename))) { return at; } at = at->next; // use forward ptr } return NULL; } static MAPDATA* FindLine(int line) { return NULL; } static void ReadWindow(HWND window, FILE* in) { char buffer[500]; ReadALine(buffer, in); char* data = buffer; char word[MAX_WORD_SIZE]; data = ReadCompiledWord(data, word); data = ReadCompiledWord(data, word); int x = atoi(word); data = ReadCompiledWord(data, word); int y = atoi(word); data = ReadCompiledWord(data, word); int z = atoi(word); data = ReadCompiledWord(data, word); int q = atoi(word); MoveWindow(window, x, y, z, q, true); } static void RestoreWindows() { FILE* in = FopenReadOnly("idesettings.txt"); if (!in) return; ReadWindow(scriptData.window, in); UpdateWindowMetrics(scriptData, true); ReadWindow(inputData.window, in); ReadWindow(outputData.window, in); UpdateWindowMetrics(outputData, true); ReadWindow(statData.window, in); UpdateWindowMetrics(statData, true); ReadWindow(varData.window, in); UpdateWindowMetrics(varData, true); ReadWindow(stackData.window, in); UpdateWindowMetrics(stackData, true); ReadWindow(hGoButton, in); ReadWindow(hInButton, in); ReadWindow(hOutButton, in); ReadWindow(hNextButton, in); ReadWindow(hStopButton, in); ReadWindow(hBreakMessageButton, in); ReadWindow(hClearButton, in); ReadWindow(hLocalsButton, in); ReadWindow(hBackButton, in); ReadWindow(hFontButton, in); ReadWindow(hFailButton, in); char buffer[100]; ReadALine(buffer, in); fontsize = atoi(buffer + 10); fclose(in); } static void SaveWindow(HWND window, char* name, FILE* out) { RECT rect; GetWindowRect(window, &rect); fprintf(out, "%s: %d %d %d %d \r\n", name, rect.left, rect.top, rect.right, rect.bottom); } static void SaveWindows() { FILE* out = FopenBinaryWrite("idesettings.txt"); if (!out) return; SaveWindow(scriptData.window, "script", out); SaveWindow(inputData.window, "input", out); SaveWindow(outputData.window, "output", out); SaveWindow(statData.window, "statistics", out); SaveWindow(varData.window, "variables", out); SaveWindow(stackData.window, "stack", out); SaveWindow(hGoButton, "go", out); SaveWindow(hInButton, "in", out); SaveWindow(hOutButton, "out", out); SaveWindow(hNextButton, "next", out); SaveWindow(hStopButton, "stop", out); SaveWindow(hBreakMessageButton, "msgbreak", out); SaveWindow(hClearButton, "clear", out); SaveWindow(hLocalsButton, "locals", out); SaveWindow(hBackButton, "back", out); SaveWindow(hFontButton, "font", out); SaveWindow(hFailButton, "fail", out); fprintf(out, "fontsize: %d\r\n", fontsize); fclose(out); } static void DumpMaps() { FILE* out = FopenBinaryWrite("tmp/tmp.txt"); MAPDATA* map = firstMap; while (map) { fprintf(out, "%d %s %s\r\n", map->fileline, map->filename, map->name); map = map->next; } fclose(out); } static MAPDATA* FindMap(char* name, char* filename) { MAPDATA* at = firstMap; char* oldname = NULL; while (at) { if (at->filename != oldname) { oldname = at->filename; Log(STDDEBUGLOG, "%s\r\n", oldname); } char* entry = at->name; // map has link, file, line, name if (filename && stricmp(at->filename, filename)) { ; } else { if (*entry == '^' || *entry == '~') priorMapLine = at; if (!stricmp(name, entry)) return at; } at = at->next; // use forward ptr } return NULL; } static MAPDATA* FindLabelMap(char* label, uint64 botid) { MAPDATA* at = firstMap; while (at) { // map has link, file, line, name // we match either full path or tail naming only if ((at->botid == botid || at->botid & botid) && *at->name == '~') { char* hyphen = strchr(at->name, '-'); if (hyphen && strchr(at->name, '.')) // tag + label { if (!stricmp(hyphen + 1, label)) return at; } } at = at->next; // use forward ptr } return NULL; } static void DefineVertScroll(WINDOWSTRUCT& data, int pos) { if (!data.window) return; si.fMask = SIF_POS | SIF_RANGE; if (pos >= 0) si.nPos = pos; si.nMin = 0; si.nMax = data.maxLines; SetScrollInfo(data.window, SB_VERT, &si, true); InvalidateRgn(data.window, NULL, true); } static char* ShowActions(char* actions, int level) { static char src[100]; sprintf(src, "lvl:%d ", level); char* at = src + strlen(src); strncpy(at, actions, 40); at[40] = 0; at = strchr(at, '`'); if (at) *at = 0; return src; } static char* GetDefn(int depth) { CALLFRAME* frame = GetCallFrame(depth); if (*frame->label != '^') return NULL; // not a callframe char* definition = frame->definition; if (!definition) return NULL; return ++definition; // ( xxx xxx ) } static void StackVariables(int depth) { fnvars = 0; fnlevel = -1; if (depth <= 0 || depth > globalDepth) return; fnvars = GetDefn(depth); sprintf(windowTitle, "local variables"); SetWindowText(varData.window, (LPCTSTR)windowTitle); fnlevel = depth; // now at "(xxx xxx xxx )" argument list + locals } static void BackClick() { if (!clickList) return; CLICKLIST* click = clickList; clickList = click->next; mouseLine = click->mousey; scriptData.yposition = click->yposition; } static void AddClick() { // already there if (clickList && clickList->file == currentFileData && clickList->yposition == scriptData.yposition) return; CLICKLIST* click = (CLICKLIST*)malloc(sizeof(CLICKLIST)); click->next = clickList; clickList = click; click->file = currentFileData; click->yposition = scriptData.yposition; click->mousey = mouseLine; } static void RestoreClick() { if (!clickList) return; CLICKLIST* click = clickList; clickList = clickList->next; scriptData.yposition = click->yposition; mouseLine = click->mousey; currentFileData = click->file; AddTab(click->file->filename); scriptData.maxLines = currentFileData->lineCount; scriptData.maxChars = currentFileData->charsize; free(click); InvalidateRgn(scriptData.window, NULL, true); } static void FreeClicklist() { while (clickList) { CLICKLIST* next = clickList->next; free(clickList); clickList = next; } } static char* ChaseFnVariable(char* name, int mydepth) { if (globalDepth <= 0) return NULL; // not stopped in execution int depth = (mydepth <= 0) ? 1 : mydepth; // go to current char label[MAX_WORD_SIZE]; sprintf(label, "%s ", name); CALLFRAME* frame = GetCallFrame(depth); if (*name == '$') while (++depth <= globalDepth) // go deeper to see { frame = GetCallFrame(depth); if (*frame->label == '~' && strchr(frame->label, '.')) continue; char* defn = frame->definition; if (!defn) continue; char* end = strchr((char*)defn, ')'); *end = 0; // find variable in list char* found = strstr((char*)defn, label); *end = ')'; if (!found) continue; // not used by this // find which display arg it is *found = 0; int n = 0; char* at = (char*)defn + 2; char arg[MAX_WORD_SIZE]; while (*at) { at = ReadCompiledWord(at, arg); if (*arg == USERVAR_PREFIX) ++n; // we dont count ^args } *found = *label; // need the nth arg old display value char* val = frame->display[n]; return (!*val) ? "null" : val; } if (*name == '^') { // find which display arg it is char* defn = frame->definition; if (!defn) return "null"; // not yet visible char* at = (char*)defn + 2; char arg[MAX_WORD_SIZE]; int n = 1; // ARGUMENT(1) while (*at) { at = ReadCompiledWord(at, arg); if (!stricmp(arg, name)) break; ++n; if (n > frame->arguments) return "null"; // not there, may not have been even called } char* answer = callArgumentList[frame->varBaseIndex + n]; return answer; } return GetUserVariable(name); // current value is correct } static void DefineHorzScroll(WINDOWSTRUCT& data, int pos) { if (!data.window) return; si.fMask = SIF_POS | SIF_RANGE; if (pos >= 0) si.nPos = pos; si.nMin = 0; si.nMax = data.maxChars; SetScrollInfo(data.window, SB_HORZ, &si, true); InvalidateRgn(data.window, NULL, true); } static void ShowStack() { if (stackData.window) // compute scroll data for stack window { int maxchar = 0; for (int i = 1; i <= globalDepth; ++i) { CALLFRAME* frame = GetCallFrame(i); size_t len = strlen(frame->label); if (len > maxchar) maxchar = len; } stackData.maxChars = maxchar; stackData.maxLines = globalDepth; stackData.xposition = 0; if (globalDepth > stackData.linesPerPage) stackData.yposition = globalDepth - stackData.linesPerPage; DefineVertScroll(stackData, stackData.yposition); DefineHorzScroll(stackData, 0); InvalidateRgn(stackData.window, NULL, true); StackVariables(globalDepth); InvalidateRgn(varData.window, NULL, true); } } static void ShowVariables() { if (varData.window) InvalidateRgn(varData.window, NULL, true); } char* DoneCallback(char* buffer) { sprintf(windowTitle, "%s=>%s (%I64u)", loginID, computerID, myBot); SetWindowText(scriptData.window, (LPCTSTR)windowTitle); ShowVariables(); stackData.maxLines = 0; stackData.maxChars = 0; DefineVertScroll(stackData, 0); DefineHorzScroll(stackData, 0); // no reason to update stack window, we have finished volley return buffer; } static void UpdateWindowMetrics(WINDOWSTRUCT& data, bool font) { HDC dc = GetDC(data.window); if (font) SelectObject(dc, hFontBigger); else SelectObject(dc, hFont); GetTextExtentPoint32(dc, (LPCTSTR)"12TzqbABCDEFGHIJKLMNOPQRSTUVWXYZ", 32, &data.metrics); ReleaseDC(data.window, dc); data.metrics.cx /= 32; data.metrics.cx += 1; data.charsPerPage = ((data.rect.right - data.rect.left) / data.metrics.cx) - 1; data.linesPerPage = ((data.rect.bottom - data.rect.top) / data.metrics.cy); si.fMask = SIF_RANGE | SIF_PAGE; si.nPage = data.charsPerPage; si.nMin = 0; si.nMax = data.maxChars; SetScrollInfo(data.window, SB_HORZ, &si, false); // we can display this many lines si.nPage = data.linesPerPage; si.nMin = 0; si.nMax = data.maxLines; SetScrollInfo(data.window, SB_VERT, &si, false); } static void UpdateMetrics() { UpdateWindowMetrics(scriptData); scriptData.rect.top = scriptData.metrics.cy; titlerect.bottom = scriptData.metrics.cy; InvalidateRgn(scriptData.window, NULL, true); if (varData.window) { UpdateWindowMetrics(varData); InvalidateRgn(varData.window, NULL, true); } if (outputData.window) { UpdateWindowMetrics(outputData); InvalidateRgn(outputData.window, NULL, true); } if (statData.window) { UpdateWindowMetrics(statData); InvalidateRgn(statData.window, NULL, true); } if (stackData.window) { UpdateWindowMetrics(stackData); InvalidateRgn(stackData.window, NULL, true); } } void EraseVariable(int which) { if (!*varnames) return; char* var = varnames; size_t len; char name[MAX_WORD_SIZE]; char* end; while (*var) { // get next variable name end = strstr(var, "\r\n"); if (!end) break; *end = 0; if (which-- == 0) break; *end = '\r'; var = end + 2; } ReadCompiledWord(var, name); if (end) *end = '\r'; char junk[MAX_WORD_SIZE]; sprintf(junk, "%s\r\n", name); char* found = strstr(varnames, junk); if (!found) return; len = strlen(name); --varData.maxLines; char* after = found + len + 2; memmove(found, after, strlen(after) + 2); // remove name } static void VerifyMap() { FILEDATA* file = fileList; int count = 0; bool found = false; while (file) { LINEDATA* fileLines = file->filelines; while (fileLines) { MAPDATA* map = fileLines->mapentry; if (map->name && (map->name, "control.9")) found = true; ++count; fileLines = fileLines->next; } file = file->next; } if (found) { int xx = 0; } else { int xx = 0; } } static void DoBreakVariable(int which) { if (!*varnames && !fnvars) { return; } char* var = (fnvars) ? fnvars : varnames; size_t len; char name[MAX_WORD_SIZE]; char* end; while (*var) { // get next variable name end = strstr(var, "\r\n"); if (!end) end = strstr(var, " "); // fnvars if (!end) end = strstr(var, ")"); // fnvars if (!end) break; *end = 0; if (which-- == 0) break; *end = '\r'; var = end + 2; } ReadCompiledWord(var, name); if (*name == '^') { DebugPrint("cannot breakpoint a ^var\r\n"); return; // cannot break on ^var } if (end) *end = '\r'; char junk[MAX_WORD_SIZE]; sprintf(junk, "%s\r\n", name); char* found = strstr(varbreaknames, junk); len = strlen(name); if (found) // remove name from existing list { char* after = found + len + 2; memmove(found, after, strlen(after) + 2); // remove name if (!*varbreaknames) debugVar = NULL; return; } // insert at start of list memmove(varbreaknames + len + 2, varbreaknames, strlen(varbreaknames) + 1); memmove(varbreaknames, name, len); varbreaknames[len] = '\r'; varbreaknames[len + 1] = '\n'; debugVar = DebugVar; } static void AddVariable(char* name) { char junk[MAX_WORD_SIZE]; sprintf(junk, "%s\r\n", name); MakeLowerCase(junk); char* found = strstr(varnames, junk); size_t len = strlen(name); if (found) // remove name from existing list { --varData.maxLines; char* after = found + len + 2; memmove(found, after, strlen(after) + 2); // remove name } // insert at start of list memmove(varnames + len + 2, varnames, strlen(varnames) + 1); memmove(varnames, junk, len); varnames[len] = '\r'; varnames[len + 1] = '\n'; ++varData.maxLines; DefineVertScroll(varData, 0); if (*loginID && !csThread) ReadUserData(); // but not if suspended or unstarted ShowVariables(); if (!csThread) ResetToPreUser();// but not if suspended } static int NameLine(char* name) { MAPDATA* symbol = FindMap(name, NULL); // find name in any file if (!symbol) return -1; char* file = symbol->filename; MakeCurrentFile(file, symbol->botid); return symbol->fileline; } uint64 FindBotID(char* name) { char id[MAX_WORD_SIZE]; MakeLowerCopy(id, name); strcat(id, "`bot"); MAPDATA* at = firstMap; while (at) { char* entry = at->name; // map has link, file, line, name if (!stricmp(id, entry)) return at->botid; at = at->next; // use forward ptr } return (uint64)(int64)-1; } static void RemoveTab(char* name) { char fullname[1000]; sprintf(fullname, " %s ", name); char* found = strstr(filenames, fullname); size_t len = strlen(fullname); if (found) // remove short name + space from existing list { char* after = found + len - 1; memmove(found, after, strlen(after) + 1); // remove name if (filenames[1] == ' ') // if it was leader, change leader { memmove(filenames, filenames + 1, strlen(filenames) + 1); char word[MAX_WORD_SIZE]; ReadCompiledWord(filenames, word); AddTab(word); // reinsert properly } InvalidateRgn(scriptData.window, NULL, true); } } static void AddTab(char* name) { RemoveTab(name); size_t len = strlen(name); // remove 2 extra spaces on separator, make single space char old[1000]; char* triple = strstr(filenames, " "); if (triple) { strcpy(old, triple + 4); strcpy(triple + 1, old); } strcpy(old, filenames); *filenames = ' '; strcpy(filenames + 1, name); strcat(filenames, " "); if (*old) strcat(filenames, old + 1); //leave off extra space } MAPDATA* AlignName(char* name) { char namex[1000]; strcpy(namex, name); char* at = strchr(namex, '('); if (at) *at = 0; at = strchr(namex, '{'); if (at) *at = 0; MAPDATA* symbol = FindMap(namex, NULL); // find name in any file if (!symbol)symbol = FindLabelMap(namex, NULL); if (!symbol) return NULL; char* file = symbol->filename; FILEDATA* oldfile = currentFileData; AddClick(); MakeCurrentFile(file, symbol->botid); mouseLine = symbol->fileline; // 1-based, whereas yposition is 0-based mouseCharacter = 0; scriptData.maxLines = currentFileData->lineCount; scriptData.maxChars = currentFileData->charsize; if (oldfile != currentFileData) { scriptData.yposition = symbol->fileline - 3; // start with item showing in context scriptData.xposition = 0; // reset } else if (mouseLine > (scriptData.yposition + 1 + scriptData.linesPerPage)) scriptData.yposition = symbol->fileline - 3; // start with item showing in context else if (mouseLine < scriptData.yposition + 1) scriptData.yposition = symbol->fileline - 3; // start with item showing in context else if ((symbol->fileline - scriptData.yposition - 1) < (scriptData.yposition + scriptData.linesPerPage)) { ; } // same page else if (currentFileData->lineCount > scriptData.maxLines) scriptData.yposition = symbol->fileline - 3; // start with item showing in context else scriptData.yposition = 0; if (scriptData.yposition < 0) scriptData.yposition = 0; // file name must not back up DefineVertScroll(scriptData, scriptData.yposition); scriptData.maxChars = currentFileData->charsize; DefineHorzScroll(scriptData, 0); return symbol; } void FindBot(char* name) { myBot = -1; // all access pass if (name) // happens when we have logged in and gotten a bot { AlignName(name); myBot = FindBotID(name); sprintf(windowTitle, "%s=>%s (%I64u)", loginID, computerID, myBot); SetWindowText(scriptData.window, (LPCTSTR)windowTitle); return; } // happens on startup before login has occured if (*defaultbot) { AlignName(defaultbot); myBot = FindBotID(defaultbot); sprintf(windowTitle, "%s=>%s (%I64u)", "", defaultbot, myBot); SetWindowText(scriptData.window, (LPCTSTR)windowTitle); return; } WORDP D = FindWord("defaultbot"); FACT* F = GetVerbNondeadHead(D); while (F) { if (F->verb == F->object) { char name[MAX_WORD_SIZE]; D = Meaning2Word(F->subject); sprintf(name, "^%s", D->word); AlignName(name); myBot = FindBotID(name); sprintf(windowTitle, "%s=>%s (%I64u)", "", name, myBot); SetWindowText(scriptData.window, (LPCTSTR)windowTitle); break; } F = GetVerbNondeadNext(F); } } // // FUNCTION: MyRegisterClass() // // PURPOSE: Registers the scriptData.window class. // ATOM MyRegisterClass(HINSTANCE hInstance, LPCSTR szWindowClass) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_CHATSCRIPTIDE)); wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wcex.lpszMenuName = MAKEINTRESOURCE(IDC_CHATSCRIPTIDE); wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); return RegisterClassEx(&wcex); } static char* GetStartCharacter(LINEDATA* line) { if (!line) return NULL; char* msg = (char*)&line->text; if (scriptData.xposition) { int count = scriptData.xposition; while (count-- && *msg) ++msg; } return msg; } static LINEDATA* GetStartLine(int count) { if (!currentFileData) return NULL; LINEDATA* at = currentFileData->filelines; if (count) { while (count-- && at) at = at->next; // use forward ptr } return at; } static MAPDATA* MapAllocate(uint64 botid, char* file, char* name, char* line) { size_t len = strlen(name); MAPDATA* map = (MAPDATA*)malloc(sizeof(MAPDATA)); // link, file, line, name map->next = NULL; // forward link map->botid = botid; map->filename = file; // set file name map->fileline = (line) ? atoi(line) : 0; // set line number // when name is a number (line number) or if/else/loop then line is an offset into block or rule data // rule: ~medical_glean.43.0-MEDICALBODYPARTKIND u: 246 char* x = (char*)malloc(len + 1); strcpy(x, name); map->name = x; if (!firstMap) firstMap = map; // ordered if (priorMapLine) priorMapLine->next = map; // set old forward ptr priorMapLine = map; return map; } static LINEDATA* ReadFile(char* name, size_t& maxchars, int& maxlines, uint64 botid) { FILE* in = fopen(name, "rb"); if (!in) return NULL; char buffer[20000]; firstline = NULL; priorline = NULL; line = NULL; maxlines = 0; maxchars = 0; MAPDATA* map = FindFileMap(name, botid); // get map for this if (!map) { fclose(in); return NULL; } int currentMapLine = map->fileline; while (fgets(buffer, 20000, in)) // make linked list of all text { ++maxlines; char* at = buffer; while ((at = strchr(at, '\t'))) { memmove(at + 4, at + 1, strlen(at)); memmove(at, " ", 4); } size_t len = strlen(buffer); if (buffer[len - 2] == '\r') { len -= 2; buffer[len] = 0; } else if (buffer[len - 1] == '\n') buffer[--len] = 0; if (len > maxchars) maxchars = len; line = (LINEDATA*)malloc(sizeof(LINEDATA) + len + 1); if (!firstline) firstline = line; strcpy(line->text, buffer); // set content line->mapentry = NULL; if (map) { int oldline = map->fileline; while (map && map->fileline < maxlines) { map = map->next; if (map && strstr(map->name, "~control")) { int xx = 0; } if (map && map->fileline < oldline) map = NULL; } if (map && map->fileline == maxlines) line->mapentry = map; } if (priorline) priorline->next = line; // set forward ptr line->prior = priorline; // set backward ptr priorline = line; } fclose(in); if (line) line->next = NULL; // set final forward ptr return firstline; } static void FakeMapEntry(char* name, char* comment, int& maxlines, int& maxchar, char* sysfile) { // create fake map entry char index[100]; char buffer[20000]; sprintf(index, "%d", maxlines); MAPDATA* map = MapAllocate(0, sysfile, (char*)name, index); if (*name == '\r') { name += 2; comment = ""; } *buffer = 0; if (*name) sprintf(buffer, "%s : %s", name, comment); size_t len = strlen(buffer); if (len > maxchar) maxchar = len; ++maxlines; line = (LINEDATA*)malloc(sizeof(LINEDATA) + len + 1); if (!firstline) firstline = line; strcpy(line->text, buffer); // set content line->mapentry = map; if (priorline) priorline->next = line; // set forward ptr line->prior = priorline; // set backward ptr priorline = line; } static void SetFile(FILEDATA* file, char* name) { currentFileData = file; scriptData.maxLines = currentFileData->lineCount; scriptData.maxChars = currentFileData->charsize; scriptData.xposition = 0; scriptData.yposition = 0; AddTab(name); } static void ReadSystemFunctionsMap(char* sysfile) { char buffer[20000]; firstline = NULL; priorline = NULL; line = NULL; int maxlines = 1; int maxchar = 0; // define a system fake file MAPDATA* filemap = MapAllocate(0, sysfile, sysfile, 0); SystemFunctionInfo* fn; int i = 0; while ((fn = &systemFunctionSet[++i]) && fn->word) { char name[MAX_WORD_SIZE]; if (strstr(fn->word, "---")) strcpy(name, fn->word); else sprintf(name, " %s", fn->word); // create fake map entry char varcount[100]; sprintf(varcount, "%d", fn->argumentCount); if (fn->argumentCount == -1) strcpy(varcount, "..."); if (fn->argumentCount == -2) strcpy(varcount, "stream"); if (fn->argumentCount == -3) strcpy(varcount, "unevaled"); sprintf(buffer, "(%s) : %s", varcount, fn->comment); FakeMapEntry(name, buffer, maxlines, maxchar, sysfile); } if (line) line->next = NULL; // set final forward ptr FILEDATA* file = (FILEDATA*)malloc(sizeof(FILEDATA)); // next, name, filedata, maxx, maxy file->next = fileList; fileList = file; file->map = filemap; char* fname = (char*)malloc(strlen(sysfile) + 1); strcpy(fname, sysfile); file->status = (char*)malloc(maxlines + 1); memset(file->status, ' ', maxlines + 1); // breakpoint data file->filename = fname; // set file name file->filelines = firstline; // set file data file->charsize = maxchar; file->lineCount = maxlines; SetFile(file, "systemFunctions"); } static void ReadSystemVariablesMap(char* sysfile) { firstline = NULL; priorline = NULL; line = NULL; int maxlines = 1; int maxchar = 0; // define a var fake file MAPDATA* filemap = MapAllocate(0, sysfile, sysfile, 0); SYSTEMVARIABLE* fn; FakeMapEntry("$cs_token", "controls input processing", maxlines, maxchar, sysfile); FakeMapEntry("$cs_response", "controls automatic handling of outputs to user", maxlines, maxchar, sysfile); FakeMapEntry("$cs_control_pre", "name of topic to run in gambit mode on pre - pass", maxlines, maxchar, sysfile); FakeMapEntry("$cs_prepass", "name of topic to run before $cs_control_main", maxlines, maxchar, sysfile); FakeMapEntry("$cs_control_main", "name of topic to run every sentence of volley", maxlines, maxchar, sysfile); FakeMapEntry("$cs_control_post", "name of topic to run once after all sentences have been handled", maxlines, maxchar, sysfile); FakeMapEntry("$cs_wildcardseparator", "when a match variable covers multiple words, what should separate them", maxlines, maxchar, sysfile); FakeMapEntry("$cs_looplimit", "stops a loop after n iterations", maxlines, maxchar, sysfile); FakeMapEntry("$cs_trace", "turn on these trace bits for user", maxlines, maxchar, sysfile); FakeMapEntry("$cs_userfactlimit", "how many facts to keep for user", maxlines, maxchar, sysfile); FakeMapEntry("$cs_response", "controls some characteristics of how responses are formatted ", maxlines, maxchar, sysfile); FakeMapEntry("$cs_numbers", "if defined, causes the system to output numbers in a different language style", maxlines, maxchar, sysfile); FakeMapEntry("$cs_externaltag", "name of a topic to use to replace existing internal English pos - parser", maxlines, maxchar, sysfile); FakeMapEntry("", "", maxlines, maxchar, sysfile); int i = 0; while ((fn = &sysvars[++i]) && fn->name) { char name[MAX_WORD_SIZE]; if (strstr(fn->name, "---")) strcpy(name, fn->name); else sprintf(name, " %s", fn->name); FakeMapEntry(name, (char*)fn->comment, maxlines, maxchar, sysfile); } if (line) line->next = NULL; // set final forward ptr FILEDATA* file = (FILEDATA*)malloc(sizeof(FILEDATA)); // next, name, filedata, maxx, maxy file->next = fileList; fileList = file; file->map = filemap; char* fname = (char*)malloc(strlen(sysfile) + 1); strcpy(fname, sysfile); file->status = (char*)malloc(maxlines + 1); memset(file->status, ' ', maxlines + 1); // breakpoint data file->filename = fname; // set file name file->filelines = firstline; // set file data file->charsize = maxchar; file->lineCount = maxlines; SetFile(file, "systemVariables"); } static void ReadDebugCommandsMap(char* sysfile) { firstline = NULL; priorline = NULL; line = NULL; int maxlines = 1; int maxchar = 0; CommandInfo* routine = NULL; // define a debug command fake file MAPDATA* filemap = MapAllocate(0, sysfile, sysfile, 0); int i = 0; while ((routine = &commandSet[++i]) && routine->word) { char name[MAX_WORD_SIZE]; if (strstr(routine->word, "---")) strcpy(name, routine->word); else sprintf(name, " %s", routine->word); FakeMapEntry(name, (char*)routine->comment, maxlines, maxchar, sysfile); } if (line) line->next = NULL; // set final forward ptr FILEDATA* file = (FILEDATA*)malloc(sizeof(FILEDATA)); // next, name, filedata, maxx, maxy file->next = fileList; fileList = file; file->map = filemap; char* fname = (char*)malloc(strlen(sysfile) + 1); strcpy(fname, sysfile); file->status = (char*)malloc(maxlines + 1); memset(file->status, ' ', maxlines + 1); // breakpoint data file->filename = fname; // set file name file->filelines = firstline; // set file data file->charsize = maxchar; file->lineCount = maxlines; SetFile(file, "debugCommands"); } static void ReadIDECommandsMap(char* sysfile) { firstline = NULL; priorline = NULL; line = NULL; int maxlines = 1; int maxchar = 0; // define a debugger fake file MAPDATA* filemap = MapAllocate(0, sysfile, sysfile, 0); FakeMapEntry("Script Window", "", maxlines, maxchar, sysfile); FakeMapEntry(" L-click in tag/line#", "set/clear breakpoint", maxlines, maxchar, sysfile); FakeMapEntry(" R-click in tag/line#", "set transient break, go, erase when stop somewhere", maxlines, maxchar, sysfile); FakeMapEntry(" Ctrl-L-click in tag/line#", "change (if possible) code pointer of this level to this line for future execution", maxlines, maxchar, sysfile); FakeMapEntry(" L-click on $var, %var, _n, @n", "display in variables window", maxlines, maxchar, sysfile); FakeMapEntry(" L-click on ^fn, %concept, %topic", "display that area of script", maxlines, maxchar, sysfile); FakeMapEntry("Title area", "", maxlines, maxchar, sysfile); FakeMapEntry(" L-click on name", "display that file of script", maxlines, maxchar, sysfile); FakeMapEntry(" R-click on name", "remove that file of script from display", maxlines, maxchar, sysfile); FakeMapEntry("Variables Window", "", maxlines, maxchar, sysfile); FakeMapEntry(" L-click left of variable", "break on change to it", maxlines, maxchar, sysfile); FakeMapEntry(" L-click on variable", "remove entry from window", maxlines, maxchar, sysfile); FakeMapEntry("Stack Window", "", maxlines, maxchar, sysfile); FakeMapEntry(" L-click on line", "display locals of that entry in variables window", maxlines, maxchar, sysfile); FakeMapEntry("Input Window", "", maxlines, maxchar, sysfile); FakeMapEntry(" :i xxx", "analogous to clicking on words in script window", maxlines, maxchar, sysfile); FakeMapEntry(" xxx", "input to ChatScript engine", maxlines, maxchar, sysfile); FakeMapEntry("Output Window", "", maxlines, maxchar, sysfile); FakeMapEntry("Sentence Window", "", maxlines, maxchar, sysfile); FakeMapEntry(" L-click cycles mode", "displays: current sentence internal, sentence user typed, cannonical form of sentence", maxlines, maxchar, sysfile); FakeMapEntry(" R-click on word", "displays: displays marked concepts/topics of word", maxlines, maxchar, sysfile); FakeMapEntry("Buttons", "", maxlines, maxchar, sysfile); FakeMapEntry(" Go", "resume execution", maxlines, maxchar, sysfile); FakeMapEntry(" In", "go to more refined level", maxlines, maxchar, sysfile); FakeMapEntry(" Out", "go to less refined level", maxlines, maxchar, sysfile); FakeMapEntry(" Next", "go to next item at same level or go out", maxlines, maxchar, sysfile); FakeMapEntry(" Stop", "used during execution, stop as soon as possible", maxlines, maxchar, sysfile); FakeMapEntry(" Msg", "l-click: break when submitting output for user r-click: turn off break", maxlines, maxchar, sysfile); FakeMapEntry(" Fail", "l-click: enable break if system function fails r-click: turn off break", maxlines, maxchar, sysfile); FakeMapEntry(" Clear", "remove all breakpoints", maxlines, maxchar, sysfile); FakeMapEntry(" Global", "flip variables window from locals back to globals", maxlines, maxchar, sysfile); FakeMapEntry(" Back", "go back to viewing prior script location", maxlines, maxchar, sysfile); FakeMapEntry(" Font", "l-click for smaller, r-click for bigger", maxlines, maxchar, sysfile); if (line) line->next = NULL; // set final forward ptr FILEDATA* file = (FILEDATA*)malloc(sizeof(FILEDATA)); // next, name, filedata, maxx, maxy file->next = fileList; fileList = file; file->map = filemap; char* fname = (char*)malloc(strlen(sysfile) + 1); strcpy(fname, sysfile); file->status = (char*)malloc(maxlines + 1); memset(file->status, ' ', maxlines + 1); // breakpoint data file->filename = fname; // set file name file->filelines = firstline; // set file data file->charsize = maxchar; file->lineCount = maxlines; SetFile(file, "ideCommands"); } static void MakeCurrentFile(char* name, uint64 botid) { currentFileData = GetFile(name, botid); scriptData.maxLines = currentFileData->lineCount; scriptData.maxChars = currentFileData->charsize; scriptData.xposition = 0; scriptData.yposition = 0; } static void ClearAllBreakpoints() { breakpointCount = 0; debugMessage = NULL; FILEDATA* at = fileList; while (at) { memset(at->status, ' ', at->lineCount + 1); at = at->next; } breakIndex = 0; // engine DebugOutput("All breakpoints cleared.\r\n"); } static FILEDATA* GetFile(char* name, uint64 botid) // name is full path cs relative { char fn[MAX_WORD_SIZE]; ReadCompiledWord(filenames, fn); if (!stricmp(fn, name)) return currentFileData; // already is there first char fxname[MAX_WORD_SIZE]; char* endname = strrchr(name, '/'); if (endname) strcpy(fxname, endname + 1); // spaces around the name always else strcpy(fxname, name); AddTab(fxname); // find the file if we can FILEDATA* at = fileList; while (at) { if (!stricmp(at->filename, name)) // found full path entry { return at; // the data } at = at->next; } // allocate the file not found int maxlines = 0; size_t maxchar = 0; LINEDATA* fileinfo = ReadFile(name, maxchar, maxlines, botid); size_t len = strlen(name); FILEDATA* file = (FILEDATA*)malloc(sizeof(FILEDATA)); // next, name, filedata, maxx, maxy file->next = fileList; fileList = file; file->map = FindFileMap(name, botid); char* fname = (char*)malloc(strlen(name) + 1); strcpy(fname, name); file->status = (char*)malloc(maxlines + 1); memset(file->status, ' ', maxlines + 1); // breakpoint data file->filename = fname; // set file name file->filelines = fileinfo; // set file data file->charsize = maxchar; file->lineCount = maxlines; return file; } static void FindClickWord(int mouseCharacter, int mouseLine) { LINEDATA* at = GetStartLine(scriptData.yposition); if (!at) return; int yline = scriptData.yposition; char name[MAX_WORD_SIZE]; *name = 0; while (at) { if (!at->mapentry) { at = at->next; // use forward ptr continue; } if (yline == mouseLine && mouseCharacter >= 0 && mouseCharacter >= scriptData.xposition) { char* msg = GetStartCharacter(at); size_t len = strlen(msg); if (mouseCharacter <= (scriptData.xposition + len)) { int n = mouseCharacter; while (IsLegalNameCharacter(msg[n]) || msg[n] == '$' || msg[n] == '@' || msg[n] == '%' || msg[n] == '~' || msg[n] == '^') --n; ++n; ReadCompiledWord(msg + n, name); n = 1; // simple # if (name[1]) while (name[++n] && (IsLegalNameCharacter(name[n]) || name[n] == '$')) { ; } name[n] = 0; } break; } if (at->mapentry->fileline <= yline) at = at->next; // use forward ptr ++yline; } char junk[MAX_WORD_SIZE]; if (*name == '\'') sprintf(junk, "%s", name + 1); // strip quote else sprintf(junk, "%s", name); MakeLowerCase(junk); if (*junk == '$' || *junk == '%' || ((*junk == '_' || *junk == '@') && IsDigit(junk[1]))) { AddVariable(junk); fnlevel = -1; // show globals } else if (*junk && AlignName(junk)) { ; } else if (*junk == '^') { AddVariable(junk); // fn var? fnlevel = -1; // show globals } } static void ReleaseFiles() { while (fileList) { RemoveTab(fileList->filename); free(fileList->filename); free(fileList->map); free(fileList->status); LINEDATA* line = fileList->filelines; while (line) { // line->text is built into the actual line struct free(line->mapentry); LINEDATA* next = line->next; free(line); line = next; } FILEDATA* next = fileList->next; free(fileList); fileList = next; } firstMap = NULL; // just trash the data here priorMapLine = NULL; *filenames = 0; currentFileData = NULL; } static void ReadMap(char* name) { FILE* in = fopen(name, "rb"); if (!in) return; char buffer[20000]; char* file; //file: 0 full_path_to_file optional_botid //macro : start_line_in_file name_of_macro optional_botid(definition of user function) //line: start_line_in_file offset_byte_in_script (action unit in output) //concept : start_line_in_file name_of_concept optional_botid(concept definition) //topic : start_line_in_file name_of_topic optional_botid(topic definition) //rule : start_line_in_file full_rule_tag_with_possible_label rule_kind(rule definition) //Complexity of name_of_macro complexity_metric(complexity metric for function) //Complexity of rule full_rule_tag_with_possible_label rule_kind complexity_metric(complexity metric for rule) while (fgets(buffer, 20000, in)) { int64 botid = 0; size_t len = strlen(buffer); if (buffer[len - 2] == '\r') buffer[len - 2] = 0; char kind[MAX_WORD_SIZE]; char line[MAX_WORD_SIZE]; char* at = ReadCompiledWord(buffer, kind); if (!*kind || *kind == '#') continue; if ((unsigned char)kind[0] == 0xEF && (unsigned char)kind[1] == 0xBB && (unsigned char)kind[2] == 0xBF) continue;// UTF8 BOM at = ReadCompiledWord(at, line); // line number char title[MAX_WORD_SIZE]; at = ReadCompiledWord(at, title); at = SkipWhitespace(at); if (strstr(kind, "file:")) { file = NULL; uint64 id = atoi64(at); // optional MakeLowerCase(title); file = (char*)malloc(strlen(title) + 1); strcpy(file, title); // start of a file char* x = strrchr(title, '/'); if (x) MapAllocate(id, file, x + 1, 0); } else if (!file) continue; // ignoring all this else if (!stricmp(kind, "MACRO:") || !stricmp(kind, "TOPIC:") || !stricmp(kind, "CONCEPT:")) { botid = atoi64(at); // optional MapAllocate(botid, file, title, line); } else if (!stricmp(kind, "LINE:")) { // line: 244 fileline scriptOffset MapAllocate(0, file, title, line); } else if (!stricmp(kind, "BOT:")) { // line: 244 botname botid strcat(title, "`bot"); uint64 botid = atoi64(at); MapAllocate(botid, file, title, line); } else if (!stricmp(kind, "RULE:")) { // rule: 246 ~medical_glean.43.0-MEDICALBODYPARTKIND u: char x[MAX_WORD_SIZE]; sprintf(x, "%s\r\n", title); ++rulesInMap; MapAllocate(0, file, title, line); // ignoring type of rule for now } else if (!strnicmp(kind, "if", 2) || !strnicmp(kind, "else", 4) || !strnicmp(kind, "loop", 4)) { // if: 246 73 (line) (offset) char x[MAX_WORD_SIZE]; sprintf(x, "%s:%s", kind, title); MapAllocate(0, file, x, line); // ignoring type of rule for now } } fclose(in); } static void StatData() { if (!statData.window) return; char word[MAX_WORD_SIZE]; int heapfree = (heapFree - stackFree) / 1000; int index = Word2Index(dictionaryFree); int factfree = factEnd - lastFactUsed; int gap = maxReleaseStackGap / 1000; int dictfree = (int)(maxDictEntries - index); sprintf(word, "%d", worstDictAvail); sprintf(word, "Memory: %dKb Worst: %dKb Buffer: %d Worst: %d Dict: %d Worst: %d Fact: %d Worst: %d BotRules: %d Executed: %d", heapfree, gap, maxBufferLimit - bufferIndex, maxBufferLimit - maxBufferUsed, dictfree, worstDictAvail, factfree, worstlastFactUsed, rulesInMap, rulesExecuted); SendMessage(statData.window, EM_SETSEL, -1, -1); // append to output SendMessage(statData.window, EM_REPLACESEL, false, (LPARAM)word); // count lines of data in answer si.nPos = 0; si.nMin = 0; si.nMax = strlen(word); SetScrollInfo(statData.window, SB_HORZ, &si, true); InvalidateRgn(statData.window, NULL, true); } static char* DebugOutput(char* output) // add to output { if (!outputData.window) return NULL; char* answer = AllocateBuffer(); if (!*answer) return NULL; changingEdit = true; SendMessage(outputData.window, EM_SETSEL, -1, -1); // append to output SendMessage(outputData.window, EM_REPLACESEL, false, (LPARAM)output); SendMessage(outputData.window, EM_SETSEL, -1, -1); // append to output // SendMessage(outputData.window, EM_LINESCROLL, -1, -1); GetWindowText(outputData.window, answer, MAX_BUFFER_SIZE); editLen = strlen(answer); // we leave off here if (editLen > 20400) // chop it 20k { char* at = answer + 20000; //49k while (*++at && *at != '\n'); ++at; // fresh start SendMessage(outputData.window, EM_SETSEL, 0, -1); SendMessage(outputData.window, EM_REPLACESEL, false, (LPARAM)at); editLen = strlen(answer); } // count lines of data in answer char* at = answer; char* start = answer; int lines = 0; int chars = 0; int maxchars = 0; while ((at = strstr(at, "\r\n"))) { *at = 0; size_t n = strlen(start); if (n > maxchars) maxchars = n; *at = '\r'; ++lines; at += 2; } si.fMask = SIF_POS | SIF_RANGE; si.nPos = lines; si.nMin = 0; si.nMax = lines; SetScrollInfo(outputData.window, SB_VERT, &si, true); si.nPos = 0; si.nMin = 0; si.nMax = maxchars; SetScrollInfo(outputData.window, SB_HORZ, &si, true); changingEdit = false; FreeBuffer(); return NULL; } BOOL CALLBACK ModelessWindow(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { // Place message cases here. default: WndProc(hwndDlg, message, wParam, lParam); return FALSE; } return TRUE; } static void ClearStops() { RemoveBreak(transientBreak); nextdepth = -1; idestop = false; nextlevel = -1; outdepth = -1; outlevel = -1; } bool StopIntended() { if (nextdepth == globalDepth || idestop || nextlevel == outputlevel) return true; // if we if (outdepth > globalDepth) return true; return false; } void MyWorkerThread(void* pParam) { char word[MAX_WORD_SIZE]; char* at = ReadCompiledWord(ourMainInputBuffer, word); rulesExecuted = 0; if (!*loginID) // initial message from chatbot given login name input { char user[MAX_WORD_SIZE]; strcpy(user, ourMainInputBuffer); PerformChat(user, computerID, ourMainInputBuffer, NULL, ourMainOutputBuffer); // unknown bot, no input,no ip EmitOutput(); } else { ProcessInputFile(); // come back when this input is used up if (!stricmp(word, ":trace")) { idetrace = trace; } else if (!stricmp(word, ":build") || !stricmp(word, ":bot") || !stricmp(word, ":restart")) // release map and files { ReleaseFiles(); rulesInMap = 0; ReadMap("TOPIC/build1/map1.txt"); ReadMap("TOPIC/build0/map0.txt"); ReadSystemFunctionsMap("systemFunctions"); ReadSystemVariablesMap("systemVariables"); ReadDebugCommandsMap("debugCommands"); ReadIDECommandsMap("ideCommands"); FindBot(computerID); scriptData.xposition = scriptData.yposition = 0; sprintf(windowTitle, "%s=>%s (%I64u) depth: %d/%d", loginID, computerID, myBot, idedepth, globalDepth); SetWindowText(scriptData.window, (LPCTSTR)windowTitle); } char fn[MAX_WORD_SIZE]; sprintf(fn, "^%s", computerID); FindBot(fn); } csThread = 0; fnlevel = -1; // terminate any stop pending since we finished ClearStops(); mouseCharacter = -1; mouseLine = -1; // no highlight now codeFile = NULL; codeLine = NULL; InvalidateRgn(scriptData.window, NULL, true); InvalidateRgn(stackData.window, NULL, true); InvalidateRgn(varData.window, NULL, true); //InvalidateRgn(hParent, NULL, true); } void MyWorkerInitThread(void* pParam) { if (InitSystem(argc, argv, NULL, NULL, NULL, NULL, DebugInput, DebugOutput)) myexit((char*)"failed to load memory\r\n"); InvalidateRgn(hParent, NULL, true); // defines the default bot ReadMap("TOPIC/build1/map1.txt"); ReadMap("TOPIC/build0/map0.txt"); ReadSystemFunctionsMap("systemFunctions"); ReadSystemVariablesMap("systemVariables"); ReadDebugCommandsMap("debugCommands"); ReadIDECommandsMap("ideCommands"); // process break requests char* at = debugEntry; char word[MAX_WORD_SIZE]; while (*at) { char* comma = strchr(at, ','); if (comma) *comma = 0; at = ReadCompiledWord(at, word); if (*word == '*') idestop = true; else ProcessBreak(word, 0); if (comma) at = comma + 1; } UpdateWindowMetrics(scriptData); if (!server) { quitting = false; // allow local bots to continue regardless *ourMainInputBuffer = 0; if (!*loginID) { (*printer)((char*)"%s", (char*)"\r\nEnter user name: "); } } if (inputData.window) SendMessage(inputData.window, EM_SCROLLCARET, 0, 0); changingEdit = false; csThread = 0; fnlevel = -1; InvalidateRgn(scriptData.window, NULL, true); InvalidateRgn(stackData.window, NULL, true); InvalidateRgn(varData.window, NULL, true); } static void Go() { if (csThread) { ideoutputlevel = outputlevel; // for action execution of function or rule idedepth = globalDepth; // restore to normal fnvars = NULL; fnlevel = -1; DebugOutput("Resume execution\r\n"); ResumeThread((HANDLE)csThread); } } static void DiscardInput() { SendMessage(inputData.window, WM_SETTEXT, 0, (LPARAM)""); SendMessage(inputData.window, EM_SETSEL, -1, -1); FreeBuffer(); } static void RemoveBreak(char* name) { /* if (!stricmp(name, "abort")) { abortCheck = false; return; } */ char* excess = strchr(name, '@'); if (excess) *excess = 0; size_t len = strlen(name); for (int i = 0; i < breakIndex; ++i) { if (!strnicmp(name, breakAt[i], len) && (breakAt[i][len] == 0 || breakAt[i][len] == '@' || breakAt[i][len] == ' ')) { --breakIndex; for (int j = i; j < breakIndex; ++j) strcpy(breakAt[j], breakAt[j + 1]); break; } } if (!breakIndex) debugAction = NULL; if (!breakIndex && nextdepth == -1) { debugCall = NULL; } } static void RemoveVar(char* name) { size_t len = strlen(name); for (int i = 0; i < breakIndex; ++i) { if (!strnicmp(name, varAt[i], len) && varAt[i][len] == 0) { --varIndex; for (int j = i; j < varIndex; ++j) strcpy(varAt[j], varAt[j + 1]); break; } } } static int ProcessAssign(char* input) // set breakpoint { int answer = 0; char word[MAX_WORD_SIZE]; while (*input) { input = ReadCompiledWord(input, word); if (!*word) break; char* dot = strchr(word, '.'); if (dot && !FindWord(word, dot - word)) { DebugPrint("Unknown context: %s\r\n", word); continue; } if (!stricmp(word, "go")) answer = 1; else if (*word == '!') RemoveVar(word + 1); else if (!dot && *word != '$') { DebugPrint("Illegal variable: %s\r\n", word); continue; } else if (dot && (dot[1] != '$' || dot[2] != '_')) { DebugPrint("Illegal context variable: %s\r\n", word); continue; } else strcpy(varAt[varIndex++], word); } return answer; } void CheckForEnter() // on input edit scriptData.window { if (!inputData.window) return; idekey = true; // some input seen char* answer = AllocateBuffer(); char* original = answer; GetWindowText(inputData.window, answer, MAX_BUFFER_SIZE); char* at = strchr(answer, '\n'); if (!at) { FreeBuffer(); // answr is still visible for use return; // request incomplete } *at = 0; if (*(at - 1) == '\r') *--at = 0; // debugger commands char word[MAX_WORD_SIZE]; at = ReadCompiledWord(answer, word); if (!stricmp(word, ":dump")) DumpMaps(); else if (!stricmp(word, ":i") && ((*at == '@' && IsDigit(at[1])) || *at == '$' || *at == '%' || !strnicmp(at, "ja-", 3) || !strnicmp(at, "jo-", 3)) || (*at == '_' && IsDigit(at[1]))) { at = ReadCompiledWord(at, word); AddVariable(word); DiscardInput(); } else if (!stricmp(word, ":i")) { at = ReadCompiledWord(at, word); if (*word != '~' && *word != '$' && *word != '^') { MAPDATA* map = FindFileMap(word, myBot); // get map for this if (map) { FILEDATA* file = GetFile(map->filename, myBot); if (file) { currentFileData = file; scriptData.yposition = 0; } } else if (AlignName(word)); else { strcat(word, " - not found\r\n"); DebugOutput(word); } } else { MAPDATA* found = AlignName(word); if (!found) { strcat(word, " - not found\r\n"); DebugOutput(word); } } DiscardInput(); InvalidateRgn(scriptData.window, NULL, true); } else if (!stricmp(word, ":break")) { ReadCompiledWord(at, word); if (*word == '!') ++at; ProcessBreak(word, 0); AlignName(at); int line = NameLine(at); currentFileData->status[line] = (*word == '!') ? ' ' : 'B'; if (*word == '!') --breakpointCount; else ++breakpointCount; DiscardInput(); } else if (csThread) { DebugPrint("Cannot input to CS at breakpoint"); DiscardInput(); } // normal cs input else if (!csThread) { idekey = false; if (!server) // refresh prompts from a loaded bot since mainloop happens before user is loaded { WORDP dBotPrefix = FindWord((char*)"$botprompt"); strcpy(botPrefix, (dBotPrefix && dBotPrefix->w.userValue) ? dBotPrefix->w.userValue : (char*)""); WORDP dUserPrefix = FindWord((char*)"$userprompt"); strcpy(userPrefix, (dUserPrefix && dUserPrefix->w.userValue) ? dUserPrefix->w.userValue : (char*)""); } char msg[100]; sprintf(msg, "\r\n%s", userPrefix); DebugOutput(msg); DebugOutput(answer); DebugOutput("\r\n"); char prefix[MAX_WORD_SIZE]; if (*botPrefix) { sprintf(prefix, (char*)"%s ", ReviseOutput(botPrefix, prefix)); DebugOutput(prefix); } DiscardInput(); strcpy(ourMainInputBuffer, answer); csThread = _beginthread(MyWorkerThread, 0, NULL); } else if (!stricmp(word, ":go")) { DiscardInput(); Go(); // resume } } static char* DebugInput(char* input) { char* answer = NULL; if (!inputData.window) return NULL; GetWindowText(inputData.window, answer, MAX_BUFFER_SIZE); answer += editLen; // swallow the input SendMessage(inputData.window, EM_SETSEL, -1, -1); // append to output GetWindowText(inputData.window, answer, MAX_BUFFER_SIZE); editLen = strlen(answer); // we leave off here return answer; } static MAPDATA* FindRuleMap(char* topicline) // get map entry for a line if there is one (line and rule and macro and topic entries) { MAPDATA* at = currentFileData->map; while (at) { if (!stricmp(topicline, at->name)) return at; at = at->next; } return NULL; } static void AssignDepth(int depth) { CALLFRAME* frame = GetCallFrame(depth); if (!stricmp(frame->label, "ruleoutput")) frame = GetCallFrame(--depth); // for rule break info is: ~topic.n.n char topic[MAX_WORD_SIZE]; strcpy(topic, frame->label); char message[MAX_WORD_SIZE]; if (offsetCode >= 0 && codePtr) { char word[MAX_WORD_SIZE]; strncpy(word, codePtr, 40); word[40] = 0; sprintf(message, "At break: %s+%d %s\r\n", frame->label, offsetCode, word); } else sprintf(message, "At break: %s\r\n", frame->label); DebugOutput(message); offsetCode = -1; } static char* DebugRealCaller() // decide who we are currently within { for (int i = globalDepth; i > 0; --i) { CALLFRAME* frame = GetCallFrame(i); if (!*(frame->label) || !stricmp(frame->label, "ruleoutput")) continue; if (*frame->label == '^' || *frame->label == '~') return frame->label; // function, rule, or topic owner } return ""; } static void ShowSentence() { char* buffer = AllocateBuffer(); char* base = buffer; if (sentenceMode == 0) strcpy(buffer, "adjusted: "); else if (sentenceMode == 1) strcpy(buffer, "raw: "); else strcpy(buffer, "canonical: "); buffer += strlen(buffer); *buffer = 0; if (sentenceMode != 1) for (int i = 1; i <= wordCount; ++i) { if (unmarked[i]) strcpy(buffer, "***"); else if (sentenceMode == 0) strcpy(buffer, wordStarts[i]); else strcpy(buffer, wordCanonical[i]); buffer += strlen(buffer); *buffer++ = ' '; } *buffer = 0; if (sentenceMode == 1 && mainInputBuffer) strcpy(buffer, mainInputBuffer); sentenceData.maxChars = buffer - base; si.fMask = SIF_POS | SIF_RANGE; si.nPos = 0; si.nMin = 0; si.nMax = sentenceData.maxChars; SetScrollInfo(sentenceData.window, SB_HORZ, &si, true); InvalidateRgn(sentenceData.window, NULL, true); SendMessage(sentenceData.window, WM_SETTEXT, 0, (LPARAM)base); FreeBuffer(buffer); } static void Wait() { ClearStops(); StatData(); fnlevel = globalDepth; char msg[MAX_WORD_SIZE]; sprintf(msg, "callstack depth: %d level:%d", globalDepth, outputlevel); SendMessage(stackData.window, WM_SETTEXT, 0, (LPARAM)msg); idedepth = globalDepth; fnvars = NULL; // drop back to globals WhereAmI(globalDepth); sentenceMode = 0; ShowSentence(); char junk[100]; DoneCallback(junk); ShowStack(); if (!breakIndex && nextdepth == -1 && outdepth == -1) debugCall = NULL; FreeClicklist(); // engine thread suspends itself now SuspendThread((HANDLE)csThread); } static char* DebugVar(char* name, char* value) // incoming variable assigns from engine { if (loadingUser) return NULL; if (!value) value = ""; size_t len = strlen(name); char id[MAX_WORD_SIZE]; strcpy(id, name); char* jsondot = strchr(id, '.'); if (jsondot) *jsondot = 0; // use raw but list change full char* jsonbrakcet = strchr(id, '['); if (jsonbrakcet) *jsonbrakcet = 0; // use raw but list change full strcat(id, "\r\n"); if (idestop || strstr(varbreaknames, id)) { char val[120]; len = strlen(value); if (len > 100) { strncpy(val, value, 100); strcpy(val + 100, "..."); } else strcpy(val, value); DebugPrint("Var Break %s = %s\r\n", name, val); InvalidateRgn(varData.window, NULL, true); // assignment happens from code (we cant see locals) trace = 0; breakType = BREAK_VAR; Wait(); } return NULL; } char* DebugCall(char* name, bool in) { bool stop = false; int i; int depth = globalDepth + 1; // if inside () dont react CALLFRAME* frame; while (--depth) // see if system function inside of some other arg processing { frame = GetCallFrame(depth); if (strchr(frame->label, '(')) { return NULL; // not stop in arg processing } if (strchr(frame->label, '{') && frame->code) { break; // legal to be here if not sys function } } depth = globalDepth; frame = GetCallFrame(globalDepth); char* paren = strchr(frame->label, '('); if (*frame->label == '~' && paren) ++rulesExecuted; // get raw label char label[500]; strcpy(label, frame->label); char* at = strchr(label, '('); if (at) *at = 0; at = strchr(label, '{'); if (at) *at = 0; if (paren && *frame->label == '^') return NULL; // no argument processing if (paren && !strstr(frame->label, "if")) return NULL; // no argument processing if (paren && !strstr(frame->label, "loop")) return NULL; // no argument processing if (sysfail && *name == '^' && !frame->code && frame->x.result & FAILCODES && stricmp(name, "^fail")) { stop = true; DebugPrint("Break failing system call %s\r\n", name); } else if (strchr(frame->label, '{') && globalDepth == outdepth) { return NULL; // we want to step over but this is in } else if (globalDepth < outdepth) // returned before, stop somewhere { stop = true; } else if (!csThread || !in) return NULL; else if (globalDepth <= nextdepth) stop = true; else if (!stricmp(name, "Loop{}") || !strncmp(name, "If", 2)) { if (StopIntended()) idestop = true; // stop in or out if we are to stop at all return NULL; } else if (strchr(name, '{') && strchr(name, '.') && idestop) { return NULL; // wait for action to trigger now. } else if (idestop) stop = true;// stop button or startup request // stop because breakpoint else for (i = 0; i < breakIndex; ++i) { if (!stricmp(label, breakAt[i]) || !stricmp(label, transientBreak)) { if (*name == '~') DebugPrint("Entering %s depth %d in %s mode\r\n", name, globalDepth, howTopic); else DebugPrint("Break entering %s(%d)\r\n", name, globalDepth); stop = true; break; } } if (!stop || !in) return NULL; breakType = BREAK_CALL; *transientBreak = 0; trace = 0; Wait(); // and is awakened by someone else return NULL; } CALLFRAME* GetCodeOwnerFrame(int depth) { CALLFRAME* ownerFrame = NULL; // find function or rule or topic owner ++depth; while (--depth > 0) { ownerFrame = GetCallFrame(depth); // LOOP and IF dont own their code if (*ownerFrame->label == '^' && ownerFrame->code) break; else if (*ownerFrame->label == '^') break; // system functions must continue to backtrack to find an owner else if (*ownerFrame->label == '~') break; // topic or rule owns what happens } return ownerFrame; } // Find where we are for script window display #ifdef INFORMATION Possible callframes are : ~topic - a topic ~topic.n.n1() - a rule at pattern evaluation ~topic.n.n1{} - a rule executing its code ^ function() - a function at argument evaluation ^ function{} - a user function executing its code ^ if () - a code if at condition evaluation ^ if{} - a code if executing its code ^ loop() - a code loop at loop count evaluation ^ loop{} - a loop executing its code -- - Code can be associated with a rule or a function. In such cases, we have entered the code when the outputlevel of the frame is less or equal to current outputlevel. #endif static bool WhereAmI(int depth) { // find offset in file of current CALLFRAME* actualFrame = GetCallFrame(depth); CALLFRAME* ownerFrame = GetCodeOwnerFrame(depth); char* codebase = ownerFrame->code; if (ownerFrame) // found owner level, now find display map entry { MAPDATA* map = AlignName(ownerFrame->label); // bring up the file/line of the named owner frame if (map && codebase && outputlevel >= ownerFrame->outputlevel) // found map and its in code itself { char* actualCode = outputCode[outputlevel]; // where it is executing now int offset = actualCode - codebase; int index; while (map) // now deal with offset within the owner { map = map->next; if (!IsDigit(map->name[0])) { if (!strnicmp(map->name, "if", 2)) {} else if (!strnicmp(map->name, "loop", 4)) {} else break; // end of line data } index = atoi(map->name); if (index >= offset) { codePtr = actualCode; codeFile = currentFileData; mouseLine = map->fileline; codeLine = mouseLine; // where are we if (mouseLine > (scriptData.yposition + 1 + scriptData.linesPerPage)) scriptData.yposition = mouseLine - 3; // start with item showing in context else if (mouseLine < scriptData.yposition + 1) scriptData.yposition = mouseLine - 3; // start with item showing in context offsetCode = offset; char* src = ShowActions(actualCode, ownerFrame->outputlevel); char name[MAX_WORD_SIZE]; strcpy(name, ownerFrame->label); char* at = strchr(name, '{'); if (at) *at = 0; DebugPrint("Code Break at %s:%d %s \r\n", name, offset, src); return true; } } } else { AssignDepth(depth); // change script window codeLine = mouseLine; // where are we codeFile = currentFileData; codePtr = NULL; } } InvalidateRgn(scriptData.window, NULL, true); return false; } static char* DebugAction(char* ptr) { if (*ptr == '}') return NULL; // just a closing marker bool stop = false; int depth = globalDepth + 1; // if inside () dont react CALLFRAME* frame; while (--depth) { frame = GetCallFrame(depth); if (strchr(frame->label, '(')) { return NULL; // not stop in arg processing } if (strchr(frame->label, '{')) break; // legal to be here } frame = GetCallFrame(globalDepth); // cant stop in argument processing, only in expected level of call stack if (outputlevel != frame->outputlevel) return NULL; if (!stricmp(frame->label, "ruleoutput") && frame->code == ptr) return NULL; // we caught this already in DebugCall else if (*ptr == '`') return NULL; // end of rule else if (outputlevel > frame->outputlevel) return NULL; // in argument processing else if (outputlevel < outlevel) // stop when you go out { stop = true; } else if (outputlevel <= nextlevel || idestop) stop = true; // triggered step in or next or out else { // find offset in file of current CALLFRAME* ownerFrame = GetCodeOwnerFrame(globalDepth); if (!ownerFrame) return NULL; char* codebase = ownerFrame->code; if (ownerFrame && codebase && ownerFrame->name) // found owner level, now find display map entry { char label[MAX_WORD_SIZE]; sprintf(label, "%s:%d", ownerFrame->name->word, (ptr - codebase)); for (int i = 0; i < breakIndex; ++i) { if (!stricmp(label, breakAt[i]) || !stricmp(label, transientBreak)) { if (*label == '~') DebugPrint("Entering %s\r\n", label); else DebugPrint("Break entering %s(%d)\r\n", label, globalDepth); stop = true; break; } } } } if (stop) { breakType = BREAK_ACTION; trace = 0; Wait(); // WhereAmI sets where we are } return NULL; } static int ProcessBreak(char* input, int flags) // set breakpoint { int answer = 0; char word[MAX_WORD_SIZE]; while (*input) { input = ReadCompiledWord(input, word); char* dot = strchr(word, '.'); char* colon = strchr(word, ':'); if (!*word) break; if (!stricmp(word, "go")) answer = 1; // continue else if (*word == '!' && word[1] == '^' && !dot) RemoveBreak(word + 1); // remove this one else if (*word == '!' && word[1] == '~' && !strchr(word, '.')) RemoveBreak(word + 1); // remove this one else if (*word == '!' && word[1] == '~' && dot && dot[1] != '$') RemoveBreak(word + 1); // remove this one else if (*word == '!' && word[1] == '~' && dot && dot[1] == '$') RemoveVar(word + 1); // remove this one else if (*word == '!' && word[1] == '^' && dot && dot[1] == '$') RemoveVar(word + 1); // remove this one else if (*word == '^' && dot && dot[1] == '$') ProcessAssign(word); else if (*word == '~' && dot && dot[1] == '$') ProcessAssign(word); else if (!FindWord(word) && !dot && !colon) DebugPrint(" Cannot find %s\r\n", word); else { if (colon) debugAction = DebugAction; char base[MAX_WORD_SIZE]; strcpy(base, word); char* at = strchr(base, '@'); if (at) *at = 0; size_t len = strlen(base); int j; for (j = 0; j < breakIndex; ++j) // replacing? { if (!strnicmp(breakAt[j], word, len) && (breakAt[j][len] == 0 || breakAt[j][len] == '@')) { strcpy(breakAt[j], word); break; } } if (flags) strcpy(transientBreak, word); if (j == breakIndex) strcpy(breakAt[breakIndex++], word); // new one } } if (breakIndex) debugCall = DebugCall; return answer; } char* DebugMessage(char* output) { char* buf = AllocateBuffer(); strcpy(buf, "UserOutput: "); strcat(buf, output); DebugOutput("Message break: "); DebugOutput(output); DebugOutput("\r\n"); FreeBuffer(); Wait(); return NULL; } HWND MakeButton(char* name, int x, int y, int width, int height, long extra = 0) { HWND window = CreateWindow( (LPCSTR)szWindowClass, // Predefined class; Unicode assumed (LPCSTR)name, // Button text WS_VISIBLE | WS_CHILDWINDOW | extra, x, y, width, height, hParent, nullptr, hInst, nullptr); MoveWindow(window, x, y, width, height, true); return window; } BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { *filenames = 0; ClearStops(); *varnames = *varbreaknames = 0; memset(varAt, 0, sizeof(varAt)); memset(breakAt, 0, sizeof(breakAt)); breakIndex = 0; ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); myBot = 0; hInst = hInstance; changingEdit = true; debugCall = DebugCall; debugEndTurn = DoneCallback; *filenames = 0; filenames[1] = 0; *varnames = 0; hParent = CreateWindow(szWindowClass, szTitle, WS_VISIBLE | WS_OVERLAPPEDWINDOW | WS_MAXIMIZE | WS_SIZEBOX, 0, 0, 0, 0, nullptr, nullptr, hInstance, nullptr); if (!hParent) return FALSE; RECT mrect; mrect.left = 100; mrect.right = 3000; mrect.top = 100; mrect.bottom = 2050; MoveWindow(hParent, 0, 0, mrect.right, mrect.bottom, true); hPen = CreatePen(PS_SOLID, 5, RGB(0, 0, 0)); hBrush = CreateSolidBrush(RGB(0, 0, 0)); hBrushBlue = CreateSolidBrush(RGB(0, 0, 255)); //https://yuilibrary.com/yui/docs/color/rgb-slider.html hBrushOrange = CreateSolidBrush(RGB(2555, 165, 0)); hFont = CreateFont(fontsize, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, TEXT("Courier New")); hFontBigger = CreateFont(fontsize + 10, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, TEXT("Courier New")); hButtonFont = hFont; hGoButton = MakeButton("Go", 10, 10, 100, 50); hInButton = MakeButton("In", 110, 10, 100, 50); hOutButton = MakeButton("Out", 210, 10, 100, 50); hNextButton = MakeButton("Next", 310, 10, 100, 50); hStopButton = MakeButton("Stop", 510, 10, 100, 50); hBreakMessageButton = MakeButton("Msg", 610, 10, 100, 50); hFailButton = MakeButton("Fail", 710, 10, 100, 50); hClearButton = MakeButton("Clear", 810, 10, 100, 50); hLocalsButton = MakeButton("Global", 1010, 10, 100, 50); hBackButton = MakeButton("Back", 1210, 10, 100, 50); hFontButton = MakeButton("-Font+", 1510, 10, 100, 50); ide = true; // we have ide attached to cs idestop = false; // source text fits in this rect of scriptwindow scriptData.rect.left = 10; scriptData.rect.right = scriptData.rect.left + 1800; scriptData.rect.top = 160; scriptData.rect.bottom = scriptData.rect.top + 1700; scriptData.window = CreateWindow(szWindowClass, (LPCSTR)"script", WS_VISIBLE | WS_CHILDWINDOW | WS_HSCROLL | WS_VSCROLL | WS_CAPTION | WS_BORDER | WS_SIZEBOX, 0, 0, 0, 0, hParent, nullptr, hInstance, nullptr); if (!scriptData.window) return FALSE; scriptData.window = scriptData.window; MoveWindow(scriptData.window, scriptData.rect.left, scriptData.rect.top, scriptData.rect.right - scriptData.rect.left, scriptData.rect.bottom - scriptData.rect.top, true); ShowWindow(scriptData.window, SW_SHOW); UpdateWindow(scriptData.window); UpdateWindowMetrics(scriptData); // output from cs outputData.rect.top = scriptData.rect.top; outputData.rect.left = scriptData.rect.right + 40; outputData.rect.right = outputData.rect.left + 1000; outputData.rect.bottom = (scriptData.rect.bottom - scriptData.rect.top) / 2; outputData.window = CreateWindow( "EDIT", (LPCSTR)"output", ES_READONLY | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | WS_BORDER | WS_SIZEBOX | WS_CAPTION | ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL, 0, 0, 0, 0, hParent, (HMENU)ID_EDITCHILD, (HINSTANCE)GetWindowLong(scriptData.window, GWL_HINSTANCE), NULL); // pointer not needed SendMessage(outputData.window, WM_SETTEXT, 0, (LPARAM)""); SendMessage(outputData.window, WM_SETFONT, (WPARAM)hFont, false); SendMessage(outputData.window, EM_SETSEL, -1, -1); MoveWindow(outputData.window, outputData.rect.left, outputData.rect.top, // starting x- and y-coordinates outputData.rect.right - outputData.rect.left, // width of client area outputData.rect.bottom - outputData.rect.top, // height of client area TRUE); ShowWindow(outputData.window, SW_SHOW); UpdateWindow(outputData.window); UpdateWindowMetrics(outputData); // output from cs statData.rect.top = scriptData.rect.bottom + 10; statData.rect.left = scriptData.rect.left; statData.rect.right = outputData.rect.right; statData.rect.bottom = statData.rect.top + 72; statData.window = CreateWindow( "EDIT", (LPCSTR)"stats", ES_READONLY | WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_SIZEBOX | ES_LEFT | ES_AUTOHSCROLL, 0, 0, 0, 0, hParent, (HMENU)ID_EDITCHILD, (HINSTANCE)GetWindowLong(statData.window, GWL_HINSTANCE), NULL); // pointer not needed SendMessage(statData.window, WM_SETTEXT, 0, (LPARAM)""); SendMessage(statData.window, WM_SETFONT, (WPARAM)hFont, false); SendMessage(statData.window, EM_SETSEL, -1, -1); MoveWindow(statData.window, statData.rect.left, statData.rect.top, // starting x- and y-coordinates statData.rect.right - statData.rect.left, // width of client area statData.rect.bottom - statData.rect.top, // height of client area TRUE); ShowWindow(statData.window, SW_SHOW); UpdateWindow(statData.window); UpdateWindowMetrics(statData); sentenceData.window = MakeButton("sentence", 20, 70, outputData.rect.right - scriptData.rect.left, 80, WS_HSCROLL); inputData.rect = outputData.rect; inputData.rect.top = outputData.rect.bottom + 20; inputData.rect.bottom = inputData.rect.top + 150; inputData.window = CreateWindow( "EDIT", (LPCSTR)"cs input", WS_BORDER | WS_SIZEBOX // | WS_CAPTION -- with this we lose edit dataentry | ES_MULTILINE | WS_VSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | ES_WANTRETURN | ES_LEFT, // | WS_CAPTION 0, 0, 0, 0, hParent, // parent window (HMENU)ID_EDITCHILD1, // edit control ID (HINSTANCE)GetWindowLong(hParent, GWL_HINSTANCE), NULL); // pointer not needed MoveWindow(inputData.window, inputData.rect.left, inputData.rect.top, // starting x- and y-coordinates inputData.rect.right - inputData.rect.left, // width of client area inputData.rect.bottom - inputData.rect.top, // height of client area TRUE); SendMessage(inputData.window, WM_SETTEXT, 0, (LPARAM)""); SendMessage(inputData.window, WM_SETFONT, (WPARAM)hFont, false); SendMessage(inputData.window, EM_SETSEL, -1, -1); ShowWindow(inputData.window, SW_SHOW); UpdateWindow(inputData.window); UpdateWindowMetrics(inputData); varData.window = CreateWindow( szWindowClass, (LPCSTR)"global variables", WS_VISIBLE | WS_CHILDWINDOW | WS_HSCROLL | WS_VSCROLL | WS_CAPTION | WS_BORDER | WS_SIZEBOX, 0, 0, 0, 0, hParent, 0, (HINSTANCE)GetWindowLong(scriptData.window, GWL_HINSTANCE), NULL); // pointer not needed varData.rect = inputData.rect; varData.rect.top = inputData.rect.bottom + 10; varData.rect.bottom = (scriptData.rect.bottom - 400); MoveWindow(varData.window, varData.rect.left, varData.rect.top, // starting x- and y-coordinates varData.rect.right - varData.rect.left, // width of client area varData.rect.bottom - varData.rect.top, // height of client area TRUE); ShowWindow(varData.window, SW_SHOW); UpdateWindow(varData.window); UpdateWindowMetrics(varData); stackData.window = CreateWindow( szWindowClass, (LPCSTR)"callstack", WS_VISIBLE | WS_CHILDWINDOW | WS_HSCROLL | WS_VSCROLL | WS_CAPTION | WS_BORDER | WS_SIZEBOX, 0, 0, 0, 0, hParent, 0, (HINSTANCE)GetWindowLong(scriptData.window, GWL_HINSTANCE), NULL); // pointer not needed stackData.rect = varData.rect; stackData.rect.top = varData.rect.bottom + 10; stackData.rect.bottom = scriptData.rect.bottom; MoveWindow(stackData.window, stackData.rect.left, stackData.rect.top, stackData.rect.right - stackData.rect.left, stackData.rect.bottom - stackData.rect.top, true); GetClientRect(stackData.window, &stackData.rect); ShowWindow(stackData.window, SW_SHOW); UpdateWindow(stackData.window); UpdateWindowMetrics(stackData); UpdateWindowMetrics(sentenceData, true); //RestoreWindows(); // rects have been set up now, get local coords GetClientRect(scriptData.window, &scriptData.rect); GetClientRect(varData.window, &varData.rect); GetClientRect(stackData.window, &stackData.rect); // assign title space titlerect = scriptData.rect; titlerect.bottom = titlerect.top + scriptData.metrics.cy; titlerect.right = scriptData.rect.right; scriptData.rect.top += scriptData.metrics.cy; scriptData.maxLines -= 2; // associated subdivisions of script window tagrect = scriptData.rect; tagrect.left = 5; tagrect.right = scriptData.metrics.cx * 5; numrect = scriptData.rect; numrect.left = tagrect.right + 10; numrect.right = numrect.left + (scriptData.metrics.cx * 5); scriptData.rect.left = numrect.right + 30; // leave room StatData(); //hDialog = CreateDialog(NULL, MAKEINTRESOURCE(IDD_DIALOG1), hParent, ModelessWindow); CreateWindowA("EDIT", NULL, WS_BORDER | WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL, 0, 100, 200, 200, scriptData.window, (HMENU)NULL, (HINSTANCE)GetWindowLongPtr(scriptData.window, GWLP_HINSTANCE), NULL); printer = myprintf; csThread = _beginthread(MyWorkerInitThread, 0, NULL); return TRUE; } static MAPDATA* FindMapLine(int line) // get map entry for a line if there is one (line and rule and macro and topic entries) { MAPDATA* at = currentFileData->map; priorMapLine = at; while (at) { if (!strnicmp(at->name, "if", 2)) {} else if (!strnicmp(at->name, "loop", 4)) {} else if (at->fileline >= line) break; // going to farr // record base of any offset for action if (*at->name == '~' || *at->name == '^') priorMapLine = at; at = at->next; } if (at && at->fileline == line) return at; return NULL; } static void ShowConcepts(int i) { char word[MAX_WORD_SIZE]; sprintf(word, "%s: --------\r\n", wordStarts[i]); DebugOutput(word); DebugConcepts(concepts[i], i); DebugConcepts(topics[i], i); } static void ChangeCodePtr(int line) { MAPDATA* map = FindMapLine(line); // look this up CALLFRAME* frame = GetCallFrame(idedepth); if (!map) return; if (IsDigit(*map->name)) // want a line number (action), not a rule { codeOffset = atoi(map->name); if (frame->code) { char* code = frame->code + codeOffset; outputCode[frame->outputlevel] = code; if (idedepth == globalDepth) codeLine = line; InvalidateRgn(stackData.window, NULL, true); InvalidateRgn(scriptData.window, NULL, true); return; } } DebugOutput("Can only move around in actions, not in rules\r\n"); } static void SetBreakpoint(int line, int flags) { MAPDATA* map = FindMapLine(line); // look this up // temp block action lines if (map && IsDigit(*map->name)) codeOffset = atoi(map->name); else codeOffset = 0; if (map) // clicked on this line within priorMapLine { char loc[MAX_WORD_SIZE]; *loc = 0; // for lines within a macro or topic/rule if (*map->name != '^' && *map->name != '~') { strcpy(loc, priorMapLine->name); // rule tag OR code offset in script off macro or rule strcat(loc, ":"); } strcat(loc, map->name); // either a duplicate of name OR an offset if (currentFileData->status[line] == ' ') // enable { currentFileData->status[line] = 'B'; ++breakpointCount; } else // disable back to normal { memcpy(loc + 1, loc, strlen(loc) + 1); *loc = '!'; currentFileData->status[line] = ' '; --breakpointCount; } ProcessBreak(loc, flags); // engine request ide &= -1 ^ HAS_BREAKPOINTS; if (breakpointCount) ide |= HAS_BREAKPOINTS; InvalidateRgn(scriptData.window, NULL, true); } } #define ID_EDITCHILD 100 #define IDM_EDUNDO 1101 #define IDM_EDCUT 1102 #define IDM_EDCOPY 1103 #define IDM_EDPASTE 1104 #define IDM_EDDEL 1105 bool tesxt = false; LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { RECT rect; GetClientRect(hWnd, &rect); WINDOWSTRUCT* data; if (hWnd == scriptData.window) data = &scriptData; else if (hWnd == outputData.window) data = &outputData; else if (hWnd == statData.window) data = &statData; else if (hWnd == stackData.window) data = &stackData; else if (hWnd == varData.window) data = &varData; else if (hWnd == inputData.window) data = &inputData; else if (hWnd == sentenceData.window) data = &sentenceData; else if (hWnd == hDialog) { data = &inputData; } switch (message) { case WM_CREATE: return 0; case WM_SETFOCUS: SetFocus(hWnd); return 0; case WM_HSCROLL: switch (LOWORD(wParam)) { case SB_THUMBTRACK: { si.fMask = SIF_PAGE | SIF_TRACKPOS | SIF_RANGE | SIF_POS; if (!GetScrollInfo(hWnd, SB_HORZ, &si)) return 1; // GetScrollInfo failed data->xposition = si.nTrackPos; si.fMask = SIF_POS; si.nPos = si.nTrackPos; SetScrollInfo(hWnd, SB_HORZ, &si, true); break; } case SB_LINELEFT: if (data->xposition == 0) return 0; --data->xposition; if (data->xposition < 0) data->xposition = 0; si.fMask = SIF_POS; si.nPos = data->xposition; SetScrollInfo(hWnd, SB_HORZ, &si, true); break; case SB_PAGELEFT: if (data->xposition == 0) return 0; data->xposition -= data->maxChars - 10; // keep some context if (data->xposition < 0) data->xposition = 0; si.fMask = SIF_POS; si.nPos = data->xposition; SetScrollInfo(hWnd, SB_HORZ, &si, true); break; case SB_LINERIGHT: ++data->xposition; if (data->xposition > data->maxChars - data->charsPerPage) data->xposition = data->maxChars - data->charsPerPage; si.nPos = data->xposition; si.fMask = SIF_POS; si.nPos = data->xposition; SetScrollInfo(hWnd, SB_HORZ, &si, true); break; case SB_PAGERIGHT: data->xposition += data->maxChars - 10; // keep some context if (data->xposition > data->maxChars - data->charsPerPage) data->xposition = data->maxChars - data->charsPerPage; si.nPos = data->xposition; si.fMask = SIF_POS; si.nPos = data->xposition; SetScrollInfo(hWnd, SB_HORZ, &si, true); break; } InvalidateRgn(hWnd, NULL, true); return 0; case WM_MOUSEMOVE: { int x = LOWORD(lParam); int y = HIWORD(lParam); } break; case WM_VSCROLL: switch (LOWORD(wParam)) { case SB_THUMBTRACK: { si.fMask = SIF_PAGE | SIF_TRACKPOS | SIF_RANGE | SIF_POS; if (!GetScrollInfo(hWnd, SB_VERT, &si)) return 1; // GetScrollInfo failed data->yposition = si.nTrackPos; si.nPos = si.nTrackPos; si.fMask = SIF_POS; SetScrollInfo(hWnd, SB_VERT, &si, true); break; } case SB_PAGEUP: if (data->yposition == 0) return 0; data->yposition -= data->linesPerPage - 3; // keep some context if (data->yposition < 0) data->yposition = 0; si.nPos = data->yposition; si.fMask = SIF_POS; SetScrollInfo(hWnd, SB_VERT, &si, true); break; case SB_LINEUP: if (data->yposition == 0) return 0; --data->yposition; si.nPos = data->yposition; si.fMask = SIF_POS; SetScrollInfo(hWnd, SB_VERT, &si, true); break; case SB_PAGEDOWN: if (data->yposition == (data->maxLines - data->linesPerPage)) return 0; data->yposition += data->maxLines - 3; // keep some context if (data->yposition > data->maxLines - data->linesPerPage) data->yposition = data->maxLines - data->linesPerPage; si.nPos = data->yposition; si.fMask = SIF_POS; SetScrollInfo(hWnd, SB_VERT, &si, true); break; case SB_LINEDOWN: ++data->yposition; if (data->yposition > data->maxLines - data->linesPerPage) data->yposition = data->maxLines - data->linesPerPage; si.nPos = data->yposition; si.fMask = SIF_POS; SetScrollInfo(hWnd, SB_VERT, &si, true); break; } InvalidateRgn(hWnd, NULL, true); return 0; case WM_KEYDOWN: // normal ascii characters in wParam if (wParam == VK_DOWN) // down { ++scriptData.yposition; if (scriptData.yposition >= currentFileData->lineCount) scriptData.yposition = currentFileData->lineCount - 1; si.fMask = SIF_POS; si.nPos = scriptData.yposition; SetScrollInfo(hWnd, SB_VERT, &si, true); InvalidateRgn(hWnd, NULL, true); } else if (wParam == VK_UP) // up { --scriptData.yposition; if (scriptData.yposition < 0) scriptData.yposition = 0; si.fMask = SIF_POS; si.nPos = scriptData.yposition; SetScrollInfo(hWnd, SB_VERT, &si, true); InvalidateRgn(hWnd, NULL, true); } else if (wParam == VK_RIGHT) // right { ++scriptData.xposition; if (scriptData.xposition > currentFileData->charsize - scriptData.maxChars) scriptData.xposition = currentFileData->charsize - scriptData.maxChars; si.nPos = scriptData.xposition; si.fMask = SIF_POS; si.nPos = scriptData.xposition; SetScrollInfo(hWnd, SB_HORZ, &si, true); InvalidateRgn(hWnd, NULL, true); } else if (wParam == VK_LEFT) // left { --scriptData.xposition; if (scriptData.xposition < 0) scriptData.xposition = 0; si.fMask = SIF_POS; si.nPos = scriptData.xposition; SetScrollInfo(hWnd, SB_HORZ, &si, true); InvalidateRgn(hWnd, NULL, true); } return 0; case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: // jump to function or concept or topic { char word[MAX_WORD_SIZE]; GetWindowText(hWnd, word, MAX_WORD_SIZE); int xPos = GET_X_LPARAM(lParam); int yPos = GET_Y_LPARAM(lParam); if (hWnd == scriptData.window) { if (xPos >= scriptData.rect.left && xPos <= scriptData.rect.right && yPos >= scriptData.rect.top && yPos <= scriptData.rect.bottom) { xPos -= scriptData.rect.left; xPos /= scriptData.metrics.cx; // avg size xPos += scriptData.xposition; mouseCharacter = xPos; // we pointed to this character yPos -= scriptData.rect.top; // where in text area? yPos /= scriptData.metrics.cy; // how many scriptData.maxLines in yPos += scriptData.yposition; // where is actual start of line ++yPos; // our 0 is file line 1 in map mouseLine = yPos; // this is the line we clicked on // find word referenced by click FindClickWord(mouseCharacter, mouseLine); } else if (xPos >= tagrect.left && xPos <= numrect.right && yPos >= scriptData.rect.top && yPos <= scriptData.rect.bottom) { // title list is outside of scriptData, so Line 1 of file == click on 0 of here yPos -= scriptData.rect.top; // where in text area? yPos /= scriptData.metrics.cy; // how many scriptData.maxLines in yPos += scriptData.yposition; // where is actual start of line ++yPos; // our 0 is file line 1 in map mouseLine = yPos; // this is the file line# we clicked on if (message == WM_LBUTTONDOWN && wParam & MK_CONTROL) { ChangeCodePtr(yPos); } else if (message == WM_LBUTTONDOWN) SetBreakpoint(mouseLine, false); // simple break else // runto { SetBreakpoint(mouseLine, true); Go(); } } else if (xPos >= titlerect.left && xPos <= titlerect.right && yPos >= titlerect.top && yPos <= titlerect.bottom) { xPos -= titlerect.left; xPos /= scriptData.metrics.cx; // avg size xPos += scriptData.xposition; // point to this character size_t len = strlen(filenames); while (IsLegalNameCharacter(filenames[xPos])) --xPos; ++xPos; char name[MAX_WORD_SIZE]; ReadCompiledWord(filenames + xPos, name); len = strlen(name); while (!IsLegalNameCharacter(name[len])) --len; name[len + 1] = 0; if (message == WM_LBUTTONDOWN) AlignName(name); else RemoveTab(name); } else { mouseCharacter = -1; mouseLine = -1; } } else if (hWnd == sentenceData.window) { if (message == WM_LBUTTONDOWN) { if (++sentenceMode > 2) sentenceMode = 0; ShowSentence(); } else { xPos -= sentenceData.rect.left + 10; xPos /= sentenceData.metrics.cx; // avg size xPos += sentenceData.xposition; char* buffer = AllocateBuffer(); GetWindowText(sentenceData.window, buffer, MAX_BUFFER_SIZE); char* in = buffer + xPos; int wordIndex = -1; for (int i = 0; i < xPos; ++i) { if (buffer[i] == ' ') ++wordIndex; } FreeBuffer(); ShowConcepts(wordIndex); } } else if (hWnd == varData.window) { xPos -= varData.rect.left; xPos /= varData.metrics.cx; xPos += varData.xposition; yPos -= varData.rect.top; // where in text area? yPos /= varData.metrics.cy; // how many scriptData.maxLines in yPos += varData.yposition; // where is actual start of line if (xPos > 2) { if (!fnvars) EraseVariable(yPos); // remove this } else DoBreakVariable(yPos); InvalidateRgn(varData.window, NULL, true); } else if (hWnd == stackData.window) { yPos -= stackData.rect.top; // where in text area? yPos /= stackData.metrics.cy; // how many scriptData.maxLines in yPos += stackData.yposition; // where is actual start of line yPos += 1; // stack starts at 1 if (yPos > globalDepth || yPos <= 0) break; // ignore bad values StackVariables(yPos); idedepth = yPos; sprintf(windowTitle, "%s Depth: %d/%d", GetCallFrame(idedepth)->label, idedepth, globalDepth); SetWindowText(stackData.window, (LPCTSTR)windowTitle); WhereAmI(yPos); InvalidateRgn(varData.window, NULL, true); InvalidateRgn(stackData.window, NULL, true); } else if (hWnd == hGoButton) { outdepth = outlevel = -1; nextdepth = nextlevel = -1; if (message == WM_LBUTTONDOWN) trace = 0; else { trace = -1; echo = true; } Go(); } else if (hWnd == hClearButton) { ClearAllBreakpoints(); } else if (hWnd == hFailButton) { if (message == WM_LBUTTONDOWN) sysfail = true; else sysfail = false; } else if (hWnd == hFontButton) { if (message == WM_LBUTTONDOWN) // smaller { if (fontsize <= 10) break; fontsize -= 10; hFont = CreateFont(fontsize, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, TEXT("Courier New")); } else // bigger { if (fontsize >= 80) break; fontsize += 10; hFont = CreateFont(fontsize, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, TEXT("Courier New")); } SendMessage(outputData.window, WM_SETFONT, (WPARAM)hFont, false); SendMessage(scriptData.window, WM_SETFONT, (WPARAM)hFont, false); SendMessage(varData.window, WM_SETFONT, (WPARAM)hFont, false); SendMessage(stackData.window, WM_SETFONT, (WPARAM)hFont, false); UpdateMetrics(); } else if (hWnd == hStopButton) { debugCall = DebugCall; idestop = true; DebugOutput("stop set\r\n"); } else if (hWnd == hNextButton) { // next is over or out outlevel = outputlevel; outdepth = globalDepth; // out can be next nextdepth = globalDepth; nextlevel = outputlevel; debugCall = DebugCall; debugAction = DebugAction; if (message == WM_LBUTTONDOWN) trace = 0; else { trace = idetrace; } Go(); } else if (hWnd == hInButton) { // IN means stop as soon as you can debugAction = DebugAction; debugCall = DebugCall; idestop = true; // break anywhere in or over or out if (message == WM_LBUTTONDOWN) trace = 0; else { trace = idetrace; } Go(); } else if (hWnd == hOutButton) { if (message == WM_LBUTTONDOWN) trace = 0; else { trace = idetrace; } // OUT means leave either current action level or call depth and // stop as soon as possible thereafter outlevel = outputlevel; outdepth = globalDepth; debugCall = DebugCall; Go(); } else if (hWnd == hBreakMessageButton) { if (message != WM_LBUTTONDOWN) { debugMessage = NULL; DebugOutput("Message break turned off\r\n"); } else { debugMessage = DebugMessage; DebugOutput("Message break turned on\r\n"); } } else if (hWnd == hLocalsButton) { fnvars = NULL; // back to globals fnlevel = -1; SetWindowText(varData.window, "global variables"); } else if (hWnd == hBackButton) { RestoreClick(); } } return 0; case WM_EXITSIZEMOVE: SaveWindows(); break; case WM_COMMAND: { int wmId = LOWORD(wParam); int val = HIWORD(wParam); switch (val) { case BN_CLICKED: break; case EN_CHANGE: if (lParam == (LPARAM)inputData.window && !changingEdit) { CheckForEnter(); } break; } switch (wmId) { case IDM_EDUNDO: // Send WM_UNDO only if there is something to be undone. if (SendMessage(hWnd, EM_CANUNDO, 0, 0)) SendMessage(hWnd, WM_UNDO, 0, 0); else { MessageBox(hWnd, (LPCSTR)"Nothing to undo.", (LPCSTR)"Undo notification", MB_OK); } break; case IDM_EDCUT: SendMessage(hWnd, WM_CUT, 0, 0); break; case IDM_EDCOPY: SendMessage(hWnd, WM_COPY, 0, 0); break; case IDM_EDPASTE: SendMessage(hWnd, WM_PASTE, 0, 0); break; case IDM_EDDEL: SendMessage(hWnd, WM_CLEAR, 0, 0); break; case IDM_ABOUT: { int bufferLen = GetWindowTextLength(hWnd) + 1; // why send the message twice? //string data(bufferLen, '\0'); //GetWindowText(hWnd, (LPCSTR)data, bufferLen); // DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); FILE* in = fopen("test.txt", "rb"); if (in) { fseek(in, 0, SEEK_END); // non-portable int size = ftell(in); fseek(in, 0, SEEK_SET); // non-portable char* msg = (char*)malloc(size + 4); fread(msg, 1, size, in); fclose(in); SendMessage(hWnd, WM_SETTEXT, 0, (LPARAM)msg); } } break; case IDM_EXIT: DestroyWindow(hWnd); break; case WM_KEYDOWN: if (hWnd == hWnd) { if (val == VK_DOWN) { int xx = 0; } } default: return DefWindowProc(hWnd, message, wParam, lParam); } } break; case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); RECT rect; GetClientRect(hWnd, &rect); RECT breakrect; breakrect = rect; rect.left += 3 * varData.metrics.cx; SelectObject(hdc, hFont); SetTextColor(hdc, RGB(0, 0, 0)); // black text SetBkColor(hdc, RGB(255, 255, 255)); // white background if (hWnd == hDialog) { char msg[MAX_WORD_SIZE]; char myvars[MAX_WORD_SIZE]; DrawText(hdc, (LPCSTR)"this is my message and love it", -1, &rect, DT_LEFT | DT_TOP); EndPaint(hWnd, &ps); break; } if (hWnd == varData.window) { char msg[MAX_WORD_SIZE]; char myvars[MAX_WORD_SIZE]; strcpy(myvars, varnames); char* var = myvars; int d = fnlevel; CALLFRAME* frame = GetCallFrame(d); // system call if (frame && frame->name && *frame->name->word == '^' && !frame->code) { for (unsigned int i = 0; i < frame->arguments; ++i) { char data[MAX_WORD_SIZE]; char* msg = callArgumentList[frame->argumentStartIndex + i]; size_t len = strlen(msg); if (len > (MAX_WORD_SIZE - 20)) len = MAX_WORD_SIZE - 20; sprintf(data, "(%d) ", i + 1); char* at = data + strlen(data); strncpy(at, msg, len); at[len] = 0; DrawText(hdc, (LPCSTR)data, -1, &rect, DT_LEFT | DT_TOP); rect.top += varData.metrics.cy; } EndPaint(hWnd, &ps); break; } if (fnvars) var = (char*)(fnvars + 1); // start of //else if (fnlevel >= 0) // var = ""; size_t len; char name[MAX_WORD_SIZE]; int limit = varData.linesPerPage; int lineCount = 0; while (*var && *var != ')') { char* at = msg; // get next variable name if (!fnvars) { char* end = strstr(var, "\r\n"); if (end) *end = 0; strcpy(name, var); if (end) *end = '\r'; var = end + 2; } else // fn var { var = ReadCompiledWord(var, name); } if (++lineCount > limit) break; // get value and line to show char* value = NULL; char* buffer = NULL; char word[MAX_WORD_SIZE]; if (*name == '^') value = ChaseFnVariable(name, fnlevel); else if (*name == '$') value = GetUserVariable(name); else if (*name == '@') { int store = GetSetID(name); unsigned int count = FACTSET_COUNT(store); sprintf(word, "[%d]", count); value = word; } else if (*name == '%') value = SystemVariable(name, NULL); else if (*name == '_') { int index = GetWildcardID(name); // which one value = wildcardOriginalText[index]; } else if (*name == 'j' && name[2] == '-') { buffer = AllocateBuffer(); WORDP D = FindWord(name); jwrite(buffer, D, true); value = buffer; } if (!value) continue; len = strlen(value); if (!*value) value = "null"; if (*name != '@') sprintf(at, "%s(%d)= ", name, len); else sprintf(at, "%s = ", name); at = at + strlen(at); bool more = false; size_t len = strlen(value); if (len > 400) { more = true; len = 400; } strncpy(at, value, len); at += len; *at = 0; if (more) strcpy(at, "...");// excessive length for display DrawText(hdc, (LPCSTR)msg, -1, &rect, DT_LEFT | DT_TOP); if (buffer) FreeBuffer(); char junk[MAX_WORD_SIZE]; sprintf(junk, "%s\r\n", name); if (strstr(varbreaknames, junk)) { DrawText(hdc, (LPCSTR)"B", -1, &breakrect, DT_LEFT | DT_TOP); } rect.top += varData.metrics.cy; } } else if (hWnd == stackData.window) { char msg[MAX_WORD_SIZE]; CALLFRAME* frame; int limit = stackData.yposition + stackData.linesPerPage; for (int i = 1; i <= globalDepth; ++i) { *msg = 0; if (i < stackData.yposition) continue; // wait to start if (i > limit) break; frame = GetCallFrame(i); bool showcode = false; if (strchr(frame->label, '(')) { ; } // not in code yet else if (!strnicmp(frame->label, "If", 2) || !strnicmp(frame->label, "Loop", 4)) showcode = true; else if (*frame->label == '^' && frame->code) showcode = true; else if (*frame->label != '^' && strchr(frame->label, '{')) showcode = true; sprintf(msg, "%d: %s", i, frame->label); if (showcode) { char* at = strchr(msg, '{'); if (at) *at = 0; // not for functions CALLFRAME* ownerFrame = GetCodeOwnerFrame(i); char size[20]; if (!stricmp(frame->label, "Loop{}")) { // show loop count char extra[10]; sprintf(extra, ":%d", frame->x.ownvalue); strcat(msg, extra); strcat(msg, ShowActions(outputCode[frame->outputlevel], frame->outputlevel)); } else if (outputlevel >= ownerFrame->outputlevel) { // at or beyond local code block int offset = outputCode[ownerFrame->outputlevel] - ownerFrame->code; sprintf(size, ":%d", offset); strcat(msg, size); if (*frame->label == '^' && frame->code && !offset) strcat(msg, "(macro) "); strcat(msg, " "); strcat(msg, ShowActions(outputCode[frame->outputlevel], frame->outputlevel)); } } else { if (*frame->label == '^' && frame->code) strcat(msg, " (macro)"); } size_t len = strlen(msg); if (idedepth == i) { SetTextColor(hdc, RGB(255, 255, 255)); SetBkColor(hdc, RGB(0, 0, 255)); } else { SetTextColor(hdc, RGB(0, 0, 0)); SetBkColor(hdc, RGB(255, 255, 255)); } int n = DrawText(hdc, (LPCSTR)msg, -1, &rect, DT_LEFT | DT_TOP); rect.top += stackData.metrics.cy; } } else if (hWnd == scriptData.window) { if (tesxt) VerifyMap(); rect = scriptData.rect; int limit = scriptData.yposition + scriptData.linesPerPage; numrect.top = rect.top; tagrect.top = rect.top; // title of visible doc if (currentFileData) { DrawText(hdc, (LPCSTR)filenames, -1, &titlerect, DT_LEFT | DT_TOP); } LINEDATA* at = GetStartLine(scriptData.yposition); if (!at) break; int yline = scriptData.yposition; // 0-based but mouseline and codeline are 1-based char* msg; while (at) { if (yline > limit) break; msg = GetStartCharacter(at); if (!msg) break; size_t len = strlen(msg); ++yline; // now 1 based data (matched file line numbers) char stuff[MAX_WORD_SIZE]; *stuff = 0; if (at->mapentry && at->mapentry->name[0] == '~') { // is it a rule id char* start = strchr(at->mapentry->name, '.'); if (start) { strcpy(stuff, start + 1); char* label = strchr(stuff, '-'); if (label) *label = 0; // pure tag DrawText(hdc, (LPCSTR)stuff, -1, &tagrect, DT_RIGHT | DT_TOP); } } // code code location if (codeFile == currentFileData && codeLine == yline) { RECT r = tagrect; r.left = 0; SetTextColor(hdc, RGB(255, 255, 255)); SetBkColor(hdc, RGB(0, 0, 255)); DrawText(hdc, (LPCSTR)">>", -1, &r, DT_LEFT | DT_TOP); SetTextColor(hdc, RGB(0, 0, 0)); SetBkColor(hdc, RGB(255, 255, 255)); } if (yline == mouseLine) // highlight text { SetTextColor(hdc, RGB(255, 255, 255)); SetBkColor(hdc, RGB(0, 0, 255)); DrawText(hdc, (LPCSTR)msg, -1, &rect, DT_LEFT | DT_TOP); SetTextColor(hdc, RGB(0, 0, 0)); SetBkColor(hdc, RGB(255, 255, 255)); } else DrawText(hdc, (LPCSTR)msg, -1, &rect, DT_LEFT | DT_TOP); // show source line numbers char num[50]; sprintf(num, "%d %c", yline, currentFileData->status[yline]); DrawText(hdc, (LPCSTR)num, -1, &numrect, DT_RIGHT | DT_TOP); *stuff = 0; if (at->mapentry && at->mapentry->name[0] == '~') { // is it a rule id char* start = strchr(at->mapentry->name, '.'); if (start) { strcpy(stuff, start + 1); char* label = strchr(stuff, '-'); if (label) *label = 0; // pure tag DrawText(hdc, (LPCSTR)stuff, -1, &tagrect, DT_RIGHT | DT_TOP); } } rect.top += scriptData.metrics.cy; numrect.top += scriptData.metrics.cy; tagrect.top += scriptData.metrics.cy; at = at->next; // use forward ptr } GetClientRect(hWnd, &rect); FrameRect(hdc, &rect, hBrush); } else if (hWnd == hParent) { GetClientRect(hWnd, &rect); FillRect(hdc, &rect, hBrushOrange); } else if (hWnd == sentenceData.window) { SelectObject(hdc, hFontBigger); GetClientRect(hWnd, &rect); FrameRect(hdc, &rect, hBrush); char word[MAX_WORD_SIZE]; GetWindowText(hWnd, word, MAX_WORD_SIZE); SetTextColor(hdc, RGB(0, 0, 0)); SetBkColor(hdc, RGB(255, 255, 255)); rect.top += 10; rect.left += 10; DrawText(hdc, (LPCSTR)word, -1, &rect, DT_SINGLELINE | DT_LEFT | DT_TOP); } else // some button rect { SelectObject(hdc, hButtonFont); GetClientRect(hWnd, &rect); FrameRect(hdc, &rect, hBrush); char word[MAX_WORD_SIZE]; GetWindowText(hWnd, word, MAX_WORD_SIZE); SetTextColor(hdc, RGB(0, 0, 0)); SetBkColor(hdc, RGB(255, 255, 255)); DrawText(hdc, (LPCSTR)word, -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); } EndPaint(hWnd, &ps); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } // Message handler for about box. INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_INITDIALOG: return (INT_PTR)TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; } if (HIWORD(wParam) == EN_CHANGE) { int xx = 0; } break; } return (INT_PTR)FALSE; }