Mercurial
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; +}