Mon, 18 Nov 2024 22:05:42 +0100
make ucx C++ compatible again (and add tests for it) - fixes #486
/* * 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" #include "array_list.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, CX_JSON_NUMBER, CX_JSON_LITERAL }; enum cx_json_literal { 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_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 int64_t CxJsonInteger; typedef double CxJsonNumber; typedef enum cx_json_literal 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 { CX_ARRAY_DECLARE(CxJsonValue*, array); }; struct cx_json_object_s { CX_ARRAY_DECLARE(CxJsonObjValue, values); }; struct cx_json_obj_value_s { char *name; CxJsonValue *value; }; 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 cx_attr_nonnull void cxJsonInit(CxJson *json); cx_attr_nonnull void cxJsonDestroy(CxJson *json); cx_attr_nonnull cx_attr_access_r(2, 3) int cxJsonFilln(CxJson *json, const char *buf, size_t len); #ifdef __cplusplus } // extern "C" cx_attr_nonnull static inline int cxJsonFill( CxJson *json, cxstring str ) { return cxJsonFilln(json, str.ptr, str.length); } cx_attr_nonnull static inline int cxJsonFill( CxJson *json, cxmutstr str ) { return cxJsonFilln(json, str.ptr, str.length); } cx_attr_nonnull cx_attr_cstr_arg(2) static inline int cxJsonFill( CxJson *json, const char *str ) { return cxJsonFilln(json, str, strlen(str)); } extern "C" { #else // __cplusplus #define cxJsonFill(json, str) _Generic((str), \ cxstring: cx_json_fill_cxstr, \ cxmutstr: cx_json_fill_mutstr, \ char*: cx_json_fill_str, \ const char*: cx_json_fill_str) \ (json, str) cx_attr_nonnull static inline int cx_json_fill_cxstr( CxJson *json, cxstring str ) { return cxJsonFilln(json, str.ptr, str.length); } cx_attr_nonnull static inline int cx_json_fill_mutstr( CxJson *json, cxmutstr str ) { return cxJsonFilln(json, str.ptr, str.length); } cx_attr_nonnull cx_attr_cstr_arg(2) static inline int cx_json_fill_str( CxJson *json, const char *str ) { return cxJsonFilln(json, str, strlen(str)); } #endif void cxJsonValueFree(CxJsonValue *value); // TODO: if the CxJsonValue was a returned value, we could reference cxJsonValueFree() as deallocator cx_attr_nonnull int cxJsonNext(CxJson *json, CxJsonValue **value); cx_attr_nonnull static inline bool cxJsonIsObject(CxJsonValue *value) { return value->type == CX_JSON_OBJECT; } cx_attr_nonnull static inline bool cxJsonIsArray(CxJsonValue *value) { return value->type == CX_JSON_ARRAY; } cx_attr_nonnull static inline bool cxJsonIsString(CxJsonValue *value) { return value->type == CX_JSON_STRING; } cx_attr_nonnull static inline bool cxJsonIsNumber(CxJsonValue *value) { return value->type == CX_JSON_NUMBER || value->type == CX_JSON_INTEGER; } cx_attr_nonnull static inline bool cxJsonIsInteger(CxJsonValue *value) { return value->type == CX_JSON_INTEGER; } cx_attr_nonnull static inline bool cxJsonIsLiteral(CxJsonValue *value) { return value->type == CX_JSON_LITERAL; } cx_attr_nonnull static inline bool cxJsonIsBool(CxJsonValue *value) { return cxJsonIsLiteral(value) && value->value.literal != CX_JSON_NULL; } cx_attr_nonnull static inline bool cxJsonIsTrue(CxJsonValue *value) { return cxJsonIsLiteral(value) && value->value.literal == CX_JSON_TRUE; } cx_attr_nonnull static inline bool cxJsonIsFalse(CxJsonValue *value) { return cxJsonIsLiteral(value) && value->value.literal == CX_JSON_FALSE; } cx_attr_nonnull static inline bool cxJsonIsNull(CxJsonValue *value) { return cxJsonIsLiteral(value) && value->value.literal == CX_JSON_NULL; } cx_attr_nonnull cx_attr_returns_nonnull static inline char *cxJsonAsString(CxJsonValue *value) { return value->value.string.ptr; } cx_attr_nonnull static inline cxstring cxJsonAsCxString(CxJsonValue *value) { return cx_strcast(value->value.string); } cx_attr_nonnull static inline cxmutstr cxJsonAsCxMutStr(CxJsonValue *value) { return value->value.string; } cx_attr_nonnull static inline double cxJsonAsDouble(CxJsonValue *value) { if (value->type == CX_JSON_INTEGER) { return (double) value->value.integer; } else { return value->value.number; } } cx_attr_nonnull static inline int64_t cxJsonAsInteger(CxJsonValue *value) { if (value->type == CX_JSON_INTEGER) { return value->value.integer; } else { return (int64_t) value->value.number; } } cx_attr_nonnull static inline bool cxJsonAsBool(CxJsonValue *value) { return value->value.literal == CX_JSON_TRUE; } cx_attr_nonnull static inline size_t cxJsonArrSize(CxJsonValue *value) { return value->value.array.array_size; } cx_attr_nonnull cx_attr_returns_nonnull CxJsonValue *cxJsonArrGet(CxJsonValue *value, size_t index); // TODO: add cxJsonArrIter() // TODO: implement cxJsonObjGet as a _Generic with support for cxstring cx_attr_nonnull cx_attr_returns_nonnull cx_attr_cstr_arg(2) CxJsonValue *cxJsonObjGet(CxJsonValue *value, const char* name); #ifdef __cplusplus } #endif #endif /* UCX_JSON_H */