Author: | Roman Neuhauser |
---|---|
Contact: | neuhauser@sigpipe.cz |
Copyright: | This document is in the public domain. |
Contents
Iniphile is a C++ library and commandline tool for parsing a dialect of the INI file format.
Iniphile is known to build and run on FreeBSD 9 with gcc >= 4.2.1, and on Windows Vista with gcc >= 4.6.2 and Windows 7 with Visual Studio 2008 (vc9).
The library uses a few header-only Boost [1] libraries in both its interface and implementation. The interface mentions Boost.Optional [2] and Boost.Variant [3], The most prominent implementation detail is Boost.Spirit [4], specifically v2.1 (Boost [1] 1.41) or higher. Unit tests require Boost.Test [5] to compile and run.
Important
For now, Iniphile supports linking only against Boost libraries built
with --layout=system
, -DBOOST_ALL_NO_LIB
is used unconditionally.
This means that if your Boost libraries have funny names like
boost_regex-vc90-mt-1_45.dll, linking the test executables will fail.
The Iniphile library depends on header-only Boost libraries and the
linker failure does not affect it. You just won't be able to run its
unit tests.
notify.ini
[notify] enabled = No addresses = alice@example.com bob@example.com chris@example.com
notify.cpp
#include <iostream> #include <sstream> #include <fstream> #include <string> #include "input.hpp" #include "ast.hpp" #include "output.hpp" bool notify(std::vector<std::string> const& addrs) { // whatever } int main() { namespace ini = iniphile; std::string fname("notify.ini"); std::ifstream input(fname); std::ostringstream diag; ini::parse_result cfg(ini::parse(fname, input, diag)); if (!cfg) { std::cerr << "garbled configuration\n"; return EXIT_FAILURE; } ini::ast::node afg(ini::normalize(*cfg)); typedef std::vector<std::string> values; bool enabled = ini::get(afg, "notify.enabled", false); long attempts = ini::get(afg, "notify.attempts", 3L); values addrs = ini::get(afg, "notify.addresses", values()); while (enabled && attempts--) { if (notify(addrs)) return EXIT_SUCCESS; } return EXIT_FAILURE; }
There's no standard definition of INI file syntax and semantics. The ABNF [6] grammar below approximates the dialect supported by this library (only significant whitespace is part of the grammar). See the following prose for clarifications).
inifile = *section EOF section = *comentline headerline sectionbody headerline = "[" sectionname "]" comment sectionname = 1*LCHAR ; except "]" sectionbody = *(assignment / comment) assignment = optname "=" optval optname = 1*VCHAR ; except "=" optval = ovlinefirst *ovlinecont ovlinefirst = [ovline] comment ovlinecont = 1*WSP ovline comment ovline = *optvalpart optvalpart = qstring / bareword qstring = DQUOTE *CHAR DQUOTE bareword = 1*VCHAR ; except ";" comment = *1(";" *LCHAR) EOL EOL = CRLF / CR / LF LCHAR = VCHAR / WSP
An inifile is a flat, possibly empty, collection of sections. A section begins at a headerline and continues until the next headerline or EOF, whichever comes first. Each section contains zero or more assignments, optname/optval pairs. Whitespace allowed around the "=". optname must begin at the start of a line. optval is a list of strings (optvalpart, either a qstring or a bareword) separated by whitespace. It may span multiple lines: continuation lines begin with horizontal whitespace, and qstrings may also contain newlines.
The tool is documented in an accompanying man page, iniphile(1).
Each header #includes all its dependencies.
metagram.hpp
typedef unspecified iniphile::config;
input.hpp
#include <boost/optional.hpp> typedef boost::optional<iniphile::config> parse_result; iniphile::parse_result iniphile::parse( std::string const& fname , std::string const& input , std::ostream& diag ); iniphile::parse_result iniphile::parse( std::string const& fname , std::istream& input , std::ostream& diag );
astfwd.hpp
#include <boost/variant.hpp> typedef std::vector<std::string> iniphile::valpath; valpath to_valpath(std::string const & path); typedef unspecified iniphile::ast::node;
ast.hpp
#include "astfwd.hpp" iniphile::ast::node iniphile::normalize(iniphile::config const & cst);
output.hpp
template<class T> T iniphile::get( iniphile::ast::node const& cfg , iniphile::valpath const& path , T dflt ); template<class T> T iniphile::get( iniphile::ast::node const& cfg , std::string const& path , T dflt );
The library defines these specializations:
std::vector<std::string>
One optvalpart per std::string. DQUOTEs from qstrings are not maintained.
std::string
The whole optval with whitespace between optvalparts normalized to single spaces. DQUOTEs from qstrings are maintained.
bool
The first optvalpart interpreted as a bool according to these rules:
true <= "1" / "true" / "yes" / "on" ; case insensitive false <= "0" / "false" / "no" / "off" ; case insensitive
long
The first optvalpart interpreted as a long using the boost::spirit::qi::long_ [7] parser (decimal representation with optional leading sign).
double
The first optvalpart interpreted as a double using the boost::spirit::qi::double_ [7] parser (decimal representation of ints and doubles, scientific representation (nnn.fff.Eeee) of doubles.
Git [8] repository: http://github.com/roman-neuhauser/iniphile
Packages [9] for several GNU/Linux distributions are in the openSUSE Build Service [10].
Iniphile is distributed with a set of Makefiles suitable for several environments. Currently supported are: GNU make with the GNU C++ compiler, MSVC nmake with the Microsoft compiler.
Let $make be your make command, and let $env be gnu or msvc as appropriate. Then
$make -f $env.mk libs
(requires Boost.Spirit [4])- creates a static library and a dll plus import library
$make -f $env.mk check
(requires Boost.Test [5])- creates the libraries and runs their unit tests
Main variables and their default values:
- CXX:
g++$(GCCVER)
- GCCVER:
<empty>
- PREFIX:
/usr/local
- LIBDIR:
$(PREFIX)/lib
- INCDIR:
$(PREFIX)/include
- PKGCONFIGDIR:
$(LIBDIR)/pkgconfig
- _BOOST:
$(PREFIX)
- SPIRIT:
$(_BOOST)/include
- UTFINC:
$(_BOOST)/include
- UTFLIB:
$(_BOOST)/lib
- UTFRUN:
$(UTFLIB)
gmake -f gnu.mk <targets-and-variables>
pkg-config files are stored in a nonstandard path on this system. If you install into /usr/local, make sure to do so with PKGCONFIGDIR=/usr/local/libdata/pkgconfig.
make -f gnu.mk <targets-and-variables>
gnu.mk assumes the GNU gcc suite.
Main variables and their default values:
- PREFIX:
.\stage
- INCDIR
$(PREFIX)\include
- LIBDIR
$(PREFIX)\lib
- BOOST_INCDIR:
<empty>
- BOOST_LIBDIR:
<empty>
msvc.mk assumes and relies on tools provided with MS Visual C++ Express exclusively. It's tested on Windows Vista and 7 with VC++ 2008/9.0 Express, and works in the Visual Studio Command Prompt and the Windows SDK CMD Shell.
nmake -f msvc.mk <targets-and-variables>
No attempt to guess or find the Boost prerequisities is made, you must supply BOOST_INCDIR and BOOST_LIBDIR or the compilation will fail.
nmake -f msvc.mk install
puts built libraries in $(LIBDIR)
(defaults to $(PREFIX)\lib
) and header files in $(INCDIR)
(defaults to $(PREFIX)\include
).
[1] | (1, 2) http://boost.org/ |
[2] | http://www.boost.org/doc/libs/1_42_0/libs/optional/index.html |
[3] | http://www.boost.org/doc/libs/1_42_0/libs/variant/index.html |
[4] | (1, 2) http://www.boost.org/doc/libs/1_42_0/libs/spirit/index.html |
[5] | (1, 2) http://www.boost.org/doc/libs/1_42_0/libs/test/index.html |
[6] | http://tools.ietf.org/html/std68 |
[7] | (1, 2) http://www.boost.org/doc/libs/1_41_0/libs/spirit/doc/html/spirit/qi/reference/numeric.html |
[8] | http://git-scm.org/ |
[9] | http://software.opensuse.org/download.html?project=home:roman-neuhauser&package=iniphile |
[10] | https://build.opensuse.org/ |