static void IniTest() { IniFile pNull((const char *)NULL); assert(pNull.sections.Count() == 0); IniFile pEmpty(""); assert(pEmpty.sections.Count() == 1 && !pEmpty.sections.At(0)->name); assert(pEmpty.FindSection(NULL)->lines.Count() == 0); IniFile pNoNL1("key = value"); assert(str::Eq(pNoNL1.sections.At(0)->lines.At(0).value, "value")); IniFile pNoNL2("[Section ]"); assert(pNoNL2.FindSection("Section ")); static const char *iniData = "\ ; NULL section \n\ key1=value1\n\ [Section 1]\n\ key2 = value2 \n\ # comment \n\ key3: \"quoted value\" \n\n\ [ Empty Section ]\n\n\ ]Section 2 \n\ key without separator\n\ "; IniLine verify[] = { IniLine(NULL, NULL), IniLine("key1", "value1"), IniLine("Section 1", NULL), IniLine("Key2", "value2"), IniLine("key3", "\"quoted value\""), IniLine(" Empty Section ", NULL), IniLine("Section 2", NULL), IniLine("key", "without separator"), }; IniFile p(iniData); size_t idxSec = (size_t)-1, idxLine = (size_t)-1; for (int i = 0; i < dimof(verify); i++) { if (!verify[i].value) { if (idxSec != (size_t)-1) { assert(p.sections.At(idxSec)->lines.Count() == idxLine); } idxSec++; idxLine = 0; assert(p.FindSection(verify[i].key) == p.sections.At(idxSec)); continue; } assert(idxSec < p.sections.Count() && idxLine < p.sections.At(idxSec)->lines.Count()); IniLine *line = p.sections.At(idxSec)->FindLine(verify[i].key); assert(line && str::EqI(line->key, verify[i].key) && str::Eq(line->value, verify[i].value)); idxLine++; } assert(p.sections.Count() == idxSec + 1 && p.sections.Last()->lines.Count() == idxLine); assert(p.FindSection("Section 1", 1) && p.FindSection("Section 2", 2)); assert(!p.FindSection("missing") && !p.FindSection("Section 1", 2)); assert(!p.FindSection("Section 1")->FindLine("missing")); }
// process a single INI file static int IniFProc(LPTSTR fname, INIFILE *InitData, unsigned int fIgnoreSection) { LPTSTR arg; unsigned int line_num, SecFound = 0, CurrentSec = 0; int fh, nReturn = 0; TCHAR szBuffer[2048]; LPTSTR errmsg; if ( ++nNestLevel > MAX_INI_NEST ) { ini_error( E_NEST, InitData, fname, 1, NULLSTR ); nReturn = -1; goto IFProcExit; } // force ignore of sections that aren't ours fIgnoreSection |= 0x100; // open the INI file if ((fh = _sopen(fname, (O_RDONLY | O_BINARY), SH_DENYWR)) < 0) { nReturn = -1; goto IFProcExit; } // loop to process each line for ( line_num = 1; ( getline( fh, szBuffer, 2047, 0 ) > 0 ); line_num++ ) { // skip line if empty or all comment arg = skipspace( szBuffer ); if ((*arg == _TEXT('\0')) || (*arg == _TEXT(';'))) continue; // query if it was requested if ( InitData->INIQuery != 0 ) { WriteTTY(szBuffer); WriteTTY(INI_QUERY); query_prompt: switch (GetKeystroke(EDIT_BIOS_KEY | EDIT_ECHO | EDIT_ECHO_CRLF | EDIT_UC_SHIFT)) { case YES_CHAR: break; case NO_CHAR: continue; case INI_QUIT_CHAR: goto ini_done; case REST_CHAR: InitData->INIQuery = 0; break; case INI_EDIT_CHAR: egets( szBuffer, 2047, EDIT_BIOS_KEY | EDIT_ECHO ); break; default: qputc( STDOUT, BS ); honk(); goto query_prompt; } } // process the line, holler if any error if ((nReturn = IniLine(szBuffer, InitData, (fIgnoreSection & CurrentSec), 0, &errmsg)) > 0) ini_error( errmsg, InitData, fname, line_num , szBuffer ); // if no error, see if we have an included file to process else if (nReturn == -1) { // call ourselves recursively to process the included file if ( is_file( szBuffer )) (void)IniFProc( szBuffer, InitData, fIgnoreSection); else ini_error( E_INCL, InitData, fname, line_num, szBuffer ); // if no error, see if we found a section name } else if (nReturn < 0) { CurrentSec = -nReturn; // save section bit if section is one of ours if (CurrentSec & 0xFF) SecFound |= CurrentSec; } } ini_done: InitData->SecFlag = SecFound; // save sections found _close(fh); nReturn = 0; IFProcExit: --nNestLevel; return nReturn; }