Moved examples to their own examples/ dir.
Only define INI_ALLOW_MULTILINE if it's not already defined.
Added C++ INIReader class.
Moved license into LICENSE.txt, added README.txt.
Added unit tests and checked in baseline files.
Made line lengths < 80 chars.
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..1d31de2
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,27 @@
+
+The "inih" library is distributed under the New BSD license:
+
+Copyright (c) 2009, Brush Technology
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of Brush Technology nor the names of its contributors
+      may be used to endorse or promote products derived from this software
+      without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY BRUSH TECHNOLOGY ''AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL BRUSH TECHNOLOGY BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..8e5f8b1
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,5 @@
+
+inih is a simple .INI file parser written in C, released under the New BSD
+license (see LICENSE.txt). Go to the project home page for more info:
+
+http://code.google.com/p/inih/
diff --git a/cpp/INIReader.cpp b/cpp/INIReader.cpp
new file mode 100644
index 0000000..7b71344
--- /dev/null
+++ b/cpp/INIReader.cpp
@@ -0,0 +1,49 @@
+// Read an INI file into easy-to-access name/value pairs.
+
+#include <cctype>
+#include "../ini.h"
+#include "INIReader.h"
+
+using std::string;
+
+INIReader::INIReader(string filename)
+{
+    _error = ini_parse(filename.c_str(), ValueHandler, this);
+}
+
+int INIReader::ParseError()
+{
+    return _error;
+}
+
+string INIReader::Get(string section, string name, string default_value)
+{
+    string key = MakeKey(section, name);
+    return _values.count(key) ? _values[key] : default_value;
+}
+
+long INIReader::GetInteger(string section, string name, long default_value)
+{
+    const char* value = Get(section, name, "").c_str();
+    char* end;
+    // This parses "1234" (decimal) and also "0x4D2" (hex)
+    long n = strtol(value, &end, 0);
+    return end > value ? n : default_value;
+}
+
+string INIReader::MakeKey(string section, string name)
+{
+    string key = section + "." + name;
+    // Convert to lower case to make lookups case-insensitive
+    for (int i = 0; i < key.length(); i++)
+        key[i] = tolower(key[i]);
+    return key;
+}
+
+int INIReader::ValueHandler(void* user, const char* section, const char* name,
+                            const char* value)
+{
+    INIReader* reader = (INIReader*)user;
+    reader->_values[MakeKey(section, name)] = value;
+    return 1;
+}
diff --git a/cpp/INIReader.h b/cpp/INIReader.h
new file mode 100644
index 0000000..d4acb65
--- /dev/null
+++ b/cpp/INIReader.h
@@ -0,0 +1,43 @@
+// Read an INI file into easy-to-access name/value pairs.
+
+// inih and INIReader are released under the New BSD license (see LICENSE.txt).
+// Go to the project home page for more info:
+//
+// http://code.google.com/p/inih/
+
+#ifndef __INIREADER_H__
+#define __INIREADER_H__
+
+#include <map>
+#include <string>
+
+// Read an INI file into easy-to-access name/value pairs. (Note that I've gone
+// for simplicity here rather than speed, but it should be pretty decent.)
+class INIReader
+{
+public:
+    // Construct INIReader and parse given filename. See ini.h for more info
+    // about the parsing.
+    INIReader(std::string filename);
+
+    // Return the result of ini_parse(), i.e., 0 on success, line number of
+    // first error on parse error, or -1 on file open error.
+    int ParseError();
+
+    // Get a string value from INI file, returning default_value if not found.
+    std::string Get(std::string section, std::string name,
+                    std::string default_value);
+
+    // Get an integer (long) value from INI file, returning default_value if
+    // not found.
+    long GetInteger(std::string section, std::string name, long default_value);
+
+private:
+    int _error;
+    std::map<std::string, std::string> _values;
+    static std::string MakeKey(std::string section, std::string name);
+    static int ValueHandler(void* user, const char* section, const char* name,
+                            const char* value);
+};
+
+#endif  // __INIREADER_H__
diff --git a/cpp/INIReaderTest.cpp b/cpp/INIReaderTest.cpp
new file mode 100644
index 0000000..d0dc0af
--- /dev/null
+++ b/cpp/INIReaderTest.cpp
@@ -0,0 +1,25 @@
+// INIReader.h example that shows simple usage of the INIReader class
+
+#include <iostream>
+#include "INIReader.h"
+
+using std::cout;
+
+int main()
+{
+    INIReader reader("../examples/test.ini");
+
+    if (reader.ParseError() < 0) {
+        cout << "Couldn't read INI file!\n";
+        return 1;
+    }
+
+    cout << "Valid config:";
+    cout << " user_name='" << reader.Get("user", "name", "UNKNOWN") << "'";
+    cout << " user_email='" << reader.Get("user", "email", "UNKNOWN") << "'";
+    cout << " protocol_version="
+         << reader.GetInteger("protocol", "version", -1);
+    cout << "\n";
+
+    return 0;
+}
diff --git a/ini_dump.c b/examples/ini_dump.c
similarity index 86%
rename from ini_dump.c
rename to examples/ini_dump.c
index 9c651a0..87253ee 100644
--- a/ini_dump.c
+++ b/examples/ini_dump.c
@@ -1,10 +1,11 @@
-/* ini.h example that simply dumps an INI file without comments. */
+/* ini.h example that simply dumps an INI file without comments */
 
 #include <stdio.h>
 #include <string.h>
-#include "ini.h"
+#include "../ini.h"
 
-static int dumper(void* user, const char* section, const char* name, const char* value)
+static int dumper(void* user, const char* section, const char* name,
+                  const char* value)
 {
     static char prev_section[50] = "";
 
diff --git a/ini_example.c b/examples/ini_example.c
similarity index 93%
rename from ini_example.c
rename to examples/ini_example.c
index 89eb553..6624750 100644
--- a/ini_example.c
+++ b/examples/ini_example.c
@@ -2,7 +2,7 @@
 
 #include <stdio.h>
 #include <string.h>
-#include "ini.h"
+#include "../ini.h"
 
 typedef struct
 {
@@ -11,7 +11,8 @@
     const char* email;
 } configuration;
 
-static int handler(void* user, const char* section, const char* name, const char* value)
+static int handler(void* user, const char* section, const char* name,
+                   const char* value)
 {
     configuration* pconfig = (configuration*)user;
 
diff --git a/test.ini b/examples/test.ini
similarity index 100%
rename from test.ini
rename to examples/test.ini
diff --git a/ini.c b/ini.c
index 5f775e7..d166009 100644
--- a/ini.c
+++ b/ini.c
@@ -1,6 +1,11 @@
-/* inih -- simple .INI file parser */
+/* inih -- simple .INI file parser
 
-/* Copyright (c) 2009, Brush Technology -- New BSD license, see ini.h */
+inih is released under the New BSD license (see LICENSE.txt). Go to the project
+home page for more info:
+
+http://code.google.com/p/inih/
+
+*/
 
 #include <stdio.h>
 #include <ctype.h>
diff --git a/ini.h b/ini.h
index 495951e..d38f257 100644
--- a/ini.h
+++ b/ini.h
@@ -1,32 +1,9 @@
-/* inih -- simple .INI file parser */
+/* inih -- simple .INI file parser
 
-/*
-The "inih" library is distributed under the New BSD license:
+inih is released under the New BSD license (see LICENSE.txt). Go to the project
+home page for more info:
 
-Copyright (c) 2009, Brush Technology
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-    * Redistributions of source code must retain the above copyright
-      notice, this list of conditions and the following disclaimer.
-    * Redistributions in binary form must reproduce the above copyright
-      notice, this list of conditions and the following disclaimer in the
-      documentation and/or other materials provided with the distribution.
-    * Neither the name of Brush Technology nor the names of its contributors
-      may be used to endorse or promote products derived from this software
-      without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY BRUSH TECHNOLOGY ''AS IS'' AND ANY
-EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL BRUSH TECHNOLOGY BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+http://code.google.com/p/inih/
 
 */
 
@@ -52,6 +29,8 @@
 /* Nonzero to allow multi-line value parsing, in the style of Python's
    ConfigParser. If allowed, ini_parse() will call the handler with the same
    name for each subsequent line parsed. */
+#ifndef INI_ALLOW_MULTILINE
 #define INI_ALLOW_MULTILINE 1
+#endif
 
 #endif /* __INI_H__ */
diff --git a/tests/bad_comment.ini b/tests/bad_comment.ini
new file mode 100644
index 0000000..7f4602e
--- /dev/null
+++ b/tests/bad_comment.ini
@@ -0,0 +1 @@
+This is an error

diff --git a/tests/bad_multi.ini b/tests/bad_multi.ini
new file mode 100644
index 0000000..6550175
--- /dev/null
+++ b/tests/bad_multi.ini
@@ -0,0 +1 @@
+  indented

diff --git a/tests/bad_section.ini b/tests/bad_section.ini
new file mode 100644
index 0000000..90e31ac
--- /dev/null
+++ b/tests/bad_section.ini
@@ -0,0 +1,5 @@
+[section1]

+name1=value1

+[section2

+[section3   ; comment ]

+name2=value2

diff --git a/tests/baseline_multi.txt b/tests/baseline_multi.txt
new file mode 100644
index 0000000..50cf410
--- /dev/null
+++ b/tests/baseline_multi.txt
@@ -0,0 +1,29 @@
+no_file.ini: e=-1 user=0
+... [section1]
+... one=This is a test;
+... two=1234;
+... [ section 2 ]
+... happy=4;
+... sad=;
+normal.ini: e=0 user=101
+... [section1]
+... name1=value1;
+... name2=value2;
+bad_section.ini: e=3 user=102
+bad_comment.ini: e=1 user=102
+... [section]
+... a=b;
+... user=parse_error;
+... c=d;
+user_error.ini: e=3 user=104
+... [section1]
+... single1=abc;
+... multi=this is a;
+... multi=multi-line value;
+... single2=xyz;
+... [section2]
+... multi=a;
+... multi=b;
+... multi=c;
+multi_line.ini: e=0 user=105
+bad_multi.ini: e=1 user=105
diff --git a/tests/baseline_single.txt b/tests/baseline_single.txt
new file mode 100644
index 0000000..75112ba
--- /dev/null
+++ b/tests/baseline_single.txt
@@ -0,0 +1,26 @@
+no_file.ini: e=-1 user=0
+... [section1]
+... one=This is a test;
+... two=1234;
+... [ section 2 ]
+... happy=4;
+... sad=;
+normal.ini: e=0 user=101
+... [section1]
+... name1=value1;
+... name2=value2;
+bad_section.ini: e=3 user=102
+bad_comment.ini: e=1 user=102
+... [section]
+... a=b;
+... user=parse_error;
+... c=d;
+user_error.ini: e=3 user=104
+... [section1]
+... single1=abc;
+... multi=this is a;
+... single2=xyz;
+... [section2]
+... multi=a;
+multi_line.ini: e=4 user=105
+bad_multi.ini: e=1 user=105
diff --git a/tests/multi_line.ini b/tests/multi_line.ini
new file mode 100644
index 0000000..4f75ed4
--- /dev/null
+++ b/tests/multi_line.ini
@@ -0,0 +1,9 @@
+[section1]

+single1 = abc

+multi = this is a

+        multi-line value

+single2 = xyz

+[section2]

+multi = a

+        b

+        c

diff --git a/tests/normal.ini b/tests/normal.ini
new file mode 100644
index 0000000..2a64258
--- /dev/null
+++ b/tests/normal.ini
@@ -0,0 +1,12 @@
+; This is an INI file

+[section1]  ; section comment

+one=This is a test  ; name=value comment

+two = 1234

+; x=y

+

+[ section 2 ]

+happy  =  4

+sad =

+

+[empty]

+; do nothing

diff --git a/tests/unittest.c b/tests/unittest.c
new file mode 100644
index 0000000..6d5d4ee
--- /dev/null
+++ b/tests/unittest.c
@@ -0,0 +1,57 @@
+/* inih -- unit tests
+
+This works simply by dumping a bunch of info to standard output, which is
+redirected to an output file (baseline_*.txt) and checked into the Subversion
+repository. This baseline file is the test output, so the idea is to check it
+once, and if it changes -- look at the diff and see which tests failed.
+
+Here's how I produced the two baseline files (with Tiny C Compiler):
+
+tcc -DINI_ALLOW_MULTILINE=1 ../ini.c -run unittest.c > baseline_multi.txt
+tcc -DINI_ALLOW_MULTILINE=0 ../ini.c -run unittest.c > baseline_single.txt
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "../ini.h"
+
+int User;
+char Prev_section[50];
+
+int dumper(void* user, const char* section, const char* name,
+           const char* value)
+{
+    User = (int)user;
+    if (strcmp(section, Prev_section)) {
+        printf("... [%s]\n", section);
+        strncpy(Prev_section, section, sizeof(Prev_section));
+        Prev_section[sizeof(Prev_section) - 1] = '\0';
+    }
+    printf("... %s=%s;\n", name, value);
+
+    return strcmp(name, "user")==0 && strcmp(value, "parse_error")==0 ? 0 : 1;
+}
+
+void parse(const char* fname) {
+    static int u = 100;
+    int e;
+
+    *Prev_section = '\0';
+    e = ini_parse(fname, dumper, (void*)u);
+    printf("%s: e=%d user=%d\n", fname, e, User);
+    u++;
+}
+
+int main(void)
+{
+    parse("no_file.ini");
+    parse("normal.ini");
+    parse("bad_section.ini");
+    parse("bad_comment.ini");
+    parse("user_error.ini");
+    parse("multi_line.ini");
+    parse("bad_multi.ini");
+    return 0;
+}
diff --git a/tests/user_error.ini b/tests/user_error.ini
new file mode 100644
index 0000000..9798af3
--- /dev/null
+++ b/tests/user_error.ini
@@ -0,0 +1,4 @@
+[section]

+a = b

+user = parse_error

+c = d