00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "ArExport.h"
00027 #include "ariaOSDef.h"
00028 #include "ArFileParser.h"
00029 #include "ArLog.h"
00030 #include "ariaUtil.h"
00031 #include <ctype.h>
00032
00033 AREXPORT ArFileParser::ArFileParser(const char *baseDirectory)
00034 {
00035 myRemainderHandler = NULL;
00036 setBaseDirectory(baseDirectory);
00037 resetCounters();
00038 }
00039
00040 AREXPORT ArFileParser::~ArFileParser(void)
00041 {
00042
00043 }
00044
00045 AREXPORT bool ArFileParser::addHandler(
00046 const char *keyword, ArRetFunctor1<bool, ArArgumentBuilder *> *functor)
00047 {
00048 std::map<std::string, HandlerCBType *, ArStrCaseCmpOp>::iterator it;
00049 if (keyword == NULL)
00050 {
00051 if (myRemainderHandler != NULL)
00052 {
00053 ArLog::log(ArLog::Verbose, "There is already a functor to handle unhandled lines");
00054 return false;
00055 }
00056 else
00057 {
00058 delete myRemainderHandler;
00059 myRemainderHandler = new HandlerCBType(functor);
00060 return true;
00061 }
00062 }
00063
00064 if ((it = myMap.find(keyword)) != myMap.end())
00065 {
00066 ArLog::log(ArLog::Verbose, "There is already a functor to handle keyword '%s'", keyword);
00067 return false;
00068 }
00069 ArLog::log(ArLog::Verbose, "keyword '%s' handler added", keyword);
00070 myMap[keyword] = new HandlerCBType(functor);
00071 return true;
00072 }
00073
00080 AREXPORT bool ArFileParser::addHandlerWithError(
00081 const char *keyword,
00082 ArRetFunctor3<bool, ArArgumentBuilder *, char *, size_t> *functor)
00083 {
00084 std::map<std::string, HandlerCBType *, ArStrCaseCmpOp>::iterator it;
00085 if (keyword == NULL)
00086 {
00087 if (myRemainderHandler != NULL)
00088 {
00089 ArLog::log(ArLog::Verbose, "There is already a functor to handle unhandled lines");
00090 return false;
00091 }
00092 else
00093 {
00094 delete myRemainderHandler;
00095 myRemainderHandler = new HandlerCBType(functor);
00096 return true;
00097 }
00098 }
00099
00100 if ((it = myMap.find(keyword)) != myMap.end())
00101 {
00102 ArLog::log(ArLog::Verbose, "There is already a functor to handle keyword '%s'", keyword);
00103 return false;
00104 }
00105 ArLog::log(ArLog::Verbose, "keyword '%s' handler added", keyword);
00106 myMap[keyword] = new HandlerCBType(functor);
00107 return true;
00108 }
00109
00110 AREXPORT bool ArFileParser::remHandler(const char *keyword,
00111 bool logIfCannotFind)
00112 {
00113 std::map<std::string, HandlerCBType *, ArStrCaseCmpOp>::iterator it;
00114 HandlerCBType *handler;
00115
00116 if (myRemainderHandler != NULL && keyword == NULL)
00117 {
00118 delete myRemainderHandler;
00119 myRemainderHandler = NULL;
00120 ArLog::log(ArLog::Verbose, "Functor for remainder handler removed");
00121 return true;
00122 }
00123
00124 if ((it = myMap.find(keyword)) == myMap.end())
00125 {
00126 if (logIfCannotFind)
00127 ArLog::log(ArLog::Normal, "There is no keyword '%s' to remove.",
00128 keyword);
00129 return false;
00130 }
00131 ArLog::log(ArLog::Verbose, "keyword '%s' removed", keyword);
00132 handler = (*it).second;
00133 myMap.erase(it);
00134 delete handler;
00135 remHandler(keyword, false);
00136 return true;
00137
00138 }
00139
00140 AREXPORT bool ArFileParser::remHandler(
00141 ArRetFunctor1<bool, ArArgumentBuilder *> *functor)
00142 {
00143 std::map<std::string, HandlerCBType *, ArStrCaseCmpOp>::iterator it;
00144 HandlerCBType *handler;
00145
00146 if (myRemainderHandler != NULL && myRemainderHandler->haveFunctor(functor))
00147 {
00148 delete myRemainderHandler;
00149 myRemainderHandler = NULL;
00150 ArLog::log(ArLog::Verbose, "Functor for remainder handler removed");
00151 return true;
00152 }
00153
00154 for (it = myMap.begin(); it != myMap.end(); it++)
00155 {
00156 if ((*it).second->haveFunctor(functor))
00157 {
00158 ArLog::log(ArLog::Verbose, "Functor for keyword '%s' removed.",
00159 (*it).first.c_str());
00160 handler = (*it).second;
00161 myMap.erase(it);
00162 delete handler;
00163 remHandler(functor);
00164 return true;
00165 }
00166 }
00167 return false;
00168
00169 }
00170
00171 AREXPORT bool ArFileParser::remHandler(
00172 ArRetFunctor3<bool, ArArgumentBuilder *, char *, size_t> *functor)
00173 {
00174 std::map<std::string, HandlerCBType *, ArStrCaseCmpOp>::iterator it;
00175 HandlerCBType *handler;
00176
00177 if (myRemainderHandler != NULL && myRemainderHandler->haveFunctor(functor))
00178 {
00179 delete myRemainderHandler;
00180 myRemainderHandler = NULL;
00181 ArLog::log(ArLog::Verbose, "Functor for remainder handler removed");
00182 return true;
00183 }
00184
00185 for (it = myMap.begin(); it != myMap.end(); it++)
00186 {
00187 if ((*it).second->haveFunctor(functor))
00188 {
00189 ArLog::log(ArLog::Verbose, "Functor for keyword '%s' removed.",
00190 (*it).first.c_str());
00191 handler = (*it).second;
00192 myMap.erase(it);
00193 delete handler;
00194 remHandler(functor);
00195 return true;
00196 }
00197 }
00198 return false;
00199
00200 }
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216 AREXPORT void ArFileParser::setBaseDirectory(const char *baseDirectory)
00217 {
00218 if (baseDirectory != NULL && strlen(baseDirectory) > 0)
00219 myBaseDir = baseDirectory;
00220 else
00221 myBaseDir = "";
00222 }
00223
00224 AREXPORT const char *ArFileParser::getBaseDirectory(void) const
00225 {
00226 return myBaseDir.c_str();
00227 }
00228
00229 AREXPORT void ArFileParser::resetCounters(void)
00230 {
00231 myLineNumber = 0;
00232 }
00233
00234 AREXPORT bool ArFileParser::parseLine(char *line,
00235 char *errorBuffer, size_t errorBufferLen)
00236 {
00237 char keyword[512];
00238 char *choppingPos;
00239 char *valueStart;
00240 size_t textStart;
00241 size_t len;
00242 size_t i;
00243 bool noArgs;
00244 std::map<std::string, HandlerCBType *, ArStrCaseCmpOp>::iterator it;
00245 HandlerCBType *handler;
00246
00247 myLineNumber++;
00248 noArgs = false;
00249
00250
00251 if ((choppingPos = strstr(line, ";")) != NULL)
00252 line[choppingPos-line] = '\0';
00253 if ((choppingPos = strstr(line, "#")) != NULL)
00254 line[choppingPos-line] = '\0';
00255
00256
00257
00258
00259 if ((choppingPos = strstr(line, "\n")) != NULL)
00260 line[choppingPos-line] = '\0';
00261
00262 while ((choppingPos = strstr(line, "\r")) != NULL)
00263 memmove(choppingPos, choppingPos + 1, strlen(line));
00264
00265
00266 len = strlen(line);
00267
00268
00269
00270 if (len == 0)
00271 {
00272 ArLog::log(ArLog::Verbose, "line %d: empty line", myLineNumber);
00273 return true;
00274 }
00275
00276 for (i = 0; i < len; i++)
00277 {
00278
00279 if (!isspace(line[i]))
00280 {
00281 textStart = i;
00282 break;
00283 };
00284 }
00285
00286 if (i == len)
00287 {
00288 ArLog::log(ArLog::Verbose, "line %d: just white space at start of line", myLineNumber);
00289 return true;
00290 }
00291
00292
00293 bool quoted = false;
00294 for (i = textStart;
00295 i < len && i < sizeof(keyword) + textStart - 3;
00296 i++)
00297 {
00298
00299 if (!quoted && i == textStart && line[i] == '"')
00300 {
00301
00302
00303 quoted = true;
00304
00305 textStart++;
00306 continue;
00307 }
00308
00309 if (!quoted && isspace(line[i]))
00310 {
00311 break;
00312 }
00313
00314
00315
00316 else if (quoted && line[i] == '"')
00317 {
00318 keyword[i-textStart] = '\0';
00319 i++;
00320 break;
00321 }
00322
00323 else
00324 keyword[i-textStart] = line[i];
00325 }
00326
00327 keyword[i-textStart] = '\0';
00328
00329
00330 for (; i < len; i++)
00331 {
00332
00333 if (!isspace(line[i]))
00334 {
00335 valueStart = &line[i];
00336 break;
00337 };
00338 }
00339
00340 ArUtil::lower(keyword, keyword, 512);
00341
00342
00343
00344
00345 bool usingRemainder = false;
00346
00347 if ((it = myMap.find(keyword)) != myMap.end())
00348 {
00349
00350
00351 handler = (*it).second;
00352
00353 if (i == len)
00354 noArgs = true;
00355 }
00356
00357 else
00358 {
00359
00360
00361 if (myRemainderHandler != NULL)
00362 {
00363 usingRemainder = true;
00364 handler = myRemainderHandler;
00365
00366 valueStart = &line[textStart];
00367 }
00368
00369 else
00370 {
00371 ArLog::log(ArLog::Verbose,
00372 "line %d: unknown keyword '%s' line '%s', continuing",
00373 myLineNumber, keyword, &line[textStart]);
00374 return true;
00375 }
00376 }
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388 ArArgumentBuilder builder;
00389
00390 if (!noArgs)
00391 builder.add(valueStart);
00392
00393
00394 if (!usingRemainder)
00395 builder.setExtraString(keyword);
00396
00397
00398 if (errorBuffer != NULL && errorBuffer[0] != '\0')
00399 {
00400 errorBuffer = NULL;
00401 errorBufferLen = 0;
00402 }
00403
00404
00405
00406 if (!handler->call(&builder, errorBuffer, errorBufferLen))
00407 {
00408
00409
00410 if (errorBuffer != NULL)
00411 {
00412 std::string errorString = errorBuffer;
00413 snprintf(errorBuffer, errorBufferLen, "Line %d: %s", myLineNumber,
00414 errorString.c_str());
00415
00416 }
00417 return false;
00418 }
00419 return true;
00420 }
00421
00437 AREXPORT bool ArFileParser::parseFile(const char *fileName,
00438 bool continueOnErrors,
00439 bool noFileNotFoundMessage,
00440 char *errorBuffer,
00441 size_t errorBufferLen)
00442 {
00443 FILE *file;
00444
00445 char line[10000];
00446 bool ret = true;
00447
00448 if (errorBuffer)
00449 errorBuffer[0] = '\0';
00450
00451 std::string realFileName;
00452 if (fileName[0] == '/' || fileName[0] == '\\')
00453 {
00454 realFileName = fileName;
00455 }
00456 else
00457 {
00458 realFileName = myBaseDir;
00459 realFileName += fileName;
00460 }
00461
00462 ArLog::log(ArLog::Verbose, "Opening file %s from fileName given %s and base directory %s", realFileName.c_str(), fileName, myBaseDir.c_str());
00463
00464
00465
00466 if ((file = fopen(realFileName.c_str(), "r")) == NULL)
00467 {
00468 if (errorBuffer != NULL)
00469 snprintf(errorBuffer, errorBufferLen, "cannot open file %s", fileName);
00470 if (!noFileNotFoundMessage)
00471 ArLog::log(ArLog::Terse, "ArFileParser::parseFile: Could not open file %s to parse file.", realFileName.c_str());
00472 return false;
00473 }
00481 resetCounters();
00482
00483 while (fgets(line, sizeof(line), file) != NULL)
00484 {
00485 if (!parseLine(line, errorBuffer, errorBufferLen))
00486 {
00487 ArLog::log(ArLog::Terse, "## Last error on line %d of file '%s'",
00488 myLineNumber, realFileName.c_str());
00489 ret = false;
00490 if (!continueOnErrors)
00491 break;
00492 }
00493 }
00494
00495 fclose(file);
00496 return ret;
00497 }
00498
00499
00512 AREXPORT bool ArFileParser::parseFile(FILE *file, char *buffer,
00513 int bufferLength,
00514 bool continueOnErrors,
00515 char *errorBuffer,
00516 size_t errorBufferLen)
00517 {
00518 if (errorBuffer)
00519 errorBuffer[0] = '\0';
00520
00521 if ((file == NULL) || (buffer == NULL) || (bufferLength <= 0))
00522 {
00523 if (errorBuffer != NULL)
00524 snprintf(errorBuffer, errorBufferLen, "parseFile: bad setup");
00525 return false;
00526 }
00527
00528 bool ret = true;
00529 resetCounters();
00530
00531
00532 while (fgets(buffer, bufferLength, file) != NULL)
00533 {
00534 if (!parseLine(buffer, errorBuffer, errorBufferLen))
00535 {
00536 ret = false;
00537 if (!continueOnErrors)
00538 break;
00539 }
00540 }
00541 return ret;
00542 }