diff postdog/main.c @ 112:d6d578b49a19

[PostDog] Got CRUD working.
author June Park <parkjune1995@gmail.com>
date Sun, 04 Jan 2026 11:38:44 -0800
parents 48f260576059
children e2a73e64e8e6
line wrap: on
line diff
--- a/postdog/main.c	Sun Jan 04 06:39:16 2026 -0800
+++ b/postdog/main.c	Sun Jan 04 11:38:44 2026 -0800
@@ -14,37 +14,26 @@
 #define SCREEN_WIDTH 1280
 #define SCREEN_HEIGHT 780
 #define TEXT_SIZE 10
-#define LINE_HEIGHT 15
-#define GENERIC_PADDING 15
-
-#define SIDEBAR_WIDTH 200
-#define SIDEBAR_PADDING_GENERAL 5
-#define SIDEBAR_AREA_PADDING_X 10
-#define SIDEBAR_AREA_PADDING_Y 10
-#define SIDEBAR_REFERSH_BUTTON_WIDTH 90
-#define SIDEBAR_REFERSH_BUTTON_HEIGHT 20
-#define SIDEBAR_HISTORY_ITEM_HEIGHT 45
-
-#define URL_INPUT_HEIGHT 40
-
-#define TAB_LEN 3
-#define METHOD_BUTTON_WIDTH 100
-#define METHOD_BUTTON_HEIGHT 40
-#define SEND_BUTTON_WIDTH 100
-#define SEND_BUTTON_HEIGHT 40
 
 #define JSON_INPUT_BUFFER_LEN 8192
 #define HEADER_INPUT_BUFFER_LEN 4096
 #define PARAM_INPUT_BUFFER_LEN 4096
 #define MAX_HISTORY_ITEMS 100
 
-// Structure to hold response data
+#define HEADER_BUFFER_LENGTH 1024 * 4
+#define DEFAULT_TEXT_BUFFER_LENGTH 1024 * 4
+#define URL_TEXT_BUFFER 1024 * 10
+#define BODY_BUFFER_LENGTH 1024 * 1025 * 5
+#define RESULT_BUFFER_LENGTH 1024 * 1025 * 5
+#define AREANA_BUFFER_LENGTH 1024 * 1025 * 15
+
+typedef Dowa_KV(char*, char*) INPUT_HASHMAP;
+
 typedef struct {
   char *data;
   size_t size;
 } ResponseBuffer;
 
-// Structure to hold history item
 typedef struct {
   char filename[256];
   char displayName[128];
@@ -52,11 +41,16 @@
   time_t timestamp;
 } HistoryItem;
 
-typedef enum {
-  ActiveTab_JSON = 0,
-  ActiveTab_Headers, 
-  ActiveTab_Params,
-} ActiveTab;
+char *PostDog_Enum_To_String(int active_enum)
+{
+  switch(active_enum)
+  {
+    case 0: return "GET";
+    case 1: return "POST";
+    case 2: return "PUT";
+    case 3: return "DELETE";
+  }
+}
 
 static size_t Postdog_Curl_Callback(void *contents, size_t size, size_t nmemb, void *userp)
 {
@@ -78,13 +72,19 @@
   return real_size;
 }
 
-int PostDog_Make_HttpRequest(const char *url, const char *method, const char *headers,
-                    const char *body, char *response, size_t responseSize)
+int PostDog_Make_HttpRequest(
+    const char *url,
+    const char *method,
+    const char *headers,
+    const char *body, 
+    char *response, size_t responseSize)
 {
   CURL *curl;
   CURLcode res;
   ResponseBuffer buffer = { .data = malloc(1), .size = 0 };
 
+  response[0] = '\n';
+
   if (buffer.data == NULL)
   {
     snprintf(response, responseSize, "Error: Failed to allocate memory");
@@ -180,8 +180,77 @@
 typedef struct {
   Rectangle rectangle;
   char *label;
+  bool active;
 } TabItem;
 
+typedef enum {
+  TAB_HEADER = 0,
+  TAB_BODY,
+  TAB_GET_PARAMS,
+  TAB_BAR,
+} PostDog_Tab_Enum;
+
+void PostDog_Update_URL(char **p_url_input_text, char* get_params)
+{
+  char *url_input_text = *p_url_input_text;
+
+  // Reset
+  char *question_mark = strchr(url_input_text, '?');
+  if (question_mark)
+    *question_mark = '\0';
+
+  int get_params_length = (int)strlen(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);
+
+  size_t url_len = strlen(url_input_text);
+  size_t url_capacity = URL_TEXT_BUFFER;
+
+  for (int i = 0; i < Dowa_Array_Length(lines); i++)
+  {
+    char *line = lines[i];
+    char **key_value = Dowa_String_Split(line, " ", (int)strlen(line), 1, arena);
+
+    if (Dowa_Array_Length(key_value) < 2)
+      continue;  // Skip this line, not break entire loop
+
+    // Check buffer capacity before each append
+    size_t needed = url_len + strlen(separator) + strlen(key_value[0]) + 1 + 10; // +10 for "=" and safety
+    if (needed >= url_capacity) break;
+
+    strcat(url_input_text, separator);
+    strcat(url_input_text, key_value[0]);
+    strcat(url_input_text, "=");
+    url_len = strlen(url_input_text);
+
+    for (int i = 1; i < Dowa_Array_Length(key_value); i++)
+    {
+      if (!key_value[i] || key_value[i][0] == '\0')
+        break;
+
+      size_t value_len = strlen(key_value[i]);
+      needed = url_len + value_len + 4; // +4 for "%20" if needed
+      if (needed >= url_capacity) break;
+
+      printf("\n\n------\n\n");
+      printf("key_value[%i]: %s, p = %p\n", i, key_value[i], key_value[i]);
+      printf("\n\n------\n\n");
+
+      if (i > 1) strcat(url_input_text, "%20");
+      strcat(url_input_text, key_value[i]);
+      url_len = strlen(url_input_text);
+    }
+    separator = "&";
+  }
+
+  Dowa_Arena_Free(arena);
+}
+
 int main()
 {
   // -- initizlied --//
@@ -189,7 +258,7 @@
   SetWindowState(FLAG_WINDOW_RESIZABLE);
   SetTargetFPS(60);
 
-  Dowa_Arena *arena = Dowa_Arena_Create(1024 * 1025 * 10);
+  Dowa_Arena *arena = Dowa_Arena_Create(AREANA_BUFFER_LENGTH);
 
   // -- Starting pos ---//
   float side_bar_x = 10;
@@ -200,36 +269,44 @@
   Rectangle url_area = { 0 };
   Rectangle textBounds = { 0 };
   Rectangle url_input_bounds = { 0 };
+  bool url_input_bool = false;
   Rectangle url_text_bounds = { 0 };
   Rectangle url_enter_button = { 0 };
+  Rectangle method_dropdown = { 0 };
 
-  char *input_text = (char *)Dowa_Arena_Allocate(arena, 1024 * 4);
+  char *url_input_text = (char *)Dowa_Arena_Allocate(arena, URL_TEXT_BUFFER);
+  snprintf(url_input_text, URL_TEXT_BUFFER, "https://httpbin.org/get");
+
+  INPUT_HASHMAP *url_body_map = NULL;
+  Dowa_HashMap_Push_Arena(url_body_map, "Header", (char *)Dowa_Arena_Allocate(arena, HEADER_BUFFER_LENGTH), arena);
+  Dowa_HashMap_Push_Arena(url_body_map, "Body", (char *)Dowa_Arena_Allocate(arena, BODY_BUFFER_LENGTH), arena);
+  Dowa_HashMap_Push_Arena(url_body_map, "Get Param", (char *)Dowa_Arena_Allocate(arena, DEFAULT_TEXT_BUFFER_LENGTH), arena);
+  Dowa_HashMap_Push_Arena(url_body_map, "Bar",  (char *)Dowa_Arena_Allocate(arena, DEFAULT_TEXT_BUFFER_LENGTH), arena);
+
+  snprintf(url_body_map[0].value, HEADER_BUFFER_LENGTH, "Content-Type: application/json");
+  snprintf(url_body_map[1].value, HEADER_BUFFER_LENGTH, "");
+
+  char *url_result_text = (char *)Dowa_Arena_Allocate(arena, RESULT_BUFFER_LENGTH);
+
+  int active_method_dropdown = 0;
+  bool method_edit = false;
+
   int sendRequest;
 
+  // -- input --//
   Rectangle input_area = { 0 };
   Rectangle input_tab = { 0 };
-  TabItem input_tab_items[4] = {
-    {
-      .rectangle={0}, .label="body"
-    },
-    {
-      .rectangle={0}, .label="header"
-    },
-    {
-      .rectangle={0}, .label="foo"
-    },
-    {
-      .rectangle={0}, .label="bar"
-    },
-  };
+  Rectangle input_tab_item = { 0 };
   Rectangle input_body = { 0 };
+  bool input_body_bool = false;
 
+  // -- result --//
   Rectangle result_area = { 0 };
   Rectangle result_body = { 0 };
 
   // General styling.
   int padding = 10; // TODO make it % based?
-
+  int active_input_tab = 0;
 
   while (!WindowShouldClose())
   {
@@ -260,6 +337,11 @@
     url_enter_button.width = (url_area.width - padding) * 0.1;
     url_enter_button.height = TEXT_SIZE * 2;
 
+    method_dropdown.x = url_enter_button.x + url_enter_button.width + padding;
+    method_dropdown.y = (url_area.height) / 2;
+    method_dropdown.width = (url_area.width - padding) * 0.1;
+    method_dropdown.height = TEXT_SIZE * 2;
+
     // -- Input Area --//
     input_area.x = (side_bar_x + history_sidebar.width);
     input_area.y = (side_bar_y + url_area.height);
@@ -270,12 +352,8 @@
     input_tab.y = (side_bar_y + url_area.height) + padding;
     input_tab.width = url_area.width * 0.49 - padding;
     input_tab.height = input_area.height * 0.1;
-    for (int pos = 0; pos < 4; pos++)
-    {
-      input_tab_items[pos].rectangle = input_tab;
-      input_tab_items[pos].rectangle.x = input_tab.x + (pos * input_tab.width / 4);
-      input_tab_items[pos].rectangle.width = input_tab.width / 4;
-    }
+    input_tab_item = input_tab;
+    input_tab_item.width = input_tab.width / 4;
 
     input_body.x = input_tab.x;
     input_body.y = input_tab.y + input_tab.height;
@@ -302,21 +380,34 @@
       // URL area Rect
       GuiDrawText("URL: ", url_text_bounds, TEXT_ALIGN_CENTER, RED); 
       DrawRectangleRec(url_area, Fade(RED, 0.1f));
-      GuiTextBox(url_input_bounds, input_text, 1024 * 4, true);
+      if (GuiTextBox(url_input_bounds, url_input_text, DEFAULT_TEXT_BUFFER_LENGTH, url_input_bool))
+        url_input_bool = !url_input_bool;
       sendRequest = GuiButton(url_enter_button, "ENTER");
+      if (sendRequest)
+        PostDog_Make_HttpRequest(
+            url_input_text,
+            PostDog_Enum_To_String(active_method_dropdown),
+            url_body_map[0].value,
+            url_body_map[1].value,
+            url_result_text,
+            RESULT_BUFFER_LENGTH
+        );
+      if (GuiDropdownBox(method_dropdown, "GET;POST;PUT;DELETE", &active_method_dropdown, method_edit))
+        method_edit = !method_edit;
 
       // Input Tabs Rect
       DrawRectangleRec(input_area, Fade(BLUE, 0.1f));
       DrawRectangleRec(input_tab,  Fade(DARKBLUE, 0.1f));
-      for (int pos = 0; pos < 4; pos++)
-      {
-        JUNE_GuiButton(input_tab_items[pos].rectangle, input_tab_items[pos].label, 0, Fade(DARKBLUE, 0.1f)); 
-      }
-      JUNE_GuiTextBox(input_body, input_text, 1024 * 4, true);
+      GuiSetStyle(TOGGLE, GROUP_PADDING, 0);
+      if (JUNE_GuiTextBox(input_body, url_body_map[active_input_tab].value, DEFAULT_TEXT_BUFFER_LENGTH, input_body_bool))
+        input_body_bool = !input_body_bool;
+      GuiToggleGroup(input_tab_item, "Header;Body;Get Param;Bar", &active_input_tab);
+      PostDog_Update_URL(&url_input_text, url_body_map[TAB_GET_PARAMS].value);
 
       // Result Rect
       DrawRectangleRec(result_area, Fade(GREEN, 0.1f));
       DrawRectangleRec(result_body, Fade(DARKGREEN, 0.1f));
+      GuiTextBoxMulti(result_body, url_result_text, RESULT_BUFFER_LENGTH, false);
     EndDrawing();
   }
   CloseWindow();