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) error("not enough memory to allocate group name");
00067 str_validate(this->name, this->name + len);
00068
00069 this->last_item = &this->item;
00070 *parent->last_group = this;
00071 parent->last_group = &this->next;
00072
00073 if (parent->list_group_names != NULL) {
00074 for (uint i = 0; parent->list_group_names[i] != NULL; i++) {
00075 if (strcmp(this->name, parent->list_group_names[i]) == 0) {
00076 this->type = IGT_LIST;
00077 return;
00078 }
00079 }
00080 }
00081 if (parent->seq_group_names != NULL) {
00082 for (uint i = 0; parent->seq_group_names[i] != NULL; i++) {
00083 if (strcmp(this->name, parent->seq_group_names[i]) == 0) {
00084 this->type = IGT_SEQUENCE;
00085 return;
00086 }
00087 }
00088 }
00089 }
00090
00092 IniGroup::~IniGroup()
00093 {
00094 free(this->name);
00095 free(this->comment);
00096
00097 delete this->item;
00098 delete this->next;
00099 }
00100
00108 IniItem *IniGroup::GetItem(const char *name, bool create)
00109 {
00110 for (IniItem *item = this->item; item != NULL; item = item->next) {
00111 if (strcmp(item->name, name) == 0) return item;
00112 }
00113
00114 if (!create) return NULL;
00115
00116
00117 return new IniItem(this, name, strlen(name));
00118 }
00119
00123 void IniGroup::Clear()
00124 {
00125 delete this->item;
00126 this->item = NULL;
00127 this->last_item = &this->item;
00128 }
00129
00135 IniLoadFile::IniLoadFile(const char * const *list_group_names, const char * const *seq_group_names) :
00136 group(NULL),
00137 comment(NULL),
00138 list_group_names(list_group_names),
00139 seq_group_names(seq_group_names)
00140 {
00141 this->last_group = &this->group;
00142 }
00143
00145 IniLoadFile::~IniLoadFile()
00146 {
00147 free(this->comment);
00148 delete this->group;
00149 }
00150
00159 IniGroup *IniLoadFile::GetGroup(const char *name, size_t len, bool create_new)
00160 {
00161 if (len == 0) len = strlen(name);
00162
00163
00164 for (IniGroup *group = this->group; group != NULL; group = group->next) {
00165 if (!strncmp(group->name, name, len) && group->name[len] == 0) {
00166 return group;
00167 }
00168 }
00169
00170 if (!create_new) return NULL;
00171
00172
00173 IniGroup *group = new IniGroup(this, name, len);
00174 group->comment = strdup("\n");
00175 return group;
00176 }
00177
00182 void IniLoadFile::RemoveGroup(const char *name)
00183 {
00184 size_t len = strlen(name);
00185 IniGroup *prev = NULL;
00186 IniGroup *group;
00187
00188
00189 for (group = this->group; group != NULL; prev = group, group = group->next) {
00190 if (strncmp(group->name, name, len) == 0) {
00191 break;
00192 }
00193 }
00194
00195 if (group == NULL) return;
00196
00197 if (prev != NULL) {
00198 prev->next = prev->next->next;
00199 if (this->last_group == &group->next) this->last_group = &prev->next;
00200 } else {
00201 this->group = this->group->next;
00202 if (this->last_group == &group->next) this->last_group = &this->group;
00203 }
00204
00205 group->next = NULL;
00206 delete group;
00207 }
00208
00215 void IniLoadFile::LoadFromDisk(const char *filename, Subdirectory subdir)
00216 {
00217 assert(this->last_group == &this->group);
00218
00219 char buffer[1024];
00220 IniGroup *group = NULL;
00221
00222 char *comment = NULL;
00223 uint comment_size = 0;
00224 uint comment_alloc = 0;
00225
00226 size_t end;
00227 FILE *in = this->OpenFile(filename, subdir, &end);
00228 if (in == NULL) return;
00229
00230 end += ftell(in);
00231
00232
00233 while ((size_t)ftell(in) < end && fgets(buffer, sizeof(buffer), in)) {
00234 char c, *s;
00235
00236 for (s = buffer; *s == ' ' || *s == '\t'; s++) {}
00237
00238
00239 char *e = s + strlen(s);
00240 while (e > s && ((c = e[-1]) == '\n' || c == '\r' || c == ' ' || c == '\t')) e--;
00241 *e = '\0';
00242
00243
00244 if ((group == NULL || group->type != IGT_SEQUENCE) && (*s == '#' || *s == ';' || *s == '\0')) {
00245 uint ns = comment_size + (e - s + 1);
00246 uint a = comment_alloc;
00247
00248 if (ns > a) {
00249 a = max(a, 128U);
00250 do a *= 2; while (a < ns);
00251 comment = ReallocT(comment, comment_alloc = a);
00252 }
00253 uint pos = comment_size;
00254 comment_size += (e - s + 1);
00255 comment[pos + e - s] = '\n';
00256 memcpy(comment + pos, s, e - s);
00257 continue;
00258 }
00259
00260
00261 if (s[0] == '[') {
00262 if (e[-1] != ']') {
00263 this->ReportFileError("ini: invalid group name '", buffer, "'");
00264 } else {
00265 e--;
00266 }
00267 s++;
00268 group = new IniGroup(this, s, e - s);
00269 if (comment_size != 0) {
00270 group->comment = strndup(comment, comment_size);
00271 comment_size = 0;
00272 }
00273 } else if (group != NULL) {
00274 if (group->type == IGT_SEQUENCE) {
00275
00276 IniItem *item = new IniItem(group, buffer, e - buffer);
00277 if (comment_size) {
00278 item->comment = strndup(comment, comment_size);
00279 comment_size = 0;
00280 }
00281 continue;
00282 }
00283 char *t;
00284
00285 if (*s == '\"') {
00286 s++;
00287 for (t = s; *t != '\0' && *t != '\"'; t++) {}
00288 if (*t == '\"') *t = ' ';
00289 } else {
00290 for (t = s; *t != '\0' && *t != '=' && *t != '\t' && *t != ' '; t++) {}
00291 }
00292
00293
00294 IniItem *item = new IniItem(group, s, t - s);
00295 if (comment_size != 0) {
00296 item->comment = strndup(comment, comment_size);
00297 comment_size = 0;
00298 }
00299
00300
00301 while (*t == '=' || *t == ' ' || *t == '\t') t++;
00302
00303 bool quoted = (*t == '\"');
00304
00305 if (*t == '\"') t++;
00306
00307 e = t + strlen(t);
00308 if (e > t && e[-1] == '\"') e--;
00309 *e = '\0';
00310
00311
00312 item->value = (!quoted && e == t) ? NULL : strndup(t, e - t);
00313 if (item->value != NULL) str_validate(item->value, item->value + strlen(item->value));
00314 } else {
00315
00316 this->ReportFileError("ini: '", buffer, "' outside of group");
00317 }
00318 }
00319
00320 if (comment_size > 0) {
00321 this->comment = strndup(comment, comment_size);
00322 comment_size = 0;
00323 }
00324
00325 free(comment);
00326 fclose(in);
00327 }
00328