Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
bin
obj
Makefile
2 changes: 1 addition & 1 deletion example.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const char *read_file(const char *path) {
return (const char *)buffer;
}

int main() {
int main(void) {
const char *json = read_file("../sample/reddit.json");
if (json == NULL) {
return -1;
Expand Down
94 changes: 53 additions & 41 deletions json.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,31 @@
#include <stdlib.h>
#include <string.h>

/**
* @brief Determines whether a character `ch` is whitespace
*/
#define is_whitespace(ch) (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t')

#ifdef JSON_SKIP_WHITESPACE
#define json_skip_whitespace(arg) json_skip_whitespace_actual(arg)
void json_skip_whitespace(typed(json_string) * str_ptr) {
while (is_whitespace(**str_ptr))
(*str_ptr)++;
}
#else
#define json_skip_whitespace(arg)
#endif

#ifdef JSON_DEBUG
#define log(str, ...) printf(str "\n", ##__VA_ARGS__)
void json_debug_print(typed(json_string) str, typed(size) len) {
for (size_t i = 0; i < len; i++) {
if (str[i] == '\0')
break;

putchar(str[i]);
}
printf("\n");
}
#else
#define log(str, ...)
#endif
Expand Down Expand Up @@ -71,11 +88,6 @@
*/
#define reallocN(ptr, type, count) (type *)realloc(ptr, (count) * sizeof(type))

/**
* @brief Determines whether a character `ch` is whitespace
*/
#define is_whitespace(ch) (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t')

/**
* @brief Parses a JSON element {json_element_t} and moves the string
* pointer to the end of the parsed element
Expand Down Expand Up @@ -217,7 +229,7 @@ static bool json_skip_boolean(typed(json_string) *);
/**
* @brief Moves a JSON string pointer beyond any whitespace
*/
static void json_skip_whitespace_actual(typed(json_string) *);
// static void json_skip_whitespace_actual(typed(json_string) *);

/**
* @brief Moves a JSON string pointer beyond `null` literal
Expand Down Expand Up @@ -281,11 +293,6 @@ static result(json_string)
*/
static typed(size) json_string_len(typed(json_string));

/**
* @brief Debug print some characters from a string
*/
static void json_debug_print(typed(json_string) str, typed(size) len);

result(json_element) json_parse(typed(json_string) json_str) {
if (json_str == NULL) {
return result_err(json_element)(JSON_ERROR_EMPTY);
Expand Down Expand Up @@ -423,7 +430,10 @@ result(json_element_value) json_parse_string(typed(json_string) * str_ptr) {
// Skip to beyond the string
(*str_ptr) += len + 1;

return result_ok(json_element_value)((typed(json_element_value))output);
typed(json_element_value) retval = {0};
retval.as_string = output;

return result_ok(json_element_value)(retval);
}

result(json_element_value) json_parse_number(typed(json_string) * str_ptr) {
Expand All @@ -438,28 +448,35 @@ result(json_element_value) json_parse_number(typed(json_string) * str_ptr) {
temp_str++;
}

typed(json_number) number = {};
typed(json_number) number = {0};
typed(json_number_value) val = {0};

if (has_decimal) {
errno = 0;

val.as_double = strtod(*str_ptr, (char **)str_ptr);

number.type = JSON_NUMBER_TYPE_DOUBLE;
number.value = (typed(json_number_value))strtod(*str_ptr, (char **)str_ptr);
number.value = val;

if (errno == EINVAL || errno == ERANGE)
return result_err(json_element_value)(JSON_ERROR_INVALID_VALUE);
} else {
errno = 0;

val.as_long = strtol(*str_ptr, (char **)str_ptr, 10);

number.type = JSON_NUMBER_TYPE_LONG;
number.value =
(typed(json_number_value))strtol(*str_ptr, (char **)str_ptr, 10);
number.value = val;

if (errno == EINVAL || errno == ERANGE)
return result_err(json_element_value)(JSON_ERROR_INVALID_VALUE);
}

return result_ok(json_element_value)((typed(json_element_value))number);
typed(json_element_value) retval = {0};
retval.as_number = number;

return result_ok(json_element_value)(retval);
}

result(json_element_value) json_parse_object(typed(json_string) * str_ptr) {
Expand Down Expand Up @@ -552,7 +569,10 @@ result(json_element_value) json_parse_object(typed(json_string) * str_ptr) {
object->count = count;
object->entries = entries;

return result_ok(json_element_value)((typed(json_element_value))object);
typed(json_element_value) retval = {0};
retval.as_object = object;

return result_ok(json_element_value)(retval);
}

typed(uint64) json_key_hash(typed(json_string) str) {
Expand Down Expand Up @@ -623,7 +643,10 @@ result(json_element_value) json_parse_array(typed(json_string) * str_ptr) {
array->count = count;
array->elements = elements;

return result_ok(json_element_value)((typed(json_element_value))array);
typed(json_element_value) retval = {0};
retval.as_array = array;

return result_ok(json_element_value)(retval);
}

result(json_element_value) json_parse_boolean(typed(json_string) * str_ptr) {
Expand All @@ -640,8 +663,11 @@ result(json_element_value) json_parse_boolean(typed(json_string) * str_ptr) {
(*str_ptr) += 5;
break;
}

typed(json_element_value) retval = {0};
retval.as_boolean = output;

return result_ok(json_element_value)((typed(json_element_value))output);
return result_ok(json_element_value)(retval);
}

result(json_element)
Expand Down Expand Up @@ -817,11 +843,6 @@ bool json_skip_boolean(typed(json_string) * str_ptr) {
return false;
}

void json_skip_whitespace_actual(typed(json_string) * str_ptr) {
while (is_whitespace(**str_ptr))
(*str_ptr)++;
}

void json_skip_null(typed(json_string) * str_ptr) { (*str_ptr) += 4; }

void json_print(typed(json_element) * element, int indent) {
Expand Down Expand Up @@ -1074,19 +1095,10 @@ result(json_string)
return result_ok(json_string)((typed(json_string))output);
}

void json_debug_print(typed(json_string) str, typed(size) len) {
for (size_t i = 0; i < len; i++) {
if (str[i] == '\0')
break;

putchar(str[i]);
}
printf("\n");
}
define_result_type(json_element_type)
define_result_type(json_element_value)
define_result_type(json_element)
define_result_type(json_entry)
define_result_type(json_string)
define_result_type(size)

define_result_type(json_element_type);
define_result_type(json_element_value);
define_result_type(json_element);
define_result_type(json_entry);
define_result_type(json_string);
define_result_type(size);
30 changes: 14 additions & 16 deletions json.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,11 @@ typedef unsigned int bool;
typedef const char *typed(json_string);
typedef bool typed(json_boolean);

typedef enum json_number_type_e typed(json_number_type);
typedef union json_number_value_u typed(json_number_value);
typedef signed long typed(json_number_long);
typedef double typed(json_number_double);
typedef struct json_number_s typed(json_number);
typedef enum json_element_type_e typed(json_element_type);
typedef union json_element_value_u typed(json_element_value);
typedef enum json_error_e typed(json_error);
typedef struct json_element_s typed(json_element);
typedef struct json_entry_s typed(json_entry);
typedef struct json_object_s typed(json_object);
Expand Down Expand Up @@ -55,19 +52,19 @@ typedef struct json_array_s typed(json_array);
typed(name) result_unwrap(name)(result(name) *); \
typed(json_error) result_unwrap_err(name)(result(name) *);

enum json_element_type_e {
typedef enum json_element_type_e {
JSON_ELEMENT_TYPE_STRING = 0,
JSON_ELEMENT_TYPE_NUMBER,
JSON_ELEMENT_TYPE_OBJECT,
JSON_ELEMENT_TYPE_ARRAY,
JSON_ELEMENT_TYPE_BOOLEAN,
JSON_ELEMENT_TYPE_NULL
};
} typed(json_element_type);

enum json_number_type_e {
typedef enum json_number_type_e {
JSON_NUMBER_TYPE_LONG = 0,
JSON_NUMBER_TYPE_DOUBLE,
};
} typed(json_number_type);

union json_number_value_u {
typed(json_number_long) as_long;
Expand Down Expand Up @@ -107,19 +104,19 @@ struct json_array_s {
typed(json_element) * elements;
};

enum json_error_e {
typedef enum json_error_e {
JSON_ERROR_EMPTY = 0,
JSON_ERROR_INVALID_TYPE,
JSON_ERROR_INVALID_KEY,
JSON_ERROR_INVALID_VALUE
};
} typed(json_error);

declare_result_type(json_element_type);
declare_result_type(json_element_value);
declare_result_type(json_element);
declare_result_type(json_entry);
declare_result_type(json_string);
declare_result_type(size);
declare_result_type(json_element_type)
declare_result_type(json_element_value)
declare_result_type(json_element)
declare_result_type(json_entry)
declare_result_type(json_string)
declare_result_type(size)

/**
* @brief Parses a JSON string into a JSON element {json_element_t}
Expand Down Expand Up @@ -162,4 +159,5 @@ void json_free(typed(json_element) * element);
* @param error The JSON error enum {json_error_t} type
* @return The string representation
*/
typed(json_string) json_error_to_string(typed(json_error) error);
typed(json_string) json_error_to_string(typed(json_error) error);