Path: blob/main/contrib/libucl/src/ucl_internal.h
104148 views
/* Copyright (c) 2013, Vsevolod Stakhov1* All rights reserved.2*3* Redistribution and use in source and binary forms, with or without4* modification, are permitted provided that the following conditions are met:5* * Redistributions of source code must retain the above copyright6* notice, this list of conditions and the following disclaimer.7* * Redistributions in binary form must reproduce the above copyright8* notice, this list of conditions and the following disclaimer in the9* documentation and/or other materials provided with the distribution.10*11* THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY12* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED13* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE14* DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY15* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES16* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;17* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND18* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT19* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS20* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.21*/2223#ifndef UCL_INTERNAL_H_24#define UCL_INTERNAL_H_2526#ifdef HAVE_CONFIG_H27#include "config.h"28#else29/* Help embedded builds */30#define HAVE_SYS_TYPES_H31#define HAVE_SYS_MMAN_H32#define HAVE_SYS_STAT_H33#define HAVE_SYS_PARAM_H34#define HAVE_LIMITS_H35#define HAVE_FCNTL_H36#define HAVE_ERRNO_H37#define HAVE_UNISTD_H38#define HAVE_CTYPE_H39#define HAVE_STDIO_H40#define HAVE_STRING_H41#define HAVE_FLOAT_H42#define HAVE_LIBGEN_H43#define HAVE_MATH_H44#define HAVE_STDBOOL_H45#define HAVE_STDINT_H46#define HAVE_STDARG_H47#ifndef _WIN3248# define HAVE_REGEX_H49#endif50#endif5152#ifdef HAVE_SYS_TYPES_H53#include <sys/types.h>54#endif5556#ifdef HAVE_SYS_MMAN_H57# ifndef _WIN3258# include <sys/mman.h>59# endif60#endif61#ifdef HAVE_SYS_STAT_H62#include <sys/stat.h>63#endif64#ifdef HAVE_SYS_PARAM_H65# ifndef _WIN3266# include <sys/param.h>67# endif68#endif6970#ifdef HAVE_LIMITS_H71#include <limits.h>72#endif73#ifdef HAVE_FCNTL_H74#include <fcntl.h>75#endif76#ifdef HAVE_ERRNO_H77#include <errno.h>78#endif79#ifdef HAVE_UNISTD_H80# ifndef _WIN3281# include <unistd.h>82# endif83#endif84#ifdef HAVE_CTYPE_H85#include <ctype.h>86#endif87#ifdef HAVE_STDIO_H88#include <stdio.h>89#endif90#ifdef HAVE_STRING_H91#include <string.h>92#endif93#ifdef HAVE_STRINGS_H94#include <strings.h>95#endif9697#if defined(_MSC_VER)98/* Windows hacks */99#include <BaseTsd.h>100#include <inttypes.h>101typedef SSIZE_T ssize_t;102#define strdup _strdup103#define snprintf _snprintf104#define vsnprintf _vsnprintf105#define strcasecmp _stricmp106#define strncasecmp _strnicmp107#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)108#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)109#if _MSC_VER >= 1900110#include <../ucrt/stdlib.h>111#else112#include <../include/stdlib.h>113#endif114#ifndef PATH_MAX115#define PATH_MAX _MAX_PATH116#endif117118/* Dirname, basename implementations */119120121#endif122123#include "utlist.h"124#include "utstring.h"125#include "uthash.h"126#include "ucl.h"127#include "ucl_hash.h"128129#ifdef HAVE_OPENSSL130#include <openssl/evp.h>131#endif132133#ifndef __DECONST134#define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var))135#endif136137/**138* @file rcl_internal.h139* Internal structures and functions of UCL library140*/141142#define UCL_MAX_RECURSION 16143#define UCL_TRASH_KEY 0144#define UCL_TRASH_VALUE 1145146enum ucl_parser_state {147UCL_STATE_INIT = 0,148UCL_STATE_OBJECT,149UCL_STATE_ARRAY,150UCL_STATE_KEY,151UCL_STATE_KEY_OBRACE,152UCL_STATE_VALUE,153UCL_STATE_AFTER_VALUE,154UCL_STATE_ARRAY_VALUE,155UCL_STATE_SCOMMENT,156UCL_STATE_MCOMMENT,157UCL_STATE_MACRO_NAME,158UCL_STATE_MACRO,159UCL_STATE_ERROR160};161162enum ucl_character_type {163UCL_CHARACTER_DENIED = (1 << 0),164UCL_CHARACTER_KEY = (1 << 1),165UCL_CHARACTER_KEY_START = (1 << 2),166UCL_CHARACTER_WHITESPACE = (1 << 3),167UCL_CHARACTER_WHITESPACE_UNSAFE = (1 << 4),168UCL_CHARACTER_VALUE_END = (1 << 5),169UCL_CHARACTER_VALUE_STR = (1 << 6),170UCL_CHARACTER_VALUE_DIGIT = (1 << 7),171UCL_CHARACTER_VALUE_DIGIT_START = (1 << 8),172UCL_CHARACTER_ESCAPE = (1 << 9),173UCL_CHARACTER_KEY_SEP = (1 << 10),174UCL_CHARACTER_JSON_UNSAFE = (1 << 11),175UCL_CHARACTER_UCL_UNSAFE = (1 << 12)176};177178struct ucl_macro {179char *name;180union _ucl_macro {181ucl_macro_handler handler;182ucl_context_macro_handler context_handler;183} h;184void* ud;185bool is_context;186UT_hash_handle hh;187};188189enum ucl_stack_flags {190UCL_STACK_HAS_OBRACE = (1u << 0),191UCL_STACK_MAX = (1u << 1),192};193194struct ucl_stack {195ucl_object_t *obj;196struct ucl_stack *next;197union {198struct {199uint16_t level;200uint16_t flags;201uint32_t line;202} params;203uint64_t len;204} e;205struct ucl_chunk *chunk;206};207208struct ucl_parser_special_handler_chain {209unsigned char *begin;210size_t len;211struct ucl_parser_special_handler *special_handler;212struct ucl_parser_special_handler_chain *next;213};214215struct ucl_chunk {216const unsigned char *begin;217const unsigned char *end;218const unsigned char *pos;219char *fname;220size_t remain;221unsigned int line;222unsigned int column;223unsigned priority;224enum ucl_duplicate_strategy strategy;225enum ucl_parse_type parse_type;226struct ucl_parser_special_handler_chain *special_handlers;227struct ucl_chunk *next;228};229230#ifdef HAVE_OPENSSL231struct ucl_pubkey {232EVP_PKEY *key;233struct ucl_pubkey *next;234};235#else236struct ucl_pubkey {237struct ucl_pubkey *next;238};239#endif240241struct ucl_variable {242char *var;243char *value;244size_t var_len;245size_t value_len;246struct ucl_variable *prev, *next;247};248249struct ucl_parser {250enum ucl_parser_state state;251enum ucl_parser_state prev_state;252unsigned int recursion;253int flags;254unsigned default_priority;255int err_code;256ucl_object_t *top_obj;257ucl_object_t *cur_obj;258ucl_object_t *trash_objs;259ucl_object_t *includepaths;260char *cur_file;261struct ucl_macro *macroes;262struct ucl_stack *stack;263struct ucl_chunk *chunks;264struct ucl_pubkey *keys;265struct ucl_parser_special_handler *special_handlers;266ucl_include_trace_func_t *include_trace_func;267void *include_trace_ud;268struct ucl_variable *variables;269ucl_variable_handler var_handler;270void *var_data;271ucl_object_t *comments;272ucl_object_t *last_comment;273UT_string *err;274};275276struct ucl_object_userdata {277ucl_object_t obj;278ucl_userdata_dtor dtor;279ucl_userdata_emitter emitter;280};281282/**283* Unescape json string inplace284* @param str285*/286size_t ucl_unescape_json_string (char *str, size_t len);287288289/**290* Unescape single quoted string inplace291* @param str292*/293size_t ucl_unescape_squoted_string (char *str, size_t len);294295/**296* Handle include macro297* @param data include data298* @param len length of data299* @param args UCL object representing arguments to the macro300* @param ud user data301* @return302*/303bool ucl_include_handler (const unsigned char *data, size_t len,304const ucl_object_t *args, void* ud);305306/**307* Handle tryinclude macro308* @param data include data309* @param len length of data310* @param args UCL object representing arguments to the macro311* @param ud user data312* @return313*/314bool ucl_try_include_handler (const unsigned char *data, size_t len,315const ucl_object_t *args, void* ud);316317/**318* Handle includes macro319* @param data include data320* @param len length of data321* @param args UCL object representing arguments to the macro322* @param ud user data323* @return324*/325bool ucl_includes_handler (const unsigned char *data, size_t len,326const ucl_object_t *args, void* ud);327328/**329* Handle priority macro330* @param data include data331* @param len length of data332* @param args UCL object representing arguments to the macro333* @param ud user data334* @return335*/336bool ucl_priority_handler (const unsigned char *data, size_t len,337const ucl_object_t *args, void* ud);338339/**340* Handle load macro341* @param data include data342* @param len length of data343* @param args UCL object representing arguments to the macro344* @param ud user data345* @return346*/347bool ucl_load_handler (const unsigned char *data, size_t len,348const ucl_object_t *args, void* ud);349/**350* Handle inherit macro351* @param data include data352* @param len length of data353* @param args UCL object representing arguments to the macro354* @param ctx the current context object355* @param ud user data356* @return357*/358bool ucl_inherit_handler (const unsigned char *data, size_t len,359const ucl_object_t *args, const ucl_object_t *ctx, void* ud);360361size_t ucl_strlcpy (char *dst, const char *src, size_t siz);362size_t ucl_strlcpy_unsafe (char *dst, const char *src, size_t siz);363size_t ucl_strlcpy_tolower (char *dst, const char *src, size_t siz);364365char *ucl_strnstr (const char *s, const char *find, int len);366char *ucl_strncasestr (const char *s, const char *find, int len);367368#ifdef __GNUC__369static inline void370ucl_create_err (UT_string **err, const char *fmt, ...)371__attribute__ (( format( printf, 2, 3) ));372#endif373374#undef UCL_FATAL_ERRORS375376static inline void377ucl_create_err (UT_string **err, const char *fmt, ...)378{379if (*err == NULL) {380utstring_new (*err);381va_list ap;382va_start (ap, fmt);383utstring_printf_va (*err, fmt, ap);384va_end (ap);385}386387#ifdef UCL_FATAL_ERRORS388assert (0);389#endif390}391392/**393* Check whether a given string contains a boolean value394* @param obj object to set395* @param start start of a string396* @param len length of a string397* @return true if a string is a boolean value398*/399static inline bool400ucl_maybe_parse_boolean (ucl_object_t *obj, const unsigned char *start, size_t len)401{402const char *p = (const char *)start;403bool ret = false, val = false;404405if (len == 5) {406if ((p[0] == 'f' || p[0] == 'F') && strncasecmp (p, "false", 5) == 0) {407ret = true;408val = false;409}410}411else if (len == 4) {412if ((p[0] == 't' || p[0] == 'T') && strncasecmp (p, "true", 4) == 0) {413ret = true;414val = true;415}416}417else if (len == 3) {418if ((p[0] == 'y' || p[0] == 'Y') && strncasecmp (p, "yes", 3) == 0) {419ret = true;420val = true;421}422else if ((p[0] == 'o' || p[0] == 'O') && strncasecmp (p, "off", 3) == 0) {423ret = true;424val = false;425}426}427else if (len == 2) {428if ((p[0] == 'n' || p[0] == 'N') && strncasecmp (p, "no", 2) == 0) {429ret = true;430val = false;431}432else if ((p[0] == 'o' || p[0] == 'O') && strncasecmp (p, "on", 2) == 0) {433ret = true;434val = true;435}436}437438if (ret && obj != NULL) {439obj->type = UCL_BOOLEAN;440obj->value.iv = val;441}442443return ret;444}445446/**447* Check numeric string448* @param obj object to set if a string is numeric449* @param start start of string450* @param end end of string451* @param pos position where parsing has stopped452* @param allow_double allow parsing of floating point values453* @return 0 if string is numeric and error code (EINVAL or ERANGE) in case of conversion error454*/455int ucl_maybe_parse_number (ucl_object_t *obj,456const char *start, const char *end, const char **pos,457bool allow_double, bool number_bytes, bool allow_time);458459460static inline const ucl_object_t *461ucl_hash_search_obj (ucl_hash_t* hashlin, ucl_object_t *obj)462{463return (const ucl_object_t *)ucl_hash_search (hashlin, obj->key, obj->keylen);464}465466static inline ucl_hash_t * ucl_hash_insert_object (ucl_hash_t *hashlin,467const ucl_object_t *obj,468bool ignore_case) UCL_WARN_UNUSED_RESULT;469470static inline ucl_hash_t *471ucl_hash_insert_object (ucl_hash_t *hashlin,472const ucl_object_t *obj,473bool ignore_case)474{475ucl_hash_t *nhp;476477if (hashlin == NULL) {478nhp = ucl_hash_create (ignore_case);479if (nhp == NULL) {480return NULL;481}482} else {483nhp = hashlin;484}485if (!ucl_hash_insert (nhp, obj, obj->key, obj->keylen)) {486if (nhp != hashlin) {487ucl_hash_destroy(nhp, NULL);488}489return NULL;490}491492return nhp;493}494495/**496* Get standard emitter context for a specified emit_type497* @param emit_type type of emitter498* @return context or NULL if input is invalid499*/500const struct ucl_emitter_context *501ucl_emit_get_standard_context (enum ucl_emitter emit_type);502503/**504* Serialize string as JSON string505* @param str string to emit506* @param buf target buffer507*/508void ucl_elt_string_write_json (const char *str, size_t size,509struct ucl_emitter_context *ctx);510511512/**513* Serialize string as single quoted string514* @param str string to emit515* @param buf target buffer516*/517void518ucl_elt_string_write_squoted (const char *str, size_t size,519struct ucl_emitter_context *ctx);520521/**522* Write multiline string using `EOD` as string terminator523* @param str524* @param size525* @param ctx526*/527void ucl_elt_string_write_multiline (const char *str, size_t size,528struct ucl_emitter_context *ctx);529530/**531* Emit a single object to string532* @param obj533* @return534*/535unsigned char * ucl_object_emit_single_json (const ucl_object_t *obj);536537/**538* Check whether a specified string is long and should be likely printed in539* multiline mode540* @param obj541* @return542*/543bool ucl_maybe_long_string (const ucl_object_t *obj);544545/**546* Print integer to the msgpack output547* @param ctx548* @param val549*/550void ucl_emitter_print_int_msgpack (struct ucl_emitter_context *ctx,551int64_t val);552/**553* Print integer to the msgpack output554* @param ctx555* @param val556*/557void ucl_emitter_print_double_msgpack (struct ucl_emitter_context *ctx,558double val);559/**560* Print double to the msgpack output561* @param ctx562* @param val563*/564void ucl_emitter_print_bool_msgpack (struct ucl_emitter_context *ctx,565bool val);566/**567* Print string to the msgpack output568* @param ctx569* @param s570* @param len571*/572void ucl_emitter_print_string_msgpack (struct ucl_emitter_context *ctx,573const char *s, size_t len);574575/**576* Print binary string to the msgpack output577* @param ctx578* @param s579* @param len580*/581void ucl_emitter_print_binary_string_msgpack (struct ucl_emitter_context *ctx,582const char *s, size_t len);583584/**585* Print array preamble for msgpack586* @param ctx587* @param len588*/589void ucl_emitter_print_array_msgpack (struct ucl_emitter_context *ctx,590size_t len);591592/**593* Print object preamble for msgpack594* @param ctx595* @param len596*/597void ucl_emitter_print_object_msgpack (struct ucl_emitter_context *ctx,598size_t len);599/**600* Print NULL to the msgpack output601* @param ctx602*/603void ucl_emitter_print_null_msgpack (struct ucl_emitter_context *ctx);604/**605* Print object's key if needed to the msgpack output606* @param print_key607* @param ctx608* @param obj609*/610void ucl_emitter_print_key_msgpack (bool print_key,611struct ucl_emitter_context *ctx,612const ucl_object_t *obj);613614/**615* Fetch URL into a buffer616* @param url url to fetch617* @param buf pointer to buffer (must be freed by callee)618* @param buflen pointer to buffer length619* @param err pointer to error argument620* @param must_exist fail if cannot find a url621*/622bool ucl_fetch_url (const unsigned char *url,623unsigned char **buf,624size_t *buflen,625UT_string **err,626bool must_exist);627628/**629* Fetch a file and save results to the memory buffer630* @param filename filename to fetch631* @param len length of filename632* @param buf target buffer633* @param buflen target length634* @return635*/636bool ucl_fetch_file (const unsigned char *filename,637unsigned char **buf,638size_t *buflen,639UT_string **err,640bool must_exist);641642/**643* Add new element to an object using the current merge strategy and priority644* @param parser645* @param nobj646* @return647*/648bool ucl_parser_process_object_element (struct ucl_parser *parser,649ucl_object_t *nobj);650651/**652* Parse msgpack chunk653* @param parser654* @return655*/656bool ucl_parse_msgpack (struct ucl_parser *parser);657658bool ucl_parse_csexp (struct ucl_parser *parser);659660/**661* Free ucl chunk662* @param chunk663*/664void ucl_chunk_free (struct ucl_chunk *chunk);665666#endif /* UCL_INTERNAL_H_ */667668669