00001
00002
00003
00004
00005
00006 #include "iniparser.h"
00007
00008 #include <stdarg.h>
00009 #include <errno.h>
00010 #include <string.h>
00011 #include <stdlib.h>
00012
00013 #ifdef WIN32
00014 #define _WIN32_WINNT 0x400
00015 #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
00016
00017 #include <windows.h>
00018 #else
00019 #include <stdio.h>
00020 #endif
00021
00022 void errorPrint(const char* szMessage, ...)
00023 {
00024 va_list arglist;
00025 char str[256];
00026
00027 va_start(arglist, szMessage);
00028
00029 vsprintf(str, szMessage, arglist);
00030 va_end(arglist);
00031
00032 #ifdef WIN32
00033 MessageBoxA(NULL, str, "Error", MB_ICONERROR | MB_OK);
00034 #else
00035 fprintf(stderr, "%s\n", str);
00036 #endif
00037 }
00038
00039 IniParser::IniParser(void *userdata) : in(0), userdata(userdata), col(0), line(1)
00040 {
00041 }
00042
00043 int IniParser::readChar() {
00044 int c= fgetc(in);
00045 if (c=='\n') {
00046 line++;
00047 col=0;
00048 }
00049 col++;
00050 return c;
00051 }
00052
00053 int IniParser::getChar() {
00054
00055 int c = readChar();
00056
00057 if (c=='#') {
00058 while ((c=readChar()) != '\n') {
00059 if (feof(in))
00060 break;
00061 }
00062 }
00063 return c;
00064 }
00065
00066 bool IniParser::nextToken() {
00067 const char *blanks=" \t\r\n";
00068 const char *endstring = "\"";
00069 const char *onecharToken = "[]=";
00070 char blanksAndOnecharToken[32];
00071 const char *stop;
00072 int c;
00073 int count = 0;
00074 bool inString = false;
00075
00076
00077 do {
00078 c= getChar();
00079 } while (strchr(blanks,c));
00080
00081
00082 if (strchr(onecharToken, c)) {
00083 buffer[0] = c;
00084 buffer[1] = 0;
00085 return !feof(in);
00086 }
00087
00088
00089 if (c=='"') {
00090 stop = endstring;
00091 inString = true;
00092 } else {
00093 stop = blanksAndOnecharToken;
00094 sprintf(blanksAndOnecharToken, "%s%s", blanks, onecharToken);
00095 buffer[count++] = c;
00096 }
00097
00098
00099 while (count < (LOADER_BUFFER_LENGTH - 1)) {
00100 if (inString)
00101 c = readChar();
00102 else
00103 c = getChar();
00104
00105 if (strchr(stop, c) || c == EOF) {
00106 if (strchr(onecharToken, c)) {
00107 if (c == '\n')
00108 --line;
00109 --col;
00110 ungetc(c, in);
00111 }
00112 buffer[count]=0;
00113 break;
00114 } else {
00115 buffer[count++]=c;
00116 }
00117 }
00118
00119 buffer[LOADER_BUFFER_LENGTH-1]=0;
00120 return !feof(in);
00121 }
00122
00123 bool IniParser::parse(const char *filename) {
00124 this->filename = filename;
00125 return parse(fopen(filename, "rt"));
00126 }
00127
00128 bool IniParser::wparse(const wchar_t *filename) {
00129 #ifdef WIN32
00130 int len = int(wcslen(filename))*2;
00131 this->filename = new char[len];
00132 if (WideCharToMultiByte(CP_ACP, 0, filename, -1, (LPSTR) this->filename, len, "?", NULL) == 0) {
00133 DWORD err = GetLastError();
00134 errorPrint("unable to translate string! err=%d", err);
00135 delete[] this->filename;
00136 this->filename =0;
00137 return false;
00138 }
00139 return parse(_wfopen(filename, L"rt"));
00140 #else
00141 return false;
00142 #endif
00143 }
00144
00145 bool IniParser::parse(FILE *f) {
00146
00147 in = f;
00148
00149 if (in==0) {
00150 errorPrint("%s: %s", filename, strerror( errno ));
00151 return false;
00152 }
00153
00154 nextToken();
00155 while (!feof(in)) {
00156
00157 if (strcmp(buffer, "[") ==0) {
00158 if (!readNextSection()) {
00159 printError("failed to read section");
00160 fclose(in);
00161 in=0;
00162 return false;
00163 }
00164 } else {
00165 printError("expecting '['");
00166 fclose(in);
00167 in=0;
00168 return false;
00169 }
00170 }
00171
00172 fclose(in);
00173 in=0;
00174 return true;
00175 }
00176
00177 void IniParser::printError(const char *err) {
00178 errorPrint("%s:%d:%d (%s) %s\n",
00179 filename,
00180 line,
00181 col,
00182 buffer,
00183 err);
00184 }
00185
00186 bool IniParser::readNextSection() {
00187
00188 if (strcmp(buffer, "[") !=0) return false;
00189
00190 nextToken();
00191
00192 char *sectionName = new char[strlen(buffer)+1];
00193 strcpy(sectionName, buffer);
00194
00195 nextToken();
00196
00197 if (strcmp(buffer, "]") != 0) {
00198
00199 delete[] sectionName;
00200 printError("expecting ']'");
00201 return false;
00202 }
00203
00204 for (IniSectionVector::iterator it(sections.begin()); it != sections.end(); ++it)
00205 {
00206 if (strcmp(sectionName, (*it)->name) == 0) {
00207 delete[] sectionName;
00208 return (*it)->parse(this);
00209 }
00210 }
00211
00212 printError("unkown section name");
00213 fprintf(stderr, "%s", sectionName);
00214 delete[] sectionName;
00215 return false;
00216 }
00217
00218 bool IniParser::dumpExampleFile(const char *filename) {
00219 FILE *f = fopen(filename, "wt");
00220
00221 if (!f) {
00222 perror(filename);
00223 return false;
00224 }
00225 for (IniSectionVector::iterator it(sections.begin()); it != sections.end(); ++it)
00226 (*it)->print(f);
00227
00228 fclose(f);
00229
00230 return true;
00231 }
00233
00234 ParamSection::ParamSection() {
00235 name = "PARAMETERS";
00236 }
00237
00238 bool ParamSection::parse(IniParser *parser) {
00239
00240 while (parser->nextToken()) {
00241
00242 if (strcmp(parser->buffer, "[")==0) return true;
00243
00244 ParamVector::iterator it;
00245 for (it = params.begin(); it!= params.end(); ++it) {
00246 if (strcmp(parser->buffer, (*it)->name)==0) {
00247
00248 parser->nextToken();
00249 if (strcmp(parser->buffer, "=") != 0) {
00250 parser->printError("expecting '='");
00251 return false;
00252 }
00253
00254 if (!parser->nextToken()) {
00255 parser->printError("unexpected end of file.");
00256 return false;
00257 }
00258
00259 if (!(*it)->parse(parser)) return false;
00260 break;
00261 }
00262 }
00263 if (it == params.end()) {
00264 parser->printError("warning: unknown parameter");
00265 parser->nextToken();
00266 if (strcmp(parser->buffer, "=") != 0) return false;
00267 parser->nextToken();
00268 }
00269 }
00270
00271 return true;
00272 }
00273
00274 void ParamSection::print(FILE *f) {
00275 IniSection::print(f);
00276 ParamVector::iterator it;
00277 for (it = params.begin(); it!= params.end(); ++it) {
00278 fprintf(f, "%s = ", (*it)->name);
00279 (*it)->print(f);
00280 }
00281 }
00282
00283 bool ParamSection::DoubleParam::parse(IniParser *parser)
00284 {
00285 double d;
00286 if (sscanf(parser->buffer, "%lf", &d) != 1) {
00287 parser->printError("warning: cannot convert to double.");
00288 return false;
00289 }
00290
00291 if ((d<min) || (d>max)) {
00292 parser->printError("value out of range");
00293 return false;
00294 }
00295 *val = d;
00296 return true;
00297 }
00298
00299 void ParamSection::DoubleParam::print(FILE *f) {
00300 fprintf(f, "%lf\n", *val);
00301 }
00302
00303 int ParamSection::DoubleParam::visit(ParamSection::ParamVisitor *v) {
00304 return v->doDouble(this);
00305 }
00306
00307 bool ParamSection::BoolParam::parse(IniParser *parser)
00308 {
00309 if (strcmp(parser->buffer, "true") == 0) {
00310 *val = true;
00311 return true;
00312 } else if (strcmp(parser->buffer, "false") == 0) {
00313 *val = false;
00314 return true;
00315 }
00316
00317 parser->printError("boolean option should be \"true\" or \"false\".");
00318 return false;
00319 }
00320
00321 void ParamSection::BoolParam::print(FILE *f) {
00322 if (*val)
00323 fprintf(f,"true\n");
00324 else
00325 fprintf(f,"false\n");
00326 }
00327
00328 int ParamSection::BoolParam::visit(ParamSection::ParamVisitor *v) {
00329 return v->doBool(this);
00330 }
00331
00332 bool ParamSection::StringParam::parse(IniParser *parser)
00333 {
00334 if (*val) free(*val);
00335 *val = strdup(parser->buffer);
00336 return true;
00337 }
00338
00339 void ParamSection::StringParam::print(FILE *f) {
00340 fprintf(f,"\"%s\"\n", *val);
00341 }
00342
00343 int ParamSection::StringParam::visit(ParamSection::ParamVisitor *v) {
00344 return v->doString(this);
00345 }
00346
00347 bool ParamSection::IntParam::parse(IniParser *parser)
00348 {
00349 int d;
00350 if (sscanf(parser->buffer, "%d", &d) != 1) {
00351 parser->printError("warning: cannot convert to int.");
00352 return false;
00353 }
00354
00355 if ((d<min) || (d>max)) {
00356 parser->printError("value out of range");
00357 return false;
00358 }
00359 *val = d;
00360 return true;
00361 }
00362
00363 void ParamSection::IntParam::print(FILE *f) {
00364 fprintf(f, "%d\n", *val);
00365 }
00366
00367 int ParamSection::IntParam::visit(ParamSection::ParamVisitor *v) {
00368 return v->doInt(this);
00369 }
00370
00371 void ParamSection::addDoubleParam(const char *name, double *val, double def, double min, double max)
00372 {
00373 DoubleParam *p = new DoubleParam();
00374
00375 p->name = name;
00376 p->min = min;
00377 p->max = max;
00378 p->val = val;
00379 *val = def;
00380
00381 params.push_back(p);
00382 }
00383
00384 void ParamSection::addBoolParam(const char *name, bool *val, bool def)
00385 {
00386 BoolParam *p = new BoolParam();
00387 p->name = name;
00388 p->val = val;
00389 *val = def;
00390 params.push_back(p);
00391 }
00392
00393 void ParamSection::addStringParam(const char *name, char **val, const char *def)
00394 {
00395 StringParam *p = new StringParam();
00396 p->name = name;
00397 p->val = val;
00398 *val = strdup(def);
00399 params.push_back(p);
00400 }
00401
00402 void ParamSection::addIntParam(const char *name, int *val, int def, int min, int max)
00403 {
00404 IntParam *p = new IntParam();
00405
00406 p->name = name;
00407 p->min = min;
00408 p->max = max;
00409 p->val = val;
00410 *val = def;
00411
00412 params.push_back(p);
00413 }