Last active
July 7, 2022 16:12
-
-
Save DieTime/96a5bd22c8ed27bc638d0f6dde4d536f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <glib.h> | |
typedef enum { | |
JSON_STR, | |
JSON_INT, | |
JSON_FLOAT, | |
JSON_ARRAY, | |
JSON_OBJECT, | |
} JsonType; | |
struct json_array_t; | |
struct json_object_t; | |
typedef struct | |
{ | |
JsonType type; | |
union { | |
char *string; | |
int integer; | |
double floating; | |
struct json_array_t *array; | |
struct json_object_t *object; | |
} as; | |
} JsonEntry; | |
typedef struct json_array_t JsonArray; | |
struct json_array_t { | |
size_t length; | |
JsonEntry **entries; | |
}; | |
typedef struct json_object_t JsonObject; | |
struct json_object_t { | |
size_t length; | |
const char **keys; | |
JsonEntry **entries; | |
}; | |
JsonEntry *json_str_new(const char *string) { | |
JsonEntry *entry = malloc(sizeof(JsonEntry)); | |
entry->type = JSON_STR; | |
entry->as.string = strdup(string); | |
return entry; | |
} | |
JsonEntry *json_int_new(int integer) { | |
JsonEntry *entry = malloc(sizeof(JsonEntry)); | |
entry->type = JSON_INT; | |
entry->as.integer = integer; | |
return entry; | |
} | |
JsonEntry *json_double_new(double floating) { | |
JsonEntry *entry = malloc(sizeof(JsonEntry)); | |
entry->type = JSON_FLOAT; | |
entry->as.floating = floating; | |
return entry; | |
} | |
JsonEntry *json_arr_new(size_t length, JsonEntry **entries) { | |
JsonEntry *entry = malloc(sizeof(JsonEntry)); | |
entry->type = JSON_ARRAY; | |
entry->as.array = malloc(sizeof(JsonArray)); | |
entry->as.array->length = length; | |
entry->as.array->entries = malloc(length * sizeof(JsonEntry *)); | |
for (size_t i = 0; i < length; i++) { | |
entry->as.array->entries[i] = entries[i]; | |
} | |
return entry; | |
} | |
JsonEntry *json_obj_new(size_t length, const char **keys, JsonEntry **entries) { | |
if (keys == NULL || entries == NULL || length == 0) | |
return NULL; | |
JsonEntry *entry = g_new0(JsonEntry, 1); | |
entry->type = JSON_OBJECT; | |
entry->as.object = g_new0(JsonObject, 1); | |
entry->as.object->keys = g_new0(const char *, length); | |
entry->as.object->entries = g_new0(JsonEntry *, length); | |
for (size_t i = 0; i < length; i++) { | |
if (keys[i] == NULL || entries[i] == NULL) { | |
g_free(entry); | |
return NULL; | |
} | |
entry->as.object->keys[i] = keys[i]; | |
entry->as.object->entries[i] = entries[i]; | |
} | |
entry->as.object->length = length; | |
return entry; | |
} | |
void strappend(char **str, const char *src, size_t *size) | |
{ | |
if (strlen(*str) + strlen(src) >= *size) { | |
*str = realloc(*str, *size * 2); | |
*size *= 2; | |
} | |
strcat(*str, src); | |
} | |
void json_to_string(JsonEntry *json, char **result, size_t *result_size) { | |
if (*result == NULL) { | |
*result = malloc(1); | |
*result_size = 1; | |
} | |
char buffer[1024] = {0}; | |
switch (json->type) { | |
case JSON_STR: | |
strappend(result, "\"", result_size); | |
strappend(result, json->as.string, result_size); | |
strappend(result, "\"", result_size); | |
break; | |
case JSON_INT: | |
sprintf(buffer, "%d", json->as.integer); | |
strappend(result, buffer, result_size); | |
break; | |
case JSON_FLOAT: | |
sprintf(buffer, "%f", json->as.floating); | |
strappend(result, buffer, result_size); | |
break; | |
case JSON_ARRAY: { | |
char *sep = "["; | |
for (size_t i = 0; i < json->as.array->length; i++) { | |
strappend(result, sep, result_size); | |
json_to_string(json->as.array->entries[i], result, result_size); | |
sep = ", "; | |
} | |
strappend(result, "]", result_size); | |
} break; | |
case JSON_OBJECT: { | |
char *sep = "{"; | |
for (size_t i = 0; i < json->as.object->length; i++) { | |
strappend(result, sep, result_size); | |
strappend(result, "\"", result_size); | |
strappend(result, json->as.object->keys[i], result_size); | |
strappend(result, "\": ", result_size); | |
json_to_string(json->as.object->entries[i], result, result_size); | |
sep = ", "; | |
} | |
strappend(result, "}", result_size); | |
} break; | |
default: | |
break; | |
} | |
} | |
void json_free(JsonEntry *json) { | |
switch (json->type) { | |
case JSON_STR: | |
g_free(json->as.string); | |
break; | |
case JSON_ARRAY: | |
for (size_t i = 0; i < json->as.array->length; i++) | |
json_free(json->as.array->entries[i]); | |
g_free(json->as.array->entries); | |
g_free(json->as.array); | |
break; | |
case JSON_OBJECT: | |
for (size_t i = 0; i < json->as.object->length; i++) | |
json_free(json->as.object->entries[i]); | |
g_free(json->as.object->entries); | |
g_free(json->as.object->keys); | |
g_free(json->as.object); | |
break; | |
case JSON_INT: | |
case JSON_FLOAT: | |
default: | |
break; | |
} | |
g_free(json); | |
} | |
#define K(l,...) (const char *[(l)]) __VA_ARGS__ | |
#define V(l,...) (JsonEntry *[(l)]) __VA_ARGS__ | |
#define JS(s) json_str_new((s)) | |
#define JI(i) json_int_new((i)) | |
#define JD(d) json_double_new((d)) | |
#define JO(l,...) json_obj_new((l), __VA_ARGS__) | |
#define JA(l,...) json_arr_new((l), __VA_ARGS__) | |
#define J JO | |
int main() { | |
JsonEntry *json = J( | |
5, | |
K(5, { "1", "2", "3", "4", "5" }), | |
V(5, { | |
JS("1"), | |
JI(2), | |
JD(3.0), | |
JA( | |
1, | |
V(1, { JI(1) }) | |
), | |
JO( | |
1, | |
K(1, { "1" }), | |
V(1, { JS("1") }) | |
) | |
}) | |
); | |
char *json_str = NULL; | |
size_t json_str_size = 0; | |
// {"1": "1", "2": 2, "3": 3.000000, "4": [1], "5": {"1": "1"}} | |
json_to_string(json, &json_str, &json_str_size); | |
printf("%s\n", json_str); | |
g_free(json_str); | |
json_free(json); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment