/* * Copyright (c) 2004-2006 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set * forth in the LICENSE file which can be found at the top level of * the sendmail distribution. * * $Id: sm-conf.h,v 1.37 2006/05/14 04:54:05 ca Exp $ */ #ifndef SM_CONF_H #define SM_CONF_H 1 #include "sm/generic.h" #include "sm/assert.h" #include "sm/magic.h" #include "sm/error.h" #include #if SM_LIBCONF_ALONE #include /* ptrdiff_t */ #endif #ifndef SM_LIBCONF_ISSET #define SM_LIBCONF_ISSET 1 #endif #ifndef SM_LIBCONF_MAGIC #define SM_LIBCONF_MAGIC 1 #endif #ifndef HAVE_SNPRINTF #define snprintf sm_snprintf #define vsnprintf sm_vsnprintf #endif /* SM-CONF.H -- API declarations. */ /* ** SM_CONF_NODE_TYPE_E -- node types: value, list, section. */ #define SM_CONF_NODE_NONE 0 enum sm_conf_node_type_E { SM_CONF_NODE_VALUE = 1, SM_CONF_NODE_LIST = 2, SM_CONF_NODE_SECTION = 3 }; typedef void *sm_conf_iterator_T; /* ** SM_CONF_ERROR_E -- errors from tokenizer, parser and file I/O */ enum SM_CONF_ERROR_E { SM_CONF_NO_ERROR = 0 ,SM_CONF_ERR_NEWLINE_IN_STRING = SM_CNF_E_NEWLINE_IN_STRING ,SM_CONF_ERR_EOF_IN_STRING = SM_CNF_E_EOF_IN_STRING ,SM_CONF_ERR_BAD_CHAR = SM_CNF_E_BAD_CHAR ,SM_CONF_ERR_NO_MEMORY = SM_CNF_E_NO_MEMORY ,SM_CONF_ERR_HEX_EXPECTED = SM_CNF_E_HEX_EXPECTED ,SM_CONF_ERR_CHAR_OVERFLOW = SM_CNF_E_CHAR_OVERFLOW ,SM_CONF_ERR_INVALID = SM_CNF_E_INVALID ,SM_CONF_ERR_READ = SM_CNF_E_READ ,SM_CONF_ERR_READ_OPEN = SM_CNF_E_READ_OPEN ,SM_CONF_ERR_READ_CLOSE = SM_CNF_E_READ_CLOSE ,SM_CONF_ERR_EOF = SM_CNF_E_EOF ,SM_CONF_ERR_SYNTAX = SM_CNF_E_SYNTAX ,SM_CONF_ERR_NOT_FOUND = SM_CNF_E_NOT_FOUND ,SM_CONF_ERR_ALREADY = SM_CNF_E_ALREADY ,SM_CONF_ERR_TYPE = SM_CNF_E_TYPE ,SM_CONF_ERR_NUL_IN_STRING = SM_CNF_E_NUL_IN_STRING ,SM_CONF_ERR_TOO_MANY = SM_CNF_E_TOO_MANY }; #define SM_CONF_ERROR_BUFFER_SIZE 200 /* complete configuration state; catch-all handle */ typedef struct sm_conf_S sm_conf_T; /* a single node in the parsed configuration tree. */ typedef union sm_conf_node_U sm_conf_node_T; /* a value type */ typedef struct sm_conf_type_S sm_conf_type_T; /* high-level API calls */ sm_conf_T *sm_conf_new(char const *); int sm_conf_read_FILE(sm_conf_T *, char const *, FILE *); int sm_conf_read_data(sm_conf_T *, char *, size_t n, bool copy); void sm_conf_destroy(sm_conf_T *); char const *sm_conf_strerror(int err, char *buf, size_t bufsize); char const *sm_conf_syntax_error(sm_conf_T *smc, char const *prev); /* node access functions */ sm_conf_node_T *sm_conf_root(sm_conf_T *_smc); int sm_conf_node_type( sm_conf_T *_smc, sm_conf_node_T const *_node); char const * sm_conf_node_type_name( sm_conf_T *_smc, sm_conf_node_T const *_node); sm_conf_node_T *sm_conf_node_next( sm_conf_T *_smc, sm_conf_node_T const *_node); sm_conf_node_T *sm_conf_node_parent( sm_conf_T *_smc, sm_conf_node_T const *_node); int sm_conf_value( sm_conf_T *smc, sm_conf_node_T const *node, char const **text_out, size_t *text_n_out); sm_conf_node_T *sm_conf_list_next( sm_conf_T *_smc, sm_conf_node_T const *_list, sm_conf_node_T const *_prev); size_t sm_conf_list_n( sm_conf_T *_smc, sm_conf_node_T const *_list); sm_conf_node_T *sm_conf_section_next( sm_conf_T *_smc, sm_conf_node_T const *_section, char const **_name_out, size_t *_name_n_out, sm_conf_node_T const *_prev); sm_conf_node_T *sm_conf_section_next_subsection( sm_conf_T *smc, sm_conf_node_T const *parent, char const *keyword, size_t keyword_n, char const *name, size_t name_n, sm_conf_node_T const *pred); sm_conf_node_T *sm_conf_section_next_option( sm_conf_T *smc, sm_conf_node_T const *parent, char const *name, size_t name_n, sm_conf_node_T const *pred); int sm_conf_section_keyword( sm_conf_T *_smc, sm_conf_node_T const *_section, char const **_kw_out, size_t *_kw_n_out); int sm_conf_section_name( sm_conf_T *_smc, sm_conf_node_T const *_section, char const **_name_out, size_t *_name_n_out); size_t sm_conf_section_n( sm_conf_T *_smc, sm_conf_node_T const *_section); char const *sm_conf_node_location( sm_conf_T *_smc, sm_conf_node_T const *_node, char *_buf, size_t _bufsize); /* types */ typedef struct sm_conf_bytes_S { char const *scb_data; size_t scb_size; } sm_conf_bytes_T; #define sm_conf_type_bool (&sm_conf_type_bool_data) #define sm_conf_type_u32 (&sm_conf_type_u32_data) #define sm_conf_type_u32_suffix (&sm_conf_type_u32_suffix_data) #define sm_conf_type_u32_maximum (&sm_conf_type_u32_maximum_data) #define sm_conf_type_u32_minimum (&sm_conf_type_u32_minimum_data) #define sm_conf_type_ipv4 (&sm_conf_type_ipv4_data) #define sm_conf_type_char (&sm_conf_type_char_data) #define sm_conf_type_string (&sm_conf_type_string_data) #if 0 #define sm_conf_type_name (&sm_conf_type_name_data) #endif #define sm_conf_type_argv (&sm_conf_type_argv_data) #define sm_conf_type_choice (&sm_conf_type_choice_data) #define sm_conf_type_choice_value (&sm_conf_type_choice_value_data) #if 0 #define sm_conf_type_flag (&sm_conf_type_flag_data) #define sm_conf_type_flag_value (&sm_conf_type_flag_value_data) #define sm_conf_type_flags (&sm_conf_type_flags_data) #endif /* 0 */ #define sm_conf_type_bytes (&sm_conf_type_bytes_data) #define sm_conf_type_section (&sm_conf_type_section_data) #define sm_conf_type_section_title (&sm_conf_type_section_title_data) #define sm_conf_type_union (&sm_conf_type_union_data) #define sm_conf_type_union_choice (&sm_conf_type_union_choice_data) #define sm_conf_type_union_type (&sm_conf_type_union_type_data) #define sm_conf_type_array (&sm_conf_type_array_data) #define sm_conf_type_array_n (&sm_conf_type_array_n_data) #define sm_conf_type_array_elem_size (&sm_conf_type_array_elem_size_data) extern const sm_conf_type_T /* ** SM_CONF_TYPE_BOOL -- 1 or 0 in a byte-sized location. */ sm_conf_type_bool_data, /* ** SM_CONF_TYPE_U32 -- numbers, stored as unsigned char, ** unsigned short, unsigned int, or unsigned long ** (sizeof(value) is the size.) ** ** Parameter types for use in a sm_conf_type_u32's scd_contents: ** ** SM_CONF_TYPE_U32_SUFFIX -- scd_offset is suffix multiplier ** SM_CONF_TYPE_U32_MAXIMUM -- scd_offset is maximum value ** SM_CONF_TYPE_U32_MINIMUM -- scd_offset is minimum value */ sm_conf_type_u32_data, sm_conf_type_u32_suffix_data, sm_conf_type_u32_maximum_data, sm_conf_type_u32_minimum_data, /* ** SM_CONF_TYPE_IPV4 -- IPv4 addresses */ sm_conf_type_ipv4_data, /* ** SM_CONF_TYPE_CHAR -- char */ sm_conf_type_char_data, /* ** SM_CONF_TYPE_STRING -- \0-terminated string pointed to by char * */ sm_conf_type_string_data, #if 0 sm_conf_type_name_data, #endif /* ** SM_CONF_TYPE_ARGV -- NULL-terminated arary of \0-terminated strings */ sm_conf_type_argv_data, /* ** SM_CONF_TYPE_CHOICE -- enumerated values; ** contents list values. ** SM_CONF_TYPE_CHOICE_VALUE -- one possible value; ** scd_offset is the numerical value. */ sm_conf_type_choice_data, sm_conf_type_choice_value_data, #if 0 /* ** SM_CONF_TYPE_FLAG -- enumerated values; ** contents list values. ** SM_CONF_TYPE_FLAG_VALUE -- one possible value; ** scd_offset is the numerical value. */ sm_conf_type_flag_data, sm_conf_type_flag_value_data, sm_conf_type_flags_data, #endif /* 0 */ /* ** SM_CONF_TYPE_BYTES -- string that can contain \0. ** stored in a sm_conf_bytes_T */ sm_conf_type_bytes_data, /* ** SM_CONF_TYPE_SECTION -- compound; scd_contents are contents. */ sm_conf_type_section_data, sm_conf_type_section_title_data, /* ** SM_CONF_TYPE_UNION -- one of multiple types */ sm_conf_type_union_data, sm_conf_type_union_choice_data, sm_conf_type_union_type_data, /* ** SM_CONF_TYPE_ARRAY -- a fixed or dynamic array */ sm_conf_type_array_data, sm_conf_type_array_n_data, sm_conf_type_array_elem_size_data; /* ** SM_CONF_FLAG_... -- flags for use with sm_conf_scan(). */ /* ** SM_CONF_FLAG_ALLOW_ANY_OPTION -- allow options not in the definition ** SM_CONF_FLAG_ALLOW_ANY_SECTION -- allow section elements ** SM_CONF_FLAG_ALLOW_ANY -- conjunction of the previous two. ** ** Scanning with a definition list isn't the only way of getting at ** values; an application could use the node access interface to ** read individual values, perhaps under control of user input elsewhere ** (e.g. a command that causes it to load and execute a new module.) ** ** The following two flags allow scanned definitions to coexist with ** values whose meaning isn't yet known to the application. They can ** be used as parameters to sm_conf_scan() or with section definitions. */ #define SM_CONF_FLAG_ALLOW_ANY_OPTION 0x0001 #define SM_CONF_FLAG_ALLOW_ANY_SECTION 0x0002 #define SM_CONF_FLAG_ALLOW_ANY ( SM_CONF_FLAG_ALLOW_ANY_OPTION \ | SM_CONF_FLAG_ALLOW_ANY_SECTION ) /* ** SM_CONF_FLAG_STRICTLY_REQUIRED -- value must be explicitly provided, ** can't be defaulted. ** SM_CONF_FLAG_REQUIRED -- value can be defaulted, but must be there. */ #define SM_CONF_FLAG_STRICTLY_REQUIRED 0x0004 #define SM_CONF_FLAG_REQUIRED 0x0008 /* ** SM_CONF_FLAG_MULTIPLE -- apply definition to multiple occurrences. ** ** for unnamed entries, the definition applies to this unnamed ** value and all following. ** for named entries, multiple mentions of the name are parsed ** using the same type into the same location (which, ** hopefully, is some sort of vector that can accomodate ** multiple values.) */ #define SM_CONF_FLAG_MULTIPLE 0x0010 /* ** SM_CONF_FLAG_SECTION_MUST_BE_NAMED -- section must be named ** SM_CONF_FLAG_SECTION_MUST_BE_ANONYMOUS -- section must be anonymous ** ** -- controls whether a section construct can, must, or must not ** have a name. ** ** (A section name is the optional name after the ** type, but before the opening {. For example, ** foo "bar" { ** } ** is a foo-section named "bar", and ** ** foo { ** } ** is an anonymous foo-section.) */ #define SM_CONF_FLAG_SECTION_MUST_BE_NAMED 0x0020 #define SM_CONF_FLAG_SECTION_MUST_BE_ANONYMOUS 0x0040 /* ** SM_CONF_FLAG_SECTION_DEFAULT_FROM_ANONYMOUS -- default from anonymous ** ** -- When reading a named section, if there is an unnamed ** section of the same type, default values for not explicitly ** listed elements in the named sections from the unnamed section's ** elements. ** ** For example, in ** ** interface { ** port = 25; ** ip = "0.0.0.0"; ** } ** ** interface "local" { ** ip = "127.0.0.1"; ** } ** ** the value of interface{local}.port is 25. */ #define SM_CONF_FLAG_SECTION_DEFAULT_FROM_ANONYMOUS 0x0080 /* ** SM_CONF_FLAG_DEFAULT_FROM_ENVIRONMENT -- default a named ** value from the environment. ** ** When reading a section, if one of its properties isn't ** specified in either the section itself or in a defaulting ** unnamed section (if any), look for the property in one ** of the containing sections, and default from it. */ #define SM_CONF_FLAG_DEFAULT_FROM_ENVIRONMENT 0x0100 /* For arrays, at least one element is required. */ #define SM_CONF_FLAG_AT_LEAST_ONE 0x0004 /* For arrays or choices, choose either none or one. */ #define SM_CONF_FLAG_AT_MOST_ONE 0x0008 /* For arrays or choices, choose exactly one. */ #define SM_CONF_FLAG_ONE 0x000C /* Don't set this value to zero. */ #define SM_CONF_FLAG_KEEP_DEFAULT 0x0200 /* this section will be scanned explicitly */ /* syntax check only; don't assign a value. */ #define SM_CONF_FLAG_PARSE_ONLY 0x0400 /* Allow numeric specification for a flag or choice */ #define SM_CONF_FLAG_NUMERIC 0x0800 /* ** SM_CONF_FLAG_FLAT -- For arrays or argv-style arrays: ** the location is the array itself, not a pointer. */ #define SM_CONF_FLAG_FLAT 0x1000 /* ** SM_CONF_FLAG_OR -- apply a binary OR when setting options ** as multiple options may point to a single value. ** This is similar to SM_CONF_FLAG_MULTIPLE in its behavior, ** but only one value is valid for some (sub)option. */ #define SM_CONF_FLAG_OR 0x2000 /* print in hex */ #define SM_CONF_FLAG_HEX 0x4000 /* deprecated option (don't print for now, warn later on) */ #define SM_CONF_FLAG_DPRCD 0x8000 /* "is" vs "are" in printing configuration */ #define SM_CONF_FLAG_PLURAL 0x00010000 /* do not print */ #define SM_CONF_FLAG_DONTPRINT 0x00020000 #if SM_LIBCONF_ISSET # define SM_LC_SET_DIRECT 1 # define SM_LC_SET_FRM_ENV 2 # define SM_LC_SET_FRM_ANON 3 # define SM_LC_NO_ISSET , 0 # define SM_LC_ISSET(x) , x #else # define SM_LC_NO_ISSET # define SM_LC_ISSET(x) #endif typedef struct sm_conf_definition_S sm_conf_definition_T; typedef int sm_conf_definition_check_T( sm_conf_T *_handle, void *_callback_data, sm_conf_definition_T const *_definition, void const *_value_data); #define SM_CONF_DEF_MAGIC SM_MAGIC('C', 'F', 'D', 'E') #define SM_IS_CONF_DEF(sm_conf_definition) \ SM_REQUIRE_ISA((sm_conf_definition), SM_CONF_DEF_MAGIC) /* definition of a configuration element */ struct sm_conf_definition_S { sm_magic_T sm_magic; /* name of option */ char const *scd_name; /* type, see sm_conf_type_* */ const sm_conf_type_T *scd_type; /* offset of data entry in struct */ ptrdiff_t scd_offset; /* size of the data entry */ size_t scd_size; /* something to scan as default value */ char const *scd_default; /* various flags, see SM_CONF_FLAG_* */ uint32_t scd_flags; /* configuration description of item (depending on type) */ sm_conf_definition_T const *scd_contents; /* optional function to check whether entry is valid */ sm_conf_definition_check_T *scd_check; /* argument for check */ void *scd_check_data; /* textual description of configuration element */ char const *scd_description; #if SM_LIBCONF_ISSET /* ** offset of "is this option set" in struct. ** 0: no field in struct available! that means, that field ** MUST NOT be the first element in the struct! */ ptrdiff_t scd_isset_offset; #endif #if SM_LIBCONF_MAGIC /* check struct for this magic (if != 0) */ sm_magic_T scd_magic; #endif }; #if SM_LIBCONF_MAGIC # define SM_LC_ISA(def, data) \ do \ { \ if ((data) != NULL && (def)->scd_magic != 0) \ SM_ASSERT((def)->scd_magic == *(sm_magic_T *)data); \ } while (0) # define SM_LC_SET_MAGIC(magic) , magic #else # define SM_LC_ISA(def, data) SM_NOOP # define SM_LC_SET_MAGIC(magic) #endif int sm_conf_scan( sm_conf_T *_handle, sm_conf_definition_T const *_definition, unsigned int _flags, void *_data); int sm_conf_get_relative( sm_conf_T *_smc, sm_conf_node_T *_node, char const *_name, sm_conf_type_T const *_type, void const *_type_data, unsigned int _flags, void *_data, size_t _size); int sm_conf_get( sm_conf_T *_smc, char const *_name, sm_conf_type_T const *_type, void const *_type_data, unsigned int f_lags, void *_data, size_t _size); int sm_conf_scan_next_relative( sm_conf_T *_smc, sm_conf_node_T *_parent, char const *_path, sm_conf_definition_T const *_defs, unsigned int _flags, char const **_name_out, size_t *_name_n_out, void *_data, sm_conf_iterator_T *_iter); int sm_conf_scan_next( sm_conf_T *_smc, char const *_path, sm_conf_definition_T const *_defs, unsigned int _flags, char const **_name_out, size_t *_name_n_out, void *_data, sm_conf_iterator_T *_iter); int sm_conf_null( sm_conf_T *_handle, sm_conf_definition_T const *_definitions, unsigned int _flags, void *_data); #endif /* SM_CONF_H */