Mercurial
comparison dowa/d_string.c @ 182:d6ab5921fedc
Merging in changes I had on my mac related to JSON parser and MPC endpoints.
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Fri, 23 Jan 2026 21:09:49 -0800 |
| parents | a2720eac50ce |
| children |
comparison
equal
deleted
inserted
replaced
| 179:8d17f6e6e290 | 182:d6ab5921fedc |
|---|---|
| 131 } | 131 } |
| 132 | 132 |
| 133 char *Dowa_String_Copy_Arena(char *from, Dowa_Arena *p_arena) | 133 char *Dowa_String_Copy_Arena(char *from, Dowa_Arena *p_arena) |
| 134 { | 134 { |
| 135 char *buffer = Dowa_Arena_Allocate(p_arena, sizeof(char*) * strlen(from) + 1); | 135 char *buffer = Dowa_Arena_Allocate(p_arena, sizeof(char*) * strlen(from) + 1); |
| 136 if (buffer); | 136 if (buffer) |
| 137 memcpy(buffer, from, strlen(from)); | 137 memcpy(buffer, from, strlen(from)); |
| 138 buffer[strlen(from)] = '\0'; | 138 buffer[strlen(from)] = '\0'; |
| 139 return buffer; | 139 return buffer; |
| 140 } | 140 } |
| 141 | 141 |
| 158 res[i++] = POOL[seed % 16]; | 158 res[i++] = POOL[seed % 16]; |
| 159 } | 159 } |
| 160 res[36] = '\0'; | 160 res[36] = '\0'; |
| 161 return res; | 161 return res; |
| 162 } | 162 } |
| 163 | |
| 164 // --- JSON Parser --- // | |
| 165 | |
| 166 static void json_skip_ws(const char *json, int32 *pos, int32 len) | |
| 167 { | |
| 168 while (*pos < len && (json[*pos] == ' ' || json[*pos] == '\t' || | |
| 169 json[*pos] == '\n' || json[*pos] == '\r')) | |
| 170 (*pos)++; | |
| 171 } | |
| 172 | |
| 173 static char *json_parse_str(const char *json, int32 *pos, int32 len, Dowa_Arena *arena) | |
| 174 { | |
| 175 if (*pos >= len || json[*pos] != '"') | |
| 176 return NULL; | |
| 177 | |
| 178 (*pos)++; | |
| 179 int32 start = *pos; | |
| 180 | |
| 181 while (*pos < len && json[*pos] != '"') | |
| 182 (*pos)++; | |
| 183 | |
| 184 int32 slen = *pos - start; | |
| 185 char *str = arena ? Dowa_Arena_Allocate(arena, slen + 1) : malloc(slen + 1); | |
| 186 if (!str) return NULL; | |
| 187 | |
| 188 int32 j = 0; | |
| 189 for (int32 i = start; i < *pos; i++) | |
| 190 { | |
| 191 if (json[i] == '\\' && i + 1 < *pos) | |
| 192 { | |
| 193 i++; | |
| 194 switch (json[i]) | |
| 195 { | |
| 196 case 'n': str[j++] = '\n'; break; | |
| 197 case 't': str[j++] = '\t'; break; | |
| 198 case 'r': str[j++] = '\r'; break; | |
| 199 case '\\': str[j++] = '\\'; break; | |
| 200 case '"': str[j++] = '"'; break; | |
| 201 default: str[j++] = json[i]; break; | |
| 202 } | |
| 203 } | |
| 204 else | |
| 205 str[j++] = json[i]; | |
| 206 } | |
| 207 str[j] = '\0'; | |
| 208 | |
| 209 if (*pos < len && json[*pos] == '"') | |
| 210 (*pos)++; | |
| 211 | |
| 212 return str; | |
| 213 } | |
| 214 | |
| 215 // Forward declaration for recursion | |
| 216 static Dowa_JSON_Value json_parse_val(const char *json, int32 *pos, int32 len, Dowa_Arena *arena); | |
| 217 | |
| 218 static Dowa_JSON_Entry *json_parse_obj(const char *json, int32 *pos, int32 len, Dowa_Arena *arena) | |
| 219 { | |
| 220 if (*pos >= len || json[*pos] != '{') | |
| 221 return NULL; | |
| 222 | |
| 223 (*pos)++; | |
| 224 Dowa_JSON_Entry *map = NULL; | |
| 225 | |
| 226 while (*pos < len) | |
| 227 { | |
| 228 json_skip_ws(json, pos, len); | |
| 229 | |
| 230 if (*pos >= len) break; | |
| 231 if (json[*pos] == '}') { (*pos)++; break; } | |
| 232 if (json[*pos] == ',') { (*pos)++; continue; } | |
| 233 | |
| 234 char *key = json_parse_str(json, pos, len, arena); | |
| 235 if (!key) break; | |
| 236 | |
| 237 json_skip_ws(json, pos, len); | |
| 238 if (*pos >= len || json[*pos] != ':') break; | |
| 239 (*pos)++; | |
| 240 | |
| 241 Dowa_JSON_Value val = json_parse_val(json, pos, len, arena); | |
| 242 | |
| 243 if (arena) | |
| 244 Dowa_HashMap_Push_Arena(map, key, val, arena); | |
| 245 else | |
| 246 Dowa_HashMap_Push(map, key, val); | |
| 247 } | |
| 248 | |
| 249 return map; | |
| 250 } | |
| 251 | |
| 252 static Dowa_JSON_Value *json_parse_arr(const char *json, int32 *pos, int32 len, Dowa_Arena *arena) | |
| 253 { | |
| 254 if (*pos >= len || json[*pos] != '[') | |
| 255 return NULL; | |
| 256 | |
| 257 (*pos)++; | |
| 258 Dowa_JSON_Value *arr = NULL; | |
| 259 | |
| 260 while (*pos < len) | |
| 261 { | |
| 262 json_skip_ws(json, pos, len); | |
| 263 | |
| 264 if (*pos >= len) break; | |
| 265 if (json[*pos] == ']') { (*pos)++; break; } | |
| 266 if (json[*pos] == ',') { (*pos)++; continue; } | |
| 267 | |
| 268 Dowa_JSON_Value val = json_parse_val(json, pos, len, arena); | |
| 269 | |
| 270 if (arena) | |
| 271 Dowa_Array_Push_Arena(arr, val, arena); | |
| 272 else | |
| 273 Dowa_Array_Push(arr, val); | |
| 274 } | |
| 275 | |
| 276 return arr; | |
| 277 } | |
| 278 | |
| 279 static Dowa_JSON_Value json_parse_val(const char *json, int32 *pos, int32 len, Dowa_Arena *arena) | |
| 280 { | |
| 281 Dowa_JSON_Value val = {0}; | |
| 282 json_skip_ws(json, pos, len); | |
| 283 | |
| 284 if (*pos >= len) | |
| 285 { | |
| 286 val.type = DOWA_JSON_NULL; | |
| 287 return val; | |
| 288 } | |
| 289 | |
| 290 char c = json[*pos]; | |
| 291 | |
| 292 // String | |
| 293 if (c == '"') | |
| 294 { | |
| 295 val.type = DOWA_JSON_STRING; | |
| 296 val.str_val = json_parse_str(json, pos, len, arena); | |
| 297 return val; | |
| 298 } | |
| 299 | |
| 300 // Object | |
| 301 if (c == '{') | |
| 302 { | |
| 303 val.type = DOWA_JSON_OBJECT; | |
| 304 val.object_val = json_parse_obj(json, pos, len, arena); | |
| 305 return val; | |
| 306 } | |
| 307 | |
| 308 // Array | |
| 309 if (c == '[') | |
| 310 { | |
| 311 val.type = DOWA_JSON_ARRAY; | |
| 312 val.array_val = json_parse_arr(json, pos, len, arena); | |
| 313 return val; | |
| 314 } | |
| 315 | |
| 316 // Number | |
| 317 if (c == '-' || (c >= '0' && c <= '9')) | |
| 318 { | |
| 319 val.type = DOWA_JSON_NUMBER; | |
| 320 int32 start = *pos; | |
| 321 while (*pos < len && (json[*pos] == '-' || json[*pos] == '+' || | |
| 322 json[*pos] == '.' || json[*pos] == 'e' || json[*pos] == 'E' || | |
| 323 (json[*pos] >= '0' && json[*pos] <= '9'))) | |
| 324 (*pos)++; | |
| 325 | |
| 326 char tmp[64]; | |
| 327 int32 nlen = *pos - start; | |
| 328 if (nlen >= 64) nlen = 63; | |
| 329 memcpy(tmp, &json[start], nlen); | |
| 330 tmp[nlen] = '\0'; | |
| 331 val.num_val = atof(tmp); | |
| 332 return val; | |
| 333 } | |
| 334 | |
| 335 // true | |
| 336 if (c == 't' && *pos + 4 <= len && memcmp(&json[*pos], "true", 4) == 0) | |
| 337 { | |
| 338 val.type = DOWA_JSON_BOOL; | |
| 339 val.bool_val = TRUE; | |
| 340 *pos += 4; | |
| 341 return val; | |
| 342 } | |
| 343 | |
| 344 // false | |
| 345 if (c == 'f' && *pos + 5 <= len && memcmp(&json[*pos], "false", 5) == 0) | |
| 346 { | |
| 347 val.type = DOWA_JSON_BOOL; | |
| 348 val.bool_val = FALSE; | |
| 349 *pos += 5; | |
| 350 return val; | |
| 351 } | |
| 352 | |
| 353 // null | |
| 354 if (c == 'n' && *pos + 4 <= len && memcmp(&json[*pos], "null", 4) == 0) | |
| 355 { | |
| 356 val.type = DOWA_JSON_NULL; | |
| 357 *pos += 4; | |
| 358 return val; | |
| 359 } | |
| 360 | |
| 361 val.type = DOWA_JSON_NULL; | |
| 362 return val; | |
| 363 } | |
| 364 | |
| 365 Dowa_JSON_Value Dowa_JSON_Parse(const char *json, int32 length, Dowa_Arena *p_arena) | |
| 366 { | |
| 367 Dowa_JSON_Value val = {0}; | |
| 368 if (!json || length <= 0) | |
| 369 { | |
| 370 val.type = DOWA_JSON_NULL; | |
| 371 return val; | |
| 372 } | |
| 373 | |
| 374 int32 pos = 0; | |
| 375 return json_parse_val(json, &pos, length, p_arena); | |
| 376 } | |
| 377 | |
| 378 Dowa_JSON_Value *Dowa_JSON_Get(Dowa_JSON_Entry *map, const char *key) | |
| 379 { | |
| 380 if (!map || !key) | |
| 381 return NULL; | |
| 382 | |
| 383 void *kv = Dowa_HashMap_Get_Ptr(map, key); | |
| 384 if (!kv) | |
| 385 return NULL; | |
| 386 | |
| 387 return &((Dowa_JSON_Entry *)kv)->value; | |
| 388 } | |
| 389 | |
| 390 char *Dowa_JSON_Get_String(Dowa_JSON_Entry *map, const char *key) | |
| 391 { | |
| 392 Dowa_JSON_Value *val = Dowa_JSON_Get(map, key); | |
| 393 if (!val || val->type != DOWA_JSON_STRING) | |
| 394 return NULL; | |
| 395 return val->str_val; | |
| 396 } | |
| 397 | |
| 398 double Dowa_JSON_Get_Number(Dowa_JSON_Entry *map, const char *key) | |
| 399 { | |
| 400 Dowa_JSON_Value *val = Dowa_JSON_Get(map, key); | |
| 401 if (!val || val->type != DOWA_JSON_NUMBER) | |
| 402 return 0.0; | |
| 403 return val->num_val; | |
| 404 } | |
| 405 | |
| 406 boolean Dowa_JSON_Get_Bool(Dowa_JSON_Entry *map, const char *key) | |
| 407 { | |
| 408 Dowa_JSON_Value *val = Dowa_JSON_Get(map, key); | |
| 409 if (!val || val->type != DOWA_JSON_BOOL) | |
| 410 return FALSE; | |
| 411 return val->bool_val; | |
| 412 } |