From 863999caf6efd04d3181aa86e3bdccbb284a2824 Mon Sep 17 00:00:00 2001
From: madmurphy What Almost everything in libconfini is implemented from scratch, with the only notable exception of the I/O functions In libconfini almost everything is implemented from scratch, with the only notable exception of the I/O functions In the past, the build environment of libconfini did not offer shortcuts for facing this kind of situations – although, thanks to the modularity of the source code, it was still relatively simple to get rid of every tie with the C Standard Library and compile libconfini as “bare metal”, with Starting from version 1.13.0 a “bare metal” version of libconfini has been made available simply by passing a When the When the Only a very small amount of code in libconfini depends on the C Standard Library besides the I/O functions, so it is relatively easy to produce a “bare metal” fork with or without the latter. The The file The file The file The The The To create the source code of a “bare metal” version of libconfini a fifth amendment to the public header is also required, containing some common C standard definitions. This amendment is automatically generated for each platform during the build process and will be located under Here follows the summary of what is required by The first four files (the ones located in the The first four files (the ones located in the Whether you are using the bare-metal version of libconfini for a regular computer, a fridge or a microwave oven, you might have eventually to deal with some kind of filesystem. If the C standard Whether you are using the bare-metal version of libconfini for a regular computer, a fridge or a microwave oven, you might have eventually to deal with some kind of filesystem. If the C standard A good way to proceed is to hack the original pair of functions that rely on the C standard I/O API and adapt them to your platform: If instead of using the The same libconfini functions Try to determine the type of a member "as if it was active". Try to determine the type of a member assuming it is active After invoking The parsing algorithms used by libconfini are able to parse any type of file encoded in 8-bit code units, as long as the characters that match the regular expression Possible return values are: CONFINI_SUCCESS, CONFINI_IINTR, CONFINI_FEINTR, CONFINI_EOOR. The argument libconfini header See also IniNodeType. Check whether a given Check whether a format does not support escape sequences. Call a user-given macro (that accepts four arguments) for each row of the table. Content of the table: will always match the result of the literal comparison between the same two INI strings after these have been parsed by ini_string_parse() when INI strings are the strings typically dispatched by load_ini_file(), load_ini_path() or strip_ini_cache(), which may contain quotes and the three escape sequences In order to be suitable for both names and values, this function always considers sequences of one or more spaces out of quotes in both strings as collapsed, even when The ./configure --without-io-api
doesload_ini_file()
and load_ini_path()
, which rely on standard libraries (either the C Standard or the POSIX Standard, depending on the build settings). On some platforms, however, only a rather exotic I/O API is available, while for some other platforms the C Standard Library is simply too heavy or just not implementable.load_ini_file()
and load_ini_path()
, which rely on standard libraries – either the C Standard or the POSIX Standard, depending on the build settings. On some platforms, however, only a rather exotic I/O API is available, while for some other platforms the C Standard Library is simply too heavy or just not implementable.strip_ini_cache()
as the only parsing function (as this relies only on a buffer for its input), i.e. without load_ini_file()
and load_ini_path()
, and possibly even without any header at all.--without-io-api
option to the configure
script. This modified version presents the following characteristics:
@@ -77,11 +77,11 @@
The
-dev/hackings/baremetal/
subdirectoryconfigure
script is launched with the --without-io-api
option (or, equivalently, with --with-io-api=baremetal
), it assumes that no standard library at all could be present in the system. Hence it runs a series of tests and creates an inventory of what is present and what is not, in order to amend the source code accordingly – to ignore all the tests and assume that literally nothing from the C Standard Library is supported use --without-libc
. The amendments are necessary (instead of just relying on the C preprocessor) because it is required to change the public header, not just the compiled code.configure
script is launched with the --without-io-api
option (or, equivalently, with --with-io-api=baremetal
), it assumes that no standard library at all could be present in the system. Hence it runs a series of tests and creates an inventory of what is present and what is not, in order to amend the source code accordingly – to ignore all the tests and assume that literally nothing from the C Standard Library is supported, use --without-libc
. The amendments are necessary (instead of just relying on the C preprocessor) because it is required to change the public header, not just the compiled code.dev/hackings/baremetal
subdirectory contains all the necessary amendments. These are automatically applied when launching make all
or make baremetal-source-code
after having launched ./configure --without-io-api
(the original source code will be preserved).str2num.c
constitutes a re-implementation of the functions ini_get_int()
, ini_get_lint()
, ini_get_llint()
, ini_get_float()
and ini_get_double()
, which in the original code are implemented as pointers to standard functions (see below). This file amends src/confini.c
.str2num.h
, which amends src/confini.h
(i.e. the public header), exports the function headers of what str2num.c
implements.confini-header.c
contains only a nominal workaround-amendment to src/confini.c
(for facilitating the build system) that does not change the final C code compiled.str2num.c
file contains re-implementation of the functions ini_get_int()
, ini_get_lint()
, ini_get_llint()
, ini_get_float()
and ini_get_double()
, which in the original code are implemented as pointers to standard functions (see below). This file amends src/confini.c
.str2num.h
file, which amends src/confini.h
(i.e. the public header), exports the function headers of what str2num.c
implements.confini-header.c
file contains only a nominal workaround-amendment to src/confini.c
(for facilitating the build system) that does not change the final C code compiled.no-dist/hackings/baremetal/c-standard-library.h
../configure --without-io-api
:
@@ -90,9 +90,10 @@
-The
dev/hackings/baremetal/
subdirectorydev/hackings/baremetal/str2num.h
(pasted to the public header src/confini.h
)no-dist/hackings/baremetal/c-standard-library.h
(pasted to the public header src/confini.h
after having been automaticaly generated either by the configure
script, as an exact copy of dev/hackings/baremetal/c-standard-library.h
, or by make approve-revision
, in the few cases where manual user's intervention is required during the build process)dev/hackings/baremetal
subdirectory) are static and do not need any intervention from the user, unless (s)he wants to participate in the development of libconfini. The fifth file might require manual intervention in some situations, depending on the platform or on the user's choice (the build system will emit a warning in such cases).dev/hackings/baremetal
subdirectory) are static and do not need any intervention from the user, unless (s)he wants to participate in the development of libconfini. The fifth file might require manual intervention in some situations, depending on the platform or the user's will (the build system will emit a warning in such cases).Re-implementing
-load_ini_file()
and load_ini_path()
for your platformfopen()
, fseek()
, ftell()
, rewind()
, fread()
and fclose()
do not suit your needs, you can re-implement your own version of load_ini_file()
and load_ini_path()
. The only requirement is that at the end of the day you find a way to pass a disposable buffer containing an entire INI file to strip_ini_cache()
. A good way to proceed is to hack the original pair of functions that rely on the C standard I/O API and adapt them to your platform.fopen()
, fseek()
, ftell()
, rewind()
, fread()
and fclose()
do not suit your needs, you can re-implement your own version of load_ini_file()
and load_ini_path()
. The only requirement is that at the end of the day you find a way to pass a disposable buffer containing an entire INI file to strip_ini_cache()
.Going manual
--without-io-api
option you prefer to adapt the code manually, follow these simple steps (or adjust them according to your needs), which map verbatim what --without-io-api
does:
@@ -262,11 +263,11 @@
Parsing numbers without the C Standard Library
configure
option amends in src/confini.c
(at the end of the file) the corresponding pointers with the code below. Note that the C language does not possess a templating mechanism, so the following code needs to rely on a macro for not repeating five times the same function body with only minimal variations. Remove all comment initializers ( #
and/or ;
) from the beginning of each line of a comment. More...
-static uint_least8_t get_type_as_active (const char *const srcstr, const size_t len, const unsigned char allow_implicit, const IniFormat format)
+ Try to determine the type of a member "as if it was active". More... Try to determine the type of a member assuming it is active More... static size_t further_cuts (char *const srcstr, const IniFormat format)
@@ -249,7 +249,7 @@
Examine a (single-/multi-line) segment and check whether it contains more than just one node. More...
-
+Macro Definition Documentation
@@ -607,7 +607,7 @@
-
@@ -2899,7 +2942,7 @@
str The target string
- offs The offset where to start the left trim
+ depth What is actually considered a space (possible values: _LIBCONFINI_WITH_EOL_
, _LIBCONFINI_NO_EOL_
, _LIBCONFINI_JUST_S_T_
)
@@ -2952,7 +2995,7 @@ depth What is actually considered a space (possible values: _CONFINI_WITH_EOL_
, _CONFINI_NO_EOL_
, _CONFINI_JUST_S_T_
)
str The target string
- offs The offset where to start the left trim
+ depth What is actually considered a space (possible values: _LIBCONFINI_WITH_EOL_
, _LIBCONFINI_NO_EOL_
, _LIBCONFINI_JUST_S_T_
)
@@ -3058,7 +3101,7 @@ depth What is actually considered a space (possible values: _CONFINI_WITH_EOL_
, _CONFINI_NO_EOL_
, _CONFINI_JUST_S_T_
)
str The target string
- len The length of the string
+ depth What is actually considered a space (possible values: _LIBCONFINI_WITH_EOL_
, _LIBCONFINI_NO_EOL_
, _LIBCONFINI_JUST_S_T_
)
@@ -3111,7 +3154,7 @@ depth What is actually considered a space (possible values: _CONFINI_WITH_EOL_
, _CONFINI_NO_EOL_
, _CONFINI_JUST_S_T_
)
str The target string
- len The length of the string
+ depth What is actually considered a space (possible values: _LIBCONFINI_WITH_EOL_
, _LIBCONFINI_NO_EOL_
, _LIBCONFINI_JUST_S_T_
)
@@ -3272,7 +3315,7 @@ depth What is actually considered a space (possible values: _CONFINI_WITH_EOL_
, _CONFINI_NO_EOL_
, _CONFINI_JUST_S_T_
) IniDispHandler data type) will be invoked with two arguments:
dispatch
(a pointer to an IniDispatch structure containing the parsed member of the INI file) and user_data
(the custom argument user_data
previously passed). If f_foreach
returns a non-zero value the caller function will be interrupted.
strip_ini_cache()
, the buffer pointed by the ini_source
parameter must be considered as a corrupted buffer and should be freed or overwritten. For more information about this function, please refer to the Library Functions Manual./[\s\[\]\.\\;#"']/
refer to the same code points they refer to in ASCII (as they do, for example, in UTF-8 and ISO-8859-1), independently of platform-specific conventions.
+NUL
characters possibly present in the buffer (with the exception of the last one).NUL
characters possibly present in the buffer (with the exception of the last one). size_t ini_length = strlen(original_ini_buffer);
-
srcstr.replace(/^[#;]+|(\n\r?|\r\n?)[\t \v\f]*[#;]+/g, "$1")
srcstr.replace(/^[#;]+/, "")
srcstr.replace(/^[#;]+|(\n\r?|\r\n?)[\t \v\f]*[#;]+/g, "$1")
srcstr.replace(/^[#;]+/, "")
srcstr
may begin with a comment initializer (#
or ;
depending on the format), or with the character that immediately follows it.
diff --git a/docs/html/confini_8h.html b/docs/html/confini_8h.html
index ae183e3..38e22b8 100644
--- a/docs/html/confini_8h.html
+++ b/docs/html/confini_8h.html
@@ -295,10 +295,10 @@
-
+ ini_string ini_string The string to parse as a double
double(*const ini_get_float )(const char *ini_string) Legacy support for parsing a double
data type – please do not use this function: use ini_get_double()
instead. More...
-
+static const IniFormat INI_DEFAULT_FORMAT = { INI_EQUALS , false , INI_DISABLED_OR_COMMENT , INI_DISABLED_OR_COMMENT , INI_ABSOLUTE_AND_RELATIVE , INI_MULTILINE_EVERYWHERE , false , false , false , false , false , false , false , false , } static const IniFormat INI_DEFAULT_FORMAT = { INI_EQUALS, false, INI_DISABLED_OR_COMMENT, INI_DISABLED_OR_COMMENT, INI_ABSOLUTE_AND_RELATIVE, INI_MULTILINE_EVERYWHERE, false, false, false, false, false, false, false, false } A model format for standard INI files. More...
-
+static const IniFormat INI_UNIXLIKE_FORMAT = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } static const IniFormat INI_UNIXLIKE_FORMAT = { INI_ANY_SPACE, false, INI_DISABLED_OR_COMMENT, INI_DISABLED_OR_COMMENT, INI_ABSOLUTE_AND_RELATIVE, INI_MULTILINE_EVERYWHERE, false, false, false, false, false, false, false, false } A model format for Unix-like .conf files (where space characters are delimiters between keys and values) More...
@@ -315,7 +315,7 @@
bool INI_GLOBAL_LOWERCASE_MODE
-
+Macro Definition Documentation
@@ -357,7 +357,7 @@
Value:
char *
data type points to the global variable INI_GLOBAL_IMPLICIT_VALUE or to any fragment of it.
Value:
_____( preserve_empty_quotes, 21, 1, false ) \
#include <stdio.h>
}
#include <confini.h>
@@ -1163,12 +1177,12 @@ #include <confini.h>
#include <stdio.h>
#include <stdio.h>
#include <confini.h>
- simple_string A string to check (it can be NULL
)
+ when_fail A value that is returned if no matching boolean is found when_fail The value that is returned if no matching boolean is found int my_section_my_number;
return 0;
if (THEYMATCH("my_string", dsp->data)) {
dsp->format
return 1;
- ini_string A string to check (it can be NULL
)
+ when_fail A value that is returned if no matching boolean is found when_fail The value that is returned if no matching boolean is found format The format of the INI file int my_section_my_number;
return 0;
if (THEYMATCH("my_string", dsp->data)) {
dsp->format
return 1;
#include <stdio.h>
my_format.implicit_is_not_empty = true;
:
format.do_not_collapse_values
is set to false
. :
\\
, \'
and \"
.format.do_not_collapse_values
is set to true
.format
argument is used for the following fields:#include <stdio.h>
#include <stdio.h>
return 0;
#include <stdio.h>
#include <stdio.h>
#include <stdio.h>
IniDispHandler data type) will be invoked with two arguments:
dispatch
(a pointer to an IniDispatch structure containing the parsed member of the INI file) and user_data
(the custom argument user_data
previously passed). If f_foreach
returns a non-zero value the caller function will be interrupted.
After invoking strip_ini_cache()
, the buffer pointed by the ini_source
parameter must be considered as a corrupted buffer and should be freed or overwritten. For more information about this function, please refer to the Library Functions Manual.
The parsing algorithms used by libconfini are able to parse any type of file encoded in 8-bit code units, as long as the characters that match the regular expression /[\s\[\]\.\\;#"']/
refer to the same code points they refer to in ASCII (as they do, for example, in UTF-8 and ISO-8859-1), independently of platform-specific conventions.
NUL
characters possibly present in the buffer (with the exception of the last one).NUL
characters possibly present in the buffer (with the exception of the last one).Possible return values are: CONFINI_SUCCESS, CONFINI_IINTR, CONFINI_FEINTR, CONFINI_EOOR.
const IniFormat INI_DEFAULT_FORMAT = { INI_EQUALS , false , INI_DISABLED_OR_COMMENT , INI_DISABLED_OR_COMMENT , INI_ABSOLUTE_AND_RELATIVE , INI_MULTILINE_EVERYWHERE , false , false , false , false , false , false , false , false , } | +const IniFormat INI_DEFAULT_FORMAT = { INI_EQUALS, false, INI_DISABLED_OR_COMMENT, INI_DISABLED_OR_COMMENT, INI_ABSOLUTE_AND_RELATIVE, INI_MULTILINE_EVERYWHERE, false, false, false, false, false, false, false, false } |
ini_string | |
ini_string | The string to parse as a double |
const IniFormat INI_UNIXLIKE_FORMAT = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } | +const IniFormat INI_UNIXLIKE_FORMAT = { INI_ANY_SPACE, false, INI_DISABLED_OR_COMMENT, INI_DISABLED_OR_COMMENT, INI_ABSOLUTE_AND_RELATIVE, INI_MULTILINE_EVERYWHERE, false, false, false, false, false, false, false, false } |
If you are using Microsoft Windows, a batch script for compiling libconfini under MinGW without GNU Make is available (mgwmake.bat
). If you want instead to compile the library manually, you can run:
cd src +If you are using Microsoft Windows, a batch script for compiling libconfini with MinGW without GNU Make is available (
mgwmake.bat
). If you want instead to compile the library manually, you can run:cd src windres.exe -i winres.rc -o winres.o gcc.exe -std=c99 -g -O3 -Wall -shared -static-libgcc -Wl,--no-undefined \ -Wl,-out-implib,libconfini.lib -o libconfini.dll winres.o confini.c @@ -100,7 +100,7 @@MinGW
gcc.exe -std=c99 -g -O3 -Wall -shared -static-libgcc -Wl,--no-undefined \ -Wl,-out-implib,libconfini.lib -o libconfini.dll confini.o winres.o strip.exe libconfini.dll -If you want to build (and install) libconfini via GNU Make under Microsoft Windows several options are available, such as MinGW + MSYS, MSYS2, GnuWin32 and Cygwin (for which an unofficial port of libconfini exists).
+
If you want to build (and install) libconfini via GNU Make under Microsoft Windows several options are available, such as MinGW + MSYS, MSYS2 (which ships an official port of the library, Cygwin (for which an unofficial port of libconfini exists) and GnuWin32.
To compile the library with Microsoft Visual Studio use the following commands:
cd src rc.exe winres.rc @@ -125,7 +125,7 @@Precompiled DLL
Often a compiled DLL is available among the assets of each release of this package on GitHub.
Bare metal
The library has almost everything implemented from scratch, with the only notable exception of the I/O functions
-load_ini_file()
andload_ini_path()
, which rely on C standard libraries. On some platforms, however, only a rather exotic I/O API is available, while for some other platforms the C Standard Library is simply too heavy or just not implementable.In these situations it will be needed to get rid of every tie with the C Standard Library and compile libconfini as "bare metal". The
+configure
script has a--without-io-api
option that allows to create a special fork of the original library able to function in any environment. For information about how to proceed, please seedev/hackings/baremetal/README.md
.In these situations it will be needed to get rid of every tie with the C Standard Library and compile libconfini as "bare metal". The
configure
script has two options for creating special forks of the original library able to function in any environment,--without-io-api
and--without-libc
. For information about how to proceed, please seedev/hackings/baremetal/README.md
.Complex installations
This package has been designed to be able to coexist with other major releases of itself. However, when two versions share the same major number but have different minor or revision numbers, only the most recent package must be installed.
For two or more different major releases to be able to coexist, the major number of each version must be appended to the package name it refers to, with the possible exception of only one package (usually version 1.X.X). This can be done easily by passing the
--with-other-versions
option to theconfigure
script:./configure --with-other-versions @@ -135,7 +135,7 @@Complex installations
Do not use Autoconf transforming rules in place of the built-in
./configure --with-other-versions
for appending the major version number to the name of the package. If you do so, the header file will be installed asconfiniX.h
, instead of the more standardconfini-X.h
.For any issue, drop a message at https://github.com/madmurphy/libconfini/issues.
Distributing the source code
-If you aim to re-distribute the source code of libconfini you should first make sure that the
+configure
script is present, for granting the possibility to compile the package without having Autotools installed. If theconfigure
script is present and you have already launched it, usemake distclean
to reset the configuration that this has created, or usemake source-release
to build a fresh archive that ignores the current configuration.If you aim to re-distribute the source code of libconfini you must first make sure that the
configure
script is present, for granting the possibility to compile the package without having Autotools installed. If theconfigure
script is present and you have already launched it, usemake distclean
to reset the configuration that this has created, or usemake source-release
to build a fresh archive that ignores the current configuration.Distributing the compiled package
Use
diff --git a/docs/html/libconfini.html b/docs/html/libconfini.html index 446a3e6..8efdd72 100644 --- a/docs/html/libconfini.html +++ b/docs/html/libconfini.html @@ -89,6 +89,7 @@make binary-release
to create a binary package of libconfini for a particular platform. If you want to obtain the list of the files that are going to be installed, usemake manifest
.
IniStatistics
and IniDispatch
structuresDuring the years several interpretations of INI files have appeared. In some implementations the colon character (:
) has been adopted as delimiter between keys and values instead of the classic equals sign (a typical example under GNU/Linux is /etc/nsswitch.conf
); in other implementations, under the influence of Unix standard configuration files, a sequence of one or more spaces (/[ \t\v\f]+/
or /(?:\\(?:\n\r?|\r\n?)|[\t \v\f])+/
) has been used instead (see for example /etc/host.conf
).
During the years several interpretations of INI files appeared. In some implementations the colon character (:
) was adopted as delimiter between keys and values instead of the classic equals sign (a typical example under GNU/Linux is /etc/nsswitch.conf
); in other implementations, under the influence of Unix standard configuration files, a sequence of one or more spaces (/[ \t\v\f]+/
or /(?:\\(?:\n\r?|\r\n?)|[\t \v\f])+/
) was adopted instead (see for example /etc/host.conf
).
Equals sign used as delimiter between keys and values:
libconfini has been born as a general INI parser for GNU, so the support of most part of INI dialects has been implemented within it.
-Especially in Microsoft Windows a more radical syntax variation has been implemented: the use of semicolon, instead of new lines, as delimiter between nodes, as in the following example:
+libconfini was born as a general INI parser for GNU, so the support of most part of INI dialects has been implemented within it.
+Especially in Microsoft Windows a more radical syntax variation found its way into INI files: the use of semicolon, instead of new lines, as delimiter between nodes, as in the following example:
#2 Using a path:
where
ini_file
in load_ini_file()
is the FILE
handle pointing to the INI file#2 Using a path:
The function above can then be invoked directly on a const
buffer:
or, equivalently, in macro form:
Starting from version 1.7.0 a format named INI_UNIXLIKE_FORMAT is available.
This format is a clone of INI_DEFAULT_FORMAT with the only exception of IniFormat::delimiter_symbol
, whose value is set to INI_ANY_SPACE instead of INI_EQUALS.
The semantics of the IniFormat
bitfield has been designed in order to ensure that when all its fields are set to zero it equals INI_UNIXLIKE_FORMAT.
According to the ini_fton()
function this format is univocally the format No. 56637. The function ini_ntof()
then gives us a shortcut to construct the very same format using its format number. Hence, the code above corresponds to:
IniStatistics
and IniDispatch
structuresWhen the functions load_ini_file()
, load_ini_path()
read an INI file, or when the function strip_ini_cache()
parses a buffer, they dispatch the file content to the f_foreach()
listener. Before the dispatching begins some statistics about the parsed file can be dispatched to the f_init()
listener (if this is non-NULL
).
Or, for instance, in the following example the first two arrays are considered equal, while the third one is considered different.
In formats that support quotes, the function ini_array_match()
is also the function that should be used, with '.'
or INI_DOT as delimiter (see enum
IniDelimiters), to compare properly section paths containing more than one level of nesting.
In case of multiple comparisons you might want to use a macro:
The four functions ini_string_match_ss()
, ini_string_match_si()
, ini_string_match_ii()
, ini_array_match()
perform case-sensitive or case-insensitive comparisons depending on the format given. UTF-8 codepoints out of the ASCII range are always compared case-sensitive.
Note that within INI strings empty quotes and spaces out of quotes are always collapsed during comparisons. Furthermore, remember that the multi-line escape sequence /\\(?:\n\r?|\r\n?)/
is not considered as such in INI strings, since this is the only escape sequence automatically unescaped by libconfini before each dispatch.
It is possible with libconfini to parse INI strings as arrays. In order to avoid that any particular character be treated as a metacharacter throughout an entire configuration file, INI arrays do not have a fixed delimiter symbol specified in the INI format.
+Abstractly speaking, this means that array delimiters are not part of the INI syntax, but of the INI semantics instead. Concretely speaking, it means that developers have to provide a delimiter as soon as they decide to parse an INI string as an array.
+Out in the wild, the most widespread INI array delimiter is probably the space sequence (INI_ANY_SPACE
– i.e. /(?:\\(?:\n\r?|\r\n?)|[\t \v\f])+/
or /[ \t\v\f]+/
, depending on whether the format is multi-line or not). Another widespread delimiter is the comma (','
or INI_COMMA
). Besides these two, occasionally other characters can be found as array delimiters (':'
, '|'
, ';'
, ...).
For iterating through an INI array using a delimiter libconfini provides the following tools:
+ini_array_get_length()
ini_array_foreach()
ini_array_collapse()
ini_array_break()
ini_array_release()
ini_array_shift()
ini_array_split()
None of the functions above actually ever allocates any array, as libconfini does not know what kind of data type an array should be composed of – the developer might be looking for an array of strings, or an array of integers, or anything else. These tools only provide safe mechanisms to iterate through, or tokenize, the members of INI arrays according to the format and the delimiter given – making sure for example that when the delimiter symbol is found nested within quotes it is treated as a normal character – but allocating memory is something that must be done manually.
+An example function that parses INI strings as newly allocated arrays of C strings is available under examples/utilities/make_strarray.h
. If your program requires other data types (such as integers, booleans, etc.) you may adapt that example to your needs.
The strings dispatched, as already said, must not be freed. Nevertheless, before being copied or analyzed they can be edited, with some precautions:
+The strings dispatched, as already said, must not be freed. Nevertheless, before being copied or analyzed they can be edited, with some precautions:
IniDispatch::d_len
and IniDispatch::v_len
).IniDispatch::data
and this contains a section path, the IniDispatch::append_to
properties of its children will either share this buffer or will concatenate it to another buffer. Hence, if you edit its content – and depending on how you edit it – you might no more be able to rely on the IniDispatch::append_to
properties of this node's children. You would not make any damage, the loop will continue just fine: so if you think you are never going to use the property IniDispatch::append_to
, just do it; alternatively, use strndup()
. If instead IniDispatch::data
contains a key name or a comment, it is granted that no other dispatch will share this buffer, so feel free to edit it before it gets lost.IniDispatch::data
field of a section: the IniDispatch::append_to
properties of its children will either share this buffer or will concatenate it to another buffer. Thus, if you edit its content – and depending on how you edit it – you might be no more able to rely on the IniDispatch::append_to
properties of this node's children. You would not make any damage, the loop will continue just fine: so if you think you are never going to use the property IniDispatch::append_to
, just do it; alternatively, use strndup()
. If instead IniDispatch::data
contains a key name or a comment, it is granted that no other dispatch will share this buffer, so feel free to edit it before it gets lost.IniDispatch::value
, if it does not represent an implicit value (see § Implicit keys) or if IniFormat::implicit_is_not_empty
is set to false
, this buffer is never shared between dispatches, so feel free to edit it.IniDispatch::append_to
, this buffer is likely to be shared with other dispatches. Again, you would not destroy the world nor generate errors, but you would make the next IniDispatch::append_to
s useless. For this reason the buffer pointed by IniDispatch::append_to
is passed as constant. To unquote the path parts listed in this field please use strndup()
.IniDispatch::data
, IniDispatch::value
and IniDispatch::append_to
and the fields IniDispatch::type
, IniDispatch::d_len
, IniDispatch::v_len
and IniDispatch::at_len
, are constantly reset, so feel free to use them as custom placeholders if you like – but check their types: IniDispatch::type
has only eight bits available and IniDispatch::append_to
will always point to a const
buffer.If all these rules, although thoroughly exposed, sound still confusing to you, use always strndup()
on the strings dispatched and feel free to edit your own buffers as you wish. Under examples/utilities/clone_ini_dispatch.h
you can find a function designed to make a hard copy of an entire IniDispatch
, including all the strings that this points to.
In order to set the value to assign to implicit keys (i.e. keys without a delimiter and a value), please use the ini_global_set_implicit_value()
function. A true
boolean is usually a good choice:
Alternatively, instead of ini_global_set_implicit_value()
you can manually declare at the beginning of your code the two global variables INI_GLOBAL_IMPLICIT_VALUE and INI_GLOBAL_IMPLICIT_V_LEN, which will be retrieved by libconfini:
Or you can assign a value to them at the beginning of the main()
function of your program:
The functions ini_unquote()
, ini_string_parse()
, ini_array_collapse()
, ini_array_break()
, ini_array_release()
and ini_array_split()
change the content of the given strings. It is important to point out that the edit is always performed within the lengths of the strings given.
In order to be as flexible as possible, libconfini does not store the dispatched data, nor indicizes them. This gives the developer the power to deal with them in many different ways.
+In order to be as flexible as possible, libconfini does not store the dispatched data, nor indicizes them. This gives developers the power to deal with them in many different ways.
For small INI files a normal if/else chain, using ini_array_match()
for comparing section paths and ini_string_match_si()
/ini_string_match_ii()
for comparing key names, usually represents the most practical way to obtain the information required from an INI file. Sometimes however, especially in case of sizeable INI files, the most efficient solution would be to store the parsed data in a hash table before trying to access it.
Some INI parsers are released with a hash table API included by default. This is often an unpractical solution, since fantastic free software libraries that focus solely on hash tables already exist, and providing a further API for managing a hash function together with an INI parser only complicates the code, makes it harder to maintain, and does not give the user the real freedom to choose what suits best to each single case. Some programming languages have even hash tables in their standard libraries (see std::map
in C++ for example).
When needed, the data parsed by libconfini can still be stored in a hash table while it is being dispatched. If you are interested in combining libconfini with a hash table, I have left a general example of how to use GLib's GHashTable
together with libconfini under examples/miscellanea/glib_hash_table.c
. If you are using C++, you can find an example of how to construct a C++ class that relies on a std::unordered_map
object under examples/cplusplus/map.cpp
. By keeping these examples as models other solutions can be easily explored as well.
In the past, besides the two global variables INI_GLOBAL_IMPLICIT_VALUE and INI_GLOBAL_IMPLICIT_V_LEN, a third variable named INI_GLOBAL_LOWERCASE_MODE would tell libconfini whether to dispatch in lower case all key names and section paths of case-insensitive INI files. This variable rarely needed to be set to true
, since string comparisons made by libconfini are always either case-sensitive or case-insensitive depending on the format given.
Comparing an ASCII upper case letter to an ASCII lower case letter is an invariant process. But comparing two Unicode letter cases is a process that depends on the locale of the machine. Consider for example the lower case letter i
: in most European languages its upper case is I
, while this is not the case in Turkish, where the upper case of i
is İ
(and the lower case of I
is ı
). Therefore for a person living in Italy or France, i
and I
will represent the same letter, while for a person living in Turkey they will not.
Key and section names of an INI file however cannot depend on the locale of the machine, since they must be reliably searched for independently of where a machine is located. Imagine for example a key named “INI” and imagine that Unicode case folding were performed on key names during string comparisons. If you lived in Europe you could look up for such key using its lower case “ini”, while if you lived in Turkey you would have to use the lower case “ını” to find it. So the only solution in this context is to consider Unicode characters out of the ASCII range always as case-sensitive. For this reason, libconfini (and probably any senseful INI parser) will never perform case folding of Unicode characters out of the ASCII range within key and section names.
-It must be said however that most Unicode characters do not possess a lower and upper case, and most characters outside of the ASCII range could theoretically appear without problems in key and section names also in case-insensitive INI files (think of the character §
for example). And, as for case-sensitive INI files, no Unicode character would ever represent a problem. Nonetheless, it is still generally more acceptable to use ASCII only within key and section names – and possibly, if needed, non-ASCII Unicode characters within values and comments.
It must be said that most Unicode characters do not possess a lower and upper case, and most characters outside of the ASCII range could theoretically appear without problems in key and section names also in case-insensitive INI files (think of the character §
for example). And, as for case-sensitive INI files, no Unicode character would ever represent a problem. Nonetheless, it is generally more acceptable to use ASCII only within key and section names – and possibly, if needed, non-ASCII Unicode characters within values and comments.
That said, libconfini deals perfectly fine with UTF-8 (but is always case-sensitive outside of the ASCII range), so use the latter as you feel appropriate.
When an INI node is wrongly written in respect to the format given, it is dispatched verbatim as an INI_UNKNOWN node – see enum
IniNodeType. Empty lines, or lines containing only spaces and empty quotes (if the latter are supported) will be skipped.
In order to avoid error exceptions, strings containing an unterminated quote will be always treated as if they had a virtual quote as their last + 1 character. For example,
will always determine the same behavior as if it were
+will always determine the same behavior as if it had been
Any format containing the following three settings will never produce INI_UNKNOWN nodes, even if instead of an INI file we tried to parse a .jpeg image (or anything else):
The algorithms used by libconfini stand in a delicate equilibrium between flexibility, speed and code readability, with flexibility as primary target. Performance can vary with the format used to parse an INI file, but in most cases is not a concern.
@@ -1328,7 +1370,7 @@we would obtain the following result:
As you can see, all comments but now=Sunday April 3rd, 2016
would be parsed as disabled entries – which is not what the author intended. Therefore, to ensure that such INI file be parsed properly, you can follow two possible approaches.
1. Intervene on the INI file. The reason why now=Sunday April 3rd, 2016
has been properly parsed as a comment – despite it really looks like a disabled entry – is because it has been nested within a comment block opened by more than one leading marker (in this case the two ##). As a general rule, libconfini never parses a comment beginning with more than one leading marker as a disabled entry, therefore this is the surest way to ensure that proper comments are always considered as such.
Hence, by adding one more number sign to the first comment
@@ -1399,11 +1442,11 @@we obtain the wanted result:
2. Intervene on the format. There are cases where the INI file is automatically generated by machines (comments included), or distributed as such, and human intervention would be required on each machine-generated release of the INI file. In these cases – and if we are sure about the expected content of the INI file – we can restrict the format chosen in order to parse comments and disabled entries properly. In particular, the following fields of the IniFormat
bitfield can have an impact on the disambiguation between comments and disabled entries.
Reliable general patterns:
Output:
If the strip
utility is not available on your machine, use make install
instead (it will produce larger binaries)
For a minimum installation without development files (i.e. static libraries, headers, documentation, examples, etc.) use ./configure --disable-devel
.
If the configure
script is missing from your package you need to generate it by running the bootstrap
script. By default, bootstrap
will also run the configure
script immediately after having generated it, so you may type the make
command directly after bootstrap
. To list different options use ./bootstrap --help
.
If you are using Microsoft Windows, a batch script for compiling libconfini with MinGW without Bash is available (mgwmake.bat
). If you are interested in using GNU Make for compiling libconfini under Microsoft Windows, you can integrate MinGW with MSYS, or you can directly use MSYS2 and its official port of the library. Alternatively, an unofficial port of libconfini for Cygwin is available.
If you are using Microsoft Windows, a batch script for compiling libconfini with MinGW without Bash is available (mgwmake.bat
). If you are interested in using GNU Make for compiling libconfini under Microsoft Windows, you can integrate MinGW with MSYS, or you can directly use MSYS2 and its official port of the library. Alternatively, an unofficial port of libconfini for Cygwin is available.
For further information, see INSTALL.
Danilo Spinella maintains a D binding package of libconfini.
diff --git a/docs/man/man3/IniDispatch.3 b/docs/man/man3/IniDispatch.3 index aa14bc3..e3a530d 100644 --- a/docs/man/man3/IniDispatch.3 +++ b/docs/man/man3/IniDispatch.3 @@ -1,4 +1,4 @@ -.TH "IniDispatch" 3 "Mon Jun 14 2021" "libconfini" \" -*- nroff -*- +.TH "IniDispatch" 3 "Sat Sep 25 2021" "libconfini" \" -*- nroff -*- .ad l .nh .SH NAME diff --git a/docs/man/man3/IniFormat.3 b/docs/man/man3/IniFormat.3 index 66f1198..fb8bafc 100644 --- a/docs/man/man3/IniFormat.3 +++ b/docs/man/man3/IniFormat.3 @@ -1,4 +1,4 @@ -.TH "IniFormat" 3 "Mon Jun 14 2021" "libconfini" \" -*- nroff -*- +.TH "IniFormat" 3 "Sat Sep 25 2021" "libconfini" \" -*- nroff -*- .ad l .nh .SH NAME diff --git a/docs/man/man3/IniStatistics.3 b/docs/man/man3/IniStatistics.3 index 4a7d6b6..590a568 100644 --- a/docs/man/man3/IniStatistics.3 +++ b/docs/man/man3/IniStatistics.3 @@ -1,4 +1,4 @@ -.TH "IniStatistics" 3 "Mon Jun 14 2021" "libconfini" \" -*- nroff -*- +.TH "IniStatistics" 3 "Sat Sep 25 2021" "libconfini" \" -*- nroff -*- .ad l .nh .SH NAME diff --git a/docs/man/man3/confini.h.3 b/docs/man/man3/confini.h.3 index eda1235..871c02b 100644 --- a/docs/man/man3/confini.h.3 +++ b/docs/man/man3/confini.h.3 @@ -1,4 +1,4 @@ -.TH "confini.h" 3 "Mon Jun 14 2021" "libconfini" \" -*- nroff -*- +.TH "confini.h" 3 "Sat Sep 25 2021" "libconfini" \" -*- nroff -*- .ad l .nh .SH NAME @@ -234,11 +234,11 @@ confini.h \- libconfini header .br .RI "Legacy support for parsing a \fCdouble\fP data type – please \fIdo not use this function\fP: use \fC\fBini_get_double()\fP\fP instead\&. " .ti -1c -.RI "static const \fBIniFormat\fP \fBINI_DEFAULT_FORMAT\fP = { \fBINI_EQUALS\fP , false , \fBINI_DISABLED_OR_COMMENT\fP , \fBINI_DISABLED_OR_COMMENT\fP , \fBINI_ABSOLUTE_AND_RELATIVE\fP , \fBINI_MULTILINE_EVERYWHERE\fP , false , false , false , false , false , false , false , false , }" +.RI "static const \fBIniFormat\fP \fBINI_DEFAULT_FORMAT\fP = { \fBINI_EQUALS\fP, false, \fBINI_DISABLED_OR_COMMENT\fP, \fBINI_DISABLED_OR_COMMENT\fP, \fBINI_ABSOLUTE_AND_RELATIVE\fP, \fBINI_MULTILINE_EVERYWHERE\fP, false, false, false, false, false, false, false, false }" .br .RI "A model format for standard INI files\&. " .ti -1c -.RI "static const \fBIniFormat\fP \fBINI_UNIXLIKE_FORMAT\fP = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }" +.RI "static const \fBIniFormat\fP \fBINI_UNIXLIKE_FORMAT\fP = { \fBINI_ANY_SPACE\fP, false, \fBINI_DISABLED_OR_COMMENT\fP, \fBINI_DISABLED_OR_COMMENT\fP, \fBINI_ABSOLUTE_AND_RELATIVE\fP, \fBINI_MULTILINE_EVERYWHERE\fP, false, false, false, false, false, false, false, false }" .br .RI "A model format for Unix-like \&.conf files (where space characters are delimiters between keys and values) " .ti -1c @@ -272,7 +272,7 @@ GNU General Public License, version 3 or any later version .PP \fBVersion\fP .RS 4 -1\&.16\&.1 +1\&.16\&.2 .RE .PP \fBDate\fP @@ -642,13 +642,18 @@ If \fCdelimiter\fP matches a metacharacter within the format given (\fC'\\\\'\fP #include