00001
00002
00005 #include "stdafx.h"
00006 #include "core/alloc_func.hpp"
00007 #include "core/math_func.hpp"
00008 #include "debug.h"
00009 #include "ini_type.h"
00010 #include "string_func.h"
00011 #include "fileio_func.h"
00012
00013 IniItem::IniItem(IniGroup *parent, const char *name, size_t len) : next(NULL), value(NULL), comment(NULL)
00014 {
00015 if (len == 0) len = strlen(name);
00016
00017 this->name = strndup(name, len);
00018 *parent->last_item = this;
00019 parent->last_item = &this->next;
00020 }
00021
00022 IniItem::~IniItem()
00023 {
00024 free(this->name);
00025 free(this->value);
00026 free(this->comment);
00027
00028 delete this->next;
00029 }
00030
00031 void IniItem::SetValue(const char *value)
00032 {
00033 free(this->value);
00034 this->value = strdup(value);
00035 }
00036
00037 IniGroup::IniGroup(IniFile *parent, const char *name, size_t len) : next(NULL), type(IGT_VARIABLES), item(NULL), comment(NULL)
00038 {
00039 if (len == 0) len = strlen(name);
00040
00041 this->name = strndup(name, len);
00042 this->last_item = &this->item;
00043 *parent->last_group = this;
00044 parent->last_group = &this->next;
00045
00046 if (parent->list_group_names == NULL) return;
00047
00048 for (uint i = 0; parent->list_group_names[i] != NULL; i++) {
00049 if (strcmp(this->name, parent->list_group_names[i]) == 0) {
00050 this->type = IGT_LIST;
00051 return;
00052 }
00053 }
00054 }
00055
00056 IniGroup::~IniGroup()
00057 {
00058 free(this->name);
00059 free(this->comment);
00060
00061 delete this->item;
00062 delete this->next;
00063 }
00064
00065 IniItem *IniGroup::GetItem(const char *name, bool create)
00066 {
00067 IniItem *item;
00068 size_t len = strlen(name);
00069
00070 for (item = this->item; item != NULL; item = item->next) {
00071 if (strcmp(item->name, name) == 0) return item;
00072 }
00073
00074 if (!create) return NULL;
00075
00076
00077 return new IniItem(this, name, len);
00078 }
00079
00080 void IniGroup::Clear()
00081 {
00082 delete this->item;
00083 this->item = NULL;
00084 this->last_item = &this->item;
00085 }
00086
00087 IniFile::IniFile(const char **list_group_names) : group(NULL), comment(NULL), list_group_names(list_group_names)
00088 {
00089 this->last_group = &this->group;
00090 }
00091
00092 IniFile::~IniFile()
00093 {
00094 free(this->comment);
00095 delete this->group;
00096 }
00097
00098 IniGroup *IniFile::GetGroup(const char *name, size_t len)
00099 {
00100 IniGroup *group;
00101
00102 if (len == 0) len = strlen(name);
00103
00104
00105 for (group = this->group; group != NULL; group = group->next) {
00106 if (!memcmp(group->name, name, len) && group->name[len] == 0) {
00107 return group;
00108 }
00109 }
00110
00111
00112 group = new IniGroup(this, name, len);
00113 group->comment = strdup("\n");
00114 return group;
00115 }
00116
00117 void IniFile::RemoveGroup(const char *name)
00118 {
00119 size_t len = strlen(name);
00120 IniGroup *prev = NULL;
00121 IniGroup *group;
00122
00123
00124 for (group = this->group; group != NULL; prev = group, group = group->next) {
00125 if (memcmp(group->name, name, len) == 0) {
00126 break;
00127 }
00128 }
00129
00130 if (group == NULL) return;
00131
00132 if (prev != NULL) {
00133 prev->next = prev->next->next;
00134 if (this->last_group == &group->next) this->last_group = &prev->next;
00135 } else {
00136 this->group = this->group->next;
00137 if (this->last_group == &group->next) this->last_group = &this->group;
00138 }
00139
00140 group->next = NULL;
00141 delete group;
00142 }
00143
00144 void IniFile::LoadFromDisk(const char *filename)
00145 {
00146 assert(this->last_group == &this->group);
00147
00148 char buffer[1024], c, *s, *t, *e;
00149 IniGroup *group = NULL;
00150 IniItem *item = NULL;
00151
00152 char *comment = NULL;
00153 uint comment_size = 0;
00154 uint comment_alloc = 0;
00155
00156 size_t end;
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169 FILE *in = FioFOpenFile(filename, "rb", DATA_DIR, &end);
00170 if (in == NULL) return;
00171
00172 end += ftell(in);
00173
00174
00175 while ((size_t)ftell(in) < end && fgets(buffer, sizeof(buffer), in)) {
00176
00177 for (s = buffer; *s == ' ' || *s == '\t'; s++) {}
00178
00179
00180 e = s + strlen(s);
00181 while (e > s && ((c = e[-1]) == '\n' || c == '\r' || c == ' ' || c == '\t')) e--;
00182 *e = '\0';
00183
00184
00185 if (*s == '#' || *s == ';' || *s == '\0') {
00186 uint ns = comment_size + (e - s + 1);
00187 uint a = comment_alloc;
00188 uint pos;
00189
00190 if (ns > a) {
00191 a = max(a, 128U);
00192 do a *= 2; while (a < ns);
00193 comment = ReallocT(comment, comment_alloc = a);
00194 }
00195 pos = comment_size;
00196 comment_size += (e - s + 1);
00197 comment[pos + e - s] = '\n';
00198 memcpy(comment + pos, s, e - s);
00199 continue;
00200 }
00201
00202
00203 if (s[0] == '[') {
00204 if (e[-1] != ']') {
00205 ShowInfoF("ini: invalid group name '%s'", buffer);
00206 } else {
00207 e--;
00208 }
00209 s++;
00210 group = new IniGroup(this, s, e - s);
00211 if (comment_size) {
00212 group->comment = strndup(comment, comment_size);
00213 comment_size = 0;
00214 }
00215 } else if (group) {
00216
00217 if (*s == '\"') {
00218 s++;
00219 for (t = s; *t != '\0' && *t != '\"'; t++) {}
00220 if (*t == '\"') *t = ' ';
00221 } else {
00222 for (t = s; *t != '\0' && *t != '=' && *t != '\t' && *t != ' '; t++) {}
00223 }
00224
00225
00226 item = new IniItem(group, s, t-s);
00227 if (comment_size) {
00228 item->comment = strndup(comment, comment_size);
00229 comment_size = 0;
00230 }
00231
00232
00233 while (*t == '=' || *t == ' ' || *t == '\t') t++;
00234
00235
00236
00237 if (*t == '\"') t++;
00238
00239 e = t + strlen(t);
00240 if (e > t && e[-1] == '\"') e--;
00241 *e = '\0';
00242
00243 item->value = strndup(t, e - t);
00244 } else {
00245
00246 ShowInfoF("ini: '%s' outside of group", buffer);
00247 }
00248 }
00249
00250 if (comment_size > 0) {
00251 this->comment = strndup(comment, comment_size);
00252 comment_size = 0;
00253 }
00254
00255 free(comment);
00256 fclose(in);
00257 }
00258
00259 bool IniFile::SaveToDisk(const char *filename)
00260 {
00261 FILE *f;
00262 IniGroup *group;
00263 IniItem *item;
00264
00265 f = fopen(filename, "w");
00266 if (f == NULL) return false;
00267
00268 for (group = this->group; group != NULL; group = group->next) {
00269 if (group->comment) fputs(group->comment, f);
00270 fprintf(f, "[%s]\n", group->name);
00271 for (item = group->item; item != NULL; item = item->next) {
00272 assert(item->value != NULL);
00273 if (item->comment != NULL) fputs(item->comment, f);
00274
00275
00276 if (strchr(item->name, ' ') != NULL) {
00277 fprintf(f, "\"%s\"", item->name);
00278 } else {
00279 fprintf(f, "%s", item->name);
00280 }
00281
00282 fprintf(f, " = %s\n", item->value);
00283 }
00284 }
00285 if (this->comment) fputs(this->comment, f);
00286
00287 fclose(f);
00288 return true;
00289 }