00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "core/alloc_func.hpp"
00014 #include "core/mem_func.hpp"
00015 #include "ini_type.h"
00016 #include "string_func.h"
00017
00024 IniItem::IniItem(IniGroup *parent, const char *name, size_t len) : next(NULL), value(NULL), comment(NULL)
00025 {
00026 if (len == 0) len = strlen(name);
00027
00028 this->name = strndup(name, len);
00029 if (this->name != NULL) str_validate(this->name, this->name + len);
00030
00031 *parent->last_item = this;
00032 parent->last_item = &this->next;
00033 }
00034
00036 IniItem::~IniItem()
00037 {
00038 free(this->name);
00039 free(this->value);
00040 free(this->comment);
00041
00042 delete this->next;
00043 }
00044
00049 void IniItem::SetValue(const char *value)
00050 {
00051 free(this->value);
00052 this->value = strdup(value);
00053 }
00054
00061 IniGroup::IniGroup(IniLoadFile *parent, const char *name, size_t len) : next(NULL), type(IGT_VARIABLES), item(NULL), comment(NULL)
00062 {
00063 if (len == 0) len = strlen(name);
00064
00065 this->name = strndup(name, len);
00066 if (this->name != NULL) str_validate(this->name, this->name + len);
00067
00068 this->last_item = &this->item;
00069 *parent->last_group = this;
00070 parent->last_group = &this->next;
00071
00072 if (parent->list_group_names != NULL) {
00073 for (uint i = 0; parent->list_group_names[i] != NULL; i++) {
00074 if (strcmp(this->name, parent->list_group_names[i]) == 0) {
00075 this->type = IGT_LIST;
00076 return;
00077 }
00078 }
00079 }
00080 if (parent->seq_group_names != NULL) {
00081 for (uint i = 0; parent->seq_group_names[i] != NULL; i++) {
00082 if (strcmp(this->name, parent->seq_group_names[i]) == 0) {
00083 this->type = IGT_SEQUENCE;
00084 return;
00085 }
00086 }
00087 }
00088 }
00089
00091 IniGroup::~IniGroup()
00092 {
00093 free(this->name);
00094 free(this->comment);
00095
00096 delete this->item;
00097 delete this->next;
00098 }
00099
00107 IniItem *IniGroup::GetItem(const char *name, bool create)
00108 {
00109 for (IniItem *item = this->item; item != NULL; item = item->next) {
00110 if (strcmp(item->name, name) == 0) return item;
00111 }
00112
00113 if (!create) return NULL;
00114
00115
00116 return new IniItem(this, name, strlen(name));
00117 }
00118
00122 void IniGroup::Clear()
00123 {
00124 delete this->item;
00125 this->item = NULL;
00126 this->last_item = &this->item;
00127 }
00128
00134 IniLoadFile::IniLoadFile(const char * const *list_group_names, const char * const *seq_group_names) :
00135 group(NULL),
00136 comment(NULL),
00137 list_group_names(list_group_names),
00138 seq_group_names(seq_group_names)
00139 {
00140 this->last_group = &this->group;
00141 }
00142
00144 IniLoadFile::~IniLoadFile()
00145 {
00146 free(this->comment);
00147 delete this->group;
00148 }
00149
00158 IniGroup *IniLoadFile::GetGroup(const char *name, size_t len, bool create_new)
00159 {
00160 if (len == 0) len = strlen(name);
00161
00162
00163 for (IniGroup *group = this->group; group != NULL; group = group->next) {
00164 if (!strncmp(group->name, name, len) && group->name[len] == 0) {
00165 return group;
00166 }
00167 }
00168
00169 if (!create_new) return NULL;
00170
00171
00172 IniGroup *group = new IniGroup(this, name, len);
00173 group->comment = strdup("\n");
00174 return group;
00175 }
00176
00181 void IniLoadFile::RemoveGroup(const char *name)
00182 {
00183 size_t len = strlen(name);
00184 IniGroup *prev = NULL;
00185 IniGroup *group;
00186
00187
00188 for (group = this->group; group != NULL; prev = group, group = group->next) {
00189 if (strncmp(group->name, name, len) == 0) {
00190 break;
00191 }
00192 }
00193
00194 if (group == NULL) return;
00195
00196 if (prev != NULL) {
00197 prev->next = prev->next->next;
00198 if (this->last_group == &group->next) this->last_group = &prev->next;
00199 } else {
00200 this->group = this->group->next;
00201 if (this->last_group == &group->next) this->last_group = &this->group;
00202 }
00203
00204 group->next = NULL;
00205 delete group;
00206 }
00207
00214 void IniLoadFile::LoadFromDisk(const char *filename, Subdirectory subdir)
00215 {
00216 assert(this->last_group == &this->group);
00217
00218 char buffer[1024];
00219 IniGroup *group = NULL;
00220
00221 char *comment = NULL;
00222 uint comment_size = 0;
00223 uint comment_alloc = 0;
00224
00225 size_t end;
00226 FILE *in = this->OpenFile(filename, subdir, &end);
00227 if (in == NULL) return;
00228
00229 end += ftell(in);
00230
00231
00232 while ((size_t)ftell(in) < end && fgets(buffer, sizeof(buffer), in)) {
00233 char c, *s;
00234
00235 for (s = buffer; *s == ' ' || *s == '\t'; s++) {}
00236
00237
00238 char *e = s + strlen(s);
00239 while (e > s && ((c = e[-1]) == '\n' || c == '\r' || c == ' ' || c == '\t')) e--;
00240 *e = '\0';
00241
00242
00243 if ((group == NULL || group->type != IGT_SEQUENCE) && (*s == '#' || *s == ';' || *s == '\0')) {
00244 uint ns = comment_size + (e - s + 1);
00245 uint a = comment_alloc;
00246
00247 if (ns > a) {
00248 a = max(a, 128U);
00249 do a *= 2; while (a < ns);
00250 comment = ReallocT(comment, comment_alloc = a);
00251 }
00252 uint pos = comment_size;
00253 comment_size += (e - s + 1);
00254 comment[pos + e - s] = '\n';
00255 memcpy(comment + pos, s, e - s);
00256 continue;
00257 }
00258
00259
00260 if (s[0] == '[') {
00261 if (e[-1] != ']') {
00262 this->ReportFileError("ini: invalid group name '", buffer, "'");
00263 } else {
00264 e--;
00265 }
00266 s++;
00267 group = new IniGroup(this, s, e - s);
00268 if (comment_size != 0) {
00269 group->comment = strndup(comment, comment_size);
00270 comment_size = 0;
00271 }
00272 } else if (group != NULL) {
00273 if (group->type == IGT_SEQUENCE) {
00274
00275 IniItem *item = new IniItem(group, buffer, e - buffer);
00276 if (comment_size) {
00277 item->comment = strndup(comment, comment_size);
00278 comment_size = 0;
00279 }
00280 continue;
00281 }
00282 char *t;
00283
00284 if (*s == '\"') {
00285 s++;
00286 for (t = s; *t != '\0' && *t != '\"'; t++) {}
00287 if (*t == '\"') *t = ' ';
00288 } else {
00289 for (t = s; *t != '\0' && *t != '=' && *t != '\t' && *t != ' '; t++) {}
00290 }
00291
00292
00293 IniItem *item = new IniItem(group, s, t - s);
00294 if (comment_size != 0) {
00295 item->comment = strndup(comment, comment_size);
00296 comment_size = 0;
00297 }
00298
00299
00300 while (*t == '=' || *t == ' ' || *t == '\t') t++;
00301
00302 bool quoted = (*t == '\"');
00303
00304 if (*t == '\"') t++;
00305
00306 e = t + strlen(t);
00307 if (e > t && e[-1] == '\"') e--;
00308 *e = '\0';
00309
00310
00311 item->value = (!quoted && e == t) ? NULL : strndup(t, e - t);
00312 if (item->value != NULL) str_validate(item->value, item->value + strlen(item->value));
00313 } else {
00314
00315 this->ReportFileError("ini: '", buffer, "' outside of group");
00316 }
00317 }
00318
00319 if (comment_size > 0) {
00320 this->comment = strndup(comment, comment_size);
00321 comment_size = 0;
00322 }
00323
00324 free(comment);
00325 fclose(in);
00326 }
00327