diff --git a/CMakeLists.txt b/CMakeLists.txt index 0294068..a681eac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,23 +37,25 @@ option(DEBUG_MODE "Enable debugging output and memory tracing?" ON) set(CMAKE_C_STANDARD 99) set(SOURCE_FILES - thirdparty-installed/memwatch/memwatch.c - thirdparty-installed/cwalk-master/src/cwalk.c - ui/generated/resources.c - src/main.c - src/utils.c - src/joeydev.c - src/vector.c - src/array.c - src/draw.c - src/image.c - src/vecparse.c - src/color.c - src/palette.c - src/project.c - src/ssh.c - src/http.c - src/editor.c + thirdparty-installed/memwatch/memwatch.c + thirdparty-installed/cwalk-master/src/cwalk.c + ui/generated/resources.c + src/main.c + src/utils.c + src/joeydev.c + src/vector.c + src/array.c + src/draw.c + src/image.c + src/vecparse.c + src/color.c + src/palette.c + src/project.c + src/ssh.c + src/http.c + src/editor.c + src/compiler.c + src/messages.c ) configure_file(include/config.h.in config.h) @@ -72,6 +74,8 @@ add_custom_target(GENERATE_UI_HEADERS ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/libgcrypt.a ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/libssh2.a ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/libz.a + ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/libtcc.a + ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/tcc/libtcc1.a ) add_dependencies(${CMAKE_PROJECT_NAME} GENERATE_UI_HEADERS) @@ -116,6 +120,8 @@ target_link_libraries(${CMAKE_PROJECT_NAME} ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/libgpg-error.a ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/libcurl.a ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/libz.a + ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/libtcc.a + ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/tcc/libtcc1.a ${GTK3_LIBRARIES} -ldl -pthread diff --git a/embedded/recipe.h b/embedded/recipe.h new file mode 100644 index 0000000..0c4f65d --- /dev/null +++ b/embedded/recipe.h @@ -0,0 +1,36 @@ +/* + * JoeyDev + * Copyright (C) 2018-2023 Scott Duensing + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef RECIPE_H +#define RECIPE_H + + +#include + + +extern char **___recipeTargets; + + +extern void recipeAddTarget(char *target); +extern void recipeMessage(char *format, ...); + + +#endif // RECIPE_H diff --git a/include/common.h b/include/common.h index 6b07be7..8092421 100644 --- a/include/common.h +++ b/include/common.h @@ -56,4 +56,7 @@ typedef struct WindowDataS { } WindowDataT; +extern char *__resourcePath; + + #endif // COMMON_H diff --git a/include/compiler.h b/include/compiler.h new file mode 100644 index 0000000..651ada3 --- /dev/null +++ b/include/compiler.h @@ -0,0 +1,30 @@ +/* + * JoeyDev + * Copyright (C) 2018-2023 Scott Duensing + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. +*/ + + +#ifndef COMPILER_H +#define COMPILER_H + + +int compilerRunRecipe(char *recipe, char *input, char *outputPath, void *context); + + +#endif // COMPILER_H diff --git a/include/messages.h b/include/messages.h new file mode 100644 index 0000000..f1e0eac --- /dev/null +++ b/include/messages.h @@ -0,0 +1,40 @@ +/* + * JoeyDev + * Copyright (C) 2018-2023 Scott Duensing + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. +*/ + + +#ifndef MESSAGES_H +#define MESSAGES_H + + +enum MessageTypesE { + MSG_INFO = 0, + MSG_WARN, + MSG_ERROR, + MSG_SEVERE, // This means something failed in JoeyDev itself. + MSG_COUNT +}; +typedef enum MessageTypesE MessageTypesT; + + +void message(MessageTypesT level, char *format, ...); + + +#endif //MESSAGES_H diff --git a/include/project.h b/include/project.h index 6df589d..6685e6a 100644 --- a/include/project.h +++ b/include/project.h @@ -24,7 +24,11 @@ #define PROJECT_H -void winProjectCreate(void); +struct ProjectDataS; + + +gboolean projectAddToTree(struct ProjectDataS *self, char *filename); +void winProjectCreate(void); #endif // PROJECT_H diff --git a/include/utils.h b/include/utils.h index eff4d5d..a577773 100644 --- a/include/utils.h +++ b/include/utils.h @@ -42,6 +42,7 @@ char *utilCreateStringVArgs(char *format, va_list args); char *utilDeobfuscateASCII(char *obfuscated); void utilDequote(char *string); void utilEnsureBufferSize(unsigned char **buffer, int *length, int wanted); +void utilExtractResource(char *path); char *utilFileBasename(char *path); gboolean utilFileExists(char *filename); gboolean utilFileOpen(WindowDataT *self, char *extension, char *what); diff --git a/src/compiler.c b/src/compiler.c new file mode 100644 index 0000000..d3e77f0 --- /dev/null +++ b/src/compiler.c @@ -0,0 +1,125 @@ +/* + * JoeyDev + * Copyright (C) 2018-2023 Scott Duensing + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "common.h" +#include "compiler.h" +#include "libtcc.h" +#include "project.h" +#include "messages.h" +#include "utils.h" +#include "array.h" + + +char **___recipeTargets = NULL; + + +static void compilerErrorHandler(void *opaque, const char *msg); +void recipeAddTarget(char *target); +void recipeMessage(char *format, ...); + + +static void compilerErrorHandler(void *opaque, const char *msg) { + char *isWarning = strstr(msg, " warning: "); + + (void)opaque; + + message(isWarning == NULL ? MSG_ERROR : MSG_WARN, "%s", msg); +} + + +// All the paths passed in here are expected to be complete and absolute. +int compilerRunRecipe(char *recipe, char *input, char *outputPath, void *context) { + TCCState *s; + int result; + int (*entry)(char *, char *); + + ___recipeTargets = NULL; + + s = tcc_new(); + if (!s) { + // Something bad happened. + return -1; + } + + tcc_set_options(s, "-Wall -Wno-write-strings"); + tcc_set_lib_path(s, __resourcePath); + tcc_add_sysinclude_path(s, __resourcePath); + tcc_set_error_func(s, stdout, compilerErrorHandler); + tcc_set_output_type(s, TCC_OUTPUT_MEMORY); + + if (tcc_add_file(s, recipe) < 0) { + // Errors in code. + tcc_delete(s); + return -4; + } + + tcc_add_symbol(s, "___recipeTargets", ___recipeTargets); + tcc_add_symbol(s, "recipeAddTarget", recipeAddTarget); + tcc_add_symbol(s, "recipeMessage", recipeMessage); + + if (tcc_relocate(s, TCC_RELOCATE_AUTO) < 0) { + // Something bad happened. + tcc_delete(s); + return -2; + } + + entry = tcc_get_symbol(s, "recipe"); + if (!entry) { + // Something bad happened. + tcc_delete(s); + return -3; + } + + result = entry(input, outputPath); + + while (arrlen(___recipeTargets) > 0) { + if (projectAddToTree(context, ___recipeTargets[0])) { + utilSetDirty((WindowDataT *)context, TRUE); + } + DEL(___recipeTargets[0]); + arrdel(___recipeTargets, 0); + } + ARRFREE(___recipeTargets); + + tcc_delete(s); + + return result; +} + + +void recipeAddTarget(char *target) { + arrput(___recipeTargets, strdup(target)); +} + + +void recipeMessage(char *format, ...) { + va_list args; + char *string; + + va_start(args, format); + string = utilCreateStringVArgs(format, args); + va_end(args); + + message(MSG_INFO, "%s", string); + + DEL(string); +} diff --git a/src/main.c b/src/main.c index 4c469cf..71952c6 100644 --- a/src/main.c +++ b/src/main.c @@ -26,6 +26,10 @@ #include "joeydev.h" #include "http.h" #include "ssh.h" +#include "utils.h" + + +char *__resourcePath = NULL; int main(int argc, char **argv) { @@ -35,9 +39,30 @@ int main(int argc, char **argv) { #endif gtk_init(&argc, &argv); + + // Make sure we have a config & resources folder. + __resourcePath = utilCreateString("%s%cjoeydev%cresources%c", g_get_user_config_dir(), UTIL_PATH_CHAR, UTIL_PATH_CHAR, UTIL_PATH_CHAR); + utilMkDirP(__resourcePath, 0777); + httpStartup(); sshStartup(); + // Extract files we need later. + utilExtractResource("/com/kangaroopunch/joeydev/resources/libtcc.a"); + utilExtractResource("/com/kangaroopunch/joeydev/resources/libtcc1.a"); + utilExtractResource("/com/kangaroopunch/joeydev/resources/float.h"); + utilExtractResource("/com/kangaroopunch/joeydev/resources/stdalign.h"); + utilExtractResource("/com/kangaroopunch/joeydev/resources/stdarg.h"); + utilExtractResource("/com/kangaroopunch/joeydev/resources/stdatomic.h"); + utilExtractResource("/com/kangaroopunch/joeydev/resources/stdbool.h"); + utilExtractResource("/com/kangaroopunch/joeydev/resources/stddef.h"); + utilExtractResource("/com/kangaroopunch/joeydev/resources/stdnoreturn.h"); + utilExtractResource("/com/kangaroopunch/joeydev/resources/tccdefs.h"); + utilExtractResource("/com/kangaroopunch/joeydev/resources/tcclib.h"); + utilExtractResource("/com/kangaroopunch/joeydev/resources/tgmath.h"); + utilExtractResource("/com/kangaroopunch/joeydev/resources/varargs.h"); + utilExtractResource("/com/kangaroopunch/joeydev/resources/recipe.h"); + winJoeyDevCreate(); gtk_main(); @@ -45,5 +70,7 @@ int main(int argc, char **argv) { sshShutdown(); httpShutdown(); + DEL(__resourcePath); + return 0; } diff --git a/src/messages.c b/src/messages.c new file mode 100644 index 0000000..a33d9c8 --- /dev/null +++ b/src/messages.c @@ -0,0 +1,113 @@ +/* + * JoeyDev + * Copyright (C) 2018-2023 Scott Duensing + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "common.h" +#include "messages.h" +#include "utils.h" + + +static GtkWidget *_lstMessages = NULL; + + +EVENT gboolean winMessagesClose(GtkWidget *object, gpointer userData); +static void winMessagesDelete(gpointer userData); + + +void message(MessageTypesT level, char *format, ...) { + WindowDataT *self = NULL; + char *widgetNames[] = { + "winMessages", + "lstMessages", + NULL + }; + GtkWidget **widgets[] = { + NULL, + &_lstMessages + }; + GtkWidget *row; + GtkWidget *box; + GtkWidget *label; + va_list args; + char *string; + char *temp; + char *labels[MSG_COUNT] = { + " Info:", + "Warning:", + " Error:", + " Severe:" + }; + + // Do we need to open this window? + if (!_lstMessages) { + // Set up instance data. We only need WindowDataT since this is a "singleton" window. + self = NEW(WindowDataT); + self->closeWindow = winMessagesClose; + + widgets[0] = &self->window; + utilGetWidgetsFromMemory("/com/kangaroopunch/joeydev/Messages.glade", widgetNames, widgets, self); + + // Register window. + utilWindowRegister(self); + + // Show window. + gtk_widget_show_all(self->window); + } + + // Display message. + va_start(args, format); + temp = utilCreateStringVArgs(format, args); + va_end(args); + + string = utilCreateString("%s %s", labels[level], temp); + + row = gtk_list_box_row_new(); + box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL,6); + gtk_widget_set_hexpand(box, TRUE); + label = gtk_label_new(string); + gtk_label_set_use_markup(GTK_LABEL(label), TRUE); + + DEL(string); + + gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0); + gtk_container_add(GTK_CONTAINER(row), box); + gtk_list_box_insert(GTK_LIST_BOX(_lstMessages), row, -1); + + gtk_widget_show_all(row); +} + + +EVENT gboolean winMessagesClose(GtkWidget *object, gpointer userData) { + // userData is not reliable due to util indirectly calling us. + WindowDataT *self = (WindowDataT *)utilGetWindowData(object); + + (void)userData; + + winMessagesDelete(self); + return FALSE; +} + + +static void winMessagesDelete(gpointer userData) { + utilWindowUnRegister(userData); + _lstMessages = NULL; + DEL(userData); +} diff --git a/src/project.c b/src/project.c index c65e403..4b1f1a9 100644 --- a/src/project.c +++ b/src/project.c @@ -31,6 +31,8 @@ #include "utils.h" #include "http.h" #include "ssh.h" +#include "messages.h" +#include "compiler.h" enum ProjectColumnsE { @@ -88,24 +90,25 @@ typedef struct SectionDataS { // These have to match ProjectSectionTypeT above. static SectionDataT _sectionData[] = { - { "Header", "*.h" }, - { "Code", "*.c" }, - { "Bitmap", "*.img" }, - { "Stencil", "*.stn" }, - { "Vector", "*.vic" }, - { "Sound", "*.snd" }, - { "Music", "*.mod" }, + { "Header", "*.h" }, + { "Code", "*.c" }, + { "Bitmap", "*.img" }, + { "Stencil", "*.stn" }, + { "Vector", "*.vic" }, + { "Sound", "*.snd" }, + { "Music", "*.mod" }, { "Raw Data", NULL }, { "Cooked Data", "*.dat" }, { NULL, NULL } }; +static ProjectDataT *_cookingProjectData = NULL; + #define BUILD_SETTINGS_RESPONSE_TEST 1 static void addToRecipeData(ProjectDataT *self, char *key, char *value); -static void addToTree(ProjectDataT *self, char *filename); EVENT void buildTargetClicked(GtkButton *widget, gpointer userData); EVENT void btnEditRecipeClicked(GtkButton *widget, gpointer userData); EVENT void btnNewRecipeClicked(GtkButton *widget, gpointer userData); @@ -123,6 +126,7 @@ EVENT void menuProjectProjectAdd(GtkWidget *object, gpointer userData); EVENT void menuProjectProjectRemove(GtkWidget *object, gpointer userData); EVENT void menuProjectBuildSettings(GtkWidget *object, gpointer userData); EVENT void menuProjectBuildTargets(GtkWidget *object, gpointer userData); +EVENT void menuProjectBuildCookRecipes(GtkWidget *object, gpointer userData); EVENT void menuProjectBuildBuild(GtkWidget *object, gpointer userData); EVENT void menuProjectHelpProject(GtkWidget *object, gpointer userData); static void saveConfig(ProjectDataT *self); @@ -148,59 +152,6 @@ static void addToRecipeData(ProjectDataT *self, char *key, char *value) { } -static void addToTree(ProjectDataT *self, char *filename) { - ProjectSectionTypeT section; - char *temp = NULL; - GtkTreeIter iter; - GtkTreeIter child; - GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(self->treeProject)); - ProjectSectionTypeT foundAt = SECTION_RAW_DATA; // If it isn't a file we know, put it in "Raw Data". - int fileLen; - int extLen; - - // Is it long enough? - if (strlen(filename) > 2) { - // Is this already in the tree? This is a pretty brain-dead test. - gtk_tree_model_get_iter_first(model, &iter); - do { - if (gtk_tree_model_iter_children(model, &child, &iter)) { - do { - gtk_tree_model_get(model, &child, COL_FILENAME, &temp, -1); - if (strcmp(temp, filename) == 0) { - DEL(temp); // This generates an unknown pointer warning in memwatch. Pretty sure it's bogus. - return; // Silently fail to add on name collision. - } - DEL(temp); // This generates an unknown pointer warning in memwatch. Pretty sure it's bogus. - } while (gtk_tree_model_iter_next(model, &child)); - } - } while (gtk_tree_model_iter_next(model, &iter)); - - // Find proper section. - for (section = 0; section < SECTION_COUNT; section++) { - if (_sectionData[section].extension != NULL) { - // Compare last two bytes of filename with extension - it's enough to differentiate them and allows for ".c" and ".h". - fileLen = strlen(filename) - 1; - extLen = strlen(_sectionData[section].extension) - 1; - if (filename[fileLen - 1] == _sectionData[section].extension[extLen - 1] && filename[fileLen] == _sectionData[section].extension[extLen]) { - foundAt = section; - break; - } - } - } - DEL(temp); - fileLen = 0; - utilEnsureBufferSize((unsigned char **)&temp, &fileLen, 4); // fileLen is just a throwaway here. - snprintf(temp, 4, "%d", foundAt); - gtk_tree_model_get_iter_from_string(model, &iter, temp); - gtk_tree_store_append(GTK_TREE_STORE(model), &child, &iter); - gtk_tree_store_set(GTK_TREE_STORE(model), &child, COL_FILENAME, filename, -1); - DEL(temp); - - gtk_tree_view_expand_all(GTK_TREE_VIEW(self->treeProject)); - } -} - - EVENT void buildTargetClicked(GtkButton *widget, gpointer userData) { ArchT *arch = (ArchT *)userData; @@ -232,14 +183,18 @@ EVENT void btnNewRecipeClicked(GtkButton *widget, gpointer userData) { if (utilFileSaveOtherAs((WindowDataT *)userData, "*.c", "Recipe", &newFile)) { out = fopen(newFile, "wt"); fprintf(out, "" - "//\n" - "// JoeyBuild Recipe Program\n" - "//\n" - "\n" - "int recipe(char *fileIn, char *fileOut) {\n" - "\n" - "\treturn 0; // Return a non-zero value on failure.\n" - "}\n" + "//\n" + "// JoeyBuild Recipe Program\n" + "//\n" + "\n" + "\n" + "#include \n" + "\n" + "\n" + "int recipe(char *fileIn, char *outputPath) {\n" + "\n" + "\treturn 0; // Return a positive non-zero value on failure.\n" + "}\n" ); fclose(out); gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(self->tempWidget), newFile); @@ -263,14 +218,12 @@ static void dialogCookOptions(char *filename, ProjectDataT *self) { GtkWidget *lblRaw; GtkWidget *fileRecipe; GtkWidget *btnNewRecipe; - GtkWidget *lblCooked; GtkWidget *btnCancel; GtkWidget *btnOkay; int original; int result; int i; char *raw = NULL; - char *cooked = NULL; char *temp = NULL; char *path = NULL; char *widgetNames[] = { @@ -278,7 +231,6 @@ static void dialogCookOptions(char *filename, ProjectDataT *self) { "lblRaw", "fileRecipe", "btnNewRecipe", - "lblCooked", "btnCancel", "btnOkay", NULL @@ -288,7 +240,6 @@ static void dialogCookOptions(char *filename, ProjectDataT *self) { &lblRaw, &fileRecipe, &btnNewRecipe, - &lblCooked, &btnCancel, &btnOkay }; @@ -297,9 +248,6 @@ static void dialogCookOptions(char *filename, ProjectDataT *self) { raw = utilFileBasename(filename); gtk_label_set_text(GTK_LABEL(lblRaw), raw); - cooked = utilFileRemoveExtension(raw); - strcat(cooked, ".dat"); - gtk_label_set_text(GTK_LABEL(lblCooked), cooked); self->tempWidget = fileRecipe; @@ -326,7 +274,6 @@ static void dialogCookOptions(char *filename, ProjectDataT *self) { } // Did the recipe change? if (!((original >= 0) && (strcmp(self->recipes[original]->value, temp) == 0))) { - addToTree(self, cooked); addToRecipeData(self, raw, temp); utilSetDirty((WindowDataT *)self, TRUE); } @@ -335,7 +282,6 @@ static void dialogCookOptions(char *filename, ProjectDataT *self) { } DEL(path); - DEL(cooked); DEL(raw); self->tempWidget = NULL; @@ -436,7 +382,6 @@ static void loadProject(ProjectDataT *self) { int j; char *path = NULL; char *raw = NULL; - char *cooked = NULL; in = fopen(self->windowData.filename, "rt"); if (in != NULL) { @@ -463,9 +408,9 @@ static void loadProject(ProjectDataT *self) { utilDequote(c); cwk_path_get_relative(path, c, __utilFilenameBuffer, sizeof(__utilFilenameBuffer)); if (__utilFilenameBuffer[0] == 0) { - addToTree(self, c); + projectAddToTree(self, c); } else { - addToTree(self, __utilFilenameBuffer); + projectAddToTree(self, __utilFilenameBuffer); } continue; } @@ -502,20 +447,14 @@ static void loadProject(ProjectDataT *self) { c = utilGetToken(NULL, " ", "\"", "\""); utilDequote(c); raw = strdup(c); - cooked = utilFileRemoveExtension(raw); - strcat(cooked, ".dat"); - addToTree(self, cooked); c = utilGetToken(NULL, " ", "\"", "\""); utilDequote(c); cwk_path_get_relative(path, c, __utilFilenameBuffer, sizeof(__utilFilenameBuffer)); if (__utilFilenameBuffer[0] == 0) { addToRecipeData(self, raw, c); - debug("Writing Recipe [%s] = [%s]\n", raw, c); } else { addToRecipeData(self, raw, __utilFilenameBuffer); - debug("Writing Recipe [%s] = [%s]\n", raw, __utilFilenameBuffer); } - DEL(cooked); DEL(raw); } @@ -715,7 +654,7 @@ EVENT void menuProjectProjectAdd(GtkWidget *object, gpointer userData) { DEL(temp); temp = strdup(__utilFilenameBuffer); } - addToTree(self, temp); + projectAddToTree(self, temp); utilSetDirty((WindowDataT *)self, TRUE); DEL(temp); } @@ -731,6 +670,8 @@ EVENT void menuProjectProjectRemove(GtkWidget *object, gpointer userData) { GtkWidget *dialog; GtkTreeModel *model; GtkTreeIter iter; + char *name = NULL; + int i; (void)object; @@ -743,6 +684,12 @@ EVENT void menuProjectProjectRemove(GtkWidget *object, gpointer userData) { } if (found) { + // Delete cook recipe if it exists. + gtk_tree_model_get(model, &iter, COL_FILENAME, &name, -1); + i = findRecipeData(self, name); + if (i >= 0) arrdel(self->recipes, i); + DEL(name); + // Remove item from tree. gtk_tree_store_remove(GTK_TREE_STORE(model), &iter); utilSetDirty((WindowDataT *)self, TRUE); } else { @@ -947,8 +894,51 @@ EVENT void menuProjectBuildTargets(GtkWidget *object, gpointer userData) { } -EVENT void menuProjectBuildBuild(GtkWidget *object, gpointer userData) { +EVENT void menuProjectBuildCookRecipes(GtkWidget *object, gpointer userData) { + ProjectDataT *self = (ProjectDataT *)userData; + int i; + char *raw; + char *recipe; + char *path; + int result; + // Only one cook at a time. Should not be able to happen. + if (_cookingProjectData) { + message(MSG_ERROR, "Cook currently running"); + return; + } + + // Remember who started the cook. + _cookingProjectData = self; + + // Find path of project file. + path = strdup(self->windowData.filename); + cwk_path_get_dirname(path, (size_t *)&i); + if (i > 0) path[i] = 0; + + for (i=0; irecipes); i++) { + // Build pathnames. + cwk_path_change_basename(self->windowData.filename, self->recipes[i]->key, __utilFilenameBuffer, sizeof(__utilFilenameBuffer)); + raw = strdup(__utilFilenameBuffer); + cwk_path_change_basename(self->windowData.filename, self->recipes[i]->value, __utilFilenameBuffer, sizeof(__utilFilenameBuffer)); + recipe = strdup(__utilFilenameBuffer); + + // Run it! + message(MSG_INFO, "Cooking %s", self->recipes[i]->key); + result = compilerRunRecipe(recipe, raw, path, self); + if (result != 0) { + //***TODO*** Not all negative returns are severe. + message(result > 0 ? MSG_ERROR : MSG_SEVERE, "Recipe %s returned %d", self->recipes[i]->value, result); + } + message(MSG_INFO, "Finished Cooking"); + } + + DEL(path); + _cookingProjectData = NULL; +} + + +EVENT void menuProjectBuildBuild(GtkWidget *object, gpointer userData) { } @@ -960,15 +950,65 @@ EVENT void menuProjectHelpProject(GtkWidget *object, gpointer userData) { } +gboolean projectAddToTree(ProjectDataT *self, char *filename) { + ProjectSectionTypeT section; + char *temp = NULL; + GtkTreeIter iter; + GtkTreeIter child; + GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(self->treeProject)); + ProjectSectionTypeT foundAt = SECTION_RAW_DATA; // If it isn't a file we know, put it in "Raw Data". + int fileLen; + int extLen; + + // Is it long enough? + if (strlen(filename) > 2) { + // Is this already in the tree? This is a pretty brain-dead test. + gtk_tree_model_get_iter_first(model, &iter); + do { + if (gtk_tree_model_iter_children(model, &child, &iter)) { + do { + gtk_tree_model_get(model, &child, COL_FILENAME, &temp, -1); + if (strcmp(temp, filename) == 0) { + DEL(temp); // This generates an unknown pointer warning in memwatch. Pretty sure it's bogus. + return FALSE; // Item exists and was not added. + } + DEL(temp); // This generates an unknown pointer warning in memwatch. Pretty sure it's bogus. + } while (gtk_tree_model_iter_next(model, &child)); + } + } while (gtk_tree_model_iter_next(model, &iter)); + + // Find proper section. + for (section = 0; section < SECTION_COUNT; section++) { + if (_sectionData[section].extension != NULL) { + // Compare last two bytes of filename with extension - it's enough to differentiate them and allows for ".c" and ".h". + fileLen = strlen(filename) - 1; + extLen = strlen(_sectionData[section].extension) - 1; + if (filename[fileLen - 1] == _sectionData[section].extension[extLen - 1] && filename[fileLen] == _sectionData[section].extension[extLen]) { + foundAt = section; + break; + } + } + } + DEL(temp); + fileLen = 0; + utilEnsureBufferSize((unsigned char **)&temp, &fileLen, 4); // fileLen is just a throwaway here. + snprintf(temp, 4, "%d", foundAt); + gtk_tree_model_get_iter_from_string(model, &iter, temp); + gtk_tree_store_append(GTK_TREE_STORE(model), &child, &iter); + gtk_tree_store_set(GTK_TREE_STORE(model), &child, COL_FILENAME, filename, -1); + DEL(temp); + + gtk_tree_view_expand_all(GTK_TREE_VIEW(self->treeProject)); + } + + return TRUE; // Item was added. +} + + static void saveConfig(ProjectDataT *self) { char *temp; FILE *out; - // Make sure we have a config folder. - temp = utilCreateString("%s%cjoeydev", g_get_user_config_dir(), UTIL_PATH_CHAR); - utilMkDirP(temp, 0777); - DEL(temp); - // Save config. out = fopen(self->configName, "wt"); if (out != NULL) { @@ -1058,7 +1098,7 @@ static gboolean updateBuildOptions(ProjectDataT *self) { if (utilFileExists(name) == TRUE) { in = fopen(name, "rt"); if (in != NULL) { - utilEnsureBufferSize(&line, &len, 1024); // Not technically needed, but fixes a pointer warning from memmaker. + utilEnsureBufferSize((unsigned char **)&line, (int *)&len, 1024); // Not technically needed, but fixes a pointer warning from memmaker. while (getline(&line, &len, in) != -1) { if (strlen(line) > 0) line[strlen(line) - 1] = 0; c = utilGetToken(line, " ", "\"", "\""); @@ -1236,9 +1276,6 @@ void winProjectCreate(void) { //***DEBUG*** self->windowData.filename = strdup("/home/scott/joeyapps/warehouse/Warehouse.joe"); loadProject(self); - for (int i=0; irecipes); i++) { - debug("Reading Recipe %d [%s] = [%s]\n", i, self->recipes[i]->key, self->recipes[i]->value); - } } diff --git a/src/utils.c b/src/utils.c index 34b5b36..3b6b97f 100644 --- a/src/utils.c +++ b/src/utils.c @@ -22,6 +22,7 @@ #include +#include "common.h" #include "utils.h" #include "cwalk.h" @@ -130,6 +131,46 @@ void utilEnsureBufferSize(unsigned char **buffer, int *length, int wanted) { } +void utilExtractResource(char *path) { + GInputStream *in; + gssize read; + gssize bytes = 0; + FILE *out = NULL; + unsigned char *buffer = NULL; + int name = (int)strlen(path) - 1; + char *target = NULL; + + while (name >= 0 && path[name] != '/') name--; + target = utilCreateString("%s%s", __resourcePath, &path[name + 1]); + + if (!utilFileExists(target)) { + utilEnsureBufferSize(&buffer, (int *)&bytes, 8192); + + in = g_resources_open_stream(path, G_RESOURCE_LOOKUP_FLAGS_NONE, NULL); + if (in) { + out = fopen(target, "wb"); + if (out) { + do { + read = g_input_stream_read(in, buffer, bytes, NULL, NULL); + fwrite(buffer, read, 1, out); + } while (read > 0); + fclose(out); + } else { + debug("Unable to write resource %s!\n", target); + } + g_input_stream_close(in, NULL, NULL); + g_object_unref(in); + } else { + debug("Resource %s not found!\n", path); + } + + DEL(buffer); + } + + DEL(target); +} + + char *utilFileBasename(char *path) { const char *basename; size_t length; @@ -231,6 +272,8 @@ gboolean utilFileSaveAs(WindowDataT *self, char *extension, char *what) { char *files = utilCreateString("%s Files", what); int x; + //***TODO*** Make this use utilFileSaveOtherAS + dialog = gtk_file_chooser_dialog_new("Save As", GTK_WINDOW(self->window), GTK_FILE_CHOOSER_ACTION_SAVE, @@ -240,7 +283,7 @@ gboolean utilFileSaveAs(WindowDataT *self, char *extension, char *what) { if (self->filename != NULL) { memcpy(__utilFilenameBuffer, self->filename, strlen(self->filename) + 1); - cwk_path_get_dirname(__utilFilenameBuffer, &x); + cwk_path_get_dirname(__utilFilenameBuffer, (size_t *)&x); if (x > 0) __utilFilenameBuffer[x] = 0; gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),__utilFilenameBuffer); } @@ -283,7 +326,7 @@ gboolean utilFileSaveOtherAs(WindowDataT *self, char *extension, char *what, cha if (*filename != NULL) { memcpy(__utilFilenameBuffer, *filename, strlen(*filename) + 1); - cwk_path_get_dirname(__utilFilenameBuffer, &x); + cwk_path_get_dirname(__utilFilenameBuffer, (size_t *)&x); if (x > 0) __utilFilenameBuffer[x] = 0; gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),__utilFilenameBuffer); } @@ -519,7 +562,7 @@ void utilWindowRegister(gpointer windowData) { w->title = strdup(gtk_window_get_title(GTK_WINDOW(w->window))); hmput(_windowList, w->window, windowData); - debug("Window Registered: %d\n", hmlen(_windowList)); + debug("Window Registered: %ld\n", hmlen(_windowList)); } diff --git a/src/vector.c b/src/vector.c index 900d28a..6afda50 100644 --- a/src/vector.c +++ b/src/vector.c @@ -611,7 +611,7 @@ static void loadVectorImage(VectorDataT *self) { in = fopen(self->windowData.filename, "rt"); if (in != NULL) { self->buffer[0] = 0; - utilEnsureBufferSize(&line, &len, 1024); // Not technically needed, but fixes a pointer warning from memmaker. + utilEnsureBufferSize((unsigned char **)&line, (int *)&len, 1024); // Not technically needed, but fixes a pointer warning from memmaker. while (getline(&line, &len, in) != -1) { switch (count) { case 0: // Version Number diff --git a/thirdparty/tinycc-0.9.27.tar.bz2 b/thirdparty/tinycc-0.9.27.tar.bz2 new file mode 100644 index 0000000..c6243d2 --- /dev/null +++ b/thirdparty/tinycc-0.9.27.tar.bz2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:10e6e00dc3189709ad6e14762685b5cc04e85a2039836cf5e33b6b65a63e078d +size 815307 diff --git a/tools/prebuild.sh b/tools/prebuild.sh index 8e33512..4f91236 100755 --- a/tools/prebuild.sh +++ b/tools/prebuild.sh @@ -152,6 +152,19 @@ pushd "${ROOT}" || exit &> /dev/null popd || true &> /dev/null fi + if [[ ! -f ${INSTALLED}/lib/libtcc.a ]]; then + echo Building Dependency: TinyCC... + tar xzf ${THIRDPARTY}/tinycc-0.9.27.tar.bz2 + pushd tinycc-0.9.27 || exit &> /dev/null + ./configure \ + --prefix=${INSTALLED} \ + --enable-static \ + --with-libgcc + make + make install + popd || true &> /dev/null + fi + popd || true &> /dev/null echo Generating UI Embedded Code... diff --git a/ui/Cook.glade b/ui/Cook.glade index c418800..ab2fc01 100644 --- a/ui/Cook.glade +++ b/ui/Cook.glade @@ -2,6 +2,11 @@ + + + *.c + + False Cook Data @@ -56,7 +61,7 @@ center vertical - + True False @@ -127,31 +132,6 @@ 3 - - - True - False - end - Cooked: - - - 0 - 2 - - - - - True - False - start - lblCooked - - - 1 - 2 - 3 - - Edit @@ -187,9 +167,4 @@ btnOkay - - - *.c - - diff --git a/ui/Messages.glade b/ui/Messages.glade new file mode 100644 index 0000000..6cec57e --- /dev/null +++ b/ui/Messages.glade @@ -0,0 +1,31 @@ + + + + + + False + Messages + 440 + 250 + + + + True + True + in + + + True + False + + + True + False + + + + + + + + diff --git a/ui/Project.glade b/ui/Project.glade index 65ef1bb..4512805 100644 --- a/ui/Project.glade +++ b/ui/Project.glade @@ -155,6 +155,22 @@ False + + + True + False + Cook Recipes + True + + + + + + + True + False + + True diff --git a/ui/joeydev.gresource.xml b/ui/joeydev.gresource.xml index bd3d918..bfb205c 100644 --- a/ui/joeydev.gresource.xml +++ b/ui/joeydev.gresource.xml @@ -1,12 +1,13 @@ - JoeyDev.glade - Project.glade - BuildServer.glade - Cook.glade - Editor.glade - Vector.glade + JoeyDev.glade + Project.glade + BuildServer.glade + Cook.glade + Editor.glade + Vector.glade + Messages.glade Logo.png @@ -20,4 +21,20 @@ action-color.png action-palette.png + + ../thirdparty-installed/lib/libtcc.a + ../thirdparty-installed/lib/tcc/libtcc1.a + ../thirdparty-installed/lib/tcc/include/float.h + ../thirdparty-installed/lib/tcc/include/stdalign.h + ../thirdparty-installed/lib/tcc/include/stdarg.h + ../thirdparty-installed/lib/tcc/include/stdatomic.h + ../thirdparty-installed/lib/tcc/include/stdbool.h + ../thirdparty-installed/lib/tcc/include/stddef.h + ../thirdparty-installed/lib/tcc/include/stdnoreturn.h + ../thirdparty-installed/lib/tcc/include/tccdefs.h + ../thirdparty-installed/lib/tcc/include/tcclib.h + ../thirdparty-installed/lib/tcc/include/tgmath.h + ../thirdparty-installed/lib/tcc/include/varargs.h + ../embedded/recipe.h +