json/json.c
2025-04-02 12:52:45 +00:00

193 lines
3.5 KiB
C

#include "json.h"
#include <assert.h>
#define UNREACHABLE() assert(false)
Json json_init(FILE* stream, Whitespace whitespace)
{
return (Json){
.stream = stream,
.whitespace = whitespace,
.indent_level = 0,
.next_punctuation = BEGINNING,
};
}
void json_free(Json* json)
{
}
void begin_value(Json* json);
void end_value(Json* json);
void push_indentation(Json* json);
void pop_indentation(Json* json);
void indent(Json* json);
void json_begin_array(Json* json)
{
begin_value(json);
putc('[', json->stream);
push_indentation(json);
json->next_punctuation = NONE;
}
void json_end_array(Json* json)
{
pop_indentation(json);
switch (json->next_punctuation) {
case NONE:
break;
case COMMA:
indent(json);
break;
case BEGINNING:
case COLON:
UNREACHABLE();
}
putc(']', json->stream);
end_value(json);
}
void json_begin_object(Json* json)
{
begin_value(json);
putc('{', json->stream);
push_indentation(json);
json->next_punctuation = NONE;
}
void json_end_object(Json* json)
{
pop_indentation(json);
switch (json->next_punctuation) {
case NONE:
break;
case COMMA:
indent(json);
break;
case BEGINNING:
case COLON:
UNREACHABLE();
}
putc('}', json->stream);
end_value(json);
}
void json_add_object_field(Json* json, const char* key)
{
begin_value(json);
fprintf(json->stream, "\"%s\"", key);
json->next_punctuation = COLON;
}
void json_add_string(Json* json, const char* value)
{
begin_value(json);
fprintf(json->stream, "\"%s\"", value);
end_value(json);
}
void json_add_long(Json* json, long value)
{
begin_value(json);
fprintf(json->stream, "%ld", value);
end_value(json);
}
void json_add_double(Json* json, double value)
{
begin_value(json);
fprintf(json->stream, "%f", value);
end_value(json);
}
void json_add_bool(Json* json, bool value)
{
begin_value(json);
const char* s;
if (value) {
s = "true";
} else {
s = "false";
}
fputs(s, json->stream);
end_value(json);
}
void json_add_null(Json* json)
{
begin_value(json);
fputs("null", json->stream);
end_value(json);
}
void begin_value(Json* json)
{
switch (json->next_punctuation) {
case BEGINNING:
break;
case NONE:
indent(json);
break;
case COMMA:
fputc(',', json->stream);
indent(json);
break;
case COLON:
putc(':', json->stream);
if (json->whitespace != MINIFIED) {
fputc(' ', json->stream);
}
break;
}
}
void end_value(Json* json)
{
json->next_punctuation = COMMA;
}
void push_indentation(Json* json)
{
json->indent_level += 1;
}
void pop_indentation(Json* json)
{
json->indent_level -= 1;
}
void indent(Json* json)
{
char indent_char = ' ';
int n;
switch (json->whitespace) {
case MINIFIED:
return;
case INDENT_1:
n = 1 * json->indent_level;
break;
case INDENT_2:
n = 2 * json->indent_level;
break;
case INDENT_3:
n = 3 * json->indent_level;
break;
case INDENT_4:
n = 4 * json->indent_level;
break;
case INDENT_8:
n = 8 * json->indent_level;
break;
case INDENT_TAB:
indent_char = '\t';
n = json->indent_level;
break;
}
putc('\n', json->stream);
for (int i = 0; i < n; i++) {
putc(indent_char, json->stream);
}
}