1 // File:    testsi.cpp
2 // Library: SimpleIni
3 // Author:  Brodie Thiesfield <code@jellycan.com>
4 // Source:  http://code.jellycan.com/simpleini/
5 //
6 // Demo of usage
7 
8 #ifdef _WIN32
9 # pragma warning(disable: 4786)
10 #endif
11 
12 #include <locale.h>
13 #include <stdio.h>
14 #include <cassert>
15 
16 #define SI_SUPPORT_IOSTREAMS
17 #if defined(SI_SUPPORT_IOSTREAMS) && !defined(_UNICODE)
18 # include <fstream>
19 #endif
20 
21 //#define SI_CONVERT_GENERIC
22 //#define SI_CONVERT_ICU
23 //#define SI_CONVERT_WIN32
24 #include "SimpleIni.h"
25 
26 #ifdef SI_CONVERT_ICU
27 // if converting using ICU then we need the ICU library
28 # pragma comment(lib, "icuuc.lib")
29 #endif
30 
31 #ifdef _WIN32
32 # include <tchar.h>
33 #else // !_WIN32
34 # define TCHAR      char
35 # define _T(x)      x
36 # define _tprintf   printf
37 # define _tmain     main
38 #endif // _WIN32
39 
40 static void
Test(CSimpleIni & ini)41 Test(
42     CSimpleIni &    ini
43     )
44 {
45     const TCHAR *pszSection = 0;
46     const TCHAR *pItem = 0;
47     const TCHAR *pszVal = 0;
48 
49     // get the value of the key "foo" in section "standard"
50     bool bHasMulti;
51     pszVal = ini.GetValue(_T("standard"), _T("foo"), 0, &bHasMulti);
52     _tprintf(_T("\n-- Value of standard::foo is '%s' (hasMulti = %d)\n"),
53         pszVal ? pszVal : _T("(null)"), bHasMulti);
54 
55     // set the value of the key "foo" in section "standard"
56     ini.SetValue(_T("standard"), _T("foo"), _T("wibble"));
57     pszVal = ini.GetValue(_T("standard"), _T("foo"), 0, &bHasMulti);
58     _tprintf(_T("\n-- Value of standard::foo is '%s' (hasMulti = %d)\n"),
59         pszVal ? pszVal : _T("(null)"), bHasMulti);
60 
61     // get all values of the key "foo" in section "standard"
62     CSimpleIni::TNamesDepend values;
63     if (ini.GetAllValues(_T("standard"), _T("foo"), values)) {
64         _tprintf(_T("\n-- Values of standard::foo are:\n"));
65         CSimpleIni::TNamesDepend::const_iterator i = values.begin();
66         for (; i != values.end(); ++i) {
67             pszVal = i->pItem;
68             _tprintf(_T("   -> '%s'\n"), pszVal);
69         }
70     }
71 
72     // get the size of the section [standard]
73     _tprintf(_T("\n-- Number of keys in section [standard] = %d\n"),
74         ini.GetSectionSize(_T("standard")));
75 
76     // delete the key "foo" in section "standard", if it has value "bar"
77     ini.DeleteValue(_T("standard"), _T("foo"), _T("bar"));
78     pszVal = ini.GetValue(_T("standard"), _T("foo"), 0);
79     _tprintf(_T("\n-- Value of standard::foo is now '%s'\n"),
80         pszVal ? pszVal : _T("(null)"));
81 
82     // delete the key "foo" in section "standard"
83     ini.Delete(_T("standard"), _T("foo"));
84     pszVal = ini.GetValue(_T("standard"), _T("foo"), 0);
85     _tprintf(_T("\n-- Value of standard::foo is now '%s'\n"),
86         pszVal ? pszVal : _T("(null)"));
87 
88     // get the size of the section [standard]
89     _tprintf(_T("\n-- Number of keys in section [standard] = %d\n"),
90         ini.GetSectionSize(_T("standard")));
91 
92     // get the list of all key names for the section "standard"
93     _tprintf(_T("\n-- Dumping keys of section: [standard]\n"));
94     CSimpleIni::TNamesDepend keys;
95     ini.GetAllKeys(_T("standard"), keys);
96 
97     // dump all of the key names
98     CSimpleIni::TNamesDepend::const_iterator iKey = keys.begin();
99     for ( ; iKey != keys.end(); ++iKey ) {
100         pItem = iKey->pItem;
101         _tprintf(_T("Key: %s\n"), pItem);
102     }
103 
104     // add a decimal value
105     ini.SetLongValue(_T("integer"), _T("dec"), 42, NULL, false);
106     ini.SetLongValue(_T("integer"), _T("hex"), 42, NULL, true);
107 
108     // add some bool values
109     ini.SetBoolValue(_T("bool"), _T("t"), true);
110     ini.SetBoolValue(_T("bool"), _T("f"), false);
111 
112     // get the values back
113     assert(42 == ini.GetLongValue(_T("integer"), _T("dec")));
114     assert(42 == ini.GetLongValue(_T("integer"), _T("hex")));
115     assert(true  == ini.GetBoolValue(_T("bool"), _T("t")));
116     assert(false == ini.GetBoolValue(_T("bool"), _T("f")));
117 
118     // delete the section "standard"
119     ini.Delete(_T("standard"), NULL);
120     _tprintf(_T("\n-- Number of keys in section [standard] = %d\n"),
121         ini.GetSectionSize(_T("standard")));
122 
123     // iterate through every section in the file
124     _tprintf(_T("\n-- Dumping all sections\n"));
125     CSimpleIni::TNamesDepend sections;
126     ini.GetAllSections(sections);
127     CSimpleIni::TNamesDepend::const_iterator iSection = sections.begin();
128     for ( ; iSection != sections.end(); ++iSection ) {
129         pszSection = iSection->pItem;
130 
131         // print the section name
132         printf("\n");
133         if (*pszSection) {
134             _tprintf(_T("[%s]\n"), pszSection);
135         }
136 
137         // if there are keys and values...
138         const CSimpleIni::TKeyVal * pSectionData = ini.GetSection(pszSection);
139         if (pSectionData) {
140             // iterate over all keys and dump the key name and value
141             CSimpleIni::TKeyVal::const_iterator iKeyVal = pSectionData->begin();
142             for ( ;iKeyVal != pSectionData->end(); ++iKeyVal) {
143                 pItem = iKeyVal->first.pItem;
144                 pszVal = iKeyVal->second;
145                 _tprintf(_T("%s=%s\n"), pItem, pszVal);
146             }
147         }
148     }
149 }
150 
151 #if defined(SI_SUPPORT_IOSTREAMS) && !defined(_UNICODE)
152 static bool
TestStreams(const TCHAR * a_pszFile,bool a_bIsUtf8,bool a_bUseMultiKey,bool a_bUseMultiLine)153 TestStreams(
154     const TCHAR *   a_pszFile,
155     bool            a_bIsUtf8,
156     bool            a_bUseMultiKey,
157     bool            a_bUseMultiLine
158     )
159 {
160     // load the file
161     CSimpleIni ini(a_bIsUtf8, a_bUseMultiKey, a_bUseMultiLine);
162     _tprintf(_T("Loading file: %s\n"), a_pszFile);
163     std::ifstream instream;
164     instream.open(a_pszFile, std::ifstream::in | std::ifstream::binary);
165     SI_Error rc = ini.LoadData(instream);
166     instream.close();
167     if (rc < 0) {
168         printf("Failed to open file.\n");
169         return false;
170     }
171 
172     Test(ini);
173 
174     // save the file (simple)
175     _tprintf(_T("\n-- Saving file to: testsi-out-streams.ini\n"));
176     std::ofstream outstream;
177     outstream.open("testsi-out-streams.ini", std::ofstream::out | std::ofstream::binary);
178     ini.Save(outstream);
179     outstream.close();
180 
181     return true;
182 }
183 #endif // SI_SUPPORT_IOSTREAMS
184 
185 static bool
TestFile(const TCHAR * a_pszFile,bool a_bIsUtf8,bool a_bUseMultiKey,bool a_bUseMultiLine)186 TestFile(
187     const TCHAR *   a_pszFile,
188     bool            a_bIsUtf8,
189     bool            a_bUseMultiKey,
190     bool            a_bUseMultiLine
191     )
192 {
193     // load the file
194     CSimpleIni ini(a_bIsUtf8, a_bUseMultiKey, a_bUseMultiLine);
195     _tprintf(_T("Loading file: %s\n"), a_pszFile);
196     SI_Error rc = ini.LoadFile(a_pszFile);
197     if (rc < 0) {
198         printf("Failed to open file.\n");
199         return false;
200     }
201 
202     // run the tests
203     Test(ini);
204 
205     // save the file (simple)
206     _tprintf(_T("\n-- Saving file to: testsi-out.ini\n"));
207     ini.SaveFile("testsi-out.ini");
208 
209     // save the file (with comments)
210     // Note: to save the file and add a comment to the beginning, use
211     // code such as the following.
212     _tprintf(_T("\n-- Saving file to: testsi-out-comment.ini\n"));
213 	FILE * fp = NULL;
214 #if __STDC_WANT_SECURE_LIB__
215 	fopen_s(&fp, "testsi-out-comment.ini", "wb");
216 #else
217 	fp = fopen("testsi-out-comment.ini", "wb");
218 #endif
219     if (fp) {
220         CSimpleIni::FileWriter writer(fp);
221         if (a_bIsUtf8) {
222             writer.Write(SI_UTF8_SIGNATURE);
223         }
224 
225         // add a string to the file in the correct text format
226         CSimpleIni::Converter convert = ini.GetConverter();
227         convert.ConvertToStore(_T("; output from testsi.cpp test program")
228             SI_NEWLINE SI_NEWLINE);
229         writer.Write(convert.Data());
230 
231         ini.Save(writer, false);
232         fclose(fp);
233     }
234 
235     return true;
236 }
237 
238 static bool
ParseCommandLine(int argc,TCHAR * argv[],const TCHAR * & a_pszFile,bool & a_bIsUtf8,bool & a_bUseMultiKey,bool & a_bUseMultiLine)239 ParseCommandLine(
240     int                 argc,
241     TCHAR *             argv[],
242     const TCHAR * &     a_pszFile,
243     bool &              a_bIsUtf8,
244     bool &              a_bUseMultiKey,
245     bool &              a_bUseMultiLine
246     )
247 {
248     a_pszFile = 0;
249     a_bIsUtf8 = false;
250     a_bUseMultiKey = false;
251     a_bUseMultiLine = false;
252     for (--argc; argc > 0; --argc) {
253         if (argv[argc][0] == '-') {
254             switch (argv[argc][1]) {
255             case TCHAR('u'):
256                 a_bIsUtf8 = true;
257                 break;
258             case TCHAR('m'):
259                 a_bUseMultiKey = true;
260                 break;
261             case TCHAR('l'):
262                 a_bUseMultiLine = true;
263                 break;
264             }
265         }
266         else {
267             a_pszFile = argv[argc];
268         }
269     }
270     if (!a_pszFile) {
271         _tprintf(
272             _T("Usage: testsi [-u] [-m] [-l] iniFile\n")
273             _T("   -u  Load file as UTF-8 (Default is to use system locale)\n")
274             _T("   -m  Enable multiple keys\n")
275             _T("   -l  Enable multiple line values\n")
276             );
277         return false;
278     }
279 
280     return true;
281 }
282 
283 extern bool TestStreams();
284 
285 int
_tmain(int argc,TCHAR * argv[])286 _tmain(
287     int     argc,
288     TCHAR * argv[]
289     )
290 {
291     setlocale(LC_ALL, "");
292 
293     // start of automated testing...
294     TestStreams();
295 
296     // parse the command line
297     const TCHAR * pszFile;
298     bool bIsUtf8, bUseMultiKey, bUseMultiLine;
299     if (!ParseCommandLine(argc, argv, pszFile, bIsUtf8, bUseMultiKey, bUseMultiLine)) {
300         return 1;
301     }
302 
303     // run the test
304     if (!TestFile(pszFile, bIsUtf8, bUseMultiKey, bUseMultiLine)) {
305         return 1;
306     }
307 #if defined(SI_SUPPORT_IOSTREAMS) && !defined(_UNICODE)
308     if (!TestStreams(pszFile, bIsUtf8, bUseMultiKey, bUseMultiLine)) {
309         return 1;
310     }
311 #endif
312 
313     return 0;
314 }
315 
316