IniParser.cpp
1 #include "IniParser.h" 2 3 #include <SDCardManager.h> 4 5 #include <cctype> 6 #include <cstring> 7 8 bool IniParser::parseFile(const char* path, Callback callback) { 9 FsFile file = SdMan.open(path, O_RDONLY); 10 if (!file) { 11 return false; 12 } 13 14 char currentSection[64] = ""; 15 char line[256]; 16 17 while (file.available()) { 18 // Read line 19 size_t len = 0; 20 while (file.available() && len < sizeof(line) - 1) { 21 int c = file.read(); 22 if (c < 0 || c == '\n') break; 23 if (c != '\r') { 24 line[len++] = static_cast<char>(c); 25 } 26 } 27 line[len] = '\0'; 28 29 // Discard remainder of long lines 30 if (len == sizeof(line) - 1) { 31 while (file.available()) { 32 int c = file.read(); 33 if (c < 0 || c == '\n') break; 34 } 35 } 36 37 // Check if this is a section header 38 trimWhitespace(line); 39 if (line[0] == '[') { 40 char* end = strchr(line, ']'); 41 if (end) { 42 *end = '\0'; 43 strncpy(currentSection, line + 1, sizeof(currentSection) - 1); 44 currentSection[sizeof(currentSection) - 1] = '\0'; 45 } 46 continue; 47 } 48 49 // Parse key=value 50 if (!parseLine(line, currentSection, callback)) { 51 file.close(); 52 return true; // Callback requested stop 53 } 54 } 55 56 file.close(); 57 return true; 58 } 59 60 bool IniParser::parseString(const char* content, Callback callback) { 61 if (!content) return false; 62 63 char currentSection[64] = ""; 64 char line[256]; 65 const char* ptr = content; 66 67 while (*ptr) { 68 // Read line 69 size_t len = 0; 70 while (*ptr && *ptr != '\n' && len < sizeof(line) - 1) { 71 if (*ptr != '\r') { 72 line[len++] = *ptr; 73 } 74 ptr++; 75 } 76 line[len] = '\0'; 77 78 // Discard remainder of long lines 79 if (len == sizeof(line) - 1) { 80 while (*ptr && *ptr != '\n') ptr++; 81 } 82 83 if (*ptr == '\n') ptr++; 84 85 // Check if this is a section header 86 trimWhitespace(line); 87 if (line[0] == '[') { 88 char* end = strchr(line, ']'); 89 if (end) { 90 *end = '\0'; 91 strncpy(currentSection, line + 1, sizeof(currentSection) - 1); 92 currentSection[sizeof(currentSection) - 1] = '\0'; 93 } 94 continue; 95 } 96 97 // Parse key=value 98 if (!parseLine(line, currentSection, callback)) { 99 return true; // Callback requested stop 100 } 101 } 102 103 return true; 104 } 105 106 bool IniParser::parseLine(char* line, const char* currentSection, const Callback& callback) { 107 // Skip comments and empty lines 108 if (line[0] == '#' || line[0] == ';' || line[0] == '\0') { 109 return true; 110 } 111 112 // Find '=' 113 char* eq = strchr(line, '='); 114 if (!eq) return true; 115 116 *eq = '\0'; 117 char* key = line; 118 char* value = eq + 1; 119 120 trimWhitespace(key); 121 trimWhitespace(value); 122 123 if (key[0] == '\0') return true; 124 125 return callback(currentSection, key, value); 126 } 127 128 void IniParser::trimWhitespace(char* str) { 129 if (!str || !*str) return; 130 131 // Trim leading 132 char* start = str; 133 while (isspace((unsigned char)*start)) start++; 134 135 // Handle all-whitespace string 136 if (!*start) { 137 *str = '\0'; 138 return; 139 } 140 141 // Trim trailing 142 char* end = start + strlen(start) - 1; 143 while (end > start && isspace((unsigned char)*end)) end--; 144 *(end + 1) = '\0'; 145 146 // Move to beginning if needed 147 if (start != str) { 148 memmove(str, start, strlen(start) + 1); 149 } 150 } 151 152 bool IniParser::parseBool(const char* value, bool defaultValue) { 153 if (!value || !*value) return defaultValue; 154 155 // Check true values 156 if (strcasecmp(value, "true") == 0 || strcasecmp(value, "yes") == 0 || strcasecmp(value, "on") == 0 || 157 strcmp(value, "1") == 0) { 158 return true; 159 } 160 161 // Check false values 162 if (strcasecmp(value, "false") == 0 || strcasecmp(value, "no") == 0 || strcasecmp(value, "off") == 0 || 163 strcmp(value, "0") == 0) { 164 return false; 165 } 166 167 return defaultValue; 168 } 169 170 int IniParser::parseInt(const char* value, int defaultValue) { 171 if (!value || !*value) return defaultValue; 172 173 char* end; 174 long result = strtol(value, &end, 10); 175 if (end == value) return defaultValue; // No conversion 176 177 return static_cast<int>(result); 178 } 179 180 uint8_t IniParser::parseColor(const char* value, uint8_t defaultValue) { 181 if (!value || !*value) return defaultValue; 182 183 if (strcasecmp(value, "black") == 0) return 0x00; 184 if (strcasecmp(value, "white") == 0) return 0xFF; 185 186 // Try numeric 187 int num = parseInt(value, -1); 188 if (num >= 0 && num <= 255) { 189 return static_cast<uint8_t>(num); 190 } 191 192 return defaultValue; 193 }