diff --git a/include/http.h b/include/http.h index b0e48a9..f0c6f3f 100644 --- a/include/http.h +++ b/include/http.h @@ -48,9 +48,11 @@ typedef struct HTTPS { } HTTPT; -HTTPT *httpDownload(HTTPCallback callback, char *filename, char *url); -void httpShutdown(void); -void httpStartup(void); +HTTPT *httpDownload(HTTPCallback callback, char *filename, char *url); +void httpShutdown(void); +void httpStartup(void); +gboolean httpWaitForDownload(void); +void httpWaitForDownloadCallback(HTTPT *download); #endif // HTTP_H diff --git a/include/utils.h b/include/utils.h index 3fd4e4b..62cf18b 100644 --- a/include/utils.h +++ b/include/utils.h @@ -40,10 +40,12 @@ char *utilCreateString(char *format, ...); char *utilCreateStringVArgs(char *format, va_list args); char *utilDeobfuscateASCII(char *obfuscated); +void utilDequote(char *string); void utilEnsureBufferSize(unsigned char **buffer, int *length, int wanted); gboolean utilFileExists(char *filename); gboolean utilFileOpen(WindowDataT *self, char *extension, char *what); gboolean utilFileSaveAs(WindowDataT *self, char *extension, char *what); +char *utilGetToken(char *input, char *delimit, char *openblock, char *closeblock); WindowDataT *utilGetWindowData(GtkWidget *window); gboolean utilGetWidgetsFromMemory(char *resource, char *name[], GtkWidget **widgets[], gpointer userData); gboolean utilMkDirP(const char *dir, const mode_t mode); diff --git a/src/http.c b/src/http.c index e7e28e7..4012ac4 100644 --- a/src/http.c +++ b/src/http.c @@ -20,11 +20,17 @@ */ +#pragma clang diagnostic push +#pragma ide diagnostic ignored "EndlessLoop" + + #include "http.h" -static CURLM *_curlMulti = NULL; -static HTTPT **_activeHTTPs = NULL; +static CURLM *_curlMulti = NULL; +static HTTPT **_activeHTTPs = NULL; +static gboolean _httpTestComplete = FALSE; +static gboolean _httpTestSuccess = FALSE; gboolean httpUpdate(gpointer userData); // Not static @@ -150,6 +156,22 @@ gboolean httpUpdate(gpointer userData) { } +gboolean httpWaitForDownload(void) { + _httpTestComplete = FALSE; + // This loop seriously breaks CLion's syntax highlighting for the rest of the function. + while (_httpTestComplete == FALSE) { + gtk_main_iteration(); + } + return _httpTestSuccess; +} + + +void httpWaitForDownloadCallback(HTTPT *download) { + _httpTestComplete = TRUE; + _httpTestSuccess = download->success; +} + + static size_t httpWrite(char *data, size_t num, size_t length, void *userp) { HTTPT *download = (HTTPT *)userp; @@ -171,3 +193,6 @@ static size_t httpWrite(char *data, size_t num, size_t length, void *userp) { return num * length; } + + +#pragma clang diagnostic pop diff --git a/src/project.c b/src/project.c index 524c745..f810828 100644 --- a/src/project.c +++ b/src/project.c @@ -22,7 +22,6 @@ #pragma clang diagnostic push #pragma ide diagnostic ignored "cppcoreguidelines-narrowing-conversions" -#pragma ide diagnostic ignored "EndlessLoop" #include "common.h" @@ -53,6 +52,17 @@ enum ProjectSectionTypeE { typedef enum ProjectSectionTypeE ProjectSectionTypeT; +typedef struct ArchS { + char *name; + gboolean selected; +} ArchT; + +typedef struct TargetS { + char *name; + char *longName; + ArchT **archs; +} TargetT; + typedef struct ProjectDataS { WindowDataT windowData; GtkWidget *treeProject; @@ -62,6 +72,7 @@ typedef struct ProjectDataS { int buildSSHPort; char *buildUser; char *buildPassword; + TargetT **targets; } ProjectDataT; typedef struct SectionDataS { @@ -84,15 +95,10 @@ static SectionDataT _sectionData[] = { }; -static gboolean _httpTestComplete = FALSE; -static gboolean _httpTestSuccess = FALSE; - - #define BUILD_SETTINGS_RESPONSE_TEST 1 static void addToTree(ProjectDataT *self, char *filename); -static void httpTest(HTTPT *download); static void loadConfig(ProjectDataT *self); static void loadProject(ProjectDataT *self); EVENT void menuProjectFileNew(GtkWidget *object, gpointer userData); @@ -102,11 +108,12 @@ EVENT void menuProjectFileSaveAs(GtkWidget *object, gpointer userData); EVENT void menuProjectFileClose(GtkWidget *object, gpointer userData); EVENT void menuProjectProjectAdd(GtkWidget *object, gpointer userData); EVENT void menuProjectProjectRemove(GtkWidget *object, gpointer userData); -EVENT void menuProjectProjectProperties(GtkWidget *object, gpointer userData); EVENT void menuProjectBuildSettings(GtkWidget *object, gpointer userData); +EVENT void menuProjectBuildTargets(GtkWidget *object, gpointer userData); EVENT void menuProjectBuildBuild(GtkWidget *object, gpointer userData); EVENT void menuProjectHelpProject(GtkWidget *object, gpointer userData); static void saveConfig(ProjectDataT *self); +static gboolean updateBuildOptions(ProjectDataT *self); EVENT gboolean winProjectClose(GtkWidget *object, gpointer userData); static void winProjectDelete(gpointer userData); @@ -142,12 +149,6 @@ static void addToTree(ProjectDataT *self, char *filename) { } -static void httpTest(HTTPT *download) { - _httpTestComplete = TRUE; - _httpTestSuccess = download->success; -} - - static void loadConfig(ProjectDataT *self) { FILE *in = NULL; char *line = NULL; @@ -408,11 +409,6 @@ EVENT void menuProjectProjectRemove(GtkWidget *object, gpointer userData) { } -EVENT void menuProjectProjectProperties(GtkWidget *object, gpointer userData) { - -} - - EVENT void menuProjectBuildSettings(GtkWidget *object, gpointer userData) { ProjectDataT *self = (ProjectDataT *)userData; GtkWidget *dialog; @@ -446,8 +442,6 @@ EVENT void menuProjectBuildSettings(GtkWidget *object, gpointer userData) { &btnOkay }; char temp[6]; - char *name = NULL; - char *url = NULL; int result = 0; SSHT *ssh = NULL; char *error = NULL; @@ -481,19 +475,9 @@ EVENT void menuProjectBuildSettings(GtkWidget *object, gpointer userData) { gtk_widget_set_sensitive(btnTest, FALSE); gtk_widget_set_sensitive(btnOkay, FALSE); // Run server connection tests - HTTP. - name = utilCreateString("%s%cjoeydev%cjoeydev.info", g_get_user_config_dir(), UTIL_PATH_CHAR, UTIL_PATH_CHAR); - url = utilCreateString("http://%s:%d/joeydev.info", self->buildHost, self->buildHTTPPort); - _httpTestComplete = FALSE; - httpDownload(httpTest, name, url); - // This loop seriously breaks CLion's syntax highlighting. - while (_httpTestComplete == FALSE) { - gtk_main_iteration(); - } - if (_httpTestSuccess == FALSE) { + if (updateBuildOptions(self) == FALSE) { error = utilCreateString("Unable to connect to HTTP port."); } - DEL(url); - DEL(name); // Run server connection tests - SSH. ssh = sshConnect(self->buildHost, self->buildSSHPort, self->buildUser, self->buildPassword); if (ssh) { @@ -522,6 +506,8 @@ EVENT void menuProjectBuildSettings(GtkWidget *object, gpointer userData) { gtk_widget_set_sensitive(btnTest, TRUE); gtk_widget_set_sensitive(btnOkay, TRUE); } else { + // Try to load the build options in case they didn't click TEST. + updateBuildOptions(self); // Close dialog on OKAY but not TEST. break; } @@ -533,6 +519,62 @@ EVENT void menuProjectBuildSettings(GtkWidget *object, gpointer userData) { } +EVENT void menuProjectBuildTargets(GtkWidget *object, gpointer userData) { + ProjectDataT *self = (ProjectDataT *)userData; + GtkWidget *dialog; + GtkWidget *contentArea; + GtkWidget *grid; + GtkWidget *widget; + TargetT *t; + ArchT *a; + char *temp; + int i; + int j; + int result; + + grid = gtk_grid_new(); + gtk_grid_set_column_homogeneous(GTK_GRID(grid), FALSE); + gtk_grid_set_row_homogeneous(GTK_GRID(grid), TRUE); + gtk_grid_set_column_spacing(GTK_GRID(grid), 15); + gtk_grid_set_row_spacing(GTK_GRID(grid), 5); + for (i=0; itargets); i++) { + t = self->targets[i]; + temp = utilCreateString("%s:", t->longName); + widget = gtk_label_new(temp); + DEL(temp); + gtk_label_set_line_wrap(GTK_LABEL(widget), FALSE); + gtk_label_set_xalign(GTK_LABEL(widget), 1.0); + gtk_grid_attach(GTK_GRID(grid), widget, 0, i, 1, 1); + for (j=0; jarchs); j++) { + a = t->archs[j]; + widget = gtk_check_button_new_with_label(a->name); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), a->selected); + gtk_grid_attach(GTK_GRID(grid), widget, j + 1, i, 1, 1); + } + } + + dialog = gtk_dialog_new_with_buttons( + "Targets", + GTK_WINDOW(self->windowData.window), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + "_Cancel", + GTK_RESPONSE_CANCEL, + "_OK", + GTK_RESPONSE_OK, + NULL + ); + + contentArea = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + gtk_container_add(GTK_CONTAINER(contentArea), grid); + + gtk_widget_show_all(dialog); + + result = gtk_dialog_run(dialog); + + gtk_widget_destroy(dialog); +} + + EVENT void menuProjectBuildBuild(GtkWidget *object, gpointer userData) { } @@ -574,6 +616,90 @@ static void saveConfig(ProjectDataT *self) { } +static gboolean updateBuildOptions(ProjectDataT *self) { + char *test = NULL; + char *name = NULL; + char *url = NULL; + gboolean result = FALSE; + FILE *in = NULL; + char *line = NULL; + size_t len = 0; + char *c = NULL; + TargetT *t = NULL; + ArchT *a = NULL; + + // This updates the build options file without clobbering one if it already exists and we fail to get a new one. + + test = utilCreateString("%s%cjoeydev%cjoeydev.temp", g_get_user_config_dir(), UTIL_PATH_CHAR, UTIL_PATH_CHAR); + name = utilCreateString("%s%cjoeydev%cjoeydev.info", g_get_user_config_dir(), UTIL_PATH_CHAR, UTIL_PATH_CHAR); + url = utilCreateString("http://%s:%d/joeydev.info", self->buildHost, self->buildHTTPPort); + + httpDownload(httpWaitForDownloadCallback, test, url); + if (httpWaitForDownload() == TRUE) { + unlink(name); + rename(test, name); + result = TRUE; + } + + // Unload current target listing. + while (arrlen(self->targets) > 0) { + t = self->targets[0]; + while (arrlen(t->archs) > 0) { + a = t->archs[0]; + DEL(a->name); + arrdel(t->archs, 0); + } + DEL(t->name); + DEL(t->longName); + arrdel(self->targets, 0); + } + + // If there's a list of targets on the disk, load them. + if (utilFileExists(name) == TRUE) { + in = fopen(name, "rt"); + if (in != NULL) { + while (getline(&line, &len, in) != -1) { + if (strlen(line) > 0) line[strlen(line) - 1] = 0; + // Is this a 'target' line? + c = utilGetToken(line, " ", "\"", "\""); + utilDequote(c); + if (strcasecmp(c, "target") == 0) { + t = NEW(TargetT); + // Short name. + c = utilGetToken(NULL, " ", "\"", "\""); + utilDequote(c); + t->name = strdup(c); + // Long name. + c = utilGetToken(NULL, " ", "\"", "\""); + utilDequote(c); + t->longName = strdup(c); + // Architectures. + do { + c = utilGetToken(NULL, " ", "\"", "\""); + if (c != NULL) { + utilDequote(c); + a = NEW(ArchT); + a->name = strdup(c); + a->selected = TRUE; + arrput(t->archs, a); + } + } while (c != NULL); + arrput(self->targets, t); + } + } + fclose(in); + DEL(line); + } + } + + DEL(url); + DEL(name); + DEL(test); + + return result; +} + + EVENT gboolean winProjectClose(GtkWidget *object, gpointer userData) { // userData is not reliable due to menuVectorFileClose and util indirectly calling us. ProjectDataT *self = (ProjectDataT *)utilGetWindowData(object); @@ -633,6 +759,9 @@ void winProjectCreate(void) { utilWindowRegister(self); gtk_widget_show_all(self->windowData.window); + // Attempt to load build settings from build server. + updateBuildOptions(self); + //***DEBUG*** self->windowData.filename = strdup("/home/scott/code/joeydev/cmake-build-debug/test.joe"); loadProject(self); diff --git a/src/utils.c b/src/utils.c index e105cad..3930299 100644 --- a/src/utils.c +++ b/src/utils.c @@ -97,6 +97,18 @@ char *utilDeobfuscateASCII(char *obfuscated) { } +void utilDequote(char *string) { + int x; + + if (string[0] == '"' || string[strlen(string) - 1] == '"') { + string[strlen(string) - 1] = 0; + for (x=1; x - - - True - False - - - - - True - False - Properties... - True - - - @@ -149,6 +134,15 @@ + + + True + False + Targets... + True + + + True