Thu, 31 Oct 2024 14:54:44 +0100
remove cx_for_n() macro - fixes #467
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2024 Mike Becker, Olaf Wintermann All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * \file json.h * \brief Interface for parsing data from JSON files. * \author Mike Becker * \author Olaf Wintermann * \copyright 2-Clause BSD License */ #ifndef UCX_JSON_H #define UCX_JSON_H #include "common.h" #include "string.h" #ifdef __cplusplus extern "C" { #endif enum cx_json_token_type { CX_JSON_NO_TOKEN, CX_JSON_TOKEN_ERROR, CX_JSON_TOKEN_BEGIN_ARRAY, CX_JSON_TOKEN_BEGIN_OBJECT, CX_JSON_TOKEN_END_ARRAY, CX_JSON_TOKEN_END_OBJECT, CX_JSON_TOKEN_NAME_SEPARATOR, CX_JSON_TOKEN_VALUE_SEPARATOR, CX_JSON_TOKEN_STRING, CX_JSON_TOKEN_INTEGER, CX_JSON_TOKEN_NUMBER, CX_JSON_TOKEN_LITERAL, CX_JSON_TOKEN_SPACE }; enum cx_json_value_type { CX_JSON_NOTHING, // this allows us to always return non-NULL values CX_JSON_OBJECT, CX_JSON_ARRAY, CX_JSON_STRING, CX_JSON_INTEGER, // TODO: the spec does not know integer types CX_JSON_NUMBER, CX_JSON_LITERAL }; enum cx_json_literal_type { CX_JSON_NULL, CX_JSON_TRUE, CX_JSON_FALSE }; enum cx_json_reader_type { CX_JSON_READER_OBJECT_BEGIN, CX_JSON_READER_OBJECT_END, CX_JSON_READER_ARRAY_BEGIN, CX_JSON_READER_ARRAY_END, CX_JSON_READER_STRING, CX_JSON_READER_INTEGER, CX_JSON_READER_NUMBER, CX_JSON_READER_LITERAL }; typedef enum cx_json_token_type CxJsonTokenType; typedef enum cx_json_value_type CxJsonValueType; typedef enum cx_json_literal_type CxJsonLiteralType; typedef enum cx_json_reader_type CxJsonReaderType; typedef struct cx_json_s CxJson; typedef struct cx_json_token_s CxJsonToken; typedef struct cx_json_value_s CxJsonValue; typedef struct cx_json_array_s CxJsonArray; typedef struct cx_json_object_s CxJsonObject; typedef struct cx_mutstr_s CxJsonString; typedef struct cx_json_integer_s CxJsonInteger; typedef struct cx_json_number_s CxJsonNumber; typedef struct cx_json_literal_s CxJsonLiteral; typedef struct cx_json_obj_value_s CxJsonObjValue; struct cx_json_token_s { CxJsonTokenType tokentype; const char *content; size_t length; size_t alloc; }; struct cx_json_s { const char *buffer; size_t size; size_t pos; CxJsonToken uncompleted; int tokenizer_escape; int *states; size_t nstates; size_t states_alloc; int states_internal[8]; CxJsonToken reader_token; CxJsonReaderType reader_type; int value_ready; char *value_name; size_t value_name_len; char *value_str; size_t value_str_len; int64_t value_int; double value_double; CxJsonValue **readvalue_stack; unsigned readvalue_nelm; unsigned readvalue_alloc; CxJsonValue *read_value; int readvalue_initialized; unsigned reader_array_alloc; int error; }; struct cx_json_array_s { CxJsonValue **array; size_t alloc; size_t size; }; struct cx_json_object_s { CxJsonObjValue *values; size_t alloc; size_t size; }; struct cx_json_obj_value_s { char *name; CxJsonValue *value; }; // TODO: remove single member structs struct cx_json_integer_s { int64_t value; }; struct cx_json_number_s { double value; }; struct cx_json_literal_s { CxJsonLiteralType literal; }; struct cx_json_value_s { CxJsonValueType type; union { CxJsonArray array; CxJsonObject object; CxJsonString string; CxJsonInteger integer; CxJsonNumber number; CxJsonLiteral literal; } value; }; // TODO: add support for CxAllocator __attribute__((__nonnull__)) void cxJsonInit(CxJson *json); __attribute__((__nonnull__)) void cxJsonDestroy(CxJson *json); __attribute__((__nonnull__)) void cxJsonFill(CxJson *json, const char *buf, size_t len); // TODO: discuss if it is intentional that cxJsonNext() will usually parse an entire file in one go __attribute__((__nonnull__)) int cxJsonNext(CxJson *json, CxJsonValue **value); void cxJsonValueFree(CxJsonValue *value); __attribute__((__nonnull__)) static inline bool cxJsonIsObject(CxJsonValue *value) { return value->type == CX_JSON_OBJECT; } __attribute__((__nonnull__)) static inline bool cxJsonIsArray(CxJsonValue *value) { return value->type == CX_JSON_ARRAY; } __attribute__((__nonnull__)) static inline bool cxJsonIsString(CxJsonValue *value) { return value->type == CX_JSON_STRING; } __attribute__((__nonnull__)) static inline bool cxJsonIsNumber(CxJsonValue *value) { // TODO: this is not good, because an integer is also a number return value->type == CX_JSON_NUMBER; } __attribute__((__nonnull__)) static inline bool cxJsonIsInteger(CxJsonValue *value) { return value->type == CX_JSON_INTEGER; } __attribute__((__nonnull__)) static inline bool cxJsonIsLiteral(CxJsonValue *value) { return value->type == CX_JSON_LITERAL; } __attribute__((__nonnull__)) static inline bool cxJsonIsBool(CxJsonValue *value) { return cxJsonIsLiteral(value) && value->value.literal.literal != CX_JSON_NULL; } __attribute__((__nonnull__)) static inline bool cxJsonIsTrue(CxJsonValue *value) { return cxJsonIsLiteral(value) && value->value.literal.literal == CX_JSON_TRUE; } __attribute__((__nonnull__)) static inline bool cxJsonIsFalse(CxJsonValue *value) { return cxJsonIsLiteral(value) && value->value.literal.literal == CX_JSON_FALSE; } __attribute__((__nonnull__)) static inline bool cxJsonIsNull(CxJsonValue *value) { return cxJsonIsLiteral(value) && value->value.literal.literal == CX_JSON_NULL; } __attribute__((__nonnull__)) static inline cxmutstr cxJsonAsString(CxJsonValue *value) { // TODO: do we need a separate method to return this directly as cxstring? return value->value.string; } __attribute__((__nonnull__)) static inline double cxJsonAsDouble(CxJsonValue *value) { return value->value.number.value; } __attribute__((__nonnull__)) static inline int64_t cxJsonAsInteger(CxJsonValue *value) { return value->value.integer.value; } __attribute__((__nonnull__)) static inline bool cxJsonAsBool(CxJsonValue *value) { return value->value.literal.literal == CX_JSON_TRUE; } __attribute__((__nonnull__)) static inline size_t cxJsonArrSize(CxJsonValue *value) { return value->value.array.size; } __attribute__((__nonnull__, __returns_nonnull__)) CxJsonValue *cxJsonArrGet(CxJsonValue *value, size_t index); // TODO: add cxJsonArrIter() // TODO: implement cxJsonObjGet as a _Generic with support for cxstring __attribute__((__nonnull__, __returns_nonnull__)) CxJsonValue *cxJsonObjGet(CxJsonValue *value, const char* name); #ifdef __cplusplus } #endif #endif /* UCX_JSON_H */