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 *parent->last_item = this;
00030 parent->last_item = &this->next;
00031 }
00032
00034 IniItem::~IniItem()
00035 {
00036 free(this->name);
00037 free(this->value);
00038 free(this->comment);
00039
00040 delete this->next;
00041 }
00042
00047 void IniItem::SetValue(const char *value)
00048 {
00049 free(this->value);
00050 this->value = strdup(value);
00051 }
00052
00059 IniGroup::IniGroup(IniLoadFile *parent, const char *name, size_t len) : next(NULL), type(IGT_VARIABLES), item(NULL), comment(NULL)
00060 {
00061 if (len == 0) len = strlen(name);
00062
00063 this->name = strndup(name, len);
00064 this->last_item = &this->item;
00065 *parent->last_group = this;
00066 parent->last_group = &this->next;
00067
00068 if (parent->list_group_names != NULL) {
00069 for (uint i = 0; parent->list_group_names[i] != NULL; i++) {
00070 if (strcmp(this->name, parent->list_group_names[i]) == 0) {
00071 this->type = IGT_LIST;
00072 return;
00073 }
00074 }
00075 }
00076 if (parent->seq_group_names != NULL) {
00077 for (uint i = 0; parent->seq_group_names[i] != NULL; i++) {
00078 if (strcmp(this->name, parent->seq_group_names[i]) == 0) {
00079 this->type = IGT_SEQUENCE;
00080 return;
00081 }
00082 }
00083 }
00084 }
00085
00087 IniGroup::~IniGroup()
00088 {
00089 free(this->name);
00090 free(this->comment);
00091
00092 delete this->item;
00093 delete this->next;
00094 }
00095
00103 IniItem *IniGroup::GetItem(const char *name, bool create)
00104 {
00105 for (IniItem *item = this->item; item != NULL; item = item->next) {
00106 if (strcmp(item->name, name) == 0) return item;
00107 }
00108
00109 if (!create) return NULL;
00110
00111
00112 return new IniItem(this, name, strlen(name));
00113 }
00114
00118 void IniGroup::Clear()
00119 {
00120 delete this->item;
00121 this->item = NULL;
00122 this->last_item = &this->item;
00123 }
00124
00130 IniLoadFile::IniLoadFile(const char * const *list_group_names, const char * const *seq_group_names) :
00131 group(NULL),
00132 comment(NULL),
00133 list_group_names(list_group_names),
00134 seq_group_names(seq_group_names)
00135 {
00136 this->last_group = &this->group;
00137 }
00138
00140 IniLoadFile::~IniLoadFile()
00141 {
00142 free(this->comment);
00143 delete this->group;
00144 }
00145
00154 IniGroup *IniLoadFile::GetGroup(const char *name, size_t len, bool create_new)
00155 {
00156 if (len == 0) len = strlen(name);
00157
00158
00159 for (IniGroup *group = this->group; group != NULL; group = group->next) {
00160 if (!strncmp(group->name, name, len) && group->name[len] == 0) {
00161 return group;
00162 }
00163 }
00164
00165 if (!create_new) return NULL;
00166
00167
00168 IniGroup *group = new IniGroup(this, name, len);
00169 group->comment = strdup("\n");
00170 return group;
00171 }
00172
00177 void IniLoadFile::RemoveGroup(const char *name)
00178 {
00179 size_t len = strlen(name);
00180 IniGroup *prev = NULL;
00181 IniGroup *group;
00182
00183
00184 for (group = this->group; group != NULL; prev = group, group = group->next) {
00185 if (strncmp(group->name, name, len) == 0) {
00186 break;
00187 }
00188 }
00189
00190 if (group == NULL) return;
00191
00192 if (prev != NULL) {
00193 prev->next = prev->next->next;
00194 if (this->last_group == &group->next) this->last_group = &prev->next;
00195 } else {
00196 this->group = this->group->next;
00197 if (this->last_group == &group->next) this->last_group = &this->group;
00198 }
00199
00200 group->next = NULL;
00201 delete group;
00202 }
00203
00209 void IniLoadFile::LoadFromDisk(const char *filename)
00210 {
00211 assert(this->last_group == &this->group);
00212
00213 char buffer[1024];
00214 IniGroup *group = NULL;
00215
00216 char *comment = NULL;
00217 uint comment_size = 0;
00218 uint comment_alloc = 0;
00219
00220 size_t end;
00221 FILE *in = this->OpenFile(filename, &end);
00222 if (in == NULL) return;
00223
00224 end += ftell(in);
00225
00226
00227 while ((size_t)ftell(in) < end && fgets(buffer, sizeof(buffer), in)) {
00228 char c, *s;
00229
00230 for (s = buffer; *s == ' ' || *s == '\t'; s++) {}
00231
00232
00233 char *e = s + strlen(s);
00234 while (e > s && ((c = e[-1]) == '\n' || c == '\r' || c == ' ' || c == '\t')) e--;
00235 *e = '\0';
00236
00237
00238 if ((group == NULL || group->type != IGT_SEQUENCE) && (*s == '#' || *s == ';' || *s == '\0')) {
00239 uint ns = comment_size + (e - s + 1);
00240 uint a = comment_alloc;
00241
00242 if (ns > a) {
00243 a = max(a, 128U);
00244 do a *= 2; while (a < ns);
00245 comment = ReallocT(comment, comment_alloc = a);
00246 }
00247 uint pos = comment_size;
00248 comment_size += (e - s + 1);
00249 comment[pos + e - s] = '\n';
00250 memcpy(comment + pos, s, e - s);
00251 continue;
00252 }
00253
00254
00255 if (s[0] == '[') {
00256 if (e[-1] != ']') {
00257 this->ReportFileError("ini: invalid group name '", buffer, "'");
00258 } else {
00259 e--;
00260 }
00261 s++;
00262 group = new IniGroup(this, s, e - s);
00263 if (comment_size != 0) {
00264 group->comment = strndup(comment, comment_size);
00265 comment_size = 0;
00266 }
00267 } else if (group != NULL) {
00268 if (group->type == IGT_SEQUENCE) {
00269
00270 IniItem *item = new IniItem(group, buffer, e - buffer);
00271 if (comment_size) {
00272 item->comment = strndup(comment, comment_size);
00273 comment_size = 0;
00274 }
00275 continue;
00276 }
00277 char *t;
00278
00279 if (*s == '\"') {
00280 s++;
00281 for (t = s; *t != '\0' && *t != '\"'; t++) {}
00282 if (*t == '\"') *t = ' ';
00283 } else {
00284 for (t = s; *t != '\0' && *t != '=' && *t != '\t' && *t != ' '; t++) {}
00285 }
00286
00287
00288 IniItem *item = new IniItem(group, s, t - s);
00289 if (comment_size != 0) {
00290 item->comment = strndup(comment, comment_size);
00291 comment_size = 0;
00292 }
00293
00294
00295 while (*t == '=' || *t == ' ' || *t == '\t') t++;
00296
00297 bool quoted = (*t == '\"');
00298
00299 if (*t == '\"') t++;
00300
00301 e = t + strlen(t);
00302 if (e > t && e[-1] == '\"') e--;
00303 *e = '\0';
00304
00305
00306 item->value = (!quoted && e == t) ? NULL : strndup(t, e - t);
00307 } else {
00308
00309 this->ReportFileError("ini: '", buffer, "' outside of group");
00310 }
00311 }
00312
00313 if (comment_size > 0) {
00314 this->comment = strndup(comment, comment_size);
00315 comment_size = 0;
00316 }
00317
00318 free(comment);
00319 fclose(in);
00320 }
00321