From c5fa173a178d8a747903ee469d32d203a5b481bf Mon Sep 17 00:00:00 2001 From: Stephen Molloy Date: Wed, 21 Feb 2024 11:16:13 +0100 Subject: [PATCH 1/7] Gitignore some dev stuff --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index ba077a4..62cfd93 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ bin +obj +Makefile From 51807e270a065c9ddd11ca3a6ec9a527734b736e Mon Sep 17 00:00:00 2001 From: Stephen Molloy Date: Wed, 21 Feb 2024 11:51:17 +0100 Subject: [PATCH 2/7] Hid some funcs inside #defines in order to remove complaints about unused functions. Added newlines to end of files --- json.c | 49 +++++++++++++++++++++---------------------------- json.h | 3 ++- 2 files changed, 23 insertions(+), 29 deletions(-) diff --git a/json.c b/json.c index 64edfdb..a958091 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); @@ -817,11 +824,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 +1076,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); \ No newline at end of file +define_result_type(size); + diff --git a/json.h b/json.h index 3e5d4d9..b13f6c8 100644 --- a/json.h +++ b/json.h @@ -162,4 +162,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); + From adadcdb90ee8c94701abbadea3418e4ee4202666 Mon Sep 17 00:00:00 2001 From: Stephen Molloy Date: Wed, 21 Feb 2024 12:52:19 +0100 Subject: [PATCH 3/7] Removed semicolons from the end of macros that define functions to remove complaint from -Wextra-semi --- json.c | 12 ++++++------ json.h | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/json.c b/json.c index a958091..0d795f7 100644 --- a/json.c +++ b/json.c @@ -1076,10 +1076,10 @@ result(json_string) return result_ok(json_string)((typed(json_string))output); } -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) diff --git a/json.h b/json.h index b13f6c8..142dc10 100644 --- a/json.h +++ b/json.h @@ -114,12 +114,12 @@ enum json_error_e { JSON_ERROR_INVALID_VALUE }; -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} From 89afa8c11d2d695b23163fd438f9a13b149e7488 Mon Sep 17 00:00:00 2001 From: Stephen Molloy Date: Wed, 21 Feb 2024 12:56:12 +0100 Subject: [PATCH 4/7] Empty initialisers make -pedantic unhappy --- json.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json.c b/json.c index 0d795f7..1b85522 100644 --- a/json.c +++ b/json.c @@ -445,7 +445,7 @@ result(json_element_value) json_parse_number(typed(json_string) * str_ptr) { temp_str++; } - typed(json_number) number = {}; + typed(json_number) number = {0}; if (has_decimal) { errno = 0; From 8a8a3023550e46cd583594b06e8972ab1b58aede Mon Sep 17 00:00:00 2001 From: Stephen Molloy Date: Wed, 21 Feb 2024 12:56:55 +0100 Subject: [PATCH 5/7] No empty function declarations --- example.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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; From b0861a2a51c6c6c59d629a54fe06f2bbf5625ffa Mon Sep 17 00:00:00 2001 From: Stephen Molloy Date: Wed, 21 Feb 2024 13:03:32 +0100 Subject: [PATCH 6/7] Removed forward declarations of enum types since these are forbidden by ISO C --- json.h | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/json.h b/json.h index 142dc10..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,12 +104,12 @@ 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) From 760d9d1755f0858866561f2ac4dc701fd9e08751 Mon Sep 17 00:00:00 2001 From: Stephen Molloy Date: Wed, 21 Feb 2024 14:13:28 +0100 Subject: [PATCH 7/7] Instead of casting to union types (a GNU extension), build a return val of the right type, and populate it appropriately --- json.c | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/json.c b/json.c index 1b85522..f47f52c 100644 --- a/json.c +++ b/json.c @@ -430,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) { @@ -446,27 +449,34 @@ result(json_element_value) json_parse_number(typed(json_string) * str_ptr) { } 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) { @@ -559,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) { @@ -630,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) { @@ -647,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)