Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * OpenTyrian: A modern cross-platform port of Tyrian
  3.  * Copyright (C) 2015  The OpenTyrian Development Team
  4.  *
  5.  * This program is free software; you can redistribute it and/or
  6.  * modify it under the terms of the GNU General Public License
  7.  * as published by the Free Software Foundation; either version 2
  8.  * of the License, or (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  18.  */
  19. /*!
  20.  * \file config_file.h
  21.  * \author Carl Reinke
  22.  * \date 2015
  23.  * \copyright GNU General Public License v2+ or Mozilla Public License 2.0
  24.  */
  25. #ifndef CONFIG_FILE_H
  26. #define CONFIG_FILE_H
  27.  
  28. #include <assert.h>
  29. #include <stdbool.h>
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33.  
  34. #ifndef COMPILE_TIME_ASSERT
  35. /*!
  36.  * \brief Cause compile error if compile-time computable condition fails.
  37.  *
  38.  * \param[in] name the unique identifier of the assertion
  39.  * \param[in] cond the condition
  40.  */
  41. #define COMPILE_TIME_ASSERT(name, cond) typedef int assert_ ## name[(cond) * 2 - 1]
  42. #endif
  43.  
  44. #ifndef COUNTOF
  45. /*!
  46.  * \brief Calculate the number of elements in a fixed-length array.
  47.  *
  48.  * \param[in] a the fixed-length array
  49.  * \return the number of elements in the array
  50.  */
  51. #define COUNTOF(a) (sizeof(a) / sizeof(*(a)))
  52. #endif
  53.  
  54. /* string type */
  55.  
  56. /*!
  57.  * \brief A short-string-optimizing string type.
  58.  *
  59.  * This struct allows for storing up to 15 characters (plus a terminating \c '\0') inline.  For
  60.  * longer strings memory will be allocated.
  61.  *
  62.  * The tag for this union is the last character of \p short_buf:
  63.  * \li if \c '\0' then \p short_buf is valid,
  64.  * \li otherwise \p long_buf is valid.
  65.  */
  66. typedef union
  67. {
  68.         /*!
  69.          * \brief The inline buffer for short strings.
  70.          */
  71.         char short_buf[16];
  72.        
  73.         /*!
  74.          * \brief The buffer for long strings.
  75.          *
  76.          * May be \c NULL.
  77.          */
  78.         char *long_buf;
  79. } ConfigString;
  80.  
  81. /*! \cond suppress_doxygen */
  82. COMPILE_TIME_ASSERT(string_short_buf_sufficient, sizeof(char *) + 1 <= COUNTOF(((ConfigString *)NULL)->short_buf));
  83. /*! \endcond */
  84.  
  85. /*! \cond suppress_doxygen */
  86. #define CONFIG_STRING_LONG_TAG(s) ((s).short_buf[COUNTOF((s).short_buf) - 1])
  87. /*! \endcond */
  88.  
  89. /*!
  90.  * \brief Return a C-string backed by a string.
  91.  *
  92.  * \param[in] string the string
  93.  * \return the C-string
  94.  */
  95. static inline const char *config_string_to_cstr( const ConfigString *string )
  96. {
  97.         assert(string != NULL);
  98.         char is_long = CONFIG_STRING_LONG_TAG(*string);
  99.         return is_long ?
  100.                 string->long_buf :
  101.                 string->short_buf;
  102. }
  103.  
  104. /* config types */
  105.  
  106. /*!
  107.  * \brief An option consisting of one (an item) or many (a list) values.
  108.  */
  109. typedef struct
  110. {
  111.         /*!
  112.          * \brief The key of the option.
  113.          */
  114.         ConfigString key;
  115.        
  116.         /*!
  117.          * \brief The number of values in the option if it is a 'list' option.
  118.          *
  119.          * If \c 0 then the option \e may be an 'item' option.
  120.          *
  121.          * \see ::ConfigOption::value
  122.          */
  123.         unsigned int values_count;
  124.        
  125.         /*!
  126.          * \brief The value or values.
  127.          *
  128.          * The tag for this union is \p value_count:
  129.          * \li if \c 0 then \p value is valid,
  130.          * \li otherwise \p values is valid.
  131.          */
  132.         union
  133.         {
  134.                 /*!
  135.                  * \brief The value of an 'item' option or an empty 'list' option.
  136.                  *
  137.                  * If this field is \c NULL then the option is an empty 'list' option.
  138.                  */
  139.                 ConfigString value;
  140.                
  141.                 /*!
  142.                  * \brief The values of a non-empty 'list' option.
  143.                  */
  144.                 ConfigString *values;
  145.         } v;
  146. } ConfigOption;
  147.  
  148. /*!
  149.  * \brief A section consisting of options.
  150.  */
  151. typedef struct
  152. {
  153.         /*!
  154.          * \brief The type of the section.
  155.          */
  156.         ConfigString type;
  157.        
  158.         /*!
  159.          * \brief The optional name of the section.
  160.          *
  161.          * May be \c NULL.
  162.          */
  163.         ConfigString name;
  164.        
  165.         /*!
  166.          * \brief The number of options in the section.
  167.          */
  168.         unsigned int options_count;
  169.        
  170.         /*!
  171.          * \brief The options in the section.
  172.          *
  173.          * \c NULL if \p options_count is \c 0.
  174.          */
  175.         ConfigOption *options;
  176. } ConfigSection;
  177.  
  178. /*!
  179.  * \brief A configuration consisting of sections.
  180.  */
  181. typedef struct
  182. {
  183.         /*!
  184.          * \brief The number of sections in the configuration.
  185.          */
  186.         unsigned int sections_count;
  187.        
  188.         /*!
  189.          * \brief The sections in the configuration.
  190.          *
  191.          * \c NULL if \p sections_count is \c 0.
  192.          */
  193.         ConfigSection *sections;
  194. } Config;
  195.  
  196. /* config manipulators */
  197.  
  198. /*!
  199.  * \brief Initialize a configuration.
  200.  *
  201.  * \param[in] config the configuration
  202.  * \return void
  203.  */
  204. extern void config_init( Config *config );
  205.  
  206. /*!
  207.  * \brief Release any memory allocated inside a configuration.
  208.  *
  209.  * \param[in] config the configuration
  210.  * \return void
  211.  */
  212. extern void config_deinit( Config *config );
  213.  
  214. /*!
  215.  * \brief Parse a configuration from a file.
  216.  *
  217.  * \param[in] config the uninitalized configuration
  218.  * \param[in] file the file handle
  219.  * \return whether parsing succeeded
  220.  */
  221. extern bool config_parse( Config *config, FILE *file );
  222.  
  223. /*!
  224.  * \brief Write a configuration to a file.
  225.  *
  226.  * \param[in] config the configuration
  227.  * \param[in] file the file handle
  228.  * \return void
  229.  */
  230. extern void config_write( const Config *config, FILE *file );
  231.  
  232. /* config section accessors/manipulators -- by type, name */
  233.  
  234. /*! \see ::config_add_section() */
  235. extern ConfigSection *config_add_section_len( Config *config, const char *type, size_t type_len, const char *name, size_t name_len );
  236.  
  237. /*!
  238.  * \brief Add a section to a configuration.
  239.  *
  240.  * \param[in] config the configuration to contain the section
  241.  * \param[in] type the type of the section
  242.  * \param[in] name the name of the section; may be \c NULL
  243.  * \return the added section; \c NULL if out of memory
  244.  */
  245. static inline ConfigSection *config_add_section( Config *config, const char *type, const char *name)
  246. {
  247.         assert(type != NULL);
  248.         return config_add_section_len(config, type, strlen(type), name, name == NULL ? 0 : strlen(name));
  249. }
  250.  
  251. // TODO: extern Config *config_remove_section( Config *config, unsigned int i );
  252.  
  253. /*!
  254.  * \brief Iterate sections by type.
  255.  *
  256.  * \param[in] config the configuration containing the sections
  257.  * \param[in] type the type of the section
  258.  * \param[in,out] save the saved state of the iterator; initialize \c *save to \c NULL before
  259.  *                     iteration
  260.  * \return the section; \c NULL if iteration finished
  261.  */
  262. extern ConfigSection *config_find_sections( Config *config, const char *type, ConfigSection **save );
  263.  
  264. /*!
  265.  * \brief Find a section by type and name.
  266.  *
  267.  * \param[in] config the configuration containing the section
  268.  * \param[in] type the type of the section
  269.  * \param[in] name the name of the section
  270.  * \return the section; \c NULL if it does not exist
  271.  */
  272. extern ConfigSection *config_find_section( Config *config, const char *type, const char *name );
  273.  
  274. /*!
  275.  * \brief Find a section by type and name, creating the section if it did not exist.
  276.  *
  277.  * \param[in] config the configuration containing the section
  278.  * \param[in] type the type of the section
  279.  * \param[in] name the name of the section; may be \c NULL
  280.  * \return the section; \c NULL if out of memory
  281.  */
  282. extern ConfigSection *config_find_or_add_section( Config *config, const char *type, const char *name );
  283.  
  284. /* config option accessors/manipulators -- by key */
  285.  
  286. /*! \see ::config_set_option() */
  287. extern ConfigOption *config_set_option_len( ConfigSection *section, const char *key, size_t key_len, const char *value, size_t value_len );
  288.  
  289. /*!
  290.  * \brief Set a value of an 'item' option by key, creating the option if necessary.
  291.  *
  292.  * \param[in] section the section containing the option
  293.  * \param[in] key the option key
  294.  * \param[in] value the item value; \c NULL to set an emtpy 'list' option instead of an 'item'
  295.  *                  option (can be used to delete an 'item' option)
  296.  * \return the option; \c NULL if out of memory
  297.  */
  298. static inline ConfigOption *config_set_option( ConfigSection *section, const char *key, const char *value)
  299. {
  300.         assert(key != NULL);
  301.         return config_set_option_len(section, key, strlen(key), value, value == NULL ? 0 : strlen(value));
  302. }
  303.  
  304. /*!
  305.  * \brief Get an option by key.
  306.  *
  307.  * \param[in] section the section containing the option
  308.  * \param[in] key the option key
  309.  * \return the option; \c NULL if it does not exist
  310.  */
  311. extern ConfigOption *config_get_option( const ConfigSection *section, const char *key );
  312.  
  313. /*! \see ::config_get_or_set_option() */
  314. extern ConfigOption *config_get_or_set_option_len( ConfigSection *section, const char *key, size_t key_len, const char *value, size_t value_len );
  315.  
  316. /*!
  317.  * \brief Get an option by key, creating an 'item' option if the option did not exist.
  318.  *
  319.  * \param[in] section the section containing the option
  320.  * \param[in] key the option key
  321.  * \param[in] value the default item value; \c NULL to set an empty 'list' option instead of an
  322.  *                  'item' option
  323.  * \return the option; \c NULL if out of memory
  324.  */
  325. static inline ConfigOption *config_get_or_set_option( ConfigSection *section, const char *key, const char *value )
  326. {
  327.         assert(key != NULL);
  328.         return config_get_or_set_option_len(section, key, strlen(key), value, value == NULL ? 0 : strlen(value));
  329. }
  330.  
  331. /*! \see ::config_set_string_option() */
  332. extern void config_set_string_option_len( ConfigSection *section, const char *key, size_t key_len, const char *value, size_t value_len );
  333.  
  334. /*!
  335.  * \brief Set a string value of an 'item' option by key, creating the option if necessary.
  336.  *
  337.  * \param[in] section the section containing the option
  338.  * \param[in] key the option key
  339.  * \param[in] value the item value
  340.  * \return void
  341.  */
  342. static inline void config_set_string_option( ConfigSection *section, const char *key, const char *value )
  343. {
  344.         assert(key != NULL);
  345.         config_set_string_option_len(section, key, strlen(key), value, value == NULL ? 0 : strlen(value));
  346. }
  347.  
  348. /*!
  349.  * \brief Get a string value of an 'item' option by key.
  350.  *
  351.  * \param[in] section the section containing the option
  352.  * \param[in] key the option key
  353.  * \param[out] out_value the item value if a valid option exists; otherwise unset
  354.  * \return whether \p out_value was set
  355.  */
  356. extern bool config_get_string_option( const ConfigSection *section, const char *key, const char **out_value );
  357.  
  358. /*!
  359.  * \brief Get a string value of an 'item' option by key, setting the option if it was invalid or
  360.  *        creating the option if it did not exist.
  361.  *
  362.  * \param[in] section the section containing the option
  363.  * \param[in] key the option key
  364.  * \param[in] value the default item value
  365.  * \return the value
  366.  */
  367. extern const char *config_get_or_set_string_option( ConfigSection *section, const char *key, const char *value );
  368.  
  369. /*!
  370.  * \brief The styles of boolean values.
  371.  */
  372. typedef enum
  373. {
  374.         ZERO_ONE = 0,
  375.         NO_YES = 1,
  376.         OFF_ON = 2,
  377.         FALSE_TRUE = 3,
  378. } ConfigBoolStyle;
  379.  
  380. /*!
  381.  * \brief Set a boolean value of an 'item' option by key, creating the option if necessary.
  382.  *
  383.  * \param[in] section the section containing the option
  384.  * \param[in] key the option key
  385.  * \param[in] value the item value
  386.  * \param[in] style the style of boolean value
  387.  * \return void
  388.  */
  389. extern void config_set_bool_option( ConfigSection *section, const char *key, bool value, ConfigBoolStyle style );
  390.  
  391. /*!
  392.  * \brief Get a boolean value of an 'item' option by key.
  393.  *
  394.  * \param[in] section the section containing the option
  395.  * \param[in] key the option key
  396.  * \param[out] out_value the item value if a valid option exists; otherwise unset
  397.  * \return whether \p out_value was set
  398.  */
  399. extern bool config_get_bool_option( const ConfigSection *section, const char *key, bool *out_value );
  400.  
  401. /*!
  402.  * \brief Get a boolean value of an 'item' option by key, setting the option if it was invalid or
  403.  *        creating the option if it did not exist.
  404.  *
  405.  * \param[in] section the section containing the option
  406.  * \param[in] key the option key
  407.  * \param[in] value the default item value
  408.  * \param[in] style the style of boolean value
  409.  * \return the value
  410.  */
  411. extern bool config_get_or_set_bool_option( ConfigSection *section, const char *key, bool value, ConfigBoolStyle style );
  412.  
  413. /*!
  414.  * \brief Set an integer value of an 'item' option by key, creating the option if necessary.
  415.  *
  416.  * \param[in] section the section containing the option
  417.  * \param[in] key the option key
  418.  * \param[in] value the item value
  419.  * \return void
  420.  */
  421. extern void config_set_int_option( ConfigSection *section, const char *key, int value );
  422.  
  423. /*!
  424.  * \brief Get an integer value of an 'item' option by key.
  425.  *
  426.  * \param[in] section the section containing the option
  427.  * \param[in] key the option key
  428.  * \param[out] out_value the item value if a valid option exists; otherwise unset
  429.  * \return whether \p out_value was set
  430.  */
  431. extern bool config_get_int_option( const ConfigSection *section, const char *key, int *out_value );
  432.  
  433. /*!
  434.  * \brief Get an integer value of an 'item' option by key, setting the option if it was invalid or
  435.  *        creating the option if it did not exist.
  436.  *
  437.  * \param[in] section the section containing the option
  438.  * \param[in] key the option key
  439.  * \param[in] value the default item value
  440.  * \return the value
  441.  */
  442. extern int config_get_or_set_int_option( ConfigSection *section, const char *key, int value );
  443.  
  444. /*!
  445.  * \brief Set an unsigned integer value of an 'item' option by key, creating the option if
  446.  *        necessary.
  447.  *
  448.  * \param[in] section the section containing the option
  449.  * \param[in] key the option key
  450.  * \param[in] value the item value
  451.  * \return void
  452.  */
  453. extern void config_set_uint_option( ConfigSection *section, const char *key, unsigned int value );
  454.  
  455. /*!
  456.  * \brief Get an unsigned integer value of an 'item' option by key.
  457.  *
  458.  * \param[in] section the section containing the option
  459.  * \param[in] key the option key
  460.  * \param[out] out_value the item value if a valid option exists; otherwise unset
  461.  * \return whether \p out_value was set
  462.  */
  463. extern bool config_get_uint_option( const ConfigSection *section, const char *key, unsigned int *out_value );
  464.  
  465. /*!
  466.  * \brief Get an unsigned integer value of an 'item' option by key, setting the option if it was
  467.  *        invalid or creating the option if it did not exist.
  468.  *
  469.  * \param[in] section the section containing the option
  470.  * \param[in] key the option key
  471.  * \param[in] value the default item value
  472.  * \return the value
  473.  */
  474. extern unsigned int config_get_or_set_uint_option( ConfigSection *section, const char *key, unsigned int value );
  475.  
  476. /* config option accessors/manipulators -- by reference */
  477.  
  478. /*! \see ::config_set_value() */
  479. extern ConfigOption *config_set_value_len( ConfigOption *option, const char *value, size_t value_len );
  480.  
  481. /*!
  482.  * \brief Set the value of an 'item' option.
  483.  *
  484.  * \param[in] option the option
  485.  * \param[in] value the value
  486.  * \return the option; \c NULL if out of memory
  487.  */
  488. static inline ConfigOption *config_set_value( ConfigOption *option, const char *value )
  489. {
  490.         return config_set_value_len(option, value, value == NULL ? 0 : strlen(value));
  491. }
  492.  
  493. /*! \see ::config_add_value() */
  494. extern ConfigOption *config_add_value_len( ConfigOption *option, const char *value, size_t value_len );
  495.  
  496. /*!
  497.  * \brief Add a value to a 'list' option.
  498.  *
  499.  * \param[in] option the option
  500.  * \param[in] value the value
  501.  * \return the option; \c NULL if out of memory
  502.  */
  503. static inline ConfigOption *config_add_value( ConfigOption *option, const char *value )
  504. {
  505.         assert(value != NULL);
  506.         return config_add_value_len(option, value, strlen(value));
  507. }
  508.  
  509. /*!
  510.  * \brief Remove a value from a 'list' option.
  511.  *
  512.  * \param[in] option the option
  513.  * \param[in] i the index of the value
  514.  * \return the option; \c NULL if out of memory or invalid \p index
  515.  */
  516. extern ConfigOption *config_remove_value( ConfigOption *option, unsigned int i );
  517.  
  518. /*!
  519.  * \brief Get the value of an 'item' option.
  520.  *
  521.  * \param[in] option the option
  522.  * \return the value; \c NULL if \p option was \c NULL or was a 'list' option
  523.  */
  524. extern const char *config_get_value( const ConfigOption *option );
  525.  
  526. /*!
  527.  * \brief Get the value that indicates whether the option is a 'list' option.
  528.  *
  529.  * \param[in] option the option
  530.  * \return whether the option is a 'list' option
  531.  */
  532. static inline bool config_is_value_list( const ConfigOption *option )
  533. {
  534.         assert(option != NULL);
  535.         return option->values_count > 0 ||
  536.                 config_string_to_cstr(&option->v.value) == NULL;
  537. }
  538.  
  539. /*!
  540.  * \brief Get the number of values assigned to the option.
  541.  *
  542.  * \param[in] option the option
  543.  * \return \c 1 if the option is an 'item' option; the number of elements if the option is a 'list'
  544.  *         option
  545.  */
  546. static inline unsigned int config_get_value_count( const ConfigOption *option )
  547. {
  548.         assert(option != NULL);
  549.         return option->values_count == 0 ?
  550.                 (config_string_to_cstr(&option->v.value) == NULL ? 0 : 1) :
  551.                 option->values_count;
  552. }
  553.  
  554. /*!
  555.  * \brief Iterate over the values assigned to the option.
  556.  *
  557.  * \param[out] string_value the value variable to declare
  558.  * \param[in] option the option
  559.  */
  560. #define foreach_option_value( string_value, option ) \
  561.         for (ConfigOption *_option = (option); _option != NULL; _option = NULL) \
  562.         for (ConfigString *_values_begin = _option->values_count == 0 ? &_option->v.value : &_option->v.values[0], \
  563.                           *_values_end = _option->values_count == 0 ? _values_begin + 1 : &_option->v.values[_option->values_count], \
  564.                           *_value = _values_begin; _value < _values_end; ++_value) \
  565.         for (const char *(string_value) = config_string_to_cstr(_value); (string_value) != NULL; (string_value) = NULL)
  566.  
  567. /*!
  568.  * \brief Iterate over the values assigned to the option.
  569.  *
  570.  * \param[out] i the index variable to declare
  571.  * \param[out] string_value the value variable to declare
  572.  * \param[in] option the option
  573.  */
  574. #define foreach_option_i_value( i, string_value, option ) \
  575.         for (unsigned int (i) = 0; (i) == 0; (i) = ~0) \
  576.         for (ConfigOption *_option = (option); _option != NULL; _option = NULL) \
  577.         for (ConfigString *_values_begin = _option->values_count == 0 ? &_option->v.value : &_option->v.values[0], \
  578.                           *_values_end = _option->values_count == 0 ? _values_begin + 1 : &_option->v.values[_option->values_count], \
  579.                           *_value = _values_begin; _value < _values_end; ++_value, (i) = _value - _values_begin) \
  580.         for (const char *(string_value) = config_string_to_cstr(_value); (string_value) != NULL; (string_value) = NULL)
  581.  
  582. /*!
  583.  * \brief Remove a value from an option during iteration.  Should be followed by \c continue.
  584.  */
  585. #define foreach_remove_option_value() \
  586.         { \
  587.                 extern void config_oom( void ); \
  588.                 unsigned int _value_i = _value - _values_begin; \
  589.                 if (config_remove_value(_option, _value_i) == NULL) \
  590.                         config_oom(); \
  591.                 _values_begin = _option->values_count == 0 ? &_option->v.value : &_option->v.values[0]; \
  592.                 _values_end = _option->values_count == 0 ? _values_begin + 1 : &_option->v.values[_option->values_count]; \
  593.                 _value = _values_begin + _value_i - 1; \
  594.         }
  595.  
  596. #endif
  597.