diff --git a/include/common.h b/include/common.h index ebd784b..f05dc03 100644 --- a/include/common.h +++ b/include/common.h @@ -24,10 +24,19 @@ #define COMMON_H +#define DEBUG // If we're debugging. + + #include #include "array.h" + +#ifdef DEBUG +#define debug(...) printf(__VA_ARGS__) #define MEMWATCH +#else +#define debug(s) +#endif #include "memwatch.h" diff --git a/include/utils.h b/include/utils.h index f640ebc..e3919ec 100644 --- a/include/utils.h +++ b/include/utils.h @@ -29,6 +29,7 @@ char *utilCreateString(char *format, ...); char *utilCreateStringVArgs(char *format, va_list args); +void utilEnsureBufferSize(unsigned char **buffer, int *length, int wanted); gboolean utilFileExists(char *filename); GdkPixbuf *utilGetPixbufFromMemory(char *data, unsigned int len); WindowDataT *utilGetWindowData(GtkWidget *window); diff --git a/src/joeydev.c b/src/joeydev.c index 6416936..478116f 100644 --- a/src/joeydev.c +++ b/src/joeydev.c @@ -70,7 +70,7 @@ EVENT void toolJoeyDevProjectClicked(GtkWidget *object, gpointer userData) { (void)object; (void)userData; - printf("Project Clicked!\n"); + debug("Project Clicked!\n"); } diff --git a/src/utils.c b/src/utils.c index beb6931..e75a1b8 100644 --- a/src/utils.c +++ b/src/utils.c @@ -62,6 +62,21 @@ char *utilCreateStringVArgs(char *format, va_list args) { } +void utilEnsureBufferSize(unsigned char **buffer, int *length, int wanted) { + unsigned char *temp = NULL; + + if (*length < wanted) { + *length = *length + 1024; + temp = realloc(*buffer, *length); + if (temp == NULL) { + //***TODO*** Something bad happened. + } else { + *buffer = temp; + } + } +} + + gboolean utilFileExists(char *filename) { FILE *f = fopen(filename, "rb"); diff --git a/src/vecparse.c b/src/vecparse.c index 6ba89d8..e56b440 100644 --- a/src/vecparse.c +++ b/src/vecparse.c @@ -23,6 +23,7 @@ #include #include "common.h" #include "vecparse.h" +#include "utils.h" #define IS_NUMBER(n) (n & 0x8000 ? FALSE : TRUE) @@ -45,7 +46,6 @@ typedef struct LabelS { } LabelT; -static void ensureBufferSize(VecByteCodeT *bytecode, int needed); static int labelGetValue(int lineNumber, VecByteCodeT *bytecode, LabelT *labels, LabelT ***unresolved, char *label); static void outputByte(VecByteCodeT *bytecode, unsigned short word); static void outputWord(VecByteCodeT *bytecode, unsigned short word); @@ -58,21 +58,6 @@ static gboolean parserGetXYZ(char **tokenEnd, char ***variables, int *x, int *y static int variableCollect(char *value, char ***variables); -static void ensureBufferSize(VecByteCodeT *bytecode, int needed) { - unsigned char *temp = NULL; - - if (bytecode->bufferSize < bytecode->length + needed) { - bytecode->bufferSize += 1024; - temp = realloc(bytecode->bytes, bytecode->bufferSize); - if (temp == NULL) { - //***TODO*** Something bad happened. - } else { - bytecode->bytes = temp; - } - } -} - - static int labelGetValue(int lineNumber, VecByteCodeT *bytecode, LabelT *labels, LabelT ***unresolved, char *label) { int index; int found = -1; @@ -105,7 +90,7 @@ static int labelGetValue(int lineNumber, VecByteCodeT *bytecode, LabelT *labels, static void outputByte(VecByteCodeT *bytecode, unsigned short word) { unsigned char byte = (unsigned char)word; - ensureBufferSize(bytecode, 1); + utilEnsureBufferSize(&bytecode->bytes, &bytecode->bufferSize, bytecode->length + 1); // If the word passed in is a variable, set the MSb in the byte as well. if (word & 0x8000) { @@ -117,7 +102,7 @@ static void outputByte(VecByteCodeT *bytecode, unsigned short word) { static void outputWord(VecByteCodeT *bytecode, unsigned short word) { - ensureBufferSize(bytecode, 2); + utilEnsureBufferSize(&bytecode->bytes, &bytecode->bufferSize, bytecode->length + 2); bytecode->bytes[bytecode->length++] = (word & 0xFF00) >> 8; bytecode->bytes[bytecode->length++] = word & 0x00FF; } @@ -356,7 +341,7 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) { } else { // blank line - printf("[%s]\n", token); + debug("[%s]\n", token); // Is it math? if (strlen(token) > 1 && token[0] == '%') { @@ -700,18 +685,19 @@ int vecparser(char *programIn, VecByteCodeT *bytecode) { } // read program line // Resolve forward label declarations and patch bytecode. - //***DEBUG*** +#ifdef DEBUG for (y1=0; y1key); + debug("Unresolved - %s\n", unresolved[y1]->key); } +#endif for (y1=0; y1key, labels[x1].key); + debug("Checking label %d of %d - %s == %s\n", y1, (int)arrlen(unresolved), unresolved[y1]->key, labels[x1].key); if (strcasecmp(unresolved[y1]->key, labels[x1].key) == 0) { x2 = x1; break; diff --git a/src/vector.c b/src/vector.c index 48a0170..c7c9c2e 100644 --- a/src/vector.c +++ b/src/vector.c @@ -38,6 +38,7 @@ #define VICTOR_VERSION "1.00" +#define RENDER_TIMEOUT 5 // In seconds #define SSM(m, w, l) scintilla_send_message(self->sci, m, w, l) #define MARGIN_SCRIPT_FOLD_INDEX 1 @@ -66,6 +67,8 @@ typedef struct VectorDataS { char *filename; char *title; char *tracename; + char *buffer; + int bufferLength; } VectorDataT; @@ -187,47 +190,44 @@ EVENT void editorVectorNotify(GtkWidget *sciWidget, gint ctrlID, struct SCNotifi VectorDataT *self = (VectorDataT *)userData; int lineNumber = (int)SSM(SCI_LINEFROMPOSITION, (uptr_t)notifyData->position, (sptr_t)0); int length = SSM(SCI_GETLENGTH, 0, 0); - char *code; VecByteCodeT byteCode; (void)sciWidget; (void)ctrlID; - //printf("Notification %d\n", notifyData->modificationType); + //debug("Notification %d\n", notifyData->modificationType); switch (notifyData->nmhdr.code) { case SCN_MODIFIED: if (notifyData->modificationType & SC_MOD_INSERTTEXT || notifyData->modificationType & SC_MOD_DELETETEXT) { // Allocate space to fetch code from editor. - code = (char *)malloc(length + 1); - if (!code) return; + utilEnsureBufferSize((unsigned char **)&self->buffer, &self->bufferLength, length); // Clear error markers. SSM(SCI_MARKERDELETEALL, MARKER_ERROR_ARROW, 0); SSM(SCI_MARKERDELETEALL, MARKER_ERROR_HIGHLIGHT, 0); // Fetch code. - SSM(SCI_GETTEXT, length, (sptr_t)code); + SSM(SCI_GETTEXT, length, (sptr_t)self->buffer); // Parse code. - byteCode.bytes = NULL; - byteCode.length = 0; + byteCode.bytes = NULL; + byteCode.length = 0; byteCode.bufferSize = 0; - lineNumber = vecparser(code, &byteCode); + lineNumber = vecparser(self->buffer, &byteCode); if (lineNumber >= 0) { // Mark lines that fail to parse. SSM(SCI_MARKERADD, lineNumber, MARKER_ERROR_ARROW); SSM(SCI_MARKERADD, lineNumber, MARKER_ERROR_HIGHLIGHT); } else { - //***DEBUG*** +#ifdef DEBUG FILE *out = fopen("bytecode.bin", "wb"); fwrite(byteCode.bytes, byteCode.length, 1, out); fclose(out); +#endif // All good! renderBytecode(&byteCode, self); } // Release bytecode. if (byteCode.bytes != NULL) DEL(byteCode.bytes); - // Release code. - DEL(code); // Mark text dirty. SCN_SAVEPOINTLEFT isn't being reliable. setDirty(self, TRUE); } @@ -260,7 +260,7 @@ EVENT void fileVectorTraceImageFileSet(GtkWidget *object, gpointer userData) { VectorDataT *self = (VectorDataT *)userData; char *temp = NULL; - printf("fileVectorTraceImageFileSet fired\n"); + debug("fileVectorTraceImageFileSet fired\n"); temp = (char *)gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(object)); loadTraceImage(self, temp); DEL(temp); @@ -327,22 +327,38 @@ static void loadTraceImage(VectorDataT *self, char *filename) { EVENT void menuVectorEditCopy(GtkWidget *object, gpointer userData) { + VectorDataT *self = (VectorDataT *)userData; + (void)object; + + SSM(SCI_COPY, 0, 0); } EVENT void menuVectorEditCut(GtkWidget *object, gpointer userData) { + VectorDataT *self = (VectorDataT *)userData; + (void)object; + + SSM(SCI_CUT, 0, 0); } EVENT void menuVectorEditDelete(GtkWidget *object, gpointer userData) { + VectorDataT *self = (VectorDataT *)userData; + (void)object; + + SSM(SCI_CLEAR, 0, 0); } EVENT void menuVectorEditPaste(GtkWidget *object, gpointer userData) { + VectorDataT *self = (VectorDataT *)userData; + (void)object; + + SSM(SCI_PASTE, 0, 0); } @@ -424,6 +440,7 @@ EVENT void menuVectorFileOpen(GtkWidget *object, gpointer userData) { in = fopen(self->filename, "rt"); if (in != NULL) { + self->buffer[0] = 0; while (getline(&line, &len, in) != -1) { switch (count) { case 0: // Version Number @@ -440,13 +457,15 @@ EVENT void menuVectorFileOpen(GtkWidget *object, gpointer userData) { break; default: // Code for editor - SSM(SCI_ADDTEXT, strlen(line), (sptr_t)line); + utilEnsureBufferSize((unsigned char **)&self->buffer, &self->bufferLength, strlen(self->buffer) + strlen(line)); + strcat(self->buffer, line); break; } count++; } fclose(in); if (line != NULL) DEL(line); + SSM(SCI_ADDTEXT, strlen(self->buffer), (sptr_t)self->buffer); setDirty(self, FALSE); // Do again - loading text marks us dirty. } else { //***TODO*** Something bad happened. @@ -528,26 +547,31 @@ EVENT void menuVectorFileSaveAs(GtkWidget *object, gpointer userData) { EVENT void menuVectorHelpVector(GtkWidget *object, gpointer userData) { + (void)object; + (void)userData; + gtk_show_uri_on_window(NULL, "https://skunkworks.kangaroopunch.com/skunkworks/joeydev/-/wikis/Victor-Vector-Editor", GDK_CURRENT_TIME, NULL); } static void renderBytecode(VecByteCodeT *bytecode, VectorDataT *self) { - int x1; - int y1; - int x2; - int y2; - int count; - int i; - float f1; - float f2; - int index = 0; - int *stack = NULL; + int x1; + int y1; + int x2; + int y2; + int count; + int i; + float f1; + float f2; + time_t startTime; + int index = 0; + int *stack = NULL; + GtkWidget *dialog; #define GET_BYTE (bytecode->bytes[index++]) #define GET_WORD getWord(bytecode, &index) - printf("-----------------------------------\n"); + debug("-----------------------------------\n"); self->variables = NULL; @@ -557,7 +581,9 @@ static void renderBytecode(VecByteCodeT *bytecode, VectorDataT *self) { jlDrawClear(self->jlc); jlDrawColorSet(self->jlc, 15); - while (index < bytecode->length) { + startTime = time(NULL); + + while (index < bytecode->length && difftime(time(NULL), startTime) < RENDER_TIMEOUT) { switch (bytecode->bytes[index++]) { case PARSE_NONE: @@ -569,7 +595,7 @@ static void renderBytecode(VecByteCodeT *bytecode, VectorDataT *self) { y1 = word(self, GET_WORD); x2 = word(self, GET_WORD); y2 = word(self, GET_WORD); - printf("Box %d,%d to %d,%d\n", x1, y1, x2, y2); + debug("Box %d,%d to %d,%d\n", x1, y1, x2, y2); jlDrawBox(self->jlc, x1, y1, x2, y2); break; @@ -577,25 +603,25 @@ static void renderBytecode(VecByteCodeT *bytecode, VectorDataT *self) { x1 = word(self, GET_WORD); arrput(stack, index); index = x1; - printf("Call %d\n", index); + debug("Call %d\n", index); break; case PARSE_CIRCLE: y2 = word(self, GET_WORD); x1 = word(self, GET_WORD); y1 = word(self, GET_WORD); - printf("Circle %d at %d,%d\n", y2, x1, y1); + debug("Circle %d at %d,%d\n", y2, x1, y1); jlDrawCircle(self->jlc, x1, y1, y2); break; case PARSE_CLEAR: - printf("Clear\n"); + debug("Clear\n"); jlDrawClear(self->jlc); break; case PARSE_COLOR: x1 = byte(self, GET_BYTE); - printf("Color %d\n", x1); + debug("Color %d\n", x1); jlDrawColorSet(self->jlc, x1); break; @@ -608,7 +634,7 @@ static void renderBytecode(VecByteCodeT *bytecode, VectorDataT *self) { y1 = word(self, GET_WORD); x2 = word(self, GET_WORD); y2 = word(self, GET_WORD); - printf("Ellipse %d,%d to %d,%d\n", x1, y1, x2, y2); + debug("Ellipse %d,%d to %d,%d\n", x1, y1, x2, y2); jlDrawEllipse(self->jlc, x1, y1, x2, y2); break; @@ -617,66 +643,66 @@ static void renderBytecode(VecByteCodeT *bytecode, VectorDataT *self) { y1 = word(self, GET_WORD); x2 = byte(self, GET_BYTE); if (x2 > 15) { - printf("Fill %d,%d\n", x1, y1); + debug("Fill %d,%d\n", x1, y1); jlDrawFill(self->jlc, x1, y1); } else { - printf("Fill %d,%d to %d\n", x1, y1, x2); + debug("Fill %d,%d to %d\n", x1, y1, x2); jlDrawFillTo(self->jlc, x1, y1, x2); } break; case PARSE_GOTO: index = word(self, GET_WORD); - printf("Goto %d\n", index); + debug("Goto %d\n", index); break; case PARSE_IF: x1 = word(self, GET_WORD); // arg1 y1 = byte(self, GET_BYTE); // compare x2 = word(self, GET_WORD); // arg2 - printf("If %d ", x1); + debug("If %d ", x1); y2 = -1; switch (y1) { case 0: // == - printf("=="); + debug("=="); if (x1 == x2) y2 = 1; break; case 1: // != - printf("!="); + debug("!="); if (x1 != x2) y2 = 1; break; case 2: // < - printf("<"); + debug("<"); if (x1 < x2) y2 = 1; break; case 3: // > - printf(">"); + debug(">"); if (x1 > x2) y2 = 1; break; case 4: // <= - printf("<="); + debug("<="); if (x1 <= x2) y2 = 1; break; case 5: // >= - printf(">="); + debug(">="); if (x1 >= x2) y2 = 1; break; } - printf(" %d ", x2); + debug(" %d ", x2); x1 = byte(self, GET_BYTE); // goto/call x2 = word(self, GET_WORD); // label - printf(" %s %d ", (x1 == 0 ? "Goto" : "Call"), x2); + debug(" %s %d ", (x1 == 0 ? "Goto" : "Call"), x2); if (y2 > 0) { if (x1 == 1) arrput(stack, index); index = x2; - printf("(true)"); + debug("(true)"); } - printf("\n"); + debug("\n"); break; case PARSE_LABEL: @@ -686,16 +712,16 @@ static void renderBytecode(VecByteCodeT *bytecode, VectorDataT *self) { count = word(self, GET_WORD); x1 = word(self, GET_WORD); y1 = word(self, GET_WORD); - printf("Line %d,%d", x1, y1); + debug("Line %d,%d", x1, y1); for (i=0; ijlc, x1, y1, x2, y2); x1 = x2; y1 = y2; } - printf("\n"); + debug("\n"); break; case PARSE_MATH: @@ -709,7 +735,7 @@ static void renderBytecode(VecByteCodeT *bytecode, VectorDataT *self) { } x1 &= 0x7f; // Clear variable flag. f1 = variable(self, x1); - printf("Math: %d: ", x1); + debug("Math: %d: ", x1); switch (y1) { case MATH_NONE: // Well, none! @@ -717,65 +743,65 @@ static void renderBytecode(VecByteCodeT *bytecode, VectorDataT *self) { case MATH_ASSIGN: f1 = f2; - printf("= %f", f2); + debug("= %f", f2); break; case MATH_ADD: f1 += f2; - printf("%f + %f", f1, f2); + debug("%f + %f", f1, f2); break; case MATH_SUBTRACT: f1 -= f2; - printf("%f - %f", f1, f2); + debug("%f - %f", f1, f2); break; case MATH_MULTIPLY: f1 *= f2; - printf("%f * %f", f1, f2); + debug("%f * %f", f1, f2); break; case MATH_DIVIDE: f1 /= f2; - printf("%f / %f", f1, f2); + debug("%f / %f", f1, f2); break; case MATH_MOD: f1 = modff(f1, &f2); - printf("%f mod %f", f1, f2); + debug("%f mod %f", f1, f2); break; case MATH_POW: f1 = powf(f1, f2); - printf("%f pow %f", f1, f2); + debug("%f pow %f", f1, f2); break; case MATH_SQRT: f1 = sqrtf(f2); - printf("%f sqrt %f", f1, f2); + debug("%f sqrt %f", f1, f2); break; case MATH_ABS: f1 = fabsf(f2); - printf("%f abs %f", f1, f2); + debug("%f abs %f", f1, f2); break; case MATH_COS: f1 = cosf(f2); - printf("%f cos %f", f1, f2); + debug("%f cos %f", f1, f2); break; case MATH_SIN: f1 = sinf(f2); - printf("%f sin %f", f1, f2); + debug("%f sin %f", f1, f2); break; case MATH_TAN: f1 = tanf(f2); - printf("%f tan %f", f1, f2); + debug("%f tan %f", f1, f2); break; } - printf("\n"); + debug("\n"); // Make sure we have enough slots for this variable. while (arrlen(self->variables) <= x1) { arrput(self->variables, 0.0f); @@ -788,14 +814,14 @@ static void renderBytecode(VecByteCodeT *bytecode, VectorDataT *self) { x2 = byte(self, GET_BYTE); y1 = byte(self, GET_BYTE); y2 = byte(self, GET_BYTE); - printf("Palette %d as %d,%d,%d\n", x1, x2, y1, y2); + debug("Palette %d as %d,%d,%d\n", x1, x2, y1, y2); jlPaletteSet(self->jlc, x1, x2, y1, y2); break; case PARSE_PLOT: x1 = word(self, GET_WORD); y1 = word(self, GET_WORD); - printf("Plot %d,%d\n", x1, y1); + debug("Plot %d,%d\n", x1, y1); jlDrawPixelSet(self->jlc, x1, y1); break; @@ -804,13 +830,13 @@ static void renderBytecode(VecByteCodeT *bytecode, VectorDataT *self) { y1 = word(self, GET_WORD); x2 = word(self, GET_WORD); y2 = word(self, GET_WORD); - printf("Rectangle %d,%d to %d,%d\n", x1, y1, x2, y2); + debug("Rectangle %d,%d to %d,%d\n", x1, y1, x2, y2); jlDrawBoxFilled(self->jlc, x1, y1, x2, y2); break; case PARSE_RETURN: index = arrpop(stack); - printf("Return %d\n", index); + debug("Return %d\n", index); break; } // switch @@ -828,6 +854,19 @@ static void renderBytecode(VecByteCodeT *bytecode, VectorDataT *self) { // Refresh widget. gtk_widget_queue_draw(self->drawVectorImage); + + // Did execution time out? + if (index < bytecode->length) { + dialog = gtk_message_dialog_new( + GTK_WINDOW(self->windowData.window), + GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_OK, + "Rendering is taking too long! Stopped.\n\n(Did you create an infinite loop?)"); + gtk_window_set_title(GTK_WINDOW(dialog), "Notice"); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + } } @@ -930,6 +969,9 @@ void winVectorCreate(void) { self = NEW(VectorDataT); self->windowData.closeWindow = winVectorClose; + // Set up working buffer. + utilEnsureBufferSize((unsigned char **)&self->buffer, &self->bufferLength, 1024); + // Load widgets from XML. widgets[0] = &self->windowData.window; widgets[1] = &self->boxVectorForEditor; @@ -968,9 +1010,7 @@ void winVectorCreate(void) { SSM(SCI_SETTABWIDTH, 3, 0); SSM(SCI_SETMARGINWIDTHN, 0, (int)SSM(SCI_TEXTWIDTH, STYLE_LINENUMBER, (sptr_t)"_99999")); SSM(SCI_SETMARGINWIDTHN, 1, 16); - SSM(SCI_SETWRAPMODE, SC_WRAP_WORD, 0); - SSM(SCI_SETWRAPVISUALFLAGS, SC_WRAPVISUALFLAG_END, 0); - SSM(SCI_SETWRAPINDENTMODE, SC_WRAPINDENT_INDENT, 0); + SSM(SCI_SETWRAPMODE, SC_WRAP_NONE, 0); SSM(SCI_SETCARETSTYLE, CARETSTYLE_BLOCK | CARETSTYLE_OVERSTRIKE_BLOCK, 0); SSM(SCI_SETCARETFORE, 0x00ffff, 0); SSM(SCI_STYLESETBACK, STYLE_LINENUMBER, 0x222222); @@ -1053,6 +1093,7 @@ static void winVectorDelete(gpointer userData) { if (self->filename != NULL) DEL(self->filename); if (self->title != NULL) DEL(self->title); if (self->tracename != NULL) DEL(self->tracename); + if (self->buffer != NULL) DEL(self->buffer); DEL(self); } diff --git a/ui/Vector.glade b/ui/Vector.glade index c72621e..426a87f 100644 --- a/ui/Vector.glade +++ b/ui/Vector.glade @@ -25,12 +25,10 @@ - 1500 - 600 + 1000 + 500 False Vector - 1500 - 600 @@ -56,36 +54,40 @@ True False - _New + New True + True False - _Open... + Open... True + True False - _Save + Save True + True False - Save _As... + Save As... True + @@ -98,9 +100,10 @@ True False - C_lose + Close True + @@ -124,15 +127,17 @@ Cut True + True False - _Copy + Copy True + @@ -142,6 +147,7 @@ Paste True + @@ -174,6 +180,7 @@ Vector Editor... True +