Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: Smart-WiFly-WebServer SignalGenerator WattEye X10Svr
IniManager.cpp
00001 // Simple INI file manager. 00002 // 00003 #ifdef WIN32 00004 #include "string.h" 00005 #include "stdlib.h" 00006 #include "stdio.h" 00007 #else 00008 #include "mbed.h" 00009 #endif 00010 00011 #include "IniManager.h" 00012 00013 //#include "Utility.h" // private memory manager 00014 #ifndef UTILITY_H 00015 #define swMalloc malloc // use the standard 00016 #define swFree free 00017 #endif 00018 00019 //#define DEBUG "INI " //Debug is disabled by default 00020 00021 #include <cstdio> 00022 #if (defined(DEBUG) && !defined(TARGET_LPC11U24)) 00023 #define DBG(x, ...) std::printf("[DBG %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); 00024 #define WARN(x, ...) std::printf("[WRN %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); 00025 #define ERR(x, ...) std::printf("[ERR %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); 00026 #define INFO(x, ...) std::printf("[INF %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); 00027 #else 00028 #define DBG(x, ...) 00029 #define WARN(x, ...) 00030 #define ERR(x, ...) 00031 #define INFO(x, ...) 00032 #endif 00033 00034 // 2 versions, to translate new return values to old format 00035 // return RetXLate[new value][version] 00036 INI::INI_Return RetXLate[INI::INI_INTERNAL_ERROR+1][2] = { 00037 // Ver1, Ver2 return values. 00038 INI::INI_V1_SUCCESS, INI::INI_SUCCESS, /// Success - operation succeeded 00039 INI::INI_V1_FAIL, INI::INI_NO_FILE_SPEC, /// Fail - no file was specified 00040 INI::INI_V1_FAIL, INI::INI_FILE_NOT_FOUND, /// Fail - ini file not found, or failed to open 00041 INI::INI_V1_FAIL, INI::INI_SECTION_NOT_FOUND, /// Fail - section not found 00042 INI::INI_V1_FAIL, INI::INI_KEY_NOT_FOUND, /// Fail - key not found 00043 INI::INI_V1_FAIL, INI::INI_BUF_TOO_SMALL, /// Fail - buffer to small for value 00044 INI::INI_V1_FAIL, INI::INI_INTERNAL_ERROR /// Fail - internal error - can't alloc buffers 00045 }; 00046 00047 INI::INI(const char * file, int Version) 00048 : iniFile(0) 00049 { 00050 SetFile(file); 00051 version = (Version == 2) ? 1 : 0; // Version 1 or 2 is return value index 0 or 1 00052 } 00053 00054 00055 INI::~INI(void) 00056 { 00057 if (iniFile) 00058 swFree(iniFile); 00059 } 00060 00061 00062 bool INI::GetNextSection(const char * after, char * buffer, size_t bufferSize) { 00063 bool returnNext = false; 00064 bool found = false; 00065 00066 if (!iniFile) 00067 return found; 00068 CleanUp(); 00069 INFO("GetNextSection after [%s]", after); 00070 FILE * fp = fopen(iniFile,"rt"); 00071 if (fp) { 00072 char buf[INTERNAL_BUF_SIZE]; 00073 00074 if (after == NULL || *after == '\0') 00075 returnNext = true; 00076 while(fgets(buf, sizeof(buf), fp)) { 00077 int x = strlen(buf) - 1; // remove trailing \r\n combinations 00078 while (x >= 0 && buf[x] < ' ') 00079 buf[x--] = '\0'; 00080 INFO(" reading \"%s\"", buf); 00081 if (buf[0] == '[') { 00082 char * pStart = buf + 1; 00083 char * pRBrkt = strchr(buf, ']'); 00084 if (pRBrkt) { 00085 *pRBrkt = '\0'; 00086 if (returnNext) { 00087 // Guard against "[]" which would cause it to recycle from the start 00088 if (strlen(pStart) > 0 && strlen(pStart) < bufferSize) { 00089 strcpy(buffer, pStart); 00090 found = true; 00091 break; 00092 } 00093 } else if (strcmp(after, pStart) == 0) { 00094 returnNext = true; 00095 } 00096 } 00097 } 00098 } 00099 fclose(fp); 00100 } 00101 return found; 00102 } 00103 00104 00105 bool INI::GetNextKey(const char * Section, const char * after, char * buffer, size_t bufferSize) { 00106 bool returnNext = false; 00107 bool inSection = false; 00108 bool found = false; 00109 00110 if (!iniFile) 00111 return found; 00112 CleanUp(); 00113 INFO("GetNextKey after [%s]", after); 00114 FILE * fp = fopen(iniFile,"rt"); 00115 if (fp) { 00116 char buf[INTERNAL_BUF_SIZE]; 00117 00118 if (after == NULL || *after == '\0') 00119 returnNext = true; 00120 while(fgets(buf, sizeof(buf), fp)) { 00121 int x = strlen(buf) - 1; // remove trailing \r\n combinations 00122 while (x >= 0 && buf[x] < ' ') 00123 buf[x--] = '\0'; 00124 INFO(" reading \"%s\"", buf); 00125 if (!(buf[0] == '[' || (buf[0] >= 'A' && buf[0] <= 'Z') || (buf[0] >= 'a' && buf[0] <= 'z'))) 00126 continue; 00127 if (buf[0] == '[') { 00128 char * pStart = buf + 1; 00129 char * pRBrkt = strchr(buf, ']'); 00130 if (pRBrkt) { 00131 *pRBrkt = '\0'; 00132 if (inSection == true) { // section after wanted, so done. 00133 break; 00134 } else if (strcmp(pStart, Section) == 0) { 00135 inSection = true; 00136 continue; 00137 } 00138 } 00139 } else if (inSection) { 00140 char * pStart = buf; 00141 char * pEqual = strchr(pStart, '='); 00142 if (pEqual) { 00143 *pEqual = '\0'; 00144 if (returnNext) { 00145 if (strlen(pStart) < bufferSize) { 00146 strcpy(buffer, pStart); 00147 found = true; 00148 break; 00149 } 00150 } else if (strcmp(after, pStart) == 0) { 00151 returnNext = true; 00152 } 00153 } 00154 } 00155 } 00156 fclose(fp); 00157 } 00158 return found; 00159 } 00160 00161 00162 bool INI::Exists(const char * file) 00163 { 00164 if (file == NULL) 00165 file = iniFile; 00166 INFO("Exists(%s)", file); 00167 FILE * fp = fopen(file, "r"); 00168 if (fp) { 00169 fclose(fp); 00170 INFO(" [%s] exists", file); 00171 return true; 00172 } else { 00173 INFO(" [%s] does not exist", file); 00174 return false; 00175 } 00176 } 00177 00178 00179 bool INI::SetFile(const char * file, int Version) 00180 { 00181 INFO("SetFile(%s,%d)", file, Version); 00182 version = (Version == 2) ? 1 : 0; // Version 1 or 2 is return value index 0 or 1 00183 if (file) { 00184 if (iniFile) 00185 swFree(iniFile); 00186 iniFile = (char *)swMalloc(strlen(file)+1); 00187 if (iniFile) { 00188 strcpy(iniFile, file); 00189 INFO(" SetFile(%s) success", iniFile); 00190 return true; 00191 } 00192 else { 00193 iniFile = NULL; 00194 ERR(" SetFile(%s) failed to allocate memory", file); 00195 } 00196 } 00197 return false; 00198 } 00199 00200 INI::INI_Return INI::ReadString(const char * section, const char * key, char * buffer, size_t bufferSize, const char * defaultString) 00201 { 00202 INI_Return retVal; 00203 bool found = false; 00204 00205 retVal = RetXLate[INI_SECTION_NOT_FOUND][version]; // assume we won't find the section, until we do. 00206 if (!iniFile) 00207 return RetXLate[INI_NO_FILE_SPEC][version]; 00208 CleanUp(); 00209 INFO("ReadString from %s", iniFile); 00210 FILE * fp = fopen(iniFile,"rt"); 00211 if (!fp) { 00212 if (defaultString == NULL) { 00213 return RetXLate[INI_FILE_NOT_FOUND][version]; 00214 } 00215 } else { 00216 char buf[INTERNAL_BUF_SIZE]; 00217 bool inSection = (section == NULL) ? true : false; 00218 while(fgets(buf, sizeof(buf), fp)) { 00219 int x = strlen(buf) - 1; // remove trailing \r\n combinations 00220 while (x >= 0 && buf[x] < ' ') 00221 buf[x--] = '\0'; 00222 INFO(" reading \"%s\"", buf); 00223 if (!(buf[0] == '[' || (buf[0] >= 'A' && buf[0] <= 'Z') || (buf[0] >= 'a' && buf[0] <= 'z'))) 00224 continue; 00225 00226 if (inSection && buf[0] != '[') { 00227 char * eq = strchr(buf, '='); 00228 if (eq) { 00229 *eq++ = '\0'; 00230 if (strcmp(buf,key) == 0) { // Found the key of interest 00231 if (strlen(eq) < bufferSize) { 00232 strcpy(buffer, eq); 00233 memset(buf, 0, INTERNAL_BUF_SIZE); // secure the memory space 00234 found = true; 00235 retVal = RetXLate[INI_SUCCESS][version]; 00236 } else { 00237 retVal = RetXLate[INI_BUF_TOO_SMALL][version]; 00238 } 00239 break; 00240 } 00241 } 00242 } else { 00243 if (buf[0] == '[') { 00244 char * br = strchr(buf, ']'); 00245 if (inSection) { // we were in the section of interest and just hit the next section... 00246 break; 00247 } else { 00248 inSection = false; 00249 if (br) { 00250 *br = '\0'; 00251 if (strcmp(buf+1, section) == 0) { 00252 inSection = true; 00253 retVal = RetXLate[INI_KEY_NOT_FOUND][version]; // assume we won't find the key, until we do 00254 } 00255 } 00256 } 00257 } 00258 } 00259 } 00260 fclose(fp); 00261 } 00262 if (!found && defaultString != NULL && *defaultString) { 00263 if (strlen(defaultString) < bufferSize) { 00264 strcpy(buffer, defaultString); 00265 retVal = RetXLate[INI_SUCCESS][version]; 00266 } else { 00267 retVal = RetXLate[INI_BUF_TOO_SMALL][version]; 00268 } 00269 } 00270 return retVal; 00271 } 00272 00273 00274 long int INI::ReadLongInt(const char * section, const char * key, long int defaultValue) 00275 { 00276 char localBuf[16]; 00277 00278 if (INI::INI_SUCCESS == ReadString(section, key, localBuf, sizeof(localBuf))) { 00279 return atol(localBuf); 00280 } else { 00281 return defaultValue; 00282 } 00283 } 00284 00285 bool INI::CleanUp() 00286 { 00287 char * newFile = (char *)swMalloc(strlen(iniFile)+1); 00288 char * bakFile = (char *)swMalloc(strlen(iniFile)+1); 00289 00290 if (newFile && bakFile) { 00291 INFO("CleanUp"); 00292 strcpy(bakFile, iniFile); 00293 strcpy(newFile, iniFile); 00294 strcpy(bakFile + strlen(bakFile) - 4, ".bak"); 00295 strcpy(newFile + strlen(newFile) - 4, ".new"); 00296 00297 if (Exists(newFile)) { 00298 int i; 00299 i = i; // suppress warning about i not used when !DEBUG 00300 // helps recover if the system crashed before it could swap in the new file 00301 INFO(" *** found %s, repairing ...", newFile); 00302 i = remove(bakFile); // remove an old .bak 00303 INFO(" remove(%s) returned %d", bakFile, i); 00304 i = Rename(iniFile, bakFile); // move the existing .ini to .bak 00305 INFO(" rename(%s,%s) returned %d", iniFile, bakFile, i); 00306 i = Rename(newFile, iniFile); // move the new .new to .ini 00307 INFO(" rename(%s,%s) returned %d", newFile, iniFile, i); 00308 } else { 00309 // nothing to do, move on silently. 00310 } 00311 } 00312 swFree(newFile); 00313 swFree(bakFile); 00314 return true; 00315 } 00316 00317 INI::INI_Return INI::WriteLongInt(const char * section, const char * key, long int value) 00318 { 00319 char buf[20]; 00320 snprintf(buf, 20, "%ld", value); 00321 return WriteString(section, key, buf); 00322 } 00323 00324 00325 // Create the new version as .new 00326 // once complete, if something actually changed, then rename the .ini to .bak and rename the .new to .ini 00327 // once complete, if nothing actually changed, then delete the .new 00328 // 00329 INI::INI_Return INI::WriteString(const char * section, const char * key, const char * value, int len) 00330 { 00331 bool found = false; 00332 bool fileChanged = false; 00333 INI_Return retVal; 00334 00335 if (len == -1) 00336 len = strlen(value); 00337 INFO("WriteString(%s,%s,%s)", section, key, value); 00338 if (!iniFile) 00339 return RetXLate[INI_NO_FILE_SPEC][version]; 00340 00341 if (strlen(value) > INTERNAL_BUF_SIZE) 00342 return RetXLate[INI_INTERNAL_ERROR][version]; 00343 00344 char * newFile = (char *)swMalloc(strlen(iniFile)+1); 00345 if (!newFile) 00346 return RetXLate[INI_INTERNAL_ERROR][version]; // no memory 00347 char * bakFile = (char *)swMalloc(strlen(iniFile)+1); 00348 if (!bakFile) { 00349 swFree(newFile); 00350 return RetXLate[INI_INTERNAL_ERROR][version]; 00351 } 00352 char * valBuf = (char *)swMalloc(len+1); 00353 if (!valBuf) { 00354 swFree(bakFile); 00355 swFree(newFile); 00356 return RetXLate[INI_INTERNAL_ERROR][version]; 00357 } 00358 00359 strcpy(bakFile, iniFile); 00360 strcpy(newFile, iniFile); 00361 strcpy(bakFile + strlen(bakFile) - 4, ".bak"); 00362 strcpy(newFile + strlen(newFile) - 4, ".new"); 00363 strncpy(valBuf, value, len); 00364 valBuf[len] = '\0'; 00365 CleanUp(); 00366 00367 INFO(" Opening [%s] and [%s]", iniFile, newFile); 00368 FILE * fi = fopen(iniFile, "rt"); 00369 FILE * fo = fopen(newFile, "wt"); 00370 if (fo) { 00371 char buf[INTERNAL_BUF_SIZE]; 00372 bool inSection = (section == NULL) ? true : false; 00373 00374 if (fi) { 00375 INFO(" %s opened for reading", iniFile); 00376 while(fgets(buf, sizeof(buf), fi)) { 00377 // if not inSection, copy across 00378 // if inSection and not key, copy across 00379 // if InSection and key, write new value (or skip if value is null) 00380 int x = strlen(buf) - 1; // remove trailing \r\n combinations 00381 while (x >= 0 && buf[x] < ' ') 00382 buf[x--] = '\0'; 00383 00384 if (inSection && buf[0] != '[') { 00385 char * eq = strchr(buf, '='); 00386 if (eq) { 00387 *eq++ = '\0'; 00388 if (strcmp(buf,key) == 0) { 00389 // delete, or replace the old record 00390 if (valBuf != NULL && strcmp(eq, valBuf) != 0) { 00391 // replace the old record 00392 if (valBuf != NULL) { 00393 fprintf(fo, "%s=%s\r\n", key, valBuf); 00394 INFO(" write: %s=%s", key, valBuf); 00395 } 00396 } 00397 retVal = RetXLate[INI_SUCCESS][version]; 00398 fileChanged = true; 00399 inSection = false; 00400 found = true; 00401 } else { 00402 // write old record 00403 fprintf(fo, "%s=%s\r\n", buf, eq); 00404 INFO(" write: %s=%s", buf, eq); 00405 } 00406 } else { 00407 // what to do with unknown record(s)? 00408 // fprintf(fo, "%s\n", buf); // eliminate them 00409 } 00410 } else { 00411 if (buf[0] == '[') { 00412 char * br = strchr(buf, ']'); 00413 if (inSection) { // found next section while in good section 00414 // Append new record to desired section 00415 if (valBuf != NULL) { 00416 fprintf(fo, "%s=%s\r\n", key, valBuf); 00417 INFO(" write: %s=%s", key, valBuf); 00418 fileChanged = true; 00419 } 00420 found = true; 00421 retVal = RetXLate[INI_SUCCESS][version]; 00422 } 00423 inSection = false; 00424 // write old record 00425 fprintf(fo, "\r\n%s\r\n", buf); 00426 INFO(" write: %s", buf); 00427 if (br) { 00428 *br = '\0'; 00429 if (strcmp(buf+1, section) == 0) 00430 inSection = true; 00431 } 00432 } else { 00433 // copy unaltered records across 00434 if (buf[0]) { 00435 fprintf(fo, "%s\r\n", buf); 00436 INFO(" write: %s", buf); 00437 } 00438 } 00439 } 00440 } 00441 INFO("close %s", iniFile); 00442 fclose(fi); 00443 } else { 00444 INFO(" %s did not previously exist.", iniFile); 00445 } 00446 if (!found) { 00447 // No old file, just create it now 00448 if (valBuf != NULL) { 00449 if (!inSection) { 00450 fprintf(fo, "\r\n[%s]\r\n", section); 00451 INFO(" write: [%s]", section); 00452 } 00453 fprintf(fo, "%s=%s\r\n", key, valBuf); 00454 INFO(" write: %s=%s", key, valBuf); 00455 fileChanged = true; 00456 } 00457 found = true; 00458 retVal = RetXLate[INI_SUCCESS][version]; 00459 } 00460 INFO(" close %s", newFile); 00461 fclose(fo); 00462 } else { 00463 ERR("*** Failed to open %s", newFile); 00464 retVal = RetXLate[INI_FILE_NOT_FOUND][version]; 00465 } 00466 if (fileChanged) { 00467 INFO(" File changed: remove bak, rename ini to bak, rename new to ini"); 00468 remove(bakFile); // remove an old .bak 00469 INFO(" a"); 00470 Rename(iniFile, bakFile); // move the existing .ini to .bak 00471 INFO(" b"); 00472 Rename(newFile, iniFile); // move the new .new to .ini 00473 INFO(" c"); 00474 #ifdef RTOS_H 00475 Thread::wait(1000); // this seems to help with file contention 00476 #else 00477 wait(1); 00478 #endif 00479 INFO(" d"); 00480 } 00481 swFree(valBuf); 00482 swFree(newFile); 00483 swFree(bakFile); 00484 return retVal; 00485 } 00486 00487 00488 //*********************************************************** 00489 // Private version that also works with local file system 00490 // by copying one file to the other. 00491 // Returns -1 = error; 0 = success 00492 //*********************************************************** 00493 int INI::Rename(const char *oldfname, const char *newfname) 00494 { 00495 int retval = 0; 00496 00497 INFO("Rename(%s,%s)", oldfname, newfname); 00498 if (Copy(oldfname, newfname) == 0) { 00499 remove(oldfname); 00500 retval = 0; 00501 } else { 00502 retval = -1; 00503 } 00504 return (retval); 00505 } 00506 00507 //*********************************************************** 00508 // Private version that also works with local file system 00509 // Returns -1 = error; 0 = success 00510 //*********************************************************** 00511 int INI::Copy(const char *src, const char *dst) 00512 { 00513 int retval = 0; 00514 int ch; 00515 00516 INFO("Copy(%s,%s)", src, dst); 00517 FILE *fpsrc = fopen(src, "r"); // src file 00518 FILE *fpdst = fopen(dst, "w"); // dest file 00519 00520 if (fpsrc) { 00521 INFO(" c1a"); 00522 if (fpdst) { 00523 INFO(" c1b"); 00524 while (1) { // Copy src to dest 00525 ch = fgetc(fpsrc); // until src EOF read. 00526 if (ch == EOF) break; 00527 fputc(ch, fpdst); 00528 } 00529 INFO(" c2"); 00530 fclose(fpsrc); 00531 fclose(fpdst); 00532 } 00533 } 00534 INFO(" c3"); 00535 00536 if (Exists(dst)) { 00537 retval = 0; 00538 } else { 00539 retval = -1; 00540 } 00541 INFO(" c4"); 00542 return (retval); 00543 } 00544 00545 00546 const char * INI::GetReturnMessage(INI_Return retVal) { 00547 if (version == 0) { 00548 switch (retVal) { 00549 default: 00550 case INI_V1_FAIL: return "INI Fail"; 00551 case INI_V1_SUCCESS: return "INI Success"; 00552 } 00553 } else { 00554 switch (retVal) { 00555 case INI_SUCCESS: return "INI Success - operation succeeded"; 00556 case INI_NO_FILE_SPEC: return "INI Fail - no file was specified"; 00557 case INI_FILE_NOT_FOUND: return "INI Fail - ini file not found, or failed to open"; 00558 case INI_SECTION_NOT_FOUND: return "INI Fail - section not found"; 00559 case INI_KEY_NOT_FOUND: return "INI Fail - key not found"; 00560 case INI_BUF_TOO_SMALL: return "INI Fail - buffer to small for value"; 00561 case INI_INTERNAL_ERROR: return "INI Fail - internal error - can't malloc"; 00562 default: return "INI Fail - Code Unknown"; 00563 } 00564 } 00565 } 00566 00567 #if 0 00568 // Test code for basic regression testing 00569 // 00570 #include <stdio.h> 00571 #include <assert.h> 00572 #include <string.h> 00573 00574 #include "INI.h" 00575 00576 #define TESTFILE "test.ini" 00577 00578 00579 //INI_V1_FAIL = 0, ///< Version 1 return value - Fail 00580 //INI_V1_SUCCESS = 1, ///< Version 1 return value - Success 00581 //INI_SUCCESS = 0, ///< Success - operation succeeded 00582 //INI_NO_FILE_SPEC, ///< Fail - no file was specified 00583 //INI_FILE_NOT_FOUND, ///< Fail - ini file not found, or failed to open 00584 //INI_SECTION_NOT_FOUND, ///< Fail - section not found 00585 //INI_KEY_NOT_FOUND, ///< Fail - key not found 00586 //INI_BUF_TOO_SMALL, ///< Fail - buffer to small for value 00587 //INI_INTERNAL_ERROR ///< Fail - internal error - can't alloc buffers 00588 00589 int main(int argc, char * argv[]) 00590 { 00591 FILE * fp; 00592 char buffer[100]; 00593 INI ini(TESTFILE, 2); 00594 00595 // Start testing 00596 _unlink(TESTFILE); 00597 assert(INI::INI_FILE_NOT_FOUND == ini.ReadString("Section 1", "Name 1", buffer, sizeof(buffer))); 00598 00599 fp = fopen(TESTFILE, "wt"); 00600 assert(fp); 00601 fprintf(fp, "[Section 1]\n"); 00602 fprintf(fp, "Name 1=Value 1\n"); 00603 fprintf(fp, "Name 2=Value 2\n"); 00604 fprintf(fp, "\n"); 00605 fprintf(fp, "[Section 2]\n"); 00606 fprintf(fp, "Name 1=Value 2\n"); 00607 fprintf(fp, "Name 2=Value 2\n"); 00608 fprintf(fp, "Name 3=Value 3\n"); 00609 fprintf(fp, "\n"); 00610 fclose(fp); 00611 00612 assert(INI::INI_SUCCESS == ini.ReadString("Section 2", "Name 2", buffer, sizeof(buffer))); 00613 assert(strcmp("Value 2", buffer) == 0); 00614 00615 assert(INI::INI_SECTION_NOT_FOUND == ini.ReadString("Section 3", "Name", buffer, sizeof(buffer))); 00616 assert(INI::INI_KEY_NOT_FOUND == ini.ReadString("Section 1", "Name 3", buffer, sizeof(buffer))); 00617 00618 assert(INI::INI_SUCCESS == ini.WriteString("Section 1", "Name 4", "Value 4")); 00619 assert(INI::INI_SUCCESS == ini.ReadString("Section 1", "Name 2", buffer, sizeof(buffer))); 00620 assert(INI::INI_KEY_NOT_FOUND == ini.ReadString("Section 1", "Name 3", buffer, sizeof(buffer))); 00621 assert(INI::INI_SUCCESS == ini.ReadString("Section 1", "Name 4", buffer, sizeof(buffer))); 00622 assert(strcmp("Value 4", buffer) == 0); 00623 00624 assert(INI::INI_SUCCESS == ini.WriteString("Section 1", "Name 4", NULL)); 00625 assert(INI::INI_KEY_NOT_FOUND == ini.ReadString("Section 1", "Name 4", buffer, sizeof(buffer))); 00626 00627 return 0; 00628 } 00629 #endif 00630 00631 00632
Generated on Fri Jul 15 2022 02:22:49 by
1.7.2