Skip to content

Instantly share code, notes, and snippets.

@DieTime
Last active July 7, 2022 16:12
Show Gist options
  • Save DieTime/96a5bd22c8ed27bc638d0f6dde4d536f to your computer and use it in GitHub Desktop.
Save DieTime/96a5bd22c8ed27bc638d0f6dde4d536f to your computer and use it in GitHub Desktop.
#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