A simple .ini file interface.
Dependents: Smart-WiFly-WebServer SignalGenerator WattEye X10Svr
Diff: IniManager.cpp
- Revision:
- 0:ae5bf432c249
- Child:
- 1:1e2ee9bbee40
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/IniManager.cpp Mon Aug 12 22:57:54 2013 +0000
@@ -0,0 +1,361 @@
+// Simple INI file manager.
+//
+#ifdef WIN32
+#include "string.h"
+#include "stdlib.h"
+#include "stdio.h"
+#else
+#include "mbed.h"
+#endif
+
+#include "IniManager.h"
+
+INI::INI(const char * file)
+ : iniFile(0)
+{
+ if (file) {
+ iniFile = (char *)malloc(strlen(file)+1);
+ if (iniFile)
+ strcpy(iniFile, file);
+ }
+ FILE * fo = fopen("/local/test.txt", "wt");
+ if (fo) {
+ printf("Writing to /local/test.txt\r\n");
+ fprintf(fo, "This is three - %d\r\n", 3);
+ fclose(fo);
+ }
+}
+
+
+INI::~INI(void)
+{
+ if (iniFile)
+ free(iniFile);
+}
+
+
+bool INI::ReadString(const char * section, const char * key, char * buffer, size_t bufferSize, const char * defaultString)
+{
+ bool found = false;
+ if (!iniFile)
+ return found;
+ CrashRecover();
+ printf("ReadString from %s\r\n", iniFile);
+ FILE * fp = fopen(iniFile,"rt");
+ if (fp) {
+ char buf[INTERNAL_BUF_SIZE];
+ bool inSection = (section == NULL) ? true : false;
+
+ while(fgets(buf, sizeof(buf), fp)) {
+ int x = strlen(buf) - 1; // remove trailing \r\n combinations
+ while (x >= 0 && buf[x] < ' ')
+ buf[x--] = '\0';
+ printf("read in [%s]\r\n", buf);
+ if (inSection && buf[0] != '[') {
+ char * eq = strchr(buf, '=');
+ if (eq) {
+ *eq++ = '\0';
+ if ( (strcmp(buf,key) == 0) && (strlen(eq) <= bufferSize) ) {
+ strcpy(buffer, eq);
+ memset(buf, 0, INTERNAL_BUF_SIZE); // secure the memory space
+ found = true;
+ break;
+ }
+ }
+ } else {
+ if (buf[0] == '[') {
+ char * br = strchr(buf, ']');
+ inSection = false;
+ if (br) {
+ *br = '\0';
+ if (strcmp(buf+1, section) == 0)
+ inSection = true;
+ }
+ }
+ }
+ }
+ fclose(fp);
+ }
+ if (!found && defaultString != NULL && *defaultString) {
+ strncpy(buffer, defaultString, bufferSize);
+ buffer[bufferSize-1] = '\0';
+ printf("sub %s.\r\n", buffer);
+ found = true;
+ }
+ return found;
+}
+
+bool INI::CrashRecover()
+{
+ char * newFile = (char *)malloc(strlen(iniFile)+1);
+ char * bakFile = (char *)malloc(strlen(iniFile)+1);
+
+ if (newFile && bakFile) {
+ printf("*** CrashRecover\r\n");
+ strcpy(bakFile, iniFile);
+ strcpy(newFile, iniFile);
+ strcpy(bakFile + strlen(bakFile) - 4, ".bak");
+ strcpy(newFile + strlen(newFile) - 4, ".new");
+
+ FILE * repair = fopen(newFile, "rt");
+ if (repair) {
+ // helps recover if the system crashed before it could swap in the new file
+ printf("*** repairing\r\n");
+ fclose(repair);
+ int i;
+ i = remove(bakFile); // remove an old .bak
+ printf("remove(%s) returned %d\r\n", bakFile, i);
+ i = Rename(iniFile, bakFile); // move the existing .ini to .bak
+ printf("rename(%s,%s) returned %d\r\n", iniFile, bakFile, i);
+ i = Rename(newFile, iniFile); // move the new .new to .ini
+ printf("rename(%s,%s) returned %d\r\n", newFile, iniFile, i);
+ }
+ }
+ free(newFile);
+ free(bakFile);
+ return true;
+}
+
+// Create the new version as .new
+// once complete, if something actually changed, then rename the .ini to .bak and rename the .new to .ini
+// once complete, if nothing actually changed, then delete the .new
+//
+bool INI::WriteString(const char * section, const char * key, char * value)
+{
+ bool found = false;
+ bool fileChanged = false;
+
+ if (!iniFile || (value != NULL && strlen(value) > INTERNAL_BUF_SIZE))
+ return found;
+
+ char * newFile = (char *)malloc(strlen(iniFile)+1);
+ char * bakFile = (char *)malloc(strlen(iniFile)+1);
+ if (!newFile)
+ return found; // no memory
+ if (!bakFile) {
+ free(newFile);
+ return found;
+ }
+ strcpy(bakFile, iniFile);
+ strcpy(newFile, iniFile);
+ strcpy(bakFile + strlen(bakFile) - 4, ".bak");
+ strcpy(newFile + strlen(newFile) - 4, ".new");
+
+ CrashRecover();
+
+ printf("Opening [%s] and [%s]\r\n", iniFile, newFile);
+ FILE * fi = fopen(iniFile, "rt");
+ FILE * fo = fopen(newFile, "wt");
+ if (fo) {
+ char buf[INTERNAL_BUF_SIZE];
+ bool inSection = (section == NULL) ? true : false;
+
+ if (fi) {
+ while(fgets(buf, sizeof(buf), fi)) {
+ // if not inSection, copy across
+ // if inSection and not key, copy across
+ // if InSection and key, write new value (or skip if value is null)
+ int x = strlen(buf) - 1; // remove trailing \r\n combinations
+ while (x >= 0 && buf[x] < ' ')
+ buf[x--] = '\0';
+ if (inSection && buf[0] != '[') {
+ char * eq = strchr(buf, '=');
+ if (eq) {
+ *eq++ = '\0';
+ if (strcmp(buf,key) == 0) {
+ if (value != NULL && strcmp(eq, value) != 0) {
+ // replace the old record
+ if (value != NULL) {
+ fprintf(fo, "%s=%s\n", key, value);
+ printf("write: %s=%s\r\n", key, value);
+ }
+ }
+ fileChanged = true;
+ inSection = false;
+ found = true;
+ } else {
+ // write old record
+ fprintf(fo, "%s=%s\n", buf, eq);
+ printf("write: %s=%s\r\n", buf, eq);
+ }
+ } else {
+ // what to do with unknown record(s)?
+ // fprintf(fo, "%s\n", buf); // eliminate them
+ }
+ } else {
+ if (buf[0] == '[') {
+ char * br = strchr(buf, ']');
+ if (inSection) { // found next section while in good section
+ // Append new record to desired section
+ if (value != NULL) {
+ fprintf(fo, "%s=%s\r\n", key, value);
+ printf("write: %s=%s\r\n", key, value);
+ fileChanged = true;
+ }
+ found = true;
+ }
+ inSection = false;
+ // write old record
+ fprintf(fo, "%s\r\n", buf);
+ printf("write: %s\r\n", buf);
+ if (br) {
+ *br = '\0';
+ if (strcmp(buf+1, section) == 0)
+ inSection = true;
+ }
+ } else {
+ // copy unaltered records across
+ if (buf[0]) {
+ fprintf(fo, "%s\r\n", buf);
+ printf("write: %s\r\n", buf);
+ }
+ }
+ }
+ }
+ printf("close %s\r\n", iniFile);
+ fclose(fi);
+ }
+ if (!found) {
+ // No old file, just create it now
+ if (value != NULL) {
+ if (!inSection) {
+ fprintf(fo, "[%s]\r\n", section);
+ printf("write: [%s]\r\n", section);
+ }
+ fprintf(fo, "%s=%s\r\n", key, value);
+ printf("write: %s=%s\r\n", key, value);
+ fileChanged = true;
+ }
+ found = true;
+ }
+ printf("close %s\r\n", newFile);
+ fclose(fo);
+ }
+ if (fileChanged) {
+ printf("remove bak, rename ini to bak, rename new to ini\r\n");
+ remove(bakFile); // remove an old .bak
+ Rename(iniFile, bakFile); // move the existing .ini to .bak
+ Rename(newFile, iniFile); // move the new .new to .ini
+ wait(1);
+ }
+ free(newFile);
+ free(bakFile);
+ return found;
+}
+
+
+//***********************************************************
+// Private version that also works with local file system
+// Returns -1 = error; 0 = success
+//***********************************************************
+int INI::Rename(const char *oldfname, const char *newfname)
+{
+ int retval = 0;
+ int ch;
+
+ FILE *fpold = fopen(oldfname, "r"); // src file
+ FILE *fpnew = fopen(newfname, "w"); // dest file
+
+ while (1) { // Copy src to dest
+ ch = fgetc(fpold); // until src EOF read.
+ if (ch == EOF) break;
+ fputc(ch, fpnew);
+ }
+
+ fclose(fpnew);
+ fclose(fpold);
+
+ fpnew = fopen(newfname, "r"); // Reopen dest to insure
+ if(fpnew == NULL) { // that it was created.
+ retval = (-1); // Return Error.
+ } else {
+ fclose(fpnew);
+ remove(oldfname); // Remove original file.
+ retval = (0); // Return Success.
+ }
+ return (retval);
+}
+
+//***********************************************************
+// Private version that also works with local file system
+// Returns -1 = error; 0 = success
+//***********************************************************
+int INI::Copy(const char *src, const char *dst)
+{
+ int retval = 0;
+ int ch;
+
+ FILE *fpsrc = fopen(src, "r"); // src file
+ FILE *fpdst = fopen(dst, "w"); // dest file
+
+ while (1) { // Copy src to dest
+ ch = fgetc(fpsrc); // until src EOF read.
+ if (ch == EOF) break;
+ fputc(ch, fpdst);
+ }
+ fclose(fpsrc);
+ fclose(fpdst);
+
+ fpdst = fopen(dst, "r"); // Reopen dest to insure
+ if(fpdst == NULL) { // that it was created.
+ retval = (-1); // Return error.
+ } else {
+ fclose(fpdst);
+ retval = (0); // Return success.
+ }
+ return (retval);
+}
+
+
+#if 0
+// Test code for basic regression testing
+//
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+#include "INI.h"
+
+#define TESTFILE "test.ini"
+
+int main(int argc, char * argv[])
+{
+ FILE * fp;
+ char buffer[100];
+ INI ini(TESTFILE);
+
+ // Start testing
+ _unlink(TESTFILE);
+ assert(ini.ReadString("Section 1", "Name 1", buffer, sizeof(buffer)) == false);
+
+ fp = fopen(TESTFILE, "wt");
+ assert(fp);
+ fprintf(fp, "[Section 1]\n");
+ fprintf(fp, "Name 1=Value 1\n");
+ fprintf(fp, "Name 2=Value 2\n");
+ fprintf(fp, "\n");
+ fprintf(fp, "[Section 2]\n");
+ fprintf(fp, "Name 1=Value 2\n");
+ fprintf(fp, "Name 2=Value 2\n");
+ fprintf(fp, "Name 3=Value 3\n");
+ fprintf(fp, "\n");
+ fclose(fp);
+
+ assert(ini.ReadString("Section 2", "Name 2", buffer, sizeof(buffer)) == true);
+ assert(strcmp("Value 2", buffer) == 0);
+
+ assert(ini.ReadString("Section 3", "Name", buffer, sizeof(buffer)) == false);
+ assert(ini.ReadString("Section 1", "Name 3", buffer, sizeof(buffer)) == false);
+
+ assert(ini.WriteString("Section 1", "Name 4", "Value 4") == true);
+ assert(ini.ReadString("Section 1", "Name 2", buffer, sizeof(buffer)) == true);
+ assert(ini.ReadString("Section 1", "Name 3", buffer, sizeof(buffer)) == false);
+ assert(ini.ReadString("Section 1", "Name 4", buffer, sizeof(buffer)) == true);
+ assert(strcmp("Value 4", buffer) == 0);
+
+ assert(ini.WriteString("Section 1", "Name 4", NULL) == true);
+ assert(ini.ReadString("Section 1", "Name 4", buffer, sizeof(buffer)) == false);
+
+ return 0;
+}
+#endif