A simple .ini file interface.

Dependents:   Smart-WiFly-WebServer SignalGenerator WattEye X10Svr

Committer:
WiredHome
Date:
Wed Dec 28 00:21:01 2016 +0000
Revision:
18:282ed56d983b
Parent:
15:3fc2b87a234d
Parent:
17:01c0ee144433
Child:
20:392d1ec637eb
Revised the ReadString and WriteString to return a failure code, rather than a boolean. This made the APIs incompatible, but this can be selected at construction or when setting the file, in order to be backward compatible.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
WiredHome 0:ae5bf432c249 1 // Simple INI file manager.
WiredHome 0:ae5bf432c249 2 //
WiredHome 0:ae5bf432c249 3 #ifdef WIN32
WiredHome 0:ae5bf432c249 4 #include "string.h"
WiredHome 0:ae5bf432c249 5 #include "stdlib.h"
WiredHome 0:ae5bf432c249 6 #include "stdio.h"
WiredHome 0:ae5bf432c249 7 #else
WiredHome 0:ae5bf432c249 8 #include "mbed.h"
WiredHome 0:ae5bf432c249 9 #endif
WiredHome 0:ae5bf432c249 10
WiredHome 0:ae5bf432c249 11 #include "IniManager.h"
WiredHome 0:ae5bf432c249 12
WiredHome 13:d5957065d066 13 //#include "Utility.h" // private memory manager
WiredHome 11:738604f18088 14 #ifndef UTILITY_H
WiredHome 11:738604f18088 15 #define swMalloc malloc // use the standard
WiredHome 11:738604f18088 16 #define swFree free
WiredHome 11:738604f18088 17 #endif
WiredHome 11:738604f18088 18
WiredHome 8:f128b10dfab1 19 //#define DEBUG "INI " //Debug is disabled by default
WiredHome 1:1e2ee9bbee40 20
WiredHome 8:f128b10dfab1 21 #include <cstdio>
WiredHome 1:1e2ee9bbee40 22 #if (defined(DEBUG) && !defined(TARGET_LPC11U24))
WiredHome 8:f128b10dfab1 23 #define DBG(x, ...) std::printf("[DBG %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 8:f128b10dfab1 24 #define WARN(x, ...) std::printf("[WRN %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 8:f128b10dfab1 25 #define ERR(x, ...) std::printf("[ERR %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 8:f128b10dfab1 26 #define INFO(x, ...) std::printf("[INF %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 1:1e2ee9bbee40 27 #else
WiredHome 1:1e2ee9bbee40 28 #define DBG(x, ...)
WiredHome 1:1e2ee9bbee40 29 #define WARN(x, ...)
WiredHome 1:1e2ee9bbee40 30 #define ERR(x, ...)
WiredHome 1:1e2ee9bbee40 31 #define INFO(x, ...)
WiredHome 1:1e2ee9bbee40 32 #endif
WiredHome 1:1e2ee9bbee40 33
WiredHome 18:282ed56d983b 34 // 2 versions, to translate new return values to old format
WiredHome 18:282ed56d983b 35 // return RetXLate[new value][version]
WiredHome 18:282ed56d983b 36 INI::INI_Return RetXLate[INI::INI_INTERNAL_ERROR+1][2] = {
WiredHome 18:282ed56d983b 37 // Ver1, Ver2 return values.
WiredHome 18:282ed56d983b 38 INI::INI_V1_SUCCESS, INI::INI_SUCCESS, /// Success - operation succeeded
WiredHome 18:282ed56d983b 39 INI::INI_V1_FAIL, INI::INI_NO_FILE_SPEC, /// Fail - no file was specified
WiredHome 18:282ed56d983b 40 INI::INI_V1_FAIL, INI::INI_FILE_NOT_FOUND, /// Fail - ini file not found, or failed to open
WiredHome 18:282ed56d983b 41 INI::INI_V1_FAIL, INI::INI_SECTION_NOT_FOUND, /// Fail - section not found
WiredHome 18:282ed56d983b 42 INI::INI_V1_FAIL, INI::INI_KEY_NOT_FOUND, /// Fail - key not found
WiredHome 18:282ed56d983b 43 INI::INI_V1_FAIL, INI::INI_BUF_TOO_SMALL, /// Fail - buffer to small for value
WiredHome 18:282ed56d983b 44 INI::INI_V1_FAIL, INI::INI_INTERNAL_ERROR /// Fail - internal error - can't alloc buffers
WiredHome 18:282ed56d983b 45 };
WiredHome 18:282ed56d983b 46
WiredHome 18:282ed56d983b 47 INI::INI(const char * file, int Version)
WiredHome 0:ae5bf432c249 48 : iniFile(0)
WiredHome 0:ae5bf432c249 49 {
WiredHome 7:60f5dc3467ff 50 SetFile(file);
WiredHome 18:282ed56d983b 51 version = (Version == 2) ? 1 : 0; // Version 1 or 2 is return value index 0 or 1
WiredHome 0:ae5bf432c249 52 }
WiredHome 0:ae5bf432c249 53
WiredHome 0:ae5bf432c249 54
WiredHome 0:ae5bf432c249 55 INI::~INI(void)
WiredHome 0:ae5bf432c249 56 {
WiredHome 0:ae5bf432c249 57 if (iniFile)
WiredHome 11:738604f18088 58 swFree(iniFile);
WiredHome 0:ae5bf432c249 59 }
WiredHome 0:ae5bf432c249 60
WiredHome 0:ae5bf432c249 61
WiredHome 15:3fc2b87a234d 62 bool INI::GetNextSection(const char * after, char * buffer, size_t bufferSize) {
WiredHome 15:3fc2b87a234d 63 bool returnNext = false;
WiredHome 15:3fc2b87a234d 64 bool found = false;
WiredHome 15:3fc2b87a234d 65
WiredHome 15:3fc2b87a234d 66 if (!iniFile)
WiredHome 15:3fc2b87a234d 67 return found;
WiredHome 15:3fc2b87a234d 68 CleanUp();
WiredHome 15:3fc2b87a234d 69 INFO("GetNextSection after [%s]", after);
WiredHome 15:3fc2b87a234d 70 FILE * fp = fopen(iniFile,"rt");
WiredHome 15:3fc2b87a234d 71 if (fp) {
WiredHome 15:3fc2b87a234d 72 char buf[INTERNAL_BUF_SIZE];
WiredHome 15:3fc2b87a234d 73
WiredHome 15:3fc2b87a234d 74 if (after == NULL || *after == '\0')
WiredHome 15:3fc2b87a234d 75 returnNext = true;
WiredHome 15:3fc2b87a234d 76 while(fgets(buf, sizeof(buf), fp)) {
WiredHome 15:3fc2b87a234d 77 int x = strlen(buf) - 1; // remove trailing \r\n combinations
WiredHome 15:3fc2b87a234d 78 while (x >= 0 && buf[x] < ' ')
WiredHome 15:3fc2b87a234d 79 buf[x--] = '\0';
WiredHome 15:3fc2b87a234d 80 INFO(" reading \"%s\"", buf);
WiredHome 15:3fc2b87a234d 81 if (buf[0] == '[') {
WiredHome 15:3fc2b87a234d 82 char * pStart = buf + 1;
WiredHome 15:3fc2b87a234d 83 char * pRBrkt = strchr(buf, ']');
WiredHome 15:3fc2b87a234d 84 if (pRBrkt) {
WiredHome 15:3fc2b87a234d 85 *pRBrkt = '\0';
WiredHome 15:3fc2b87a234d 86 if (returnNext) {
WiredHome 15:3fc2b87a234d 87 if (strlen(pStart) < bufferSize) {
WiredHome 15:3fc2b87a234d 88 strcpy(buffer, pStart);
WiredHome 15:3fc2b87a234d 89 found = true;
WiredHome 15:3fc2b87a234d 90 break;
WiredHome 15:3fc2b87a234d 91 }
WiredHome 15:3fc2b87a234d 92 } else if (strcmp(after, pStart) == 0) {
WiredHome 15:3fc2b87a234d 93 returnNext = true;
WiredHome 15:3fc2b87a234d 94 }
WiredHome 15:3fc2b87a234d 95 }
WiredHome 15:3fc2b87a234d 96 }
WiredHome 15:3fc2b87a234d 97 }
WiredHome 15:3fc2b87a234d 98 fclose(fp);
WiredHome 15:3fc2b87a234d 99 }
WiredHome 15:3fc2b87a234d 100 return found;
WiredHome 15:3fc2b87a234d 101 }
WiredHome 15:3fc2b87a234d 102
WiredHome 15:3fc2b87a234d 103
WiredHome 15:3fc2b87a234d 104 bool INI::GetNextKey(const char * Section, const char * after, char * buffer, size_t bufferSize) {
WiredHome 15:3fc2b87a234d 105 bool returnNext = false;
WiredHome 15:3fc2b87a234d 106 bool inSection = false;
WiredHome 15:3fc2b87a234d 107 bool found = false;
WiredHome 15:3fc2b87a234d 108
WiredHome 15:3fc2b87a234d 109 if (!iniFile)
WiredHome 15:3fc2b87a234d 110 return found;
WiredHome 15:3fc2b87a234d 111 CleanUp();
WiredHome 15:3fc2b87a234d 112 INFO("GetNextLey after [%s]", after);
WiredHome 15:3fc2b87a234d 113 FILE * fp = fopen(iniFile,"rt");
WiredHome 15:3fc2b87a234d 114 if (fp) {
WiredHome 15:3fc2b87a234d 115 char buf[INTERNAL_BUF_SIZE];
WiredHome 15:3fc2b87a234d 116
WiredHome 15:3fc2b87a234d 117 if (after == NULL || *after == '\0')
WiredHome 15:3fc2b87a234d 118 returnNext = true;
WiredHome 15:3fc2b87a234d 119 while(fgets(buf, sizeof(buf), fp)) {
WiredHome 15:3fc2b87a234d 120 int x = strlen(buf) - 1; // remove trailing \r\n combinations
WiredHome 15:3fc2b87a234d 121 while (x >= 0 && buf[x] < ' ')
WiredHome 15:3fc2b87a234d 122 buf[x--] = '\0';
WiredHome 15:3fc2b87a234d 123 INFO(" reading \"%s\"", buf);
WiredHome 15:3fc2b87a234d 124 if (!(buf[0] == '[' || (buf[0] >= 'A' && buf[0] <= 'Z') || (buf[0] >= 'a' && buf[0] <= 'z')))
WiredHome 15:3fc2b87a234d 125 continue;
WiredHome 15:3fc2b87a234d 126 if (buf[0] == '[') {
WiredHome 15:3fc2b87a234d 127 char * pStart = buf + 1;
WiredHome 15:3fc2b87a234d 128 char * pRBrkt = strchr(buf, ']');
WiredHome 15:3fc2b87a234d 129 if (pRBrkt) {
WiredHome 15:3fc2b87a234d 130 *pRBrkt = '\0';
WiredHome 15:3fc2b87a234d 131 if (inSection == true) { // section after wanted, so done.
WiredHome 15:3fc2b87a234d 132 break;
WiredHome 15:3fc2b87a234d 133 } else if (strcmp(pStart, Section) == 0) {
WiredHome 15:3fc2b87a234d 134 inSection = true;
WiredHome 15:3fc2b87a234d 135 continue;
WiredHome 15:3fc2b87a234d 136 }
WiredHome 15:3fc2b87a234d 137 }
WiredHome 15:3fc2b87a234d 138 } else if (inSection) {
WiredHome 15:3fc2b87a234d 139 char * pStart = buf;
WiredHome 15:3fc2b87a234d 140 char * pEqual = strchr(pStart, '=');
WiredHome 15:3fc2b87a234d 141 if (pEqual) {
WiredHome 15:3fc2b87a234d 142 *pEqual = '\0';
WiredHome 15:3fc2b87a234d 143 if (returnNext) {
WiredHome 15:3fc2b87a234d 144 if (strlen(pStart) < bufferSize) {
WiredHome 15:3fc2b87a234d 145 strcpy(buffer, pStart);
WiredHome 15:3fc2b87a234d 146 found = true;
WiredHome 15:3fc2b87a234d 147 break;
WiredHome 15:3fc2b87a234d 148 }
WiredHome 15:3fc2b87a234d 149 } else if (strcmp(after, pStart) == 0) {
WiredHome 15:3fc2b87a234d 150 returnNext = true;
WiredHome 15:3fc2b87a234d 151 }
WiredHome 15:3fc2b87a234d 152 }
WiredHome 15:3fc2b87a234d 153 }
WiredHome 15:3fc2b87a234d 154 }
WiredHome 15:3fc2b87a234d 155 fclose(fp);
WiredHome 15:3fc2b87a234d 156 }
WiredHome 15:3fc2b87a234d 157 return found;
WiredHome 15:3fc2b87a234d 158 }
WiredHome 15:3fc2b87a234d 159
WiredHome 15:3fc2b87a234d 160
WiredHome 8:f128b10dfab1 161 bool INI::Exists(const char * file)
WiredHome 8:f128b10dfab1 162 {
WiredHome 8:f128b10dfab1 163 if (file == NULL)
WiredHome 8:f128b10dfab1 164 file = iniFile;
WiredHome 8:f128b10dfab1 165 INFO("Exists(%s)", file);
WiredHome 8:f128b10dfab1 166 FILE * fp = fopen(file, "r");
WiredHome 8:f128b10dfab1 167 if (fp) {
WiredHome 8:f128b10dfab1 168 fclose(fp);
WiredHome 8:f128b10dfab1 169 INFO(" [%s] exists", file);
WiredHome 8:f128b10dfab1 170 return true;
WiredHome 8:f128b10dfab1 171 } else {
WiredHome 8:f128b10dfab1 172 INFO(" [%s] does not exist", file);
WiredHome 8:f128b10dfab1 173 return false;
WiredHome 8:f128b10dfab1 174 }
WiredHome 8:f128b10dfab1 175 }
WiredHome 8:f128b10dfab1 176
WiredHome 8:f128b10dfab1 177
WiredHome 18:282ed56d983b 178 bool INI::SetFile(const char * file, int Version)
WiredHome 5:bfeb0882bd82 179 {
WiredHome 18:282ed56d983b 180 INFO("SetFile(%s,%d)", file, Version);
WiredHome 18:282ed56d983b 181 version = (Version == 2) ? 1 : 0; // Version 1 or 2 is return value index 0 or 1
WiredHome 5:bfeb0882bd82 182 if (file) {
WiredHome 5:bfeb0882bd82 183 if (iniFile)
WiredHome 11:738604f18088 184 swFree(iniFile);
WiredHome 11:738604f18088 185 iniFile = (char *)swMalloc(strlen(file)+1);
WiredHome 5:bfeb0882bd82 186 if (iniFile) {
WiredHome 5:bfeb0882bd82 187 strcpy(iniFile, file);
WiredHome 8:f128b10dfab1 188 INFO(" SetFile(%s) success", iniFile);
WiredHome 5:bfeb0882bd82 189 return true;
WiredHome 5:bfeb0882bd82 190 }
WiredHome 8:f128b10dfab1 191 else {
WiredHome 8:f128b10dfab1 192 iniFile = NULL;
WiredHome 8:f128b10dfab1 193 ERR(" SetFile(%s) failed to allocate memory", file);
WiredHome 8:f128b10dfab1 194 }
WiredHome 5:bfeb0882bd82 195 }
WiredHome 5:bfeb0882bd82 196 return false;
WiredHome 5:bfeb0882bd82 197 }
WiredHome 5:bfeb0882bd82 198
WiredHome 18:282ed56d983b 199 INI::INI_Return INI::ReadString(const char * section, const char * key, char * buffer, size_t bufferSize, const char * defaultString)
WiredHome 0:ae5bf432c249 200 {
WiredHome 18:282ed56d983b 201 INI_Return retVal;
WiredHome 0:ae5bf432c249 202 bool found = false;
WiredHome 18:282ed56d983b 203
WiredHome 0:ae5bf432c249 204 if (!iniFile)
WiredHome 18:282ed56d983b 205 return RetXLate[INI_NO_FILE_SPEC][version];
WiredHome 8:f128b10dfab1 206 CleanUp();
WiredHome 8:f128b10dfab1 207 INFO("ReadString from %s", iniFile);
WiredHome 0:ae5bf432c249 208 FILE * fp = fopen(iniFile,"rt");
WiredHome 18:282ed56d983b 209 if (!fp) {
WiredHome 18:282ed56d983b 210 return RetXLate[INI_FILE_NOT_FOUND][version];
WiredHome 18:282ed56d983b 211 } else {
WiredHome 0:ae5bf432c249 212 char buf[INTERNAL_BUF_SIZE];
WiredHome 0:ae5bf432c249 213 bool inSection = (section == NULL) ? true : false;
WiredHome 18:282ed56d983b 214 retVal = RetXLate[INI_SECTION_NOT_FOUND][version]; // assume we won't find the section, until we do.
WiredHome 0:ae5bf432c249 215 while(fgets(buf, sizeof(buf), fp)) {
WiredHome 0:ae5bf432c249 216 int x = strlen(buf) - 1; // remove trailing \r\n combinations
WiredHome 0:ae5bf432c249 217 while (x >= 0 && buf[x] < ' ')
WiredHome 0:ae5bf432c249 218 buf[x--] = '\0';
WiredHome 8:f128b10dfab1 219 INFO(" reading \"%s\"", buf);
WiredHome 15:3fc2b87a234d 220 if (!(buf[0] == '[' || (buf[0] >= 'A' && buf[0] <= 'Z') || (buf[0] >= 'a' && buf[0] <= 'z')))
WiredHome 15:3fc2b87a234d 221 continue;
WiredHome 15:3fc2b87a234d 222
WiredHome 0:ae5bf432c249 223 if (inSection && buf[0] != '[') {
WiredHome 0:ae5bf432c249 224 char * eq = strchr(buf, '=');
WiredHome 0:ae5bf432c249 225 if (eq) {
WiredHome 0:ae5bf432c249 226 *eq++ = '\0';
WiredHome 18:282ed56d983b 227 if (strcmp(buf,key) == 0) { // Found the key of interest
WiredHome 18:282ed56d983b 228 if (strlen(eq) < bufferSize) {
WiredHome 18:282ed56d983b 229 strcpy(buffer, eq);
WiredHome 18:282ed56d983b 230 memset(buf, 0, INTERNAL_BUF_SIZE); // secure the memory space
WiredHome 18:282ed56d983b 231 found = true;
WiredHome 18:282ed56d983b 232 retVal = RetXLate[INI_SUCCESS][version];
WiredHome 18:282ed56d983b 233 } else {
WiredHome 18:282ed56d983b 234 retVal = RetXLate[INI_BUF_TOO_SMALL][version];
WiredHome 18:282ed56d983b 235 }
WiredHome 0:ae5bf432c249 236 break;
WiredHome 0:ae5bf432c249 237 }
WiredHome 0:ae5bf432c249 238 }
WiredHome 0:ae5bf432c249 239 } else {
WiredHome 0:ae5bf432c249 240 if (buf[0] == '[') {
WiredHome 0:ae5bf432c249 241 char * br = strchr(buf, ']');
WiredHome 18:282ed56d983b 242 if (inSection) { // we were in the section of interest and just hit the next section...
WiredHome 18:282ed56d983b 243 break;
WiredHome 18:282ed56d983b 244 } else {
WiredHome 18:282ed56d983b 245 inSection = false;
WiredHome 18:282ed56d983b 246 if (br) {
WiredHome 18:282ed56d983b 247 *br = '\0';
WiredHome 18:282ed56d983b 248 if (strcmp(buf+1, section) == 0) {
WiredHome 18:282ed56d983b 249 inSection = true;
WiredHome 18:282ed56d983b 250 retVal = RetXLate[INI_KEY_NOT_FOUND][version]; // assume we won't find the key, until we do
WiredHome 18:282ed56d983b 251 }
WiredHome 18:282ed56d983b 252 }
WiredHome 0:ae5bf432c249 253 }
WiredHome 0:ae5bf432c249 254 }
WiredHome 0:ae5bf432c249 255 }
WiredHome 0:ae5bf432c249 256 }
WiredHome 0:ae5bf432c249 257 fclose(fp);
WiredHome 0:ae5bf432c249 258 }
WiredHome 0:ae5bf432c249 259 if (!found && defaultString != NULL && *defaultString) {
WiredHome 18:282ed56d983b 260 if (strlen(defaultString) < bufferSize) {
WiredHome 18:282ed56d983b 261 strcpy(buffer, defaultString);
WiredHome 18:282ed56d983b 262 retVal = RetXLate[INI_SUCCESS][version];
WiredHome 18:282ed56d983b 263 } else {
WiredHome 18:282ed56d983b 264 retVal = RetXLate[INI_BUF_TOO_SMALL][version];
WiredHome 18:282ed56d983b 265 }
WiredHome 0:ae5bf432c249 266 }
WiredHome 18:282ed56d983b 267 return retVal;
WiredHome 0:ae5bf432c249 268 }
WiredHome 0:ae5bf432c249 269
WiredHome 18:282ed56d983b 270
WiredHome 12:6cf929bde139 271 long int INI::ReadLongInt(const char * section, const char * key, long int defaultValue)
WiredHome 12:6cf929bde139 272 {
WiredHome 12:6cf929bde139 273 char localBuf[16];
WiredHome 12:6cf929bde139 274
WiredHome 12:6cf929bde139 275 if (ReadString(section, key, localBuf, sizeof(localBuf))) {
WiredHome 12:6cf929bde139 276 return atol(localBuf);
WiredHome 12:6cf929bde139 277 } else {
WiredHome 12:6cf929bde139 278 return defaultValue;
WiredHome 12:6cf929bde139 279 }
WiredHome 12:6cf929bde139 280 }
WiredHome 12:6cf929bde139 281
WiredHome 8:f128b10dfab1 282 bool INI::CleanUp()
WiredHome 0:ae5bf432c249 283 {
WiredHome 11:738604f18088 284 char * newFile = (char *)swMalloc(strlen(iniFile)+1);
WiredHome 11:738604f18088 285 char * bakFile = (char *)swMalloc(strlen(iniFile)+1);
WiredHome 0:ae5bf432c249 286
WiredHome 0:ae5bf432c249 287 if (newFile && bakFile) {
WiredHome 8:f128b10dfab1 288 INFO("CleanUp");
WiredHome 0:ae5bf432c249 289 strcpy(bakFile, iniFile);
WiredHome 0:ae5bf432c249 290 strcpy(newFile, iniFile);
WiredHome 0:ae5bf432c249 291 strcpy(bakFile + strlen(bakFile) - 4, ".bak");
WiredHome 0:ae5bf432c249 292 strcpy(newFile + strlen(newFile) - 4, ".new");
WiredHome 0:ae5bf432c249 293
WiredHome 8:f128b10dfab1 294 if (Exists(newFile)) {
WiredHome 2:c63a794c1fee 295 int i;
WiredHome 9:4947b8c244e9 296 i = i; // suppress warning about i not used when !DEBUG
WiredHome 0:ae5bf432c249 297 // helps recover if the system crashed before it could swap in the new file
WiredHome 8:f128b10dfab1 298 INFO(" *** found %s, repairing ...", newFile);
WiredHome 0:ae5bf432c249 299 i = remove(bakFile); // remove an old .bak
WiredHome 8:f128b10dfab1 300 INFO(" remove(%s) returned %d", bakFile, i);
WiredHome 0:ae5bf432c249 301 i = Rename(iniFile, bakFile); // move the existing .ini to .bak
WiredHome 8:f128b10dfab1 302 INFO(" rename(%s,%s) returned %d", iniFile, bakFile, i);
WiredHome 0:ae5bf432c249 303 i = Rename(newFile, iniFile); // move the new .new to .ini
WiredHome 8:f128b10dfab1 304 INFO(" rename(%s,%s) returned %d", newFile, iniFile, i);
WiredHome 8:f128b10dfab1 305 } else {
WiredHome 8:f128b10dfab1 306 // nothing to do, move on silently.
WiredHome 0:ae5bf432c249 307 }
WiredHome 0:ae5bf432c249 308 }
WiredHome 11:738604f18088 309 swFree(newFile);
WiredHome 11:738604f18088 310 swFree(bakFile);
WiredHome 0:ae5bf432c249 311 return true;
WiredHome 0:ae5bf432c249 312 }
WiredHome 0:ae5bf432c249 313
WiredHome 0:ae5bf432c249 314 // Create the new version as .new
WiredHome 0:ae5bf432c249 315 // once complete, if something actually changed, then rename the .ini to .bak and rename the .new to .ini
WiredHome 0:ae5bf432c249 316 // once complete, if nothing actually changed, then delete the .new
WiredHome 0:ae5bf432c249 317 //
WiredHome 18:282ed56d983b 318 INI::INI_Return INI::WriteString(const char * section, const char * key, const char * value, int len)
WiredHome 0:ae5bf432c249 319 {
WiredHome 0:ae5bf432c249 320 bool found = false;
WiredHome 0:ae5bf432c249 321 bool fileChanged = false;
WiredHome 18:282ed56d983b 322 INI_Return retVal;
WiredHome 18:282ed56d983b 323
WiredHome 16:82e0f8747b95 324 if (len == -1)
WiredHome 16:82e0f8747b95 325 len = strlen(value);
WiredHome 8:f128b10dfab1 326 INFO("WriteString(%s,%s,%s)", section, key, value);
WiredHome 18:282ed56d983b 327 if (!iniFile)
WiredHome 18:282ed56d983b 328 return RetXLate[INI_NO_FILE_SPEC][version];
WiredHome 18:282ed56d983b 329
WiredHome 18:282ed56d983b 330 if (strlen(value) > INTERNAL_BUF_SIZE)
WiredHome 18:282ed56d983b 331 return RetXLate[INI_INTERNAL_ERROR][version];
WiredHome 0:ae5bf432c249 332
WiredHome 11:738604f18088 333 char * newFile = (char *)swMalloc(strlen(iniFile)+1);
WiredHome 0:ae5bf432c249 334 if (!newFile)
WiredHome 18:282ed56d983b 335 return RetXLate[INI_INTERNAL_ERROR][version]; // no memory
WiredHome 16:82e0f8747b95 336 char * bakFile = (char *)swMalloc(strlen(iniFile)+1);
WiredHome 0:ae5bf432c249 337 if (!bakFile) {
WiredHome 11:738604f18088 338 swFree(newFile);
WiredHome 18:282ed56d983b 339 return RetXLate[INI_INTERNAL_ERROR][version];
WiredHome 0:ae5bf432c249 340 }
WiredHome 16:82e0f8747b95 341 char * valBuf = (char *)swMalloc(len+1);
WiredHome 16:82e0f8747b95 342 if (!valBuf) {
WiredHome 16:82e0f8747b95 343 swFree(bakFile);
WiredHome 16:82e0f8747b95 344 swFree(newFile);
WiredHome 18:282ed56d983b 345 return RetXLate[INI_INTERNAL_ERROR][version];
WiredHome 16:82e0f8747b95 346 }
WiredHome 16:82e0f8747b95 347
WiredHome 0:ae5bf432c249 348 strcpy(bakFile, iniFile);
WiredHome 0:ae5bf432c249 349 strcpy(newFile, iniFile);
WiredHome 0:ae5bf432c249 350 strcpy(bakFile + strlen(bakFile) - 4, ".bak");
WiredHome 0:ae5bf432c249 351 strcpy(newFile + strlen(newFile) - 4, ".new");
WiredHome 16:82e0f8747b95 352 strncpy(valBuf, value, len);
WiredHome 16:82e0f8747b95 353 valBuf[len] = '\0';
WiredHome 8:f128b10dfab1 354 CleanUp();
WiredHome 0:ae5bf432c249 355
WiredHome 8:f128b10dfab1 356 INFO(" Opening [%s] and [%s]", iniFile, newFile);
WiredHome 0:ae5bf432c249 357 FILE * fi = fopen(iniFile, "rt");
WiredHome 0:ae5bf432c249 358 FILE * fo = fopen(newFile, "wt");
WiredHome 0:ae5bf432c249 359 if (fo) {
WiredHome 0:ae5bf432c249 360 char buf[INTERNAL_BUF_SIZE];
WiredHome 0:ae5bf432c249 361 bool inSection = (section == NULL) ? true : false;
WiredHome 0:ae5bf432c249 362
WiredHome 0:ae5bf432c249 363 if (fi) {
WiredHome 8:f128b10dfab1 364 INFO(" %s opened for reading", iniFile);
WiredHome 0:ae5bf432c249 365 while(fgets(buf, sizeof(buf), fi)) {
WiredHome 0:ae5bf432c249 366 // if not inSection, copy across
WiredHome 0:ae5bf432c249 367 // if inSection and not key, copy across
WiredHome 0:ae5bf432c249 368 // if InSection and key, write new value (or skip if value is null)
WiredHome 0:ae5bf432c249 369 int x = strlen(buf) - 1; // remove trailing \r\n combinations
WiredHome 0:ae5bf432c249 370 while (x >= 0 && buf[x] < ' ')
WiredHome 0:ae5bf432c249 371 buf[x--] = '\0';
WiredHome 8:f128b10dfab1 372
WiredHome 0:ae5bf432c249 373 if (inSection && buf[0] != '[') {
WiredHome 0:ae5bf432c249 374 char * eq = strchr(buf, '=');
WiredHome 0:ae5bf432c249 375 if (eq) {
WiredHome 0:ae5bf432c249 376 *eq++ = '\0';
WiredHome 0:ae5bf432c249 377 if (strcmp(buf,key) == 0) {
WiredHome 18:282ed56d983b 378 // delete, or replace the old record
WiredHome 16:82e0f8747b95 379 if (valBuf != NULL && strcmp(eq, valBuf) != 0) {
WiredHome 0:ae5bf432c249 380 // replace the old record
WiredHome 16:82e0f8747b95 381 if (valBuf != NULL) {
WiredHome 17:01c0ee144433 382 fprintf(fo, "%s=%s\r\n", key, valBuf);
WiredHome 16:82e0f8747b95 383 printf("write: %s=%s\r\n", key, valBuf);
WiredHome 16:82e0f8747b95 384 INFO(" write: %s=%s", key, valBuf);
WiredHome 0:ae5bf432c249 385 }
WiredHome 0:ae5bf432c249 386 }
WiredHome 18:282ed56d983b 387 retVal = RetXLate[INI_SUCCESS][version];
WiredHome 0:ae5bf432c249 388 fileChanged = true;
WiredHome 0:ae5bf432c249 389 inSection = false;
WiredHome 0:ae5bf432c249 390 found = true;
WiredHome 0:ae5bf432c249 391 } else {
WiredHome 0:ae5bf432c249 392 // write old record
WiredHome 17:01c0ee144433 393 fprintf(fo, "%s=%s\r\n", buf, eq);
WiredHome 8:f128b10dfab1 394 INFO(" write: %s=%s", buf, eq);
WiredHome 0:ae5bf432c249 395 }
WiredHome 0:ae5bf432c249 396 } else {
WiredHome 0:ae5bf432c249 397 // what to do with unknown record(s)?
WiredHome 0:ae5bf432c249 398 // fprintf(fo, "%s\n", buf); // eliminate them
WiredHome 0:ae5bf432c249 399 }
WiredHome 0:ae5bf432c249 400 } else {
WiredHome 0:ae5bf432c249 401 if (buf[0] == '[') {
WiredHome 0:ae5bf432c249 402 char * br = strchr(buf, ']');
WiredHome 0:ae5bf432c249 403 if (inSection) { // found next section while in good section
WiredHome 0:ae5bf432c249 404 // Append new record to desired section
WiredHome 16:82e0f8747b95 405 if (valBuf != NULL) {
WiredHome 16:82e0f8747b95 406 fprintf(fo, "%s=%s\r\n", key, valBuf);
WiredHome 16:82e0f8747b95 407 INFO(" write: %s=%s", key, valBuf);
WiredHome 0:ae5bf432c249 408 fileChanged = true;
WiredHome 0:ae5bf432c249 409 }
WiredHome 0:ae5bf432c249 410 found = true;
WiredHome 18:282ed56d983b 411 retVal = RetXLate[INI_SUCCESS][version];
WiredHome 0:ae5bf432c249 412 }
WiredHome 0:ae5bf432c249 413 inSection = false;
WiredHome 0:ae5bf432c249 414 // write old record
WiredHome 0:ae5bf432c249 415 fprintf(fo, "%s\r\n", buf);
WiredHome 8:f128b10dfab1 416 INFO(" write: %s", buf);
WiredHome 0:ae5bf432c249 417 if (br) {
WiredHome 0:ae5bf432c249 418 *br = '\0';
WiredHome 0:ae5bf432c249 419 if (strcmp(buf+1, section) == 0)
WiredHome 0:ae5bf432c249 420 inSection = true;
WiredHome 0:ae5bf432c249 421 }
WiredHome 0:ae5bf432c249 422 } else {
WiredHome 0:ae5bf432c249 423 // copy unaltered records across
WiredHome 0:ae5bf432c249 424 if (buf[0]) {
WiredHome 0:ae5bf432c249 425 fprintf(fo, "%s\r\n", buf);
WiredHome 8:f128b10dfab1 426 INFO(" write: %s", buf);
WiredHome 0:ae5bf432c249 427 }
WiredHome 0:ae5bf432c249 428 }
WiredHome 0:ae5bf432c249 429 }
WiredHome 0:ae5bf432c249 430 }
WiredHome 8:f128b10dfab1 431 INFO("close %s", iniFile);
WiredHome 0:ae5bf432c249 432 fclose(fi);
WiredHome 8:f128b10dfab1 433 } else {
WiredHome 8:f128b10dfab1 434 INFO(" %s did not previously exist.", iniFile);
WiredHome 0:ae5bf432c249 435 }
WiredHome 0:ae5bf432c249 436 if (!found) {
WiredHome 0:ae5bf432c249 437 // No old file, just create it now
WiredHome 16:82e0f8747b95 438 if (valBuf != NULL) {
WiredHome 0:ae5bf432c249 439 if (!inSection) {
WiredHome 17:01c0ee144433 440 fprintf(fo, "\r\n[%s]\r\n", section);
WiredHome 8:f128b10dfab1 441 INFO(" write: [%s]", section);
WiredHome 0:ae5bf432c249 442 }
WiredHome 16:82e0f8747b95 443 fprintf(fo, "%s=%s\r\n", key, valBuf);
WiredHome 16:82e0f8747b95 444 INFO(" write: %s=%s", key, valBuf);
WiredHome 0:ae5bf432c249 445 fileChanged = true;
WiredHome 0:ae5bf432c249 446 }
WiredHome 0:ae5bf432c249 447 found = true;
WiredHome 18:282ed56d983b 448 retVal = RetXLate[INI_SUCCESS][version];
WiredHome 0:ae5bf432c249 449 }
WiredHome 8:f128b10dfab1 450 INFO(" close %s", newFile);
WiredHome 0:ae5bf432c249 451 fclose(fo);
WiredHome 8:f128b10dfab1 452 } else {
WiredHome 8:f128b10dfab1 453 ERR("*** Failed to open %s", newFile);
WiredHome 18:282ed56d983b 454 retVal = RetXLate[INI_FILE_NOT_FOUND][version];
WiredHome 0:ae5bf432c249 455 }
WiredHome 0:ae5bf432c249 456 if (fileChanged) {
WiredHome 8:f128b10dfab1 457 INFO(" File changed: remove bak, rename ini to bak, rename new to ini");
WiredHome 0:ae5bf432c249 458 remove(bakFile); // remove an old .bak
WiredHome 8:f128b10dfab1 459 INFO(" a");
WiredHome 0:ae5bf432c249 460 Rename(iniFile, bakFile); // move the existing .ini to .bak
WiredHome 8:f128b10dfab1 461 INFO(" b");
WiredHome 0:ae5bf432c249 462 Rename(newFile, iniFile); // move the new .new to .ini
WiredHome 8:f128b10dfab1 463 INFO(" c");
WiredHome 4:70042853d43b 464 #ifdef RTOS_H
WiredHome 4:70042853d43b 465 Thread::wait(1000);
WiredHome 4:70042853d43b 466 #else
WiredHome 0:ae5bf432c249 467 wait(1);
WiredHome 4:70042853d43b 468 #endif
WiredHome 8:f128b10dfab1 469 INFO(" d");
WiredHome 0:ae5bf432c249 470 }
WiredHome 16:82e0f8747b95 471 swFree(valBuf);
WiredHome 11:738604f18088 472 swFree(newFile);
WiredHome 11:738604f18088 473 swFree(bakFile);
WiredHome 18:282ed56d983b 474 return retVal;
WiredHome 0:ae5bf432c249 475 }
WiredHome 0:ae5bf432c249 476
WiredHome 0:ae5bf432c249 477
WiredHome 0:ae5bf432c249 478 //***********************************************************
WiredHome 0:ae5bf432c249 479 // Private version that also works with local file system
WiredHome 8:f128b10dfab1 480 // by copying one file to the other.
WiredHome 0:ae5bf432c249 481 // Returns -1 = error; 0 = success
WiredHome 0:ae5bf432c249 482 //***********************************************************
WiredHome 0:ae5bf432c249 483 int INI::Rename(const char *oldfname, const char *newfname)
WiredHome 0:ae5bf432c249 484 {
WiredHome 0:ae5bf432c249 485 int retval = 0;
WiredHome 0:ae5bf432c249 486
WiredHome 8:f128b10dfab1 487 INFO("Rename(%s,%s)", oldfname, newfname);
WiredHome 8:f128b10dfab1 488 if (Copy(oldfname, newfname) == 0) {
WiredHome 8:f128b10dfab1 489 remove(oldfname);
WiredHome 8:f128b10dfab1 490 retval = 0;
WiredHome 0:ae5bf432c249 491 } else {
WiredHome 8:f128b10dfab1 492 retval = -1;
WiredHome 0:ae5bf432c249 493 }
WiredHome 0:ae5bf432c249 494 return (retval);
WiredHome 0:ae5bf432c249 495 }
WiredHome 0:ae5bf432c249 496
WiredHome 0:ae5bf432c249 497 //***********************************************************
WiredHome 0:ae5bf432c249 498 // Private version that also works with local file system
WiredHome 0:ae5bf432c249 499 // Returns -1 = error; 0 = success
WiredHome 0:ae5bf432c249 500 //***********************************************************
WiredHome 0:ae5bf432c249 501 int INI::Copy(const char *src, const char *dst)
WiredHome 0:ae5bf432c249 502 {
WiredHome 0:ae5bf432c249 503 int retval = 0;
WiredHome 0:ae5bf432c249 504 int ch;
WiredHome 0:ae5bf432c249 505
WiredHome 8:f128b10dfab1 506 INFO("Copy(%s,%s)", src, dst);
WiredHome 0:ae5bf432c249 507 FILE *fpsrc = fopen(src, "r"); // src file
WiredHome 0:ae5bf432c249 508 FILE *fpdst = fopen(dst, "w"); // dest file
WiredHome 0:ae5bf432c249 509
WiredHome 8:f128b10dfab1 510 if (fpsrc) {
WiredHome 8:f128b10dfab1 511 INFO(" c1a");
WiredHome 8:f128b10dfab1 512 if (fpdst) {
WiredHome 8:f128b10dfab1 513 INFO(" c1b");
WiredHome 8:f128b10dfab1 514 while (1) { // Copy src to dest
WiredHome 8:f128b10dfab1 515 ch = fgetc(fpsrc); // until src EOF read.
WiredHome 8:f128b10dfab1 516 if (ch == EOF) break;
WiredHome 8:f128b10dfab1 517 fputc(ch, fpdst);
WiredHome 8:f128b10dfab1 518 }
WiredHome 8:f128b10dfab1 519 INFO(" c2");
WiredHome 8:f128b10dfab1 520 fclose(fpsrc);
WiredHome 8:f128b10dfab1 521 fclose(fpdst);
WiredHome 8:f128b10dfab1 522 }
WiredHome 0:ae5bf432c249 523 }
WiredHome 8:f128b10dfab1 524 INFO(" c3");
WiredHome 0:ae5bf432c249 525
WiredHome 8:f128b10dfab1 526 if (Exists(dst)) {
WiredHome 8:f128b10dfab1 527 retval = 0;
WiredHome 0:ae5bf432c249 528 } else {
WiredHome 8:f128b10dfab1 529 retval = -1;
WiredHome 0:ae5bf432c249 530 }
WiredHome 8:f128b10dfab1 531 INFO(" c4");
WiredHome 0:ae5bf432c249 532 return (retval);
WiredHome 0:ae5bf432c249 533 }
WiredHome 0:ae5bf432c249 534
WiredHome 0:ae5bf432c249 535
WiredHome 18:282ed56d983b 536 const char * INI::GetReturnMessage(INI_Return retVal) {
WiredHome 18:282ed56d983b 537 if (version == 0) {
WiredHome 18:282ed56d983b 538 switch (retVal) {
WiredHome 18:282ed56d983b 539 default:
WiredHome 18:282ed56d983b 540 case INI_V1_FAIL: return "INI Fail";
WiredHome 18:282ed56d983b 541 case INI_V1_SUCCESS: return "INI Success";
WiredHome 18:282ed56d983b 542 }
WiredHome 18:282ed56d983b 543 } else {
WiredHome 18:282ed56d983b 544 switch (retVal) {
WiredHome 18:282ed56d983b 545 case INI_SUCCESS: return "INI Success - operation succeeded";
WiredHome 18:282ed56d983b 546 case INI_NO_FILE_SPEC: return "INI Fail - no file was specified";
WiredHome 18:282ed56d983b 547 case INI_FILE_NOT_FOUND: return "INI Fail - ini file not found, or failed to open";
WiredHome 18:282ed56d983b 548 case INI_SECTION_NOT_FOUND: return "INI Fail - section not found";
WiredHome 18:282ed56d983b 549 case INI_KEY_NOT_FOUND: return "INI Fail - key not found";
WiredHome 18:282ed56d983b 550 case INI_BUF_TOO_SMALL: return "INI Fail - buffer to small for value";
WiredHome 18:282ed56d983b 551 case INI_INTERNAL_ERROR: return "INI Fail - internal error - can't malloc";
WiredHome 18:282ed56d983b 552 default: return "INI Fail - Code Unknown";
WiredHome 18:282ed56d983b 553 }
WiredHome 18:282ed56d983b 554 }
WiredHome 18:282ed56d983b 555 }
WiredHome 18:282ed56d983b 556
WiredHome 0:ae5bf432c249 557 #if 0
WiredHome 0:ae5bf432c249 558 // Test code for basic regression testing
WiredHome 0:ae5bf432c249 559 //
WiredHome 0:ae5bf432c249 560 #include <stdio.h>
WiredHome 0:ae5bf432c249 561 #include <assert.h>
WiredHome 0:ae5bf432c249 562 #include <string.h>
WiredHome 0:ae5bf432c249 563
WiredHome 0:ae5bf432c249 564 #include "INI.h"
WiredHome 0:ae5bf432c249 565
WiredHome 0:ae5bf432c249 566 #define TESTFILE "test.ini"
WiredHome 0:ae5bf432c249 567
WiredHome 0:ae5bf432c249 568 int main(int argc, char * argv[])
WiredHome 0:ae5bf432c249 569 {
WiredHome 0:ae5bf432c249 570 FILE * fp;
WiredHome 0:ae5bf432c249 571 char buffer[100];
WiredHome 0:ae5bf432c249 572 INI ini(TESTFILE);
WiredHome 0:ae5bf432c249 573
WiredHome 0:ae5bf432c249 574 // Start testing
WiredHome 0:ae5bf432c249 575 _unlink(TESTFILE);
WiredHome 0:ae5bf432c249 576 assert(ini.ReadString("Section 1", "Name 1", buffer, sizeof(buffer)) == false);
WiredHome 0:ae5bf432c249 577
WiredHome 0:ae5bf432c249 578 fp = fopen(TESTFILE, "wt");
WiredHome 0:ae5bf432c249 579 assert(fp);
WiredHome 0:ae5bf432c249 580 fprintf(fp, "[Section 1]\n");
WiredHome 0:ae5bf432c249 581 fprintf(fp, "Name 1=Value 1\n");
WiredHome 0:ae5bf432c249 582 fprintf(fp, "Name 2=Value 2\n");
WiredHome 0:ae5bf432c249 583 fprintf(fp, "\n");
WiredHome 0:ae5bf432c249 584 fprintf(fp, "[Section 2]\n");
WiredHome 0:ae5bf432c249 585 fprintf(fp, "Name 1=Value 2\n");
WiredHome 0:ae5bf432c249 586 fprintf(fp, "Name 2=Value 2\n");
WiredHome 0:ae5bf432c249 587 fprintf(fp, "Name 3=Value 3\n");
WiredHome 0:ae5bf432c249 588 fprintf(fp, "\n");
WiredHome 0:ae5bf432c249 589 fclose(fp);
WiredHome 0:ae5bf432c249 590
WiredHome 0:ae5bf432c249 591 assert(ini.ReadString("Section 2", "Name 2", buffer, sizeof(buffer)) == true);
WiredHome 0:ae5bf432c249 592 assert(strcmp("Value 2", buffer) == 0);
WiredHome 0:ae5bf432c249 593
WiredHome 0:ae5bf432c249 594 assert(ini.ReadString("Section 3", "Name", buffer, sizeof(buffer)) == false);
WiredHome 0:ae5bf432c249 595 assert(ini.ReadString("Section 1", "Name 3", buffer, sizeof(buffer)) == false);
WiredHome 0:ae5bf432c249 596
WiredHome 0:ae5bf432c249 597 assert(ini.WriteString("Section 1", "Name 4", "Value 4") == true);
WiredHome 0:ae5bf432c249 598 assert(ini.ReadString("Section 1", "Name 2", buffer, sizeof(buffer)) == true);
WiredHome 0:ae5bf432c249 599 assert(ini.ReadString("Section 1", "Name 3", buffer, sizeof(buffer)) == false);
WiredHome 0:ae5bf432c249 600 assert(ini.ReadString("Section 1", "Name 4", buffer, sizeof(buffer)) == true);
WiredHome 0:ae5bf432c249 601 assert(strcmp("Value 4", buffer) == 0);
WiredHome 0:ae5bf432c249 602
WiredHome 0:ae5bf432c249 603 assert(ini.WriteString("Section 1", "Name 4", NULL) == true);
WiredHome 0:ae5bf432c249 604 assert(ini.ReadString("Section 1", "Name 4", buffer, sizeof(buffer)) == false);
WiredHome 0:ae5bf432c249 605
WiredHome 0:ae5bf432c249 606 return 0;
WiredHome 0:ae5bf432c249 607 }
WiredHome 0:ae5bf432c249 608 #endif
WiredHome 12:6cf929bde139 609
WiredHome 12:6cf929bde139 610
WiredHome 16:82e0f8747b95 611