Mercurial
diff postdog/main.c @ 118:249881ceff7b
[PostDog] Updated some core logic. Will create a bookmark for postdog until the launch as this is annoying to deal with.
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Wed, 07 Jan 2026 13:24:38 -0800 |
| parents | b91f2dd6f84d |
| children | 7387eec8e7f8 |
line wrap: on
line diff
--- a/postdog/main.c Wed Jan 07 05:02:45 2026 -0800 +++ b/postdog/main.c Wed Jan 07 13:24:38 2026 -0800 @@ -46,6 +46,7 @@ typedef struct { char *filename; + char *title; Rectangle rect; long time_modified; boolean deleted; @@ -69,10 +70,33 @@ HistoryItem *history_items = NULL; HistoryItem *new_history_items = NULL; +// Global UI state +char *url_input_text = NULL; +char *url_result_text = NULL; +char **url_body_map = NULL; +int active_method_dropdown = 0; + int CompareHistoryItemsByDate(const void *a, const void *b) { HistoryItem *itemA = (HistoryItem *)a; HistoryItem *itemB = (HistoryItem *)b; - return (itemB->time_modified - itemA->time_modified); + return (itemB->time_modified - itemA->time_modified); +} + +char *PostDog_Extract_Title(const char *filename) +{ + char full_file_path[512] = {0}; + snprintf(full_file_path, 512, "%s/%s", POSTDOG_PATHS, filename); + FILE *file = fopen(full_file_path, "r"); + if (!file) + return strdup(filename); + + char *title = malloc(sizeof(char) * 512); + if (!fgets(title, 512, file)) { + fclose(file); + return strdup(filename); + } + + return title; } // TODO: Make this into generic fucntion so I can use it across different thing. @@ -91,7 +115,8 @@ do { HistoryItem item = {0}; item.filename = strdup(fileinfo.name); - item.time_modified = fileinfo.time_write; + item.title = PostDog_Extract_Title(fileinfo.name); + item.time_modified = fileinfo.time_write; item.deleted = FALSE; Dowa_Array_Push(file_arr, item); } while (_findnext(handle, &fileinfo) == 0); @@ -113,6 +138,7 @@ { HistoryItem item = {0}; item.filename = strdup(entry->d_name); + item.title = PostDog_Extract_Title(entry->d_name); item.time_modified = file_stat.st_mtime; item.deleted = FALSE; Dowa_Array_Push(file_arr, item); @@ -188,16 +214,14 @@ fclose(file); } -void PostDog_Request_SaveFile( - const char *url, - const char *method, - const char *headers, - const char *body, - const char *response) +void PostDog_Request_SaveFile(void) { + const char *method = PostDog_Enum_To_String(active_method_dropdown); size_t new_file_size = 1024 * 1024; Dowa_Arena *arena = Dowa_Arena_Create(1024 * 1024 * 2); char *new_file = Dowa_Arena_Allocate(arena, 1024 * 1024); + char *title = malloc(strlen(method) + strlen(url_input_text) + 2); + sprintf(title, "%s %s", method, url_input_text); snprintf( new_file, new_file_size, @@ -209,12 +233,21 @@ "---\n" "%s\n" "---\n" + "%s\n" + "---\n" + "%s\n" + "---\n" + "%s\n" + "---\n" "%s\n", - url, + title, + url_input_text, method, - headers, - body, - response + url_body_map[TAB_HEADER], + url_body_map[TAB_BODY], + url_body_map[TAB_GET_PARAMS], + url_body_map[TAB_BAR], + url_result_text ); char *filename = Dowa_Arena_Allocate(arena, 1024); if (!filename) @@ -236,8 +269,8 @@ HistoryItem item = {0}; item.filename = strdup(filename); + item.title = title; item.deleted = FALSE; - memcpy(item.filename, filename, strlen(filename) + 1); Dowa_Array_Push(new_history_items, item); Dowa_Arena_Free(arena); @@ -263,22 +296,18 @@ return real_size; } -int PostDog_Http_Request( - const char *url, - const char *method, - const char *headers, - const char *body, - char *response, size_t response_size) +int PostDog_Http_Request(void) { + const char *method = PostDog_Enum_To_String(active_method_dropdown); CURL *curl; CURLcode res; ResponseBuffer buffer = { .data = malloc(1), .size = 0 }; - response[0] = '\n'; + url_result_text[0] = '\n'; if (buffer.data == NULL) { - snprintf(response, response_size, "Error: Failed to allocate memory"); + snprintf(url_result_text, RESULT_BUFFER_LENGTH, "Error: Failed to allocate memory"); return -1; } buffer.data[0] = '\0'; @@ -291,20 +320,20 @@ struct curl_slist *headerList = NULL; // Set URL - curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_URL, url_input_text); // Set HTTP method if (strcmp(method, "POST") == 0) { curl_easy_setopt(curl, CURLOPT_POST, 1L); - if (body && strlen(body) > 0) - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body); - } + if (url_body_map[TAB_BODY] && strlen(url_body_map[TAB_BODY]) > 0) + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, url_body_map[TAB_BODY]); + } else if (strcmp(method, "PUT") == 0) { curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT"); - if (body && strlen(body) > 0) - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body); + if (url_body_map[TAB_BODY] && strlen(url_body_map[TAB_BODY]) > 0) + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, url_body_map[TAB_BODY]); } else if (strcmp(method, "DELETE") == 0) { @@ -313,12 +342,11 @@ // Default is GET // Parse and add headers - if (headers && strlen(headers) > 0) + if (url_body_map[TAB_HEADER] && strlen(url_body_map[TAB_HEADER]) > 0) { - char *headersCopy = strdup(headers); + char *headersCopy = strdup(url_body_map[TAB_HEADER]); char *line = strtok(headersCopy, "\n"); while (line != NULL) { - // Trim whitespace while (*line == ' ' || *line == '\t') line++; if (strlen(line) > 0) headerList = curl_slist_append(headerList, line); @@ -334,61 +362,51 @@ // Follow redirects curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); - // Set timeout curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30L); - // Perform request res = curl_easy_perform(curl); if (res != CURLE_OK) - snprintf(response, response_size, "Error: %s\n", curl_easy_strerror(res)); + snprintf(url_result_text, RESULT_BUFFER_LENGTH, "Error: %s\n", curl_easy_strerror(res)); else { long response_code; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); - if (buffer.size > response_size) + if (buffer.size > RESULT_BUFFER_LENGTH) printf("TODO: Realloc\n"); - snprintf(response, response_size, "HTTP Status: %ld\n\n%s", + snprintf(url_result_text, RESULT_BUFFER_LENGTH, "HTTP Status: %ld\n\n%s", response_code, buffer.data ? buffer.data : ""); } - // Cleanup if (headerList) curl_slist_free_all(headerList); curl_easy_cleanup(curl); } else - snprintf(response, response_size, "Error: Failed to initialize curl"); + snprintf(url_result_text, RESULT_BUFFER_LENGTH, "Error: Failed to initialize curl"); free(buffer.data); curl_global_cleanup(); - PostDog_Request_SaveFile( - url, - method, - headers, - body, - response); + PostDog_Request_SaveFile(); return 0; } -void PostDog_Update_URL(char **p_url_input_text, char* get_params) +void PostDog_Update_URL(void) { - char *url_input_text = *p_url_input_text; - - // Reset + // Save existing query string if present char *question_mark = strchr(url_input_text, '?'); if (question_mark) *question_mark = '\0'; - int get_params_length = (int)strlen(get_params) ; + int get_params_length = (int)strlen(url_body_map[TAB_GET_PARAMS]); if (get_params_length == 0) return; char *separator = "?"; Dowa_Arena *arena = Dowa_Arena_Create(1024*1024); - char **lines = Dowa_String_Split(get_params, "\n", get_params_length, 1, arena); + char **lines = Dowa_String_Split(url_body_map[TAB_GET_PARAMS], "\n", get_params_length, 1, arena); for (int i = 0; i < Dowa_Array_Length(lines); i++) { char *line = lines[i]; @@ -426,35 +444,17 @@ return 0; } -void PostDog_Params_Reset( - char **p_url_input_text, - int *p_active_method_dropdown, - char **url_body_map, - char **p_url_result_text -) +void PostDog_Params_Reset(void) { - char *url_input_text = *p_url_input_text; - char *url_result_text = *p_url_result_text; - int active_method_dropdown = *p_active_method_dropdown; - - url_input_text = ""; - url_result_text = ""; + url_input_text[0] = '\0'; + url_result_text[0] = '\0'; active_method_dropdown = 0; for (int i = 0; i < Dowa_Array_Length(url_body_map); i++) - url_body_map[i] = ""; + url_body_map[i][0] = '\0'; } -void PostDog_Load_File( - const char *filename, - char **p_url_input_text, - int *p_active_method_dropdown, - char **url_body_map, - char **p_url_result_text -) { - char *url_input_text = *p_url_input_text; - char *url_result_text = *p_url_result_text; - int active_method_dropdown = *p_active_method_dropdown; - +void PostDog_Load_File(const char *filename) +{ char full_file_path[512] = {0}; snprintf(full_file_path, 512, "%s/%s", POSTDOG_PATHS, filename); FILE *file = fopen(full_file_path, "r"); @@ -475,27 +475,43 @@ for (int i = 0; i < Dowa_Array_Length(values); i++) { - if (i == 0) - { - snprintf(url_input_text, strlen(values[i]) + 1, "%s", values[i]); - url_input_text[strcspn(url_input_text, "\n")] = '\0'; - } - else if (i == 1) - active_method_dropdown = PostDog_String_To_MethodEnum(values[i]); - else if (i <= 3) + switch (i) { - snprintf(url_body_map[i-2], strlen(values[i]) + 1, "%s", values[i]); - for (int j = strlen(values[i]); j > 0; j--) + case 0: // Title - skip + break; + + case 1: // URL + snprintf(url_input_text, strlen(values[i]) + 1, "%s", values[i]); + url_input_text[strcspn(url_input_text, "\n")] = '\0'; + break; + + case 2: // Method + active_method_dropdown = PostDog_String_To_MethodEnum(values[i]); + break; + + case 3: // Headers (TAB_HEADER) + case 4: // Body (TAB_BODY) + case 5: // Get Params (TAB_GET_PARAMS) + case 6: // Bar (TAB_BAR) { - if (url_body_map[i-2][j] == '\n') + int map_index = i - 3; // 3->0, 4->1, 5->2, 6->3 + snprintf(url_body_map[map_index], strlen(values[i]) + 1, "%s", values[i]); + // Trim trailing newlines + for (int j = strlen(values[i]); j > 0; j--) { - url_body_map[i-2][j] = '\0'; - break; + if (url_body_map[map_index][j] == '\n') + { + url_body_map[map_index][j] = '\0'; + break; + } } + break; } + + default: // Response (index 7+) + snprintf(url_result_text, strlen(values[i]) + 1, "%s", values[i]); + break; } - else - snprintf(url_result_text, strlen(values[i]) + 1, "%s", values[i]); } Dowa_Arena_Free(init_arena); @@ -595,6 +611,7 @@ GuiSetStyle(DEFAULT, TEXT_SIZE, 10); Image logo_original = LoadImage("postdog/epi_all_colors.png"); ImageResize(&logo_original, 60, 60); + SetWindowIcon(logo_original); Texture2D logo_texture = LoadTextureFromImage(logo_original); UnloadImage(logo_original); @@ -614,10 +631,10 @@ Rectangle method_dropdown = { 0 }; - char *url_input_text = (char *)malloc(sizeof(char) * URL_TEXT_BUFFER_LENGTH); + // Initialize global UI state + url_input_text = (char *)malloc(sizeof(char) * URL_TEXT_BUFFER_LENGTH); snprintf(url_input_text, URL_TEXT_BUFFER_LENGTH, "https://httpbin.org/get"); - char **url_body_map = NULL; Dowa_Array_Push(url_body_map, (char *)malloc(sizeof(char) * HEADER_BUFFER_LENGTH)); Dowa_Array_Push(url_body_map, (char *)malloc(sizeof(char) * BODY_BUFFER_LENGTH)); Dowa_Array_Push(url_body_map, (char *)malloc(sizeof(char) * DEFAULT_TEXT_BUFFER_LENGTH)); @@ -626,9 +643,8 @@ snprintf(url_body_map[TAB_HEADER], HEADER_BUFFER_LENGTH, "Content-Type: application/json"); snprintf(url_body_map[TAB_BODY], HEADER_BUFFER_LENGTH, ""); - char *url_result_text = (char *)malloc(sizeof(char) * RESULT_BUFFER_LENGTH); + url_result_text = (char *)malloc(sizeof(char) * RESULT_BUFFER_LENGTH); - int active_method_dropdown = 0; bool method_edit = false; int sendRequest; @@ -690,7 +706,7 @@ for (int i = 0; i < total; i++) { HistoryItem *curr_history_items = i < new_history_items_length ? - &new_history_items[i] : &history_items[i - new_history_items_length]; + &new_history_items[i - new_history_items_length - 1] : &history_items[i - new_history_items_length]; if (curr_history_items->deleted) { @@ -814,12 +830,11 @@ Rectangle source = { 0, 0, logo_texture.width, logo_texture.height }; DrawTexturePro(logo_texture, source, dest, (Vector2){0, 0}, 0.0f, WHITE); - // Draw history items with scissor mode for clipping BeginScissorMode(history_list_area.x, history_list_area.y, history_list_area.width, history_list_area.height); for (int i = 0; i < total; i++) { HistoryItem *curr_history_items = i < new_history_items_length ? - &new_history_items[i] : &history_items[i - new_history_items_length]; + &new_history_items[i - new_history_items_length - 1] : &history_items[i - new_history_items_length]; if (curr_history_items->deleted) continue; @@ -838,15 +853,9 @@ Rectangle icon_area_left_column = LeftColumn(icon_area, 0.5, 0); Rectangle icon_area_right_column = RightColumn(icon_area, icon_area_left_column, 0); - GuiDrawText(curr_history_items->filename, AddPadding(filename_area, padding), TEXT_ALIGN_CENTER, RED); + GuiDrawText(curr_history_items->title, AddPadding(filename_area, padding), TEXT_ALIGN_CENTER, RED); if (GuiButton(AddPaddingHorizontal(icon_area_left_column, padding), "view")) - PostDog_Load_File( - curr_history_items->filename, - &url_input_text, - &active_method_dropdown, - url_body_map, - &url_result_text - ); + PostDog_Load_File(curr_history_items->filename); if (GuiButton(AddPaddingHorizontal(icon_area_right_column,padding), "delete")) { if (!remove(PostDog_Construct_URL(curr_history_items->filename))) @@ -857,7 +866,6 @@ } EndScissorMode(); - // Draw scroll indicator for history if (total > 0) { float content_height = total * (item_height + padding); @@ -883,14 +891,7 @@ sendRequest = GuiButton(url_enter_button, "ENTER"); if (sendRequest) - PostDog_Http_Request( - url_input_text, - PostDog_Enum_To_String(active_method_dropdown), - url_body_map[TAB_HEADER], - url_body_map[TAB_BODY], - url_result_text, - RESULT_BUFFER_LENGTH - ); + PostDog_Http_Request(); if (GuiDropdownBox(method_dropdown, "GET;POST;PUT;DELETE", &active_method_dropdown, method_edit)) method_edit = !method_edit; @@ -900,7 +901,6 @@ GuiSetStyle(TOGGLE, GROUP_PADDING, 0); GuiDrawRectangle(input_body, 1, GetColor(GuiGetStyle(TEXTBOX, BORDER)), GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_PRESSED))); - // Create scrollable input body with offset BeginScissorMode(input_body.x, input_body.y, input_body.width, input_body.height); Rectangle scrolled_input = AddPadding(input_body, padding * 2); scrolled_input.y += input_body_scroll_offset; @@ -909,11 +909,9 @@ input_body_bool = !input_body_bool; EndScissorMode(); - // Draw scroll indicator for input body if (input_body_scroll_offset < 0) { - float scrollbar_height = 50; // Fixed size indicator - float max_scroll = 1000; // Estimated max scroll - float scrollbar_y = input_body.y - (input_body_scroll_offset / max_scroll) * (input_body.height - scrollbar_height); + float scrollbar_height = 10; + float scrollbar_y = input_body.y - (input_body_scroll_offset / MAX_SCROLL_HEIGHT) * (input_body.height - scrollbar_height); Rectangle scrollbar = { input_body.x + input_body.width - 5, scrollbar_y, @@ -925,7 +923,7 @@ GuiToggleGroup(input_tab_item, "Header;Body;Get Param;Bar", &active_input_tab); - PostDog_Update_URL(&url_input_text, url_body_map[TAB_GET_PARAMS]); + PostDog_Update_URL(); // Result Rect DrawRectangleRec(result_area, Fade(GREEN, 0.1f)); @@ -939,11 +937,9 @@ GuiTextBoxMulti(scrolled_result, url_result_text, RESULT_BUFFER_LENGTH, false); EndScissorMode(); - // Draw scroll indicator for result body if (result_body_scroll_offset < 0) { - float scrollbar_height = 50; // Fixed size indicator - float max_scroll = 1000; // Estimated max scroll - float scrollbar_y = result_body.y - (result_body_scroll_offset / max_scroll) * (result_body.height - scrollbar_height); + float scrollbar_height = 10; + float scrollbar_y = result_body.y - (result_body_scroll_offset / MAX_SCROLL_HEIGHT) * (result_body.height - scrollbar_height); Rectangle scrollbar = { result_body.x + result_body.width - 5, scrollbar_y,