Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages

ArFileParser.cpp

00001 /*
00002 ActivMedia Robotics Interface for Applications (ARIA)
00003 Copyright (C) 2004,2005 ActivMedia Robotics, LLC
00004 
00005 
00006      This program is free software; you can redistribute it and/or modify
00007      it under the terms of the GNU General Public License as published by
00008      the Free Software Foundation; either version 2 of the License, or
00009      (at your option) any later version.
00010 
00011      This program is distributed in the hope that it will be useful,
00012      but WITHOUT ANY WARRANTY; without even the implied warranty of
00013      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014      GNU General Public License for more details.
00015 
00016      You should have received a copy of the GNU General Public License
00017      along with this program; if not, write to the Free Software
00018      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 
00020 If you wish to redistribute ARIA under different terms, contact 
00021 ActivMedia Robotics for information about a commercial version of ARIA at 
00022 robots@activmedia.com or 
00023 ActivMedia Robotics, 19 Columbia Drive, Amherst, NH 03031; 800-639-9481
00024 
00025 */
00026 
00027 #include "ArExport.h"
00028 #include "ariaOSDef.h"
00029 #include "ArFileParser.h"
00030 #include "ArLog.h"
00031 #include "ariaUtil.h"
00032 #include <ctype.h>
00033 
00034 ArFileParser::ArFileParser(const char *baseDirectory)
00035 {
00036   myRemainderHandler = NULL;
00037   setBaseDirectory(baseDirectory);
00038   resetCounters();
00039 }
00040 
00041 ArFileParser::~ArFileParser(void)
00042 {
00043 
00044 }
00045 
00046 bool ArFileParser::addHandler(
00047         const char *keyword, ArRetFunctor1<bool, ArArgumentBuilder *> *functor)
00048 {
00049   std::map<std::string, HandlerCBType *, ArStrCaseCmpOp>::iterator it;
00050   if (keyword == NULL)
00051   {
00052     if (myRemainderHandler != NULL)
00053     {
00054       ArLog::log(ArLog::Verbose, "There is already a functor to handle unhandled lines");
00055       return false;
00056     }
00057     else
00058     {
00059       delete myRemainderHandler;
00060       myRemainderHandler = new HandlerCBType(functor);
00061       return true;
00062     }
00063   }
00064 
00065   if ((it = myMap.find(keyword)) != myMap.end())
00066   {
00067     ArLog::log(ArLog::Verbose, "There is already a functor to handle keyword '%s'", keyword);
00068     return false;
00069   }
00070   ArLog::log(ArLog::Verbose, "keyword '%s' handler added", keyword);
00071   myMap[keyword] = new HandlerCBType(functor);
00072   return true;
00073 }
00074 
00081 bool ArFileParser::addHandlerWithError(
00082         const char *keyword, 
00083         ArRetFunctor3<bool, ArArgumentBuilder *, char *, size_t> *functor)
00084 {
00085   std::map<std::string, HandlerCBType *, ArStrCaseCmpOp>::iterator it;
00086   if (keyword == NULL)
00087   {
00088     if (myRemainderHandler != NULL)
00089     {
00090       ArLog::log(ArLog::Verbose, "There is already a functor to handle unhandled lines");
00091       return false;
00092     }
00093     else
00094     {
00095       delete myRemainderHandler;
00096       myRemainderHandler = new HandlerCBType(functor);
00097       return true;
00098     }
00099   }
00100 
00101   if ((it = myMap.find(keyword)) != myMap.end())
00102   {
00103     ArLog::log(ArLog::Verbose, "There is already a functor to handle keyword '%s'", keyword);
00104     return false;
00105   }
00106   ArLog::log(ArLog::Verbose, "keyword '%s' handler added", keyword);
00107   myMap[keyword] = new HandlerCBType(functor);
00108   return true;
00109 }
00110 
00111 bool ArFileParser::remHandler(const char *keyword, 
00112                                        bool logIfCannotFind)
00113 {
00114   std::map<std::string, HandlerCBType *, ArStrCaseCmpOp>::iterator it;
00115   HandlerCBType *handler;
00116 
00117   if (myRemainderHandler != NULL && keyword == NULL)
00118   {
00119     delete myRemainderHandler;
00120     myRemainderHandler = NULL;
00121     ArLog::log(ArLog::Verbose, "Functor for remainder handler removed");
00122     return true;
00123   }
00124 
00125   if ((it = myMap.find(keyword)) == myMap.end())
00126   {
00127     if (logIfCannotFind)
00128       ArLog::log(ArLog::Normal, "There is no keyword '%s' to remove.", 
00129                  keyword);
00130     return false;
00131   }
00132   ArLog::log(ArLog::Verbose, "keyword '%s' removed", keyword);
00133   handler = (*it).second;
00134   myMap.erase(it);
00135   delete handler;
00136   remHandler(keyword, false);
00137   return true;
00138 
00139 }
00140 
00141 bool ArFileParser::remHandler(
00142         ArRetFunctor1<bool, ArArgumentBuilder *> *functor)
00143 {
00144   std::map<std::string, HandlerCBType *, ArStrCaseCmpOp>::iterator it;
00145   HandlerCBType *handler;
00146 
00147   if (myRemainderHandler != NULL && myRemainderHandler->haveFunctor(functor))
00148   {
00149     delete myRemainderHandler;
00150     myRemainderHandler = NULL;
00151     ArLog::log(ArLog::Verbose, "Functor for remainder handler removed");
00152     return true;
00153   }
00154 
00155   for (it = myMap.begin(); it != myMap.end(); it++)
00156   {
00157     if ((*it).second->haveFunctor(functor))
00158     {
00159       ArLog::log(ArLog::Verbose, "Functor for keyword '%s' removed.", 
00160                  (*it).first.c_str());
00161       handler = (*it).second;
00162       myMap.erase(it);
00163       delete handler;
00164       remHandler(functor);
00165       return true;
00166     }
00167   }
00168   return false;
00169 
00170 }
00171 
00172 bool ArFileParser::remHandler(
00173         ArRetFunctor3<bool, ArArgumentBuilder *, char *, size_t> *functor)
00174 {
00175   std::map<std::string, HandlerCBType *, ArStrCaseCmpOp>::iterator it;
00176   HandlerCBType *handler;
00177 
00178   if (myRemainderHandler != NULL && myRemainderHandler->haveFunctor(functor))
00179   {
00180     delete myRemainderHandler;
00181     myRemainderHandler = NULL;
00182     ArLog::log(ArLog::Verbose, "Functor for remainder handler removed");
00183     return true;
00184   }
00185 
00186   for (it = myMap.begin(); it != myMap.end(); it++)
00187   {
00188     if ((*it).second->haveFunctor(functor))
00189     {
00190       ArLog::log(ArLog::Verbose, "Functor for keyword '%s' removed.", 
00191                  (*it).first.c_str());
00192       handler = (*it).second;
00193       myMap.erase(it);
00194       delete handler;
00195       remHandler(functor);
00196       return true;
00197     }
00198   }
00199   return false;
00200 
00201 }
00202 
00203 /*
00204 ArRetFunctor1<bool, ArArgumentBuilder *> *ArFileParser::getHandler(const char *keyword)
00205 {
00206   std::map<std::string, ArRetFunctor1<bool, ArArgumentBuilder *> *, ArStrCaseCmpOp>::iterator it;
00207 
00208   if ((it = myMap.find(keyword)) == myMap.end())
00209   {
00210     ArLog::log(ArLog::Normal, "There is no keyword handler for '%s'", keyword);
00211     return NULL;
00212   }
00213   
00214   return (*it).second;
00215 }
00216 */
00217 void ArFileParser::setBaseDirectory(const char *baseDirectory)
00218 {
00219   if (baseDirectory != NULL && strlen(baseDirectory) > 0)
00220     myBaseDir = baseDirectory;
00221   else
00222     myBaseDir = "";
00223 }
00224 
00225 const char *ArFileParser::getBaseDirectory(void) const
00226 {
00227   return myBaseDir.c_str();
00228 }
00229 
00230 void ArFileParser::resetCounters(void)
00231 {
00232   myLineNumber = 0;
00233 }
00234 
00235 bool ArFileParser::parseLine(char *line, 
00236                                       char *errorBuffer, size_t errorBufferLen)
00237 {
00238   char keyword[512];
00239   char *choppingPos;
00240   char *valueStart;
00241   size_t textStart;
00242   size_t len;
00243   size_t i;
00244   bool noArgs;
00245   std::map<std::string, HandlerCBType *, ArStrCaseCmpOp>::iterator it;
00246   HandlerCBType *handler;
00247 
00248   myLineNumber++;
00249   noArgs = false;
00250   
00251   // chop out the comments
00252   if ((choppingPos = strstr(line, ";")) != NULL)
00253     line[choppingPos-line] = '\0';
00254   if ((choppingPos = strstr(line, "#")) != NULL)
00255     line[choppingPos-line] = '\0';
00256   
00257   
00258   
00259   // chop out the new line if its there
00260   if ((choppingPos = strstr(line, "\n")) != NULL)
00261     line[choppingPos-line] = '\0';
00262   // chop out the windows new line if its there
00263   while ((choppingPos = strstr(line, "\r")) != NULL)
00264     memmove(choppingPos, choppingPos + 1, strlen(line));
00265   
00266   // see how long the line is
00267   len = strlen(line);
00268   
00269   // find the keyword
00270   // if this is 0 then we have an empty line so we continue
00271   if (len == 0)
00272   {
00273     ArLog::log(ArLog::Verbose, "line %d: empty line", myLineNumber);
00274     return true;
00275   }
00276   // first find the start of the text
00277   for (i = 0; i < len; i++)
00278   {
00279     // if its not a space we're done
00280     if (!isspace(line[i]))
00281     {
00282       textStart = i;
00283       break;
00284     };
00285   }
00286   // if we reached the end of the line then continue
00287   if (i == len)
00288   {
00289     ArLog::log(ArLog::Verbose, "line %d: just white space at start of line", myLineNumber);
00290     return true;
00291   }
00292   // now we chisel out the keyword
00293   for (i = textStart; 
00294        i < len && i < sizeof(keyword) + textStart - 1;
00295        i++)
00296   {
00297     // if its a space we're done
00298     if (isspace(line[i]))
00299       break;
00300     // if not its part of the keyword
00301     else
00302       keyword[i-textStart] = line[i];
00303   }
00304   keyword[i] = '\0';
00305   //ArLog::log(ArLog::Verbose, "line %d: keyword %s", lineNumber, keyword);
00306   // now find the start of the value (first non whitespace)
00307   for (; i < len; i++)
00308   {
00309     // if its not a space we're done
00310     if (!isspace(line[i]))
00311     {
00312       valueStart = &line[i];
00313       break;
00314     };
00315   }
00316   // lower that keyword
00317   ArUtil::lower(keyword, keyword, 512);
00318   
00319   // see if we have a handler for the keyword
00320   if ((it = myMap.find(keyword)) != myMap.end())
00321   {
00322     //printf("have handler for keyword %s\n", keyword);
00323     // we have a handler, so pull that out
00324     handler = (*it).second;
00325     // valueStart was set above but make sure there's an argument
00326     if (i == len)
00327       noArgs = true;
00328   }
00329   // if we don't then check for a remainder handler
00330   else
00331   {
00332     //printf("no handler for keyword %s\n", keyword);
00333     // if we have one set it
00334     if (myRemainderHandler != NULL)
00335     {
00336       handler = myRemainderHandler;
00337       // reset the value to the start of the text
00338       valueStart = &line[textStart];
00339     }
00340     // if we don't just keep going
00341     else
00342     {
00343       ArLog::log(ArLog::Verbose, 
00344                  "line %d: unknown keyword '%s' line '%s', continuing", 
00345                  myLineNumber, keyword, &line[textStart]);
00346       return true;
00347     }
00348   }
00349   /*
00350   if (noArgs)
00351     ArLog::log(ArLog::Verbose, "line %d: firstword '%s' no argument", 
00352                myLineNumber, keyword);
00353   else
00354     ArLog::log(ArLog::Verbose, "line %d: firstword '%s' argument '%s'", 
00355                myLineNumber, keyword, valueStart);
00356   */
00357   // now toss the rest of the argument into an argument builder then
00358   // form it up to send to the functor
00359   
00360   ArArgumentBuilder builder;
00361   // if we have arguments add them
00362   if (!noArgs)
00363     builder.add(valueStart);
00364   // if not we still set the name of whatever we parsed
00365   builder.setExtraString(keyword);
00366 
00367   // make sure we don't overwrite any errors
00368   if (errorBuffer != NULL && errorBuffer[0] != '\0')
00369   {
00370     errorBuffer = NULL;
00371     errorBufferLen = 0;
00372   }
00373     
00374   // call the functor and see if there are errors;
00375   // if we had an error and aren't continuing on errors then we keep going
00376   if (!handler->call(&builder, errorBuffer, errorBufferLen))
00377   {
00378     // put the line number in the error message (this won't overwrite
00379     // anything because of the check above
00380     if (errorBuffer != NULL)
00381     {
00382       std::string errorString = errorBuffer;
00383       snprintf(errorBuffer, errorBufferLen, "Line %d: %s", myLineNumber, 
00384                errorString.c_str());
00385       
00386     }
00387     return false;
00388   }
00389   return true;
00390 }
00391 
00407 bool ArFileParser::parseFile(const char *fileName, 
00408                                       bool continueOnErrors, 
00409                                       bool noFileNotFoundMessage,
00410                                       char *errorBuffer,
00411                                       size_t errorBufferLen)
00412 {
00413   FILE *file;
00414 
00415   char line[10000];
00416   bool ret = true;
00417 
00418   if (errorBuffer)
00419     errorBuffer[0] = '\0';
00420 
00421   std::string realFileName;
00422   if (fileName[0] == '/' || fileName[0] == '\\')
00423   {
00424     realFileName = fileName;
00425   }
00426   else
00427   {
00428     realFileName = myBaseDir;
00429     realFileName += fileName;
00430   }
00431 
00432   ArLog::log(ArLog::Verbose, "Opening file %s from fileName given %s and base directory %s", realFileName.c_str(), fileName, myBaseDir.c_str());
00433     
00434   //char *buf = new char[4096];
00435 
00436   if ((file = fopen(realFileName.c_str(), "r")) == NULL)
00437   {
00438     if (errorBuffer != NULL)
00439       snprintf(errorBuffer, errorBufferLen, "cannot open file %s", fileName);
00440     if (!noFileNotFoundMessage)
00441       ArLog::log(ArLog::Terse, "ArFileParser::parseFile: Could not open file %s to parse file.", realFileName.c_str());
00442     return false;
00443   }
00451   resetCounters();
00452   // read until the end of the file
00453   while (fgets(line, sizeof(line), file) != NULL)
00454   {
00455     if (!parseLine(line, errorBuffer, errorBufferLen))
00456     {
00457       ArLog::log(ArLog::Terse, "## Last error on line %d of file '%s'", 
00458                  myLineNumber, realFileName.c_str());
00459       ret = false;
00460       if (!continueOnErrors)
00461         break;
00462     }
00463   }
00464   
00465   fclose(file);
00466   return ret;
00467 }
00468 
00469 
00470 bool ArFileParser::parseFile(FILE *file, char *buffer, 
00471                                       int bufferLength, 
00472                                       bool continueOnErrors,
00473                                       char *errorBuffer,
00474                                       size_t errorBufferLen)
00475 {
00476   if (errorBuffer)
00477     errorBuffer[0] = '\0';
00478 
00479   if ((file == NULL) || (buffer == NULL) || (bufferLength <= 0)) 
00480   {
00481     if (errorBuffer != NULL)
00482       snprintf(errorBuffer, errorBufferLen, "parseFile: bad setup");
00483     return false;
00484   }
00485 
00486   bool ret = true;
00487   resetCounters();
00488 
00489   // read until the end of the file
00490   while (fgets(buffer, bufferLength, file) != NULL)
00491   {
00492     if (!parseLine(buffer, errorBuffer, errorBufferLen))
00493     {
00494       ret = false;
00495       if (!continueOnErrors)
00496         break;
00497     }
00498   }
00499   return ret;
00500 }

Generated on Wed Oct 19 12:56:34 2005 for Aria by  doxygen 1.4.0