diff --git a/include/array.h b/include/array.h index 947cfac..e174dcf 100644 --- a/include/array.h +++ b/include/array.h @@ -27,6 +27,12 @@ #include "../thirdparty/stb_ds.h" +typedef struct StringHashS { + char *key; + char *value; +} StringHashT; + + #define ARRFREE(a) do { if (a != NULL) { arrfree(a); } break; } while(1) diff --git a/src/project.c b/src/project.c index 4564d76..c65e403 100644 --- a/src/project.c +++ b/src/project.c @@ -22,6 +22,7 @@ #pragma clang diagnostic push #pragma ide diagnostic ignored "cppcoreguidelines-narrowing-conversions" +#pragma ide diagnostic ignored "cert-err34-c" // atoi warnings #include "common.h" @@ -68,6 +69,7 @@ typedef struct TargetS { typedef struct ProjectDataS { WindowDataT windowData; GtkWidget *treeProject; + StringHashT **recipes; char *configName; char *buildHost; int buildHTTPPort; @@ -93,19 +95,23 @@ static SectionDataT _sectionData[] = { { "Vector", "*.vic" }, { "Sound", "*.snd" }, { "Music", "*.mod" }, - { "Raw Data", NULL }, - { "Cooked Data", NULL }, - { NULL, NULL } + { "Raw Data", NULL }, + { "Cooked Data", "*.dat" }, + { NULL, 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); +static void clearRecipeData(ProjectDataT *self); static void dialogCookOptions(char *filename, ProjectDataT *self); +static int findRecipeData(ProjectDataT *self, char *key); static void loadConfig(ProjectDataT *self); static void loadProject(ProjectDataT *self); EVENT void menuProjectFileNew(GtkWidget *object, gpointer userData); @@ -128,6 +134,20 @@ EVENT gboolean winProjectClose(GtkWidget *object, gpointer userData); static void winProjectDelete(gpointer userData); +static void addToRecipeData(ProjectDataT *self, char *key, char *value) { + int i; + StringHashT *s; + + i = findRecipeData(self, key); + if (i >= 0) arrdel(self->recipes, i); + + s = NEW(StringHashT); + s->key = strdup(key); + s->value = strdup(value); + arrput(self->recipes, s); +} + + static void addToTree(ProjectDataT *self, char *filename) { ProjectSectionTypeT section; char *temp = NULL; @@ -176,8 +196,6 @@ static void addToTree(ProjectDataT *self, char *filename) { gtk_tree_store_set(GTK_TREE_STORE(model), &child, COL_FILENAME, filename, -1); DEL(temp); - //***TODO*** Need to store extra RAW data somewhere. - gtk_tree_view_expand_all(GTK_TREE_VIEW(self->treeProject)); } } @@ -190,6 +208,20 @@ EVENT void buildTargetClicked(GtkButton *widget, gpointer userData) { } +EVENT void btnEditRecipeClicked(GtkButton *widget, gpointer userData) { + ProjectDataT *self = (ProjectDataT *)userData; + char *file = NULL; + + (void)widget; + + file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(self->tempWidget)); + if (utilFileExists(file)) { + //***TODO*** Text Editor + } + DEL(file); +} + + EVENT void btnNewRecipeClicked(GtkButton *widget, gpointer userData) { ProjectDataT *self = (ProjectDataT *)userData; char *newFile = NULL; @@ -215,6 +247,17 @@ EVENT void btnNewRecipeClicked(GtkButton *widget, gpointer userData) { } +static void clearRecipeData(ProjectDataT *self) { + // Clear recipe data. + while (arrlen(self->recipes) > 0) { + DEL(self->recipes[0]->key); + DEL(self->recipes[0]->value); + arrdel(self->recipes, 0); + } + ARRFREE(self->recipes); +} + + static void dialogCookOptions(char *filename, ProjectDataT *self) { GtkWidget *dialogCookSettings; GtkWidget *lblRaw; @@ -223,9 +266,13 @@ static void dialogCookOptions(char *filename, ProjectDataT *self) { GtkWidget *lblCooked; GtkWidget *btnCancel; GtkWidget *btnOkay; - int result = 0; + int original; + int result; + int i; char *raw = NULL; char *cooked = NULL; + char *temp = NULL; + char *path = NULL; char *widgetNames[] = { "dialogCookSettings", "lblRaw", @@ -253,21 +300,64 @@ static void dialogCookOptions(char *filename, ProjectDataT *self) { cooked = utilFileRemoveExtension(raw); strcat(cooked, ".dat"); gtk_label_set_text(GTK_LABEL(lblCooked), cooked); - DEL(cooked); - DEL(raw); self->tempWidget = fileRecipe; - result = gtk_dialog_run(GTK_DIALOG(dialogCookSettings)); - if (result == GTK_RESPONSE_OK) { + // Find path of project file. + path = strdup(self->windowData.filename); + cwk_path_get_dirname(path, (size_t *)&i); + if (i > 0) path[i] = 0; + original = findRecipeData(self, raw); + if (original >= 0) { + cwk_path_change_basename(self->windowData.filename, self->recipes[original]->value, __utilFilenameBuffer, sizeof(__utilFilenameBuffer)); + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(fileRecipe), __utilFilenameBuffer); } + result = gtk_dialog_run(GTK_DIALOG(dialogCookSettings)); + if (result == GTK_RESPONSE_OK) { + temp = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fileRecipe)); + if (temp != NULL) { + // Convert to relative path. + cwk_path_get_relative(path, temp, __utilFilenameBuffer, sizeof(__utilFilenameBuffer)); + if (__utilFilenameBuffer[0] != 0) { + DEL(temp); + temp = strdup(__utilFilenameBuffer); + } + // 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); + } + DEL(temp); + } + } + + DEL(path); + DEL(cooked); + DEL(raw); self->tempWidget = NULL; + gtk_widget_destroy(dialogCookSettings); } +static int findRecipeData(ProjectDataT *self, char *key) { + int i; + int result = -1; + + for (i=0; irecipes); i++) { + if (strcmp(self->recipes[i]->key, key) == 0) { + result = i; + break; + } + } + + return result; +} + + static void loadConfig(ProjectDataT *self) { FILE *in = NULL; char *line = NULL; @@ -337,14 +427,16 @@ static void loadConfig(ProjectDataT *self) { static void loadProject(ProjectDataT *self) { - FILE *in = NULL; - char *line = NULL; - size_t len = 0; - char *c = NULL; - TargetT *t = NULL; + FILE *in = NULL; + char *line = NULL; + size_t len = 0; + char *c = NULL; + TargetT *t = NULL; int i; int j; - char *path = NULL; + char *path = NULL; + char *raw = NULL; + char *cooked = NULL; in = fopen(self->windowData.filename, "rt"); if (in != NULL) { @@ -354,16 +446,17 @@ static void loadProject(ProjectDataT *self) { self->targets[i]->archs[j]->selected = FALSE; } } - // Find path of config file. + // Find path of project file. path = strdup(self->windowData.filename); - cwk_path_get_dirname(path, &i); + cwk_path_get_dirname(path, (size_t *)&i); if (i > 0) path[i] = 0; - // Load config. + // Load project. 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, " ", "\"", "\""); utilDequote(c); + // Is this a 'source' line? if (strcasecmp(c, "source") == 0) { c = utilGetToken(NULL, " ", "\"", "\""); @@ -374,13 +467,15 @@ static void loadProject(ProjectDataT *self) { } else { addToTree(self, __utilFilenameBuffer); } + continue; } + // Is this a 'target' line? if (strcasecmp(c, "target") == 0) { c = utilGetToken(NULL, " ", "\"", "\""); utilDequote(c); // See if we know about this target. - for (i=0; itargets; i++) { + for (i=0; i < arrlen(self->targets); i++) { if (strcasecmp(self->targets[i]->name, c) == 0) { t = self->targets[i]; // We know this target. Iterate over specified arches and turn them on if known. @@ -399,7 +494,31 @@ static void loadProject(ProjectDataT *self) { break; } } + continue; } + + // Is this a 'recipe' line? + if (strcasecmp(c, "recipe") == 0) { + 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); + } + } fclose(in); DEL(line); @@ -445,6 +564,8 @@ EVENT void menuProjectFileNew(GtkWidget *object, gpointer userData) { } } + clearRecipeData(self); + // Nuke filename & mark clean. DEL(self->windowData.filename); utilSetDirty(&self->windowData, FALSE); @@ -493,7 +614,6 @@ EVENT void menuProjectFileSave(GtkWidget *object, gpointer userData) { do { if (gtk_tree_model_iter_children(model, &child, &iter)) { do { - //***TODO*** For RAW we need to store function name somewhere. gtk_tree_model_get(model, &child, COL_FILENAME, &temp, -1); fprintf(out, "source \"%s\"\n", temp); DEL(temp); // This generates an unknown pointer warning in memwatch. Pretty sure it's bogus. @@ -516,6 +636,10 @@ EVENT void menuProjectFileSave(GtkWidget *object, gpointer userData) { } if (archWritten == TRUE) fprintf(out, "\n"); } + // Write out any data file recipes. + for (i=0; irecipes); i++) { + fprintf(out, "recipe \"%s\" \"%s\"\n", self->recipes[i]->key, self->recipes[i]->value); + } // Close file. fclose(out); // We're clean now. @@ -566,7 +690,7 @@ EVENT void menuProjectProjectAdd(GtkWidget *object, gpointer userData) { if (self->windowData.filename != NULL) { path = strdup(self->windowData.filename); - cwk_path_get_dirname(path, &x); + cwk_path_get_dirname(path, (size_t *)&x); if (x > 0) path[x] = 0; gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),path); } @@ -608,6 +732,8 @@ EVENT void menuProjectProjectRemove(GtkWidget *object, gpointer userData) { GtkTreeModel *model; GtkTreeIter iter; + (void)object; + // Is anything selected? if (gtk_tree_selection_get_selected(selection, &model, &iter)) { // Are we on a child item? @@ -756,6 +882,8 @@ EVENT void menuProjectBuildTargets(GtkWidget *object, gpointer userData) { int result; TargetT **backup; + (void)object; + backup = targetArrayCopy(self->targets); grid = gtk_grid_new(); @@ -1108,6 +1236,9 @@ 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); + } } @@ -1117,6 +1248,7 @@ static void winProjectDelete(gpointer userData) { utilWindowUnRegister(userData); targetArrayDelete(&self->targets); + clearRecipeData(self); DEL(self->buildHost); DEL(self->buildUser); diff --git a/tools/prebuild.sh b/tools/prebuild.sh index 36b4d0c..8e33512 100755 --- a/tools/prebuild.sh +++ b/tools/prebuild.sh @@ -41,7 +41,7 @@ pushd "${ROOT}" || exit &> /dev/null if [[ ! -f ${INSTALLED}/cwalk-master/src/cwalk.c ]]; then echo Unpacking Dependency: cwalk... - unzip ${THIRDPARTY}/cwalk-master.zip + unzip -u ${THIRDPARTY}/cwalk-master.zip cp -f ${INSTALLED}/cwalk-master/include/cwalk.h ${INSTALLED}/include/. fi diff --git a/ui/Cook.glade b/ui/Cook.glade index 6786bd0..c418800 100644 --- a/ui/Cook.glade +++ b/ui/Cook.glade @@ -56,7 +56,7 @@ center vertical - + True False @@ -124,7 +124,7 @@ 1 0 - 2 + 3 @@ -149,7 +149,21 @@ 1 2 - 2 + 3 + + + + + Edit + True + True + True + 15 + + + + 3 + 1