diff dowa/d_string.c @ 186:8cf4ec5e2191 hg-web

Fixed merge conflict.
author MrJuneJune <me@mrjunejune.com>
date Fri, 23 Jan 2026 22:38:59 -0800
parents a2720eac50ce
children
line wrap: on
line diff
--- a/dowa/d_string.c	Wed Jan 21 19:32:08 2026 -0800
+++ b/dowa/d_string.c	Fri Jan 23 22:38:59 2026 -0800
@@ -133,7 +133,7 @@
 char *Dowa_String_Copy_Arena(char *from, Dowa_Arena *p_arena)
 {
   char *buffer = Dowa_Arena_Allocate(p_arena, sizeof(char*) * strlen(from) + 1);
-  if (buffer);
+  if (buffer)
     memcpy(buffer, from, strlen(from));
   buffer[strlen(from)] = '\0';
   return buffer;
@@ -160,3 +160,253 @@
   res[36] = '\0';
   return res;
 }
+
+// --- JSON Parser --- //
+
+static void json_skip_ws(const char *json, int32 *pos, int32 len)
+{
+  while (*pos < len && (json[*pos] == ' ' || json[*pos] == '\t' ||
+         json[*pos] == '\n' || json[*pos] == '\r'))
+    (*pos)++;
+}
+
+static char *json_parse_str(const char *json, int32 *pos, int32 len, Dowa_Arena *arena)
+{
+  if (*pos >= len || json[*pos] != '"')
+    return NULL;
+
+  (*pos)++;
+  int32 start = *pos;
+
+  while (*pos < len && json[*pos] != '"')
+    (*pos)++;
+
+  int32 slen = *pos - start;
+  char *str = arena ? Dowa_Arena_Allocate(arena, slen + 1) : malloc(slen + 1);
+  if (!str) return NULL;
+
+  int32 j = 0;
+  for (int32 i = start; i < *pos; i++)
+  {
+    if (json[i] == '\\' && i + 1 < *pos)
+    {
+      i++;
+      switch (json[i])
+      {
+        case 'n':  str[j++] = '\n'; break;
+        case 't':  str[j++] = '\t'; break;
+        case 'r':  str[j++] = '\r'; break;
+        case '\\': str[j++] = '\\'; break;
+        case '"':  str[j++] = '"';  break;
+        default:   str[j++] = json[i]; break;
+      }
+    }
+    else
+      str[j++] = json[i];
+  }
+  str[j] = '\0';
+
+  if (*pos < len && json[*pos] == '"')
+    (*pos)++;
+
+  return str;
+}
+
+// Forward declaration for recursion
+static Dowa_JSON_Value json_parse_val(const char *json, int32 *pos, int32 len, Dowa_Arena *arena);
+
+static Dowa_JSON_Entry *json_parse_obj(const char *json, int32 *pos, int32 len, Dowa_Arena *arena)
+{
+  if (*pos >= len || json[*pos] != '{')
+    return NULL;
+
+  (*pos)++;
+  Dowa_JSON_Entry *map = NULL;
+
+  while (*pos < len)
+  {
+    json_skip_ws(json, pos, len);
+
+    if (*pos >= len) break;
+    if (json[*pos] == '}') { (*pos)++; break; }
+    if (json[*pos] == ',') { (*pos)++; continue; }
+
+    char *key = json_parse_str(json, pos, len, arena);
+    if (!key) break;
+
+    json_skip_ws(json, pos, len);
+    if (*pos >= len || json[*pos] != ':') break;
+    (*pos)++;
+
+    Dowa_JSON_Value val = json_parse_val(json, pos, len, arena);
+
+    if (arena)
+      Dowa_HashMap_Push_Arena(map, key, val, arena);
+    else
+      Dowa_HashMap_Push(map, key, val);
+  }
+
+  return map;
+}
+
+static Dowa_JSON_Value *json_parse_arr(const char *json, int32 *pos, int32 len, Dowa_Arena *arena)
+{
+  if (*pos >= len || json[*pos] != '[')
+    return NULL;
+
+  (*pos)++;
+  Dowa_JSON_Value *arr = NULL;
+
+  while (*pos < len)
+  {
+    json_skip_ws(json, pos, len);
+
+    if (*pos >= len) break;
+    if (json[*pos] == ']') { (*pos)++; break; }
+    if (json[*pos] == ',') { (*pos)++; continue; }
+
+    Dowa_JSON_Value val = json_parse_val(json, pos, len, arena);
+
+    if (arena)
+      Dowa_Array_Push_Arena(arr, val, arena);
+    else
+      Dowa_Array_Push(arr, val);
+  }
+
+  return arr;
+}
+
+static Dowa_JSON_Value json_parse_val(const char *json, int32 *pos, int32 len, Dowa_Arena *arena)
+{
+  Dowa_JSON_Value val = {0};
+  json_skip_ws(json, pos, len);
+
+  if (*pos >= len)
+  {
+    val.type = DOWA_JSON_NULL;
+    return val;
+  }
+
+  char c = json[*pos];
+
+  // String
+  if (c == '"')
+  {
+    val.type = DOWA_JSON_STRING;
+    val.str_val = json_parse_str(json, pos, len, arena);
+    return val;
+  }
+
+  // Object
+  if (c == '{')
+  {
+    val.type = DOWA_JSON_OBJECT;
+    val.object_val = json_parse_obj(json, pos, len, arena);
+    return val;
+  }
+
+  // Array
+  if (c == '[')
+  {
+    val.type = DOWA_JSON_ARRAY;
+    val.array_val = json_parse_arr(json, pos, len, arena);
+    return val;
+  }
+
+  // Number
+  if (c == '-' || (c >= '0' && c <= '9'))
+  {
+    val.type = DOWA_JSON_NUMBER;
+    int32 start = *pos;
+    while (*pos < len && (json[*pos] == '-' || json[*pos] == '+' ||
+           json[*pos] == '.' || json[*pos] == 'e' || json[*pos] == 'E' ||
+           (json[*pos] >= '0' && json[*pos] <= '9')))
+      (*pos)++;
+
+    char tmp[64];
+    int32 nlen = *pos - start;
+    if (nlen >= 64) nlen = 63;
+    memcpy(tmp, &json[start], nlen);
+    tmp[nlen] = '\0';
+    val.num_val = atof(tmp);
+    return val;
+  }
+
+  // true
+  if (c == 't' && *pos + 4 <= len && memcmp(&json[*pos], "true", 4) == 0)
+  {
+    val.type = DOWA_JSON_BOOL;
+    val.bool_val = TRUE;
+    *pos += 4;
+    return val;
+  }
+
+  // false
+  if (c == 'f' && *pos + 5 <= len && memcmp(&json[*pos], "false", 5) == 0)
+  {
+    val.type = DOWA_JSON_BOOL;
+    val.bool_val = FALSE;
+    *pos += 5;
+    return val;
+  }
+
+  // null
+  if (c == 'n' && *pos + 4 <= len && memcmp(&json[*pos], "null", 4) == 0)
+  {
+    val.type = DOWA_JSON_NULL;
+    *pos += 4;
+    return val;
+  }
+
+  val.type = DOWA_JSON_NULL;
+  return val;
+}
+
+Dowa_JSON_Value Dowa_JSON_Parse(const char *json, int32 length, Dowa_Arena *p_arena)
+{
+  Dowa_JSON_Value val = {0};
+  if (!json || length <= 0)
+  {
+    val.type = DOWA_JSON_NULL;
+    return val;
+  }
+
+  int32 pos = 0;
+  return json_parse_val(json, &pos, length, p_arena);
+}
+
+Dowa_JSON_Value *Dowa_JSON_Get(Dowa_JSON_Entry *map, const char *key)
+{
+  if (!map || !key)
+    return NULL;
+
+  void *kv = Dowa_HashMap_Get_Ptr(map, key);
+  if (!kv)
+    return NULL;
+
+  return &((Dowa_JSON_Entry *)kv)->value;
+}
+
+char *Dowa_JSON_Get_String(Dowa_JSON_Entry *map, const char *key)
+{
+  Dowa_JSON_Value *val = Dowa_JSON_Get(map, key);
+  if (!val || val->type != DOWA_JSON_STRING)
+    return NULL;
+  return val->str_val;
+}
+
+double Dowa_JSON_Get_Number(Dowa_JSON_Entry *map, const char *key)
+{
+  Dowa_JSON_Value *val = Dowa_JSON_Get(map, key);
+  if (!val || val->type != DOWA_JSON_NUMBER)
+    return 0.0;
+  return val->num_val;
+}
+
+boolean Dowa_JSON_Get_Bool(Dowa_JSON_Entry *map, const char *key)
+{
+  Dowa_JSON_Value *val = Dowa_JSON_Get(map, key);
+  if (!val || val->type != DOWA_JSON_BOOL)
+    return FALSE;
+  return val->bool_val;
+}