ini.c (4425B)
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <ctype.h> 4 #include <string.h> 5 #include "ini.h" 6 7 internal int read_until(FILE* fp, char* buffer, int size, int delim); 8 9 internal int callback(char* section, char* config, char* value, smallDictt *r) 10 { 11 //printf("[%s] \"%s\" == \"%s\"\n", section, config, value); 12 if (isBlankG(section)) { 13 setG(r, config, value); 14 } 15 else { 16 smallDictt *sect = getG(r, rtSmallDictt, section); 17 if (sect) { 18 setG(sect, config, value); 19 setPG(r, section, sect); 20 } 21 else { 22 sect = allocG(rtSmallDictt); 23 setG(sect, config, value); 24 setNFreeG(r, section, sect); 25 } 26 } 27 return 0; 28 } 29 30 /** 31 * @brief Parse an ini file. 32 * @details Parse an ini file. Passes values to a callback function. 33 * No dynamic memory is allocated. 34 * 35 * @param fp Open file pointer to read INI file from 36 * @param callback Callback function accepting three arguments: 37 * section, variable, and value strings. 38 * @return 0 on success, error code on failure 39 */ 40 internal int iniParseFile(FILE* fp, int (*callback)(char*, char*, char*, smallDictt *), smallDictt *r) 41 { 42 if ((fp == NULL) || (callback == NULL)) 43 return -1; 44 45 char section [BUFFER_SIZE] = ""; 46 char config [BUFFER_SIZE] = ""; 47 char value [BUFFER_SIZE] = ""; 48 int c; 49 int err; 50 while((c = getc(fp)) != EOF) { 51 switch(c) { 52 case '#': { 53 while ((c = getc(fp)) != '\n') 54 ; 55 break; 56 } 57 case '[': { 58 err = read_until(fp, section, BUFFER_SIZE, ']'); 59 if (err) 60 return err; 61 break; 62 } 63 case '=': { 64 err = read_until(fp, value, BUFFER_SIZE, '\n'); 65 if (err) 66 return err; 67 err = callback(section, config, value, r); 68 if (err) 69 return err; 70 break; 71 } 72 case '\n': case ' ': case '\t': 73 break; 74 default: 75 ungetc(c, fp); 76 err = read_until(fp, config, BUFFER_SIZE, '='); 77 if (err) 78 return err; 79 break; 80 } 81 } 82 return -1; 83 } 84 85 smallDictt *parseIni(const char *filename) 86 { 87 FILE* fp = fopen(filename, "r"); 88 pTestErrorCmd(fp == NULL, return NULL); 89 90 createAllocateSmallDict(r); 91 iniParseFile(fp, callback, r); 92 fclose(fp); 93 return r; 94 } 95 96 internal int read_until(FILE* fp, char* buffer, int size, int delim) 97 { 98 char c; 99 int i = 0; 100 memset(buffer, 0, size); 101 int string = 0; 102 while (i < size) { 103 c = getc(fp); 104 if(isblank(c) && string == 0) { 105 continue; 106 } else if (c == '\"') { 107 string = 1; 108 } else if (c == delim) { 109 buffer[i] = '\0'; 110 if (delim == '=') 111 ungetc(c, fp); 112 return 0; 113 } else if (c == EOF) { 114 return 0; 115 } 116 buffer[i++] = c; 117 } 118 buffer[i] = '\0'; 119 return -1; 120 } 121 122 /** 123 * @brief Parse an ini file. 124 * @details Parse an ini file. Passes values to a callback function. 125 * No dynamic memory is allocated. 126 * 127 * @param fp Open file pointer to read INI file from 128 * @param callback Callback function accepting three arguments: 129 * section, variable, and value strings. 130 * @return 0 on success, error code on failure 131 */ 132 int ini_parse_file(FILE* fp, int (*callback)(char*, char*, char*)) 133 { 134 if ((fp == NULL) || (callback == NULL)) 135 return -1; 136 137 char section [BUFFER_SIZE] = ""; 138 char config [BUFFER_SIZE] = ""; 139 char value [BUFFER_SIZE] = ""; 140 int c; 141 int err; 142 while((c = getc(fp)) != EOF) { 143 switch(c) { 144 case '#': { 145 while ((c = getc(fp)) != '\n') 146 ; 147 break; 148 } 149 case '[': { 150 err = read_until(fp, section, BUFFER_SIZE, ']'); 151 if (err) 152 return err; 153 break; 154 } 155 case '=': { 156 err = read_until(fp, value, BUFFER_SIZE, '\n'); 157 if (err) 158 return err; 159 err = callback(section, config, value); 160 if (err) 161 return err; 162 break; 163 } 164 case '\n': case ' ': case '\t': 165 break; 166 default: 167 ungetc(c, fp); 168 err = read_until(fp, config, BUFFER_SIZE, '='); 169 if (err) 170 return err; 171 break; 172 } 173 } 174 return -1; 175 } 176 177 bool saveIni(smallDictt *ini, const char *path) { 178 if (!ini || !path) { 179 return false; 180 } 181 createAllocateSmallArray(r); 182 forEachSmallDict(ini, k, D) { 183 cast(smallDictt*, d, D); 184 pushNFreeG(r, catS("[", k, "]")); 185 {forEachSmallDict(d, k2, S) { 186 castS(s, S); 187 if (isBlankG(s)) { 188 pushNFreeG(r, catS(k2, " =")); 189 } 190 else { 191 pushNFreeG(r, catS(k2, " = ", ssGet(s))); 192 } 193 finishG(s); 194 } 195 listFreeS(libsheepyInternalKeys); 196 } 197 pushG(r, ""); 198 finishG(d); 199 } 200 listFreeS(libsheepyInternalKeys); 201 writeFileG(r, path); 202 return true; 203 } 204 205 206 bool checkLibsheepyVersionIni(const char *currentLibsheepyVersion) { 207 return eqG(currentLibsheepyVersion, LIBSHEEPY_VERSION); 208 } 209