INI File Parsing

index Local: minini inih fip sources

Preamble

20130123: Recently had the need to explore INI file parsing, so started to look around for potential open sources.

MinINI

The first explorerd was minINI http://www.compuphase.com/minini.htm. License is a modified Apache License Version 2.0, January 2004. First was to download the SVN source to c:\Projects\minini, with a batch file -

<updminini.bat>
@setlocal
@set TMPREPO=http://minini.googlecode.com/svn/trunk/
@set TMPDIR=minini
@if EXIST %TMPDIR%\nul goto UPDATE
svn co %TMPREPO% %TMPDIR%
@goto END
:UPDATE
cd %TMPDIRA%
svn up
:END
  

As is usual these days next was to create a single root CMakeLists.txt file to build the static minini.lib, and two test applications. The version is listed as 1.2.b, circa 4 Dec 2012, which I made 1.2.2 in the CMakeLists.txt file. Created a new directory, build, and proceeded to build it, with a simple build-me.bat. Needed one small change in the source to compile in Windows 7, using MSVC10, and that was to change #include <assert>, to #include <assert.h>. Also made macros for each of the test INI files names, so these could be fed in through the CMakeLists.txt

INI file syntax - as defined by minini API documentation

INI files have a simple syntax with name/value pairs in a plain text file. The name must be unique (per section) and the value must fit on a single line. INI files are commonly separated into sections —in minIni, this is optional. A section is a name between square brackets, like "[Network]" in the example below.

[Network]
hostname=My Computer
address=dhcp
dns = 192.168.1.1

In the API and in this documentation, the "name" for a setting is denoted as the key for the setting. The key and the value are separated by an equal sign ("="). minIni supports the colon (":") as an alternative to the equal sign for the key/value delimiter.

Leading a trailing spaces around values or key names are removed. If you need to include leading and/or trailing spaces in a value, put the value between double quotes. The ini_gets() function (from the minIni library, see the minIni manual) strips off the double quotes from the returned value. Function ini_puts() adds double quotes if the value to write contains trailing white space (or special characters).

minIni ignores spaces around the "=" or ":" delimiters, but it does not ignore spaces between the brackets in a section name. In other words, it is best not to put spaces behind the opening bracket "[" or before the closing bracket "]" of a section name.

Comments in the INI must start with a semicolon (";") or a hash character ("#"), and run to the end of the line. A comment can be a line of its own, or it may follow a key/value pair (the "#" character and trailing comments are extensions of minIni).

Summary

It has several configurable IO options at compile time. The INI file is NOT cached, and uses some simple functions to get values of various types, as shown in the following extract from the library header. I was ONLY interested in 'reading' so omit the write functions

int   ini_getbool(const mTCHAR *Section, const mTCHAR *Key, int DefValue, const mTCHAR *Filename);
long  ini_getl(const mTCHAR *Section, const mTCHAR *Key, long DefValue, const mTCHAR *Filename);
int   ini_gets(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *DefValue, mTCHAR *Buffer,
               int BufferSize, const mTCHAR *Filename);
int   ini_getsection(int idx, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename);
int   ini_getkey(const mTCHAR *Section, int idx, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename);

some care should be taken about some default configuration values

#if !defined INI_BUFFERSIZE
  #define INI_BUFFERSIZE  512   // this would limit the maximum line size
#endif

Conclusion:

All looks and seems to work fine, but not exactly what I was looking for...

top

inih

Then inih (Ini Not Invented Here) https://code.google.com/p/inih/ Again a batch file to download the source to c:/FG/17/inih. Code license is New BSD.

<updinih.bat<
@setlocal
@set TMPREPO=http://inih.googlecode.com/svn/trunk/
@set TMPDIR=inih
@if EXIST %TMPDIR%\nul goto UPDATE
svn co %TMPREPO% %TMPDIR%
@goto END
:UPDATE
cd %TMPDIRA%
svn up
:END

After creating a single root CMakeLists.txt, and creating a build directory, compiled 2 static libraries, and 5 test applications.

This library uses a callback technique for an application to get INI information. As defined in the library header

/* Parse given INI-style file. May have [section]s, name=value pairs
   (whitespace stripped), and comments starting with ';' (semicolon). Section
   is "" if name=value pair parsed before any section heading. name:value
   pairs are also supported as a concession to Python's ConfigParser.

   For each name=value pair parsed, call handler function with given user
   pointer as well as section, name, and value (data only valid for duration
   of handler call). Handler should return nonzero on success, zero on error.

   Returns 0 on success, line number of first error on parse error (doesn't
   stop on first error), -1 on file open error, or -2 on memory allocation
   error (only when INI_USE_STACK is zero).
*/
int ini_parse(const char* filename,
              int (*handler)(void* user, const char* section,
                             const char* name, const char* value),
              void* user);

Conclusion:

Again all tests seemed to work fine, but this is also NOT what I am looking for...

top

FIP

Finally tried feather-ini-parser, FIP, from https://code.google.com/p/feather-ini-parser/ Code license GNU GPL v2. There is no 'repository' since the download is a single header file.

It is implemented as templates, so remains very flexible. At this stage I made two minor changes. It assumed 'comment' begin with the inline C/C++ pair, '//', so I added the hash character, '#', and the original read-in buffer size was a mean 32 bytes, which I bumped to 264

A simple implmentation would be

INI<> ini(filename,false);
if (ini.Parse()) {
    if (ini.Select(section)) { // make the [section] current, if it exists
       std::string s = ini.Get<std::string,std::string>(name,def);
       int val = ini.Get<std::string,int>(name,idef);
    }
  

To test it further I wrote a simple testINI app, to either read in a known 'test.ini' and test sections, keys and values, or if given a path to a user INI file, enumerate the files contents.

Conclusion:

This is exactly the 'simple' C++ implementation I was looking for... it parses the whole file into memory, mapping each section with key=value pairs.

top

Sources

Some downloads: TAKE CARE running EXECUTABLES from the web.

Date Link Size MD5
2013/01/23 minini-01.zip 201,721 b6a53290418f770e99f2bdde855624e4
2013/01/23 inih-01.zip 14,890 5614092e35e44906ef47d2339bdd5011
2013/01/23 inif-01.zip 8,198 c8ba5b3caaaf7a7f35f42827b9c0a8cf

The above is the full sources I used, including the added CMakeLists.txt files, and the build folders, each containing a build-me.bat. I like things to be EASY ;=))

top

Valid XHTML 1.0 Strict checked by Tidy