| 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
Main variables and their default values:
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:
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/ |