diff --git a/.gitignore b/.gitignore index ba077a4..62cfd93 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ bin +obj +Makefile diff --git a/example.c b/example.c index 776d6d4..7d486d2 100644 --- a/example.c +++ b/example.c @@ -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; diff --git a/json.c b/json.c index 64edfdb..f47f52c 100644 --- a/json.c +++ b/json.c @@ -7,14 +7,31 @@ #include #include +/** + * @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 @@ -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 @@ -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 @@ -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); @@ -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) { @@ -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) { @@ -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) { @@ -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) { @@ -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) @@ -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) { @@ -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); \ No newline at end of file diff --git a/json.h b/json.h index 3e5d4d9..8c2ff18 100644 --- a/json.h +++ b/json.h @@ -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); @@ -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; @@ -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} @@ -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); \ No newline at end of file +typed(json_string) json_error_to_string(typed(json_error) error); +