A simple .ini file interface.

Dependents:   Smart-WiFly-WebServer SignalGenerator WattEye X10Svr

Committer:
WiredHome
Date:
Thu Dec 29 20:14:04 2016 +0000
Revision:
20:392d1ec637eb
Parent:
18:282ed56d983b
Child:
21:a69c8ec96cb1
Revised test cases to match API v2

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 20:392d1ec637eb 275 if (INI::INI_SUCCESS == 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 20:392d1ec637eb 568
WiredHome 20:392d1ec637eb 569 //INI_V1_FAIL = 0, ///< Version 1 return value - Fail
WiredHome 20:392d1ec637eb 570 //INI_V1_SUCCESS = 1, ///< Version 1 return value - Success
WiredHome 20:392d1ec637eb 571 //INI_SUCCESS = 0, ///< Success - operation succeeded
WiredHome 20:392d1ec637eb 572 //INI_NO_FILE_SPEC, ///< Fail - no file was specified
WiredHome 20:392d1ec637eb 573 //INI_FILE_NOT_FOUND, ///< Fail - ini file not found, or failed to open
WiredHome 20:392d1ec637eb 574 //INI_SECTION_NOT_FOUND, ///< Fail - section not found
WiredHome 20:392d1ec637eb 575 //INI_KEY_NOT_FOUND, ///< Fail - key not found
WiredHome 20:392d1ec637eb 576 //INI_BUF_TOO_SMALL, ///< Fail - buffer to small for value
WiredHome 20:392d1ec637eb 577 //INI_INTERNAL_ERROR ///< Fail - internal error - can't alloc buffers
WiredHome 20:392d1ec637eb 578
WiredHome 0:ae5bf432c249 579 int main(int argc, char * argv[])
WiredHome 0:ae5bf432c249 580 {
WiredHome 0:ae5bf432c249 581 FILE * fp;
WiredHome 0:ae5bf432c249 582 char buffer[100];
WiredHome 20:392d1ec637eb 583 INI ini(TESTFILE, 2);
WiredHome 0:ae5bf432c249 584
WiredHome 0:ae5bf432c249 585 // Start testing
WiredHome 0:ae5bf432c249 586 _unlink(TESTFILE);
WiredHome 20:392d1ec637eb 587 assert(INI::INI_FILE_NOT_FOUND == ini.ReadString("Section 1", "Name 1", buffer, sizeof(buffer)));
WiredHome 0:ae5bf432c249 588
WiredHome 0:ae5bf432c249 589 fp = fopen(TESTFILE, "wt");
WiredHome 0:ae5bf432c249 590 assert(fp);
WiredHome 0:ae5bf432c249 591 fprintf(fp, "[Section 1]\n");
WiredHome 0:ae5bf432c249 592 fprintf(fp, "Name 1=Value 1\n");
WiredHome 0:ae5bf432c249 593 fprintf(fp, "Name 2=Value 2\n");
WiredHome 0:ae5bf432c249 594 fprintf(fp, "\n");
WiredHome 0:ae5bf432c249 595 fprintf(fp, "[Section 2]\n");
WiredHome 0:ae5bf432c249 596 fprintf(fp, "Name 1=Value 2\n");
WiredHome 0:ae5bf432c249 597 fprintf(fp, "Name 2=Value 2\n");
WiredHome 0:ae5bf432c249 598 fprintf(fp, "Name 3=Value 3\n");
WiredHome 0:ae5bf432c249 599 fprintf(fp, "\n");
WiredHome 0:ae5bf432c249 600 fclose(fp);
WiredHome 0:ae5bf432c249 601
WiredHome 20:392d1ec637eb 602 assert(INI::INI_SUCCESS == ini.ReadString("Section 2", "Name 2", buffer, sizeof(buffer)));
WiredHome 0:ae5bf432c249 603 assert(strcmp("Value 2", buffer) == 0);
WiredHome 0:ae5bf432c249 604
WiredHome 20:392d1ec637eb 605 assert(INI::INI_SECTION_NOT_FOUND == ini.ReadString("Section 3", "Name", buffer, sizeof(buffer)));
WiredHome 20:392d1ec637eb 606 assert(INI::INI_KEY_NOT_FOUND == ini.ReadString("Section 1", "Name 3", buffer, sizeof(buffer)));
WiredHome 0:ae5bf432c249 607
WiredHome 20:392d1ec637eb 608 assert(INI::INI_SUCCESS == ini.WriteString("Section 1", "Name 4", "Value 4"));
WiredHome 20:392d1ec637eb 609 assert(INI::INI_SUCCESS == ini.ReadString("Section 1", "Name 2", buffer, sizeof(buffer)));
WiredHome 20:392d1ec637eb 610 assert(INI::INI_KEY_NOT_FOUND == ini.ReadString("Section 1", "Name 3", buffer, sizeof(buffer)));
WiredHome 20:392d1ec637eb 611 assert(INI::INI_SUCCESS == ini.ReadString("Section 1", "Name 4", buffer, sizeof(buffer)));
WiredHome 0:ae5bf432c249 612 assert(strcmp("Value 4", buffer) == 0);
WiredHome 0:ae5bf432c249 613
WiredHome 20:392d1ec637eb 614 assert(INI::INI_SUCCESS == ini.WriteString("Section 1", "Name 4", NULL));
WiredHome 20:392d1ec637eb 615 assert(INI::INI_KEY_NOT_FOUND == ini.ReadString("Section 1", "Name 4", buffer, sizeof(buffer)));
WiredHome 0:ae5bf432c249 616
WiredHome 0:ae5bf432c249 617 return 0;
WiredHome 0:ae5bf432c249 618 }
WiredHome 0:ae5bf432c249 619 #endif
WiredHome 12:6cf929bde139 620
WiredHome 12:6cf929bde139 621
WiredHome 16:82e0f8747b95 622