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

ArConfig.cpp

00001 /*
00002 MobileRobots Advanced Robotics Interface for Applications (ARIA)
00003 Copyright (C) 2004, 2005 ActivMedia Robotics LLC
00004 Copyright (C) 2006, 2007 MobileRobots Inc.
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 MobileRobots for information about a commercial version of ARIA at 
00022 robots@mobilerobots.com or 
00023 MobileRobots Inc, 19 Columbia Drive, Amherst, NH 03031; 800-639-9481
00024 */
00025 
00026 #include "ArExport.h"
00027 #include "ariaOSDef.h"
00028 #include "ArConfig.h"
00029 #include "ArArgumentBuilder.h"
00030 #include "ArLog.h"
00031 
00032 
00033 // Comment out this line to hide the "(probably unimportant)" messages.
00034 #define ARDEBUG_CONFIG
00035 
00036 #if (defined(ARDEBUG_CONFIG))
00037 //#if (defined(_DEBUG) && defined(ARDEBUG_CONFIG))
00038 #define IFDEBUG(code) {code;}
00039 #else
00040 #define IFDEBUG(code)
00041 #endif 
00042 
00043 // IFDEBUG2 provides even more detailed level of logging (e.g. when configs are copied)
00044 // #define ARDEBUG_CONFIG2
00045 
00046 #if (defined(_DEBUG) && defined(ARDEBUG_CONFIG2))
00047 #define IFDEBUG2(code) {code;}
00048 #else
00049 #define IFDEBUG2(code)
00050 #endif 
00051 
00052 
00060 AREXPORT ArConfig::ArConfig(const char *baseDirectory,
00061                 bool noBlanksBetweenParams,
00062                 bool ignoreBounds, 
00063                 bool failOnBadSection,
00064                 bool saveUnknown) :
00065   myRobotName(""),
00066   myConfigName(""),
00067   myLogPrefix("ArConfig: "),
00068 
00069   myProcessFileCBList(), 
00070   myNoBlanksBetweenParams(noBlanksBetweenParams),
00071   myBaseDirectory(),
00072   myParser(NULL),
00073   mySections(),
00074   mySectionsToParse(NULL),
00075   myParserCB(this, &ArConfig::parseArgument),
00076   mySectionCB(this, &ArConfig::parseSection),
00077   myUnknownCB(this, &ArConfig::parseUnknown)
00078 {
00079   /* taking this part out and just calling 'addParsrHandler' so all the codes in one spot
00080   if (!myParser.addHandlerWithError("section", &mySectionCB))
00081   {
00082     ArLog::log(ArLog::Normal, "Could not add section to file parser, horrific failure");
00083     }*/
00084   addParserHandlers();
00085 
00086   myArgumentParser = NULL;
00087   mySaveUnknown = saveUnknown;
00088   setBaseDirectory(baseDirectory);
00089   myIgnoreBounds = ignoreBounds;
00090   myFailOnBadSection = failOnBadSection;
00091   myProcessFileCallbacksLogLevel = ArLog::Verbose;
00092   myUsingSections = false;
00093   mySectionBroken = false;
00094   mySectionIgnored = false;
00095   myDuplicateParams = false;
00096 
00097   myParserCB.setName("ArConfig::parseArgument");
00098   mySectionCB.setName("ArConfig::parseSection");
00099   myUnknownCB.setName("ArConfig::parseUnknown");
00100 
00101   mySection = "";
00102 }
00103 
00104 AREXPORT ArConfig::~ArConfig()
00105 {
00106   clearSections();
00107 }
00108 
00109 
00110 AREXPORT ArConfig::ArConfig(const ArConfig &config) :
00111   myRobotName(""),
00112   myConfigName(""),
00113   myLogPrefix("ArConfig: "),
00114 
00115   myProcessFileCBList(),    // TODO: Copy? (don't think we need to)
00116   myNoBlanksBetweenParams(config.myNoBlanksBetweenParams),
00117   myBaseDirectory(),
00118   myParser(NULL),  
00119   mySections(),
00120   myParserCB(this, &ArConfig::parseArgument),
00121   mySectionCB(this, &ArConfig::parseSection),
00122   myUnknownCB(this, &ArConfig::parseUnknown) 
00123 {
00124   myArgumentParser = NULL;
00125   setBaseDirectory(config.getBaseDirectory());
00126   myIgnoreBounds = config.myIgnoreBounds;
00127   myFailOnBadSection = config.myFailOnBadSection;
00128   myProcessFileCallbacksLogLevel = config.myProcessFileCallbacksLogLevel;
00129   mySectionBroken = config.mySectionBroken;
00130   mySectionIgnored = config.mySectionIgnored;
00131   mySection = config.mySection;
00132   myUsingSections = config.myUsingSections;
00133   myDuplicateParams = config.myDuplicateParams;
00134 
00135   
00136   std::list<ArConfigSection *>::const_iterator it;
00137   for (it = config.mySections.begin(); 
00138        it != config.mySections.end(); 
00139        it++) 
00140   {
00141     mySections.push_back(new ArConfigSection(*(*it)));
00142   }
00143   copySectionsToParse(config.mySectionsToParse);
00144 
00145   myParserCB.setName("ArConfig::parseArgument");
00146   mySectionCB.setName("ArConfig::parseSection");
00147   myUnknownCB.setName("ArConfig::parseUnknown");
00148 
00149   myParser.remHandler(&myParserCB);
00150   myParser.remHandler(&mySectionCB);
00151   myParser.remHandler(&myUnknownCB);
00152   addParserHandlers();
00153 
00154 }
00155 
00156 
00157 AREXPORT ArConfig &ArConfig::operator=(const ArConfig &config)
00158 {
00159   if (this != &config) {
00160     
00161     // Note that the name is not copied...
00162     IFDEBUG2(ArLog::log(ArLog::Verbose,
00163                        "%soperator= (from %s) begins",
00164                        myLogPrefix.c_str(),
00165                        config.myLogPrefix.c_str()));
00166 
00167     // TODO: The following attributes also need to be copied (or 
00168     // something) -- ditto for copy ctor:
00169     //     myProcessFileCBList
00170     //     myParser
00171     //     myParserCB
00172     //     mySectionCB
00173     myArgumentParser = NULL;
00174     setBaseDirectory(config.getBaseDirectory());
00175     myNoBlanksBetweenParams = config.myNoBlanksBetweenParams;
00176     myIgnoreBounds = config.myIgnoreBounds;    
00177     myFailOnBadSection = config.myFailOnBadSection;
00178     mySection = config.mySection;
00179     mySectionBroken = config.mySectionBroken;
00180     mySectionIgnored = config.mySectionIgnored;
00181     myUsingSections = config.myUsingSections;
00182     myDuplicateParams = config.myDuplicateParams;
00183     mySections.clear();
00184     std::list<ArConfigSection *>::const_iterator it;
00185     for (it = config.mySections.begin(); 
00186      it != config.mySections.end(); 
00187      it++) 
00188     {
00189       mySections.push_back(new ArConfigSection(*(*it)));
00190     }
00191 
00192     copySectionsToParse(config.mySectionsToParse);
00193 
00194     myParser.remHandler(&myParserCB);
00195     myParser.remHandler(&mySectionCB);
00196     myParser.remHandler(&myUnknownCB);
00197     addParserHandlers();
00198     
00199     IFDEBUG2(ArLog::log(ArLog::Verbose,
00200                        "%soperator= (from %s) ends",
00201                        myLogPrefix.c_str(),
00202                        config.myLogPrefix.c_str()));
00203   }
00204   return *this;
00205 
00206 }
00207   
00216 AREXPORT void ArConfig::setConfigName(const char *configName,
00217                                       const char *robotName)
00218 {
00219   myConfigName = ((configName != NULL) ? configName : "");
00220   myRobotName = ((robotName != NULL) ? robotName : "");
00221   myLogPrefix = "";
00222 
00223   if (!myRobotName.empty()) {
00224     myLogPrefix = myRobotName + ": ";
00225   }
00226   myLogPrefix += "ArConfig";
00227 
00228   if (!myConfigName.empty()) {
00229     myLogPrefix += " (" + myConfigName + ")";
00230   }
00231 
00232   myLogPrefix += ": ";
00233 } 
00234 
00235 AREXPORT void ArConfig::log(bool isSummary)
00236 {
00237   std::list<ArConfigArg> *params = NULL;
00238 
00239   ArLog::log(ArLog::Normal, 
00240                "%slog",
00241              myLogPrefix.c_str());
00242 
00243   for (std::list<ArConfigSection *>::const_iterator it = mySections.begin(); 
00244        it != mySections.end(); 
00245        it++) 
00246   {
00247     params = (*it)->getParams();
00248 
00249     if (params == NULL) {
00250       ArLog::log(ArLog::Normal, "    Section %s has NULL params",
00251                  (*it)->getName());
00252 
00253       continue;
00254     }
00255 
00256     if (isSummary) {
00257       ArLog::log(ArLog::Normal, "    Section %s has %i params",
00258                  (*it)->getName(), params->size());
00259       continue;
00260     }
00261 
00262     ArLog::log(ArLog::Normal, "    Section %s:",
00263                  (*it)->getName());
00264 
00265     for (std::list<ArConfigArg>::iterator pit = params->begin(); pit != params->end(); pit++)
00266     {
00267        (*pit).log();
00268     }
00269 
00270   } // end for each section
00271 
00272     ArLog::log(ArLog::Normal, 
00273                "%send",
00274              myLogPrefix.c_str());
00275 
00276 } // end method log
00277 
00278 
00279 AREXPORT void ArConfig::clearSections(void)
00280 {
00281   IFDEBUG2(ArLog::log(ArLog::Verbose, 
00282                      "%sclearSections() begin",
00283                      myLogPrefix.c_str()));
00284 
00285   while (mySections.begin() != mySections.end())
00286   {
00287     delete mySections.front();
00288     mySections.pop_front();
00289   }
00290   // Clear this just in case...
00291   delete mySectionsToParse;
00292   mySectionsToParse = NULL;
00293 
00294   IFDEBUG2(ArLog::log(ArLog::Verbose, 
00295                      "%sclearSections() end",
00296                      myLogPrefix.c_str()));
00297 
00298 }
00299 
00300 AREXPORT void ArConfig::clearAll(void)
00301 {
00302   clearSections();
00303   myProcessFileCBList.clear();
00304 }
00305 
00306 void ArConfig::addParserHandlers(void)
00307 {
00308   std::list<ArConfigSection *>::const_iterator it;
00309   std::list<ArConfigArg> *params;
00310   std::list<ArConfigArg>::iterator pit;
00311 
00312   if (!myParser.addHandlerWithError("section", &mySectionCB)) {
00313     IFDEBUG(ArLog::log(ArLog::Verbose, 
00314                           "%sCould not add section parser (probably unimportant)",
00315                         myLogPrefix.c_str()));
00316   }
00317   for (it = mySections.begin(); 
00318        it != mySections.end(); 
00319        it++) 
00320   {
00321     params = (*it)->getParams();
00322     if (params == NULL)
00323       continue;
00324     for (pit = params->begin(); pit != params->end(); pit++)
00325     {
00326       if (!myParser.addHandlerWithError((*pit).getName(), &myParserCB)) {
00327     IFDEBUG(ArLog::log(ArLog::Verbose, 
00328            "%sCould not add keyword %s (probably unimportant)",
00329        myLogPrefix.c_str(),
00330            (*pit).getName()));
00331       }
00332     }
00333   }
00334 
00335   // add our parser for unknown params
00336   if (!myParser.addHandlerWithError(NULL, &myUnknownCB)) {
00337     IFDEBUG(ArLog::log(ArLog::Verbose, 
00338             "%sCould not add unknown param parser (probably unimportant)",
00339           myLogPrefix.c_str()));
00340   }
00341 }
00342 
00347 AREXPORT void ArConfig::setSectionComment(const char *sectionName, 
00348                       const char *comment)
00349 {
00350   ArConfigSection *section = findSection(sectionName);
00351 
00352   if (section == NULL)
00353   {
00354     ArLog::log(ArLog::Verbose, "%sMaking new section '%s' (for comment)", 
00355                myLogPrefix.c_str(), sectionName);
00356 
00357     section = new ArConfigSection(sectionName, comment);
00358     mySections.push_back(section);
00359   }
00360   else
00361     section->setComment(comment);
00362 }
00363 
00364 
00369 AREXPORT bool ArConfig::addSectionFlags(const char *sectionName, 
00370                     const char *flags)
00371 {
00372   ArConfigSection *section = findSection(sectionName);
00373 
00374   if (section == NULL)
00375   {
00376     ArLog::log(ArLog::Verbose, "%sMaking new section '%s' (flags)", 
00377                myLogPrefix.c_str(), sectionName);
00378     section = new ArConfigSection(sectionName);
00379     section->addFlags(flags);
00380 
00381     mySections.push_back(section);
00382   }
00383   else
00384     section->addFlags(flags);
00385   return true;
00386 }
00387 
00392 AREXPORT bool ArConfig::remSectionFlag(const char *sectionName, 
00393                        const char *flag)
00394 {
00395   ArConfigSection *section = findSection(sectionName);
00396 
00397   if (section == NULL)
00398     return false;
00399   
00400   section->remFlag(flag);
00401   return true;
00402 }
00403 
00410 AREXPORT bool ArConfig::addParam(const ArConfigArg &arg, 
00411                  const char *sectionName,
00412                  ArPriority::Priority priority,
00413                                  const char *displayHint)
00414 {
00415   ArConfigSection *section = findSection(sectionName);
00416 
00417   //printf("SECTION '%s' name '%s' desc '%s'\n", sectionName, arg.getName(), arg.getDescription());
00418   if (section == NULL)
00419   {
00420     ArLog::log(ArLog::Verbose, "ArConfigArg %s: Making new section '%s' (for param)", 
00421                myLogPrefix.c_str(), sectionName);
00422     section = new ArConfigSection(sectionName);
00423     mySections.push_back(section);
00424   }
00425    
00426   std::list<ArConfigArg> *params = section->getParams();
00427 
00428   if (params == NULL)
00429   {
00430     ArLog::log(ArLog::Terse, "%sSomething has gone hideously wrong in ArConfig::addParam",
00431                myLogPrefix.c_str());
00432     return false;
00433   }
00434   
00435   if (arg.getType() == ArConfigArg::SEPARATOR && 
00436       ( !params->empty() && params->back().getType() == ArConfigArg::SEPARATOR) )
00437   {
00438     //ArLog::log(ArLog::Verbose, "Last parameter a sep, so is this one, ignoring it");
00439     return true;
00440   }
00441 
00442   // see if we have this parameter in another section so we can require sections
00443   std::list<ArConfigSection *>::iterator sectionIt;
00444   
00445   for (sectionIt = mySections.begin(); 
00446        sectionIt != mySections.end(); 
00447        sectionIt++)
00448   {
00449     // if we have an argument of this name but we don't have see if
00450     // this section is our own, if its not then note we have
00451     // duplicates
00452     if (strlen(arg.getName()) > 0 && 
00453     (*sectionIt)->findParam(arg.getName()) != NULL && 
00454     strcasecmp((*sectionIt)->getName(), section->getName()) != 0)
00455     {
00456       ArLog::log(ArLog::Verbose, 
00457         "%sParameter %s duplicated in section %s and %s",
00458         myLogPrefix.c_str(),
00459             arg.getName(), (*sectionIt)->getName(), section->getName());
00460       myDuplicateParams = true;
00461     }
00462   }
00463   
00464   // now make sure we can add it to the file parser (with the section
00465   // stuff its okay if we can't)
00466   if (!myParser.addHandlerWithError(arg.getName(), &myParserCB))
00467   {
00468     IFDEBUG(ArLog::log(ArLog::Verbose, "%sCould not add parameter '%s' to file parser, probably already there.", 
00469                           myLogPrefix.c_str(), arg.getName()));
00470     //return false;
00471   }
00472 
00473   // remove any string holders for this param
00474   section->remStringHolder(arg.getName());
00475   
00476   
00477   // we didn't have a parameter with this name so add it
00478   params->push_back(arg);
00479   params->back().setConfigPriority(priority);
00480   params->back().setDisplayHint(displayHint);
00481   params->back().setIgnoreBounds(myIgnoreBounds);
00482 
00483   IFDEBUG2(ArLog::log(ArLog::Verbose, "%sAdded parameter '%s' to section '%s'", 
00484                       myLogPrefix.c_str(), arg.getName(), section->getName()));
00485   //arg.log();
00486   return true;
00487 }
00488 
00495 AREXPORT bool ArConfig::addComment(const char *comment, const char *sectionName, 
00496                    ArPriority::Priority priority)
00497 {
00498   return addParam(ArConfigArg(comment), sectionName, priority);
00499 }
00500 
00501 
00502 
00516 AREXPORT bool ArConfig::parseSection(ArArgumentBuilder *arg,
00517                       char *errorBuffer,
00518                       size_t errorBufferLen)
00519 {
00520   if (myFailOnBadSection && errorBuffer != NULL)
00521     errorBuffer[0] = '\0';
00522 
00523   std::list<ArConfigSection *>::iterator sectionIt;
00524   ArConfigSection *section = NULL;
00525   
00526   if (myFailOnBadSection && errorBuffer != NULL)
00527     errorBuffer[0] = '\0';
00528   for (sectionIt = mySections.begin(); 
00529        sectionIt != mySections.end(); 
00530        sectionIt++)
00531   {
00532     section = (*sectionIt);
00533     if (ArUtil::strcasecmp(section->getName(), arg->getFullString()) == 0)
00534     {
00535       bool isParseSection = true;
00536       if (mySectionsToParse != NULL) {
00537         isParseSection = false;
00538         for (std::list<std::string>::iterator sIter = mySectionsToParse->begin();
00539              sIter != mySectionsToParse->end();
00540              sIter++) {
00541           std::string sp = *sIter;
00542           if (ArUtil::strcasecmp(section->getName(), sp.c_str()) == 0) {
00543             isParseSection = true;
00544             break;
00545           } // end if section 
00546         } // end for each section to parse
00547 
00548       } // end else sections to parse specified
00549 
00550       if (isParseSection) {
00551 
00552         ArLog::log(ArLog::Verbose, "%sConfig switching to section '%s'",
00553                    myLogPrefix.c_str(),
00554                        arg->getFullString());
00555         //printf("Config switching to section '%s'\n", 
00556         //arg->getFullString());
00557         mySection = arg->getFullString();
00558         mySectionBroken = false;
00559         mySectionIgnored = false;
00560         myUsingSections = true;
00561         return true;
00562       }
00563       else { // section is valid but shouldn't be parsed
00564 
00565         ArLog::log(ArLog::Verbose, "%signoring section '%s'", 
00566                    myLogPrefix.c_str(),
00567                        arg->getFullString());
00568         //printf("Config switching to section '%s'\n", 
00569         //arg->getFullString());
00570         mySection = arg->getFullString();
00571         mySectionBroken = false;
00572         mySectionIgnored = true;
00573         myUsingSections = true;
00574         return true;
00575 
00576       } // end else don't parse section
00577     } // end if section found
00578   } // end for each section
00579 
00580 
00581   if (myFailOnBadSection)
00582   {
00583     mySection = "";
00584     mySectionBroken = true;
00585     mySectionIgnored = false;
00586     snprintf(errorBuffer, errorBufferLen,  "ArConfig: Could not find section '%s'", 
00587          arg->getFullString());
00588     
00589     ArLog::log(ArLog::Terse,  
00590            "%sCould not find section '%s', failing", 
00591          myLogPrefix.c_str(),
00592            arg->getFullString());
00593     return false;
00594   }
00595   else
00596   {
00597     if (mySaveUnknown)
00598     {
00599       ArLog::log(ArLog::Verbose, "%smaking new section '%s' to save unknown", 
00600                      myLogPrefix.c_str(), arg->getFullString());
00601       mySection = arg->getFullString();
00602       mySectionBroken = false;
00603       mySectionIgnored = false;
00604       section = new ArConfigSection(arg->getFullString());
00605       mySections.push_back(section);
00606     }
00607     else
00608     {
00609       mySection = "";
00610       mySectionBroken = false;
00611       mySectionIgnored = true;
00612       ArLog::log(ArLog::Normal,  
00613                      "%sIgnoring section '%s'", 
00614                  myLogPrefix.c_str(),
00615                      arg->getFullString());
00616     }
00617     return true;
00618   }
00619 }
00620 
00635 AREXPORT bool ArConfig::parseArgument(ArArgumentBuilder *arg, 
00636                       char *errorBuffer,
00637                       size_t errorBufferLen)
00638 {
00639   std::list<ArConfigSection *>::iterator sectionIt;
00640   std::list<ArConfigArg>::iterator paramIt;
00641   ArConfigSection *section = NULL;
00642   std::list<ArConfigArg> *params = NULL;
00643   ArConfigArg *param = NULL;
00644   int valInt = 0;
00645   double valDouble = 0;
00646   bool valBool = false;
00647   bool ret = true;
00648 
00649   if (mySectionBroken)
00650   {
00651     ArLog::log(ArLog::Verbose, "%sSkipping parameter %s because section broken",
00652                myLogPrefix.c_str(),
00653                  arg->getExtraString());
00654     if (myFailOnBadSection)
00655     {
00656       snprintf(errorBuffer, errorBufferLen, 
00657            "Failed because broken config section");
00658       return false;
00659     }
00660     else
00661     {
00662       return true;
00663     }
00664   }
00665   else if (mySectionIgnored) {
00666     return true;
00667   }
00668 
00669   // if we have duplicate params and don't have sections don't trash anything
00670   if (myDuplicateParams && myUsingSections && mySection.size() <= 0)
00671   {
00672     snprintf(errorBuffer, errorBufferLen, 
00673          "%s not in section, client needs an upgrade",
00674          arg->getExtraString());
00675 
00676     ArLog::log(ArLog::Normal, 
00677                "%s%s not in a section, client needs an upgrade",
00678                myLogPrefix.c_str(),
00679                  arg->getExtraString());
00680     return false;
00681   }
00682 
00683   // see if we found this parameter
00684   bool found = false;
00685 
00686   if (errorBuffer != NULL)
00687     errorBuffer[0] = '\0';
00688   for (sectionIt = mySections.begin(); 
00689        sectionIt != mySections.end(); 
00690        sectionIt++)
00691   {
00692     section = (*sectionIt);
00693     // if we have a section make sure we're in it, otherwise do the
00694     // normal thing 
00695 
00696     // MPL took out the part where if the param wasn't in a section at
00697     // all it checked all the sections, I took this out since
00698     // everything is generally in sections these days
00699     if (ArUtil::strcasecmp(mySection, section->getName()))
00700       continue;
00701     params = section->getParams();
00702     // find this parameter
00703     for (paramIt = params->begin(); paramIt != params->end(); paramIt++)
00704     {
00705       if (strcasecmp((*paramIt).getName(), arg->getExtraString()) == 0)
00706       {
00707     // we found it
00708     found = true;
00709     param = &(*paramIt);
00710     if (param->getType() != ArConfigArg::STRING &&
00711         param->getType() != ArConfigArg::FUNCTOR &&
00712         arg->getArg(0) == NULL)
00713     {
00714       IFDEBUG(ArLog::log(ArLog::Verbose, "%sparameter '%s' has no argument.",
00715                         myLogPrefix.c_str(),
00716                             param->getName()));
00717       continue;
00718     }
00719     if ((param->getType() == ArConfigArg::DESCRIPTION_HOLDER) ||
00720       (param->getType() == ArConfigArg::SEPARATOR)) 
00721     {
00722 
00723     }
00724     // see if we're an int
00725     else if (param->getType() == ArConfigArg::INT)
00726     {
00727       // if the param isn't an int fail
00728       if (!arg->isArgInt(0))
00729       {
00730         ArLog::log(ArLog::Terse, 
00731                  "%sparameter '%s' is an integer parameter but was given non-integer argument of '%s'", 
00732                  myLogPrefix.c_str(), param->getName(), arg->getArg(0));
00733         ret = false;
00734         if (errorBuffer != NULL)
00735           snprintf(errorBuffer, errorBufferLen, "%s is an integer parameter but was given non-integer argument of '%s'", param->getName(), arg->getArg(0));
00736         continue;
00737       }
00738       valInt = arg->getArgInt(0);
00739       if (param->setInt(valInt, errorBuffer, errorBufferLen))
00740       {
00741       IFDEBUG2(ArLog::log(ArLog::Verbose, "%sSet parameter '%s' to '%d'",
00742                               myLogPrefix.c_str(), param->getName(), valInt));
00743         continue;
00744       }
00745       else
00746       {
00747       ArLog::log(ArLog::Verbose, "%sCould not set parameter '%s' to '%d'",
00748                      myLogPrefix.c_str(), param->getName(), valInt);
00749         ret = false;
00750         continue;
00751       }
00752     }
00753     else if (param->getType() == ArConfigArg::DOUBLE)
00754     {
00755       // if the param isn't an in tfail
00756       if (!arg->isArgDouble(0))
00757       {
00758         ArLog::log(ArLog::Terse, "%sparameter '%s' is a double parameter but was given non-double argument of '%s'", 
00759                  myLogPrefix.c_str(), param->getName(), arg->getArg(0));
00760         if (errorBuffer != NULL)
00761           snprintf(errorBuffer, errorBufferLen, "%s is a double parameter but was given non-double argument of '%s'", param->getName(), arg->getArg(0));
00762 
00763         ret = false;
00764         continue;
00765       }
00766       valDouble = arg->getArgDouble(0);
00767       if (param->setDouble(valDouble, errorBuffer, errorBufferLen))
00768       {
00769       IFDEBUG2(ArLog::log(ArLog::Verbose, "%sSet parameter '%s' to '%.10f'",
00770                myLogPrefix.c_str(), param->getName(), valDouble));
00771         continue;
00772       }
00773       else
00774       {
00775       ArLog::log(ArLog::Verbose, "%sCould not set parameter '%s' to '%.10f'",
00776                myLogPrefix.c_str(), param->getName(), valDouble);
00777         ret = false;
00778         continue;
00779       }
00780     }
00781     else if (param->getType() == ArConfigArg::BOOL)
00782     {
00783       // if the param isn't an in tfail
00784       if (!arg->isArgBool(0))
00785       {
00786         ArLog::log(ArLog::Terse, "%sparameter '%s' is a bool parameter but was given non-bool argument of '%s'", 
00787                  myLogPrefix.c_str(), param->getName(), arg->getArg(0));
00788         ret = false;
00789         if (errorBuffer != NULL)
00790           snprintf(errorBuffer, errorBufferLen, "%s is a bool parameter but was given non-bool argument of '%s'", param->getName(), arg->getArg(0));
00791         continue;
00792       }
00793       valBool = arg->getArgBool(0);
00794       if (param->setBool(valBool, errorBuffer, errorBufferLen))
00795       {
00796       IFDEBUG2(ArLog::log(ArLog::Verbose, "%sSet parameter '%s' to %s",
00797                myLogPrefix.c_str(), param->getName(), valBool ? "true" : "false" ));
00798         continue;
00799       }
00800       else
00801       {
00802       ArLog::log(ArLog::Verbose, "%sCould not set parameter '%s' to %s",
00803                     myLogPrefix.c_str(), param->getName(), valBool ? "true" : "false" );
00804         ret = false;
00805         continue;
00806       }
00807     }
00808     else if (param->getType() == ArConfigArg::STRING)
00809     {
00810       if (param->setString(arg->getFullString()))
00811       {
00812       IFDEBUG2(ArLog::log(ArLog::Verbose, "%sSet parameter string '%s' to '%s'",
00813                           myLogPrefix.c_str(),
00814                               param->getName(), param->getString()));
00815         continue;
00816       }
00817       else
00818       {
00819       ArLog::log(ArLog::Verbose, "%sCould not set string parameter '%s' to '%s'",
00820            myLogPrefix.c_str(),
00821                param->getName(), param->getString());
00822         if (errorBuffer != NULL && errorBuffer[0] == '\0')
00823           snprintf(errorBuffer, errorBufferLen, "%s could not be set to '%s'.", param->getName(), arg->getFullString());
00824 
00825         ret = false;
00826         continue;
00827       }
00828     }
00829     else if (param->getType() == ArConfigArg::FUNCTOR)
00830     {
00831       if (param->setArgWithFunctor(arg))
00832       {
00833       IFDEBUG2(ArLog::log(ArLog::Verbose, "%sSet arg '%s' with '%s'",
00834                myLogPrefix.c_str(), param->getName(), arg->getFullString()));
00835         continue;
00836       }
00837       else
00838       {
00839       ArLog::log(ArLog::Verbose, "ArConfig: Could not set parameter '%s' to '%s'",
00840                  myLogPrefix.c_str(),
00841                       param->getName(), arg->getFullString());
00842         // if it didn't put in an error message make one
00843         if (errorBuffer != NULL && errorBuffer[0] == '\0')
00844           snprintf(errorBuffer, errorBufferLen, "%s could not be set to '%s'.", param->getName(), arg->getFullString());
00845         ret = false;
00846         continue;
00847       }
00848     }
00849     else
00850     {
00851     ArLog::log(ArLog::Terse, "%sHave no argument type for config '%s' in section, got string '%s', in section '%s'.", 
00852       myLogPrefix.c_str(), arg->getExtraString(), arg->getFullString(), mySection.c_str());
00853     }
00854       }
00855     }
00856   }
00857   // if we didn't find this param its because its a parameter in another section, so pass this off to the parser for unknown things
00858   if (!found)
00859   {
00860     ArArgumentBuilder unknown;
00861     unknown.add(arg->getExtraString());
00862     unknown.add(arg->getFullString());
00863     return parseUnknown(&unknown, errorBuffer, errorBufferLen);
00864   }
00865   return ret;
00866 }
00867 
00881 AREXPORT bool ArConfig::parseUnknown(ArArgumentBuilder *arg, 
00882                      char *errorBuffer,
00883                      size_t errorBufferLen)
00884 {
00885   if (arg->getArgc() < 1)
00886   {
00887     IFDEBUG(ArLog::log(ArLog::Verbose, "%sEmpty arg in section '%s', ignoring it", 
00888                        myLogPrefix.c_str(), mySection.c_str()));
00889     return true;
00890   }
00891   if (mySaveUnknown)
00892   {
00893     if (arg->getArgc() < 2)
00894     {
00895       ArLog::log(ArLog::Verbose, "%sNo arg for param '%s' in section '%s', saving it anyways", 
00896                  myLogPrefix.c_str(), arg->getArg(0), mySection.c_str());
00897       addParam(ArConfigArg(arg->getArg(0), ""),
00898            mySection.c_str());
00899     }
00900     else
00901     {
00902       ArLog::log(ArLog::Verbose, "%sUnknown '%s %s' in section '%s', saving it", 
00903                      myLogPrefix.c_str(), arg->getArg(0), arg->getArg(1), mySection.c_str());
00904       addParam(ArConfigArg(arg->getArg(0), arg->getArg(1)),
00905            mySection.c_str());
00906     }
00907   }
00908   else
00909   {
00910     ArLog::log(ArLog::Verbose, "%sUnknown '%s' in section '%s', ignoring it", 
00911                  myLogPrefix.c_str(), arg->getFullString(), mySection.c_str());
00912   }
00913   return true;
00914 }
00932 AREXPORT bool ArConfig::parseFile(const char *fileName, 
00933                                   bool continueOnErrors,
00934                                           bool noFileNotFoundMessage, 
00935                                           char *errorBuffer,
00936                                           size_t errorBufferLen,
00937                                   std::list<std::string> *sectionsToParse)
00938 {
00939   bool ret = true;
00940 
00941   if(fileName)
00942     myFileName = fileName;
00943   else
00944     myFileName = "";
00945 
00946   if (errorBuffer != NULL)
00947     errorBuffer[0] = '\0';
00948 
00949   delete mySectionsToParse; // Should be null, but just in case...
00950   mySectionsToParse = NULL;
00951 
00952   copySectionsToParse(sectionsToParse);
00953 
00954   // parse the file (errors will go into myErrorBuffer from the functors)
00955   ret = myParser.parseFile(fileName, continueOnErrors, noFileNotFoundMessage);
00956 
00957   // set our pointers so we don't copy anymore into/over it
00958   if (errorBuffer != NULL && errorBuffer[0] != '\0')
00959   {
00960     errorBuffer = NULL;
00961     errorBufferLen = 0;
00962   }
00963   //printf("file %s\n", ArUtil::convertBool(ret));
00964 
00965   // if we have a parser and haven't failed (or we continue on errors)
00966   // then parse the arguments from the parser
00967   if (myArgumentParser != NULL && (ret || continueOnErrors))
00968     ret = parseArgumentParser(myArgumentParser, continueOnErrors, 
00969                   errorBuffer, errorBufferLen) && ret;
00970 
00971   // set our pointers so we don't copy anymore into/over it
00972   if (errorBuffer != NULL && errorBuffer[0] != '\0')
00973   {
00974     errorBuffer = NULL;
00975     errorBufferLen = 0;
00976   }
00977   //printf("parser %s\n", ArUtil::convertBool(ret));
00978   
00979   // if we haven't failed (or we continue on errors) then call the
00980   // process file callbacks
00981   if (ret || continueOnErrors)
00982     ret = callProcessFileCallBacks(continueOnErrors, errorBuffer,
00983                       errorBufferLen) && ret;
00984   // copy our error if we have one and haven't copied in yet
00985   // set our pointers so we don't copy anymore into/over it
00986   if (errorBuffer != NULL && errorBuffer[0] != '\0')
00987   {
00988     errorBuffer = NULL;
00989     errorBufferLen = 0;
00990   }
00991 
00992   // Done with the temp parsing info, so delete it...
00993   delete mySectionsToParse; 
00994   mySectionsToParse = NULL;
00995 
00996   //printf("callbacks %s\n", ArUtil::convertBool(ret));
00997   return ret;
00998 }
00999 
01015 AREXPORT bool ArConfig::writeFile(const char *fileName, 
01016                                   bool append, 
01017                                           std::set<std::string> *alreadyWritten,
01018                                           bool writePriorities,
01019                                   std::list<std::string> *sectionsToWrite)
01020 {
01021   FILE *file;
01022 
01023   std::set<std::string> writtenSet;
01024   std::set<std::string> *written;
01025   if (alreadyWritten != NULL)
01026     written = alreadyWritten;
01027   else
01028     written = &writtenSet;
01029   //std::list<ArConfigArg>::iterator it;
01030 
01031   // later this'll have a prefix
01032   std::string realFileName;
01033   if (fileName[0] == '/' || fileName[0] == '\\')
01034   {
01035     realFileName = fileName;
01036   }
01037   else
01038   {
01039     realFileName = myBaseDirectory;
01040     realFileName += fileName;
01041   }
01042 
01043   std::string mode;
01044 
01045   if (append)
01046     mode = "a";
01047   else
01048     mode = "w";
01049 
01050   if ((file = fopen(realFileName.c_str(), mode.c_str())) == NULL)
01051   {
01052     ArLog::log(ArLog::Terse, "%sCannot open file '%s' for writing",
01053            myLogPrefix.c_str(), realFileName.c_str());
01054     return false;
01055   }
01056 
01057   bool firstSection = true;
01058   std::list<ArConfigSection *>::iterator sectionIt;
01059   ArConfigSection *section = NULL;
01060   
01061   // first write out the generic section (ie sectionless stuff, mostly
01062   // for backwards compatibility)
01063   if ( ((section = findSection("")) != NULL) &&
01064        (sectionsToWrite == NULL) )
01065   {
01066     if (!firstSection)
01067       fprintf(file, "\n");
01068     firstSection = false;
01069     writeSection(section, file, written, writePriorities);
01070   }
01071 
01072   // then write out the rest (skip the generic section if we have one)
01073   for (sectionIt = mySections.begin(); 
01074        sectionIt != mySections.end(); 
01075        sectionIt++)
01076   {
01077     section = (*sectionIt);
01078     if (strcmp(section->getName(), "") == 0)
01079       continue;
01080 
01081     if (sectionsToWrite != NULL) {
01082       bool isSectionFound = false;
01083       for (std::list<std::string>::iterator swIter = sectionsToWrite->begin();
01084            swIter != sectionsToWrite->end();
01085            swIter++) {
01086         std::string sp = *swIter;
01087         if (ArUtil::strcasecmp(section->getName(), sp.c_str()) == 0) {
01088           isSectionFound = true;
01089           break;
01090         }
01091       } // end for each section to write
01092 
01093       if (!isSectionFound) {
01094         continue;
01095       }
01096     
01097     } // end if sections specified
01098 
01099     if (!firstSection)
01100       fprintf(file, "\n");
01101     firstSection = false;
01102 
01103     writeSection(section, file, written, writePriorities);
01104   }
01105   fclose(file);
01106   return true;
01107 }
01108 
01109 AREXPORT void ArConfig::writeSection(ArConfigSection *section, FILE *file,
01110                      std::set<std::string> *alreadyWritten,
01111                      bool writePriorities)
01112 {
01113   // holds each line
01114   char line[1024];
01115   // holds the fprintf
01116   char startLine[128];
01117   bool commented = false;
01118   unsigned int startCommentColumn = 25;
01119 
01120   std::list<ArArgumentBuilder *>::const_iterator argIt;
01121   const std::list<ArArgumentBuilder *> *argList = NULL;
01122 
01123 
01124   std::list<ArConfigArg>::iterator paramIt;
01125   std::list<ArConfigArg> *params = NULL;
01126   ArConfigArg *param = NULL;
01127 
01129   alreadyWritten->clear();
01130   
01131   if (section->getName() != NULL && strlen(section->getName()) > 0)
01132   {
01133     //fprintf(file, "; %s\n", section->getName());
01134     fprintf(file, "Section %s\n", section->getName());
01135   }
01136   sprintf(line, "; ");
01137   if (section->getComment() != NULL && strlen(section->getComment()) > 0)
01138   {
01139     ArArgumentBuilder descr;
01140     descr.add(section->getComment());
01141     for (unsigned int i = 0; i < descr.getArgc(); i++)
01142     {
01143       // see if we're over, if we are write this line out and start
01144       // the next one
01145       if (strlen(line) + strlen(descr.getArg(i)) > 78)
01146       {
01147           fprintf(file, "%s\n", line);
01148           sprintf(line, "; ");
01149           sprintf(line, "%s %s", line, descr.getArg(i));
01150       }
01151       // if its not the end of the line toss this word in
01152       else
01153       {
01154           sprintf(line, "%s %s", line, descr.getArg(i));
01155       }
01156     }
01157     // put the last line into the file
01158     fprintf(file, "%s\n", line);
01159   }
01160   
01161   params = section->getParams();
01162   // find this parameter
01163   for (paramIt = params->begin(); paramIt != params->end(); paramIt++)
01164   {
01165     commented = false;
01166     param = &(*paramIt);
01167     
01168     if (param->getType() == ArConfigArg::SEPARATOR) {
01169       continue;
01170     }
01171 
01172     if (alreadyWritten != NULL && 
01173           param->getType() != ArConfigArg::DESCRIPTION_HOLDER &&
01174           alreadyWritten->find(param->getName()) != alreadyWritten->end())
01175       continue;
01176     else if (alreadyWritten != NULL && 
01177          param->getType() != ArConfigArg::DESCRIPTION_HOLDER)
01178     {
01179       alreadyWritten->insert(param->getName());
01180     }
01181     
01182     // if the type is a functor then we need to handle all of it up
01183     // here since its a special case both in regards to comments and values
01184     if (param->getType() == ArConfigArg::FUNCTOR)
01185     {
01186       // put the comments in the file first
01187       sprintf(line, "; ");
01188       if (param->getDescription() != NULL && 
01189         strlen(param->getDescription()) > 0)
01190       {
01191         ArArgumentBuilder descr;
01192         descr.add(param->getDescription());
01193         for (unsigned int i = 0; i < descr.getArgc(); i++)
01194         {
01195           // see if we're over, if we are write this line out and start
01196           // the next one
01197           if (strlen(line) + strlen(descr.getArg(i)) > 78)
01198           {
01199             fprintf(file, "%s\n", line);
01200             sprintf(line, "; ");
01201             sprintf(line, "%s %s", line, descr.getArg(i));
01202           }
01203           // if its not the end of the line toss this word in
01204           else
01205           {
01206             sprintf(line, "%s %s", line, descr.getArg(i));
01207           }
01208         }
01209         // put the last line into the file
01210         fprintf(file, "%s\n", line);
01211       }
01212       // now put in the values
01213       argList = param->getArgsWithFunctor();
01214       if (argList != NULL)
01215         for (argIt = argList->begin(); argIt != argList->end(); argIt++)
01216         {
01217           // if there's a space in the name then quote the param name
01218           if (strchr(param->getName(), ' ') != NULL || 
01219             strchr(param->getName(), '\t') != NULL)
01220             fprintf(file, "\"%s\" %s\n", param->getName(), 
01221             (*argIt)->getFullString());
01222           else
01223             fprintf(file, "%s %s\n", param->getName(), 
01224             (*argIt)->getFullString());
01225         }
01226 
01227         // okay, we did it all, now continue
01228         continue;
01229     }
01230 
01231     // if its a string holder just write the name without quotes
01232     // (since its the value not really the name)
01233     if (param->getType() == ArConfigArg::STRING_HOLDER)
01234     {
01235       fprintf(file, "%s %s\n", param->getName(), param->getString());
01236       // now put a blank line between params if we should
01237       if (!myNoBlanksBetweenParams)
01238         fprintf(file, "\n");
01239       continue;
01240     }
01241 
01242     // if there's a space in the name then quote the param name
01243     if (strchr(param->getName(), ' ') != NULL || 
01244       strchr(param->getName(), '\t') != NULL)
01245       sprintf(line, "\"%s\"", param->getName());
01246     else
01247       sprintf(line, "%s", param->getName());
01248     if (param->getType() == ArConfigArg::INT)
01249     {
01250       sprintf(line, "%s %d", line, param->getInt());
01251     }
01252     else if (param->getType() == ArConfigArg::DOUBLE)
01253     {
01254       sprintf(line, "%s %g", line, param->getDouble());
01255     }
01256     else if (param->getType() == ArConfigArg::STRING)
01257     {
01258       sprintf(line, "%s %s", line, param->getString());
01259     }
01260     else if (param->getType() == ArConfigArg::BOOL)
01261     {
01262       sprintf(line, "%s %s", line, param->getBool() ? "true" : "false"); 
01263     }
01264     else if (param->getType() == ArConfigArg::DESCRIPTION_HOLDER)
01265     {
01266       if (strlen(param->getDescription()) == 0)
01267       {
01268         fprintf(file, "\n");
01269         continue;
01270       }
01271     }
01272     else
01273     {
01274       ArLog::log(ArLog::Terse, "%sno argument type", myLogPrefix.c_str());
01275     }
01276     // configure our start of line part
01277     if (param->getType() == ArConfigArg::DESCRIPTION_HOLDER)
01278       sprintf(startLine, "; ");
01279     else
01280       sprintf(startLine, "%%-%ds;", startCommentColumn);
01281     // if our line is already longer then where we want to go put in
01282     // an extra space
01283     if (strlen(line) >= startCommentColumn)
01284       sprintf(line, "%-s ;", line);
01285     // if its not then just put the start in
01286     else
01287       sprintf(line, startLine, line);
01288     // if its an int we want to put in ranges if there are any
01289     if (param->getType() == ArConfigArg::INT)
01290     {
01291       if (param->getMinInt() != INT_MIN && param->getMaxInt() != INT_MAX)
01292       {
01293         sprintf(line, "%s range [%d, %d], ", line, 
01294           param->getMinInt(), param->getMaxInt());
01295       }
01296       else if (param->getMinInt() != INT_MIN)
01297         sprintf(line, "%s minumum %d, ", line, param->getMinInt());
01298       else if (param->getMaxInt() != INT_MAX)
01299         sprintf(line, "%s maximum %d, ", line, param->getMaxInt());
01300     }
01301     if (param->getType() == ArConfigArg::DOUBLE)
01302     {
01303       if (param->getMinDouble() != -HUGE_VAL && 
01304         param->getMaxDouble() != HUGE_VAL)
01305         sprintf(line, "%s range [%g, %g], ", line, param->getMinDouble(), 
01306         param->getMaxDouble());
01307       else if (param->getMinDouble() != -HUGE_VAL)
01308         sprintf(line, "%s minimum %g, ", line, 
01309         param->getMinDouble());
01310       else if (param->getMaxDouble() != HUGE_VAL)
01311         sprintf(line, "%s Maximum %g, ", line, 
01312         param->getMaxDouble());
01313     }
01314 
01315     // if we have a description to put in, put it in with word wrap
01316     if (param->getDescription() != NULL && 
01317       strlen(param->getDescription()) > 0)
01318     {
01319       ArArgumentBuilder descr;
01320       descr.add(param->getDescription());
01321       for (unsigned int i = 0; i < descr.getArgc(); i++)
01322       {
01323         // see if we're over, if we are write this line out and start
01324         // the next one
01325         if (strlen(line) + strlen(descr.getArg(i)) > 78)
01326         {
01327           fprintf(file, "%s\n", line);
01328           sprintf(line, startLine, "");
01329           sprintf(line, "%s %s", line, descr.getArg(i));
01330         }
01331         // if its not the end of the line toss this word in
01332         else
01333         {
01334           sprintf(line, "%s %s", line, descr.getArg(i));
01335         }
01336       }
01337       // put the last line into the file
01338       fprintf(file, "%s\n", line);
01339     }
01340     // if they're no description just end the line
01341     else 
01342       fprintf(file, "%s\n", line);
01343     // if they have a config priority put that on its own line
01344     if (writePriorities)
01345     {
01346       sprintf(line, startLine, "");
01347       fprintf(file, "%s Priority: %s\n", line,
01348         ArPriority::getPriorityName(param->getConfigPriority()));
01349     }
01350     // now put a blank line between params if we should
01351     if (!myNoBlanksBetweenParams)
01352       fprintf(file, "\n");
01353   }
01354 }
01355 
01356 AREXPORT const char *ArConfig::getBaseDirectory(void) const
01357 {
01358   return myBaseDirectory.c_str();
01359 }
01360 
01361 AREXPORT void ArConfig::setBaseDirectory(const char *baseDirectory)
01362 {
01363   if (baseDirectory != NULL && strlen(baseDirectory) > 0)
01364     myBaseDirectory = baseDirectory;
01365   else
01366     myBaseDirectory = "";
01367    
01368   myParser.setBaseDirectory(baseDirectory);
01369 }
01370 
01371 AREXPORT const char *ArConfig::getFileName(void) const
01372 {
01373   return myFileName.c_str();
01374 }
01375 
01392 AREXPORT void ArConfig::addProcessFileCB(ArRetFunctor<bool> *functor,
01393                      int priority)
01394 {
01395   myProcessFileCBList.insert(
01396       std::pair<int, ProcessFileCBType *>(-priority, 
01397                           new ProcessFileCBType(functor)));
01398 }
01399 
01403 AREXPORT void ArConfig::remProcessFileCB(ArRetFunctor<bool> *functor)
01404 {
01405   std::multimap<int, ProcessFileCBType *>::iterator it;
01406   ProcessFileCBType *cb;
01407 
01408   for (it = myProcessFileCBList.begin(); it != myProcessFileCBList.end(); ++it)
01409   {
01410     if ((*it).second->haveFunctor(functor))
01411     {
01412       cb = (*it).second;
01413       myProcessFileCBList.erase(it);
01414       delete cb;
01415       remProcessFileCB(functor);
01416       return;
01417     }
01418   }
01419 }
01420 
01444 AREXPORT void ArConfig::addProcessFileWithErrorCB(
01445     ArRetFunctor2<bool, char *, size_t> *functor,
01446     int priority)
01447 {
01448   myProcessFileCBList.insert(
01449       std::pair<int, ProcessFileCBType *>(-priority, 
01450                       new ProcessFileCBType(functor)));
01451 }
01452 
01456 AREXPORT void ArConfig::remProcessFileCB(
01457     ArRetFunctor2<bool, char *, size_t> *functor)
01458 {
01459   std::multimap<int, ProcessFileCBType *>::iterator it;
01460   ProcessFileCBType *cb;
01461 
01462   for (it = myProcessFileCBList.begin(); it != myProcessFileCBList.end(); ++it)
01463   {
01464     if ((*it).second->haveFunctor(functor))
01465     {
01466       cb = (*it).second;
01467       myProcessFileCBList.erase(it);
01468       delete cb;
01469       remProcessFileCB(functor);
01470     }
01471   }
01472 }
01473 
01474 AREXPORT bool ArConfig::callProcessFileCallBacks(bool continueOnErrors,
01475                          char *errorBuffer,
01476                          size_t errorBufferLen)
01477 {
01478   bool ret = true;
01479   std::multimap<int, ProcessFileCBType *>::iterator it;
01480   ProcessFileCBType *callback;
01481   ArLog::LogLevel level = myProcessFileCallbacksLogLevel;
01482 
01483   // reset our section to nothing again
01484   mySection = "";
01485 
01486   // in windows, can't simply declare an array of errorBufferLen -- so
01487   // allocate one.
01488   
01489   // empty the buffer, we're only going to put the first error in it
01490   if (errorBuffer != NULL && errorBufferLen > 0)
01491     errorBuffer[0] = '\0';
01492 
01493   ArLog::log(level, "%sProcessing file", myLogPrefix.c_str());
01494   for (it = myProcessFileCBList.begin(); 
01495        it != myProcessFileCBList.end(); 
01496        ++it)
01497   {
01498     callback = (*it).second;
01499     if (callback->getName() != NULL && callback->getName()[0] != '\0')
01500       ArLog::log(level, "%sProcessing functor '%s' (%d)", 
01501                  myLogPrefix.c_str(),
01502                      callback->getName(), -(*it).first);
01503     else
01504       ArLog::log(level, "%sProcessing unnamed functor (%d)", 
01505                  myLogPrefix.c_str(),
01506                  -(*it).first);
01507     if (!(*it).second->call(errorBuffer, errorBufferLen))
01508     {
01509       //printf("# %s\n", scratchBuffer); 
01510 
01511       // if there is an error buffer and it got filled get rid of our
01512       // pointer to it
01513       if (errorBuffer != NULL && errorBuffer[0] != '\0')
01514       {
01515     errorBuffer = NULL;
01516     errorBufferLen = 0;
01517       }
01518       ret = false;
01519       if (!continueOnErrors)
01520       {
01521     if (callback->getName() != NULL && callback->getName()[0] != '\0')
01522       ArLog::log(ArLog::Normal, "ArConfig: Failed, stopping because the '%s' process file callback failed", 
01523              callback->getName());
01524     else
01525       ArLog::log(ArLog::Normal, "ArConfig: Failed, stopping because unnamed process file callback failed");
01526     break;
01527       }
01528       else
01529       {
01530     if (callback->getName() != NULL && callback->getName()[0] != '\0')
01531       ArLog::log(ArLog::Normal, "ArConfig: Failed but continuing, the '%s' process file callback failed", 
01532              callback->getName());
01533     else
01534       ArLog::log(ArLog::Normal, "ArConfig: Failed but continuing, an unnamed process file callback failed");
01535       }
01536 
01537     }
01538   }
01539   if (ret || continueOnErrors)
01540   {
01541     ArLog::log(level, "%sProcessing with own processFile",
01542                  myLogPrefix.c_str());
01543     if (!processFile())
01544       ret = false;
01545   }
01546   ArLog::log(level, "%sDone processing file, ret is %s", myLogPrefix.c_str(),
01547          ArUtil::convertBool(ret));
01548 
01549   return ret;
01550 }
01551 
01552 
01553 AREXPORT std::list<ArConfigSection *> *ArConfig::getSections(void)
01554 {
01555   return &mySections;
01556 }
01557 
01558 AREXPORT void ArConfig::setNoBlanksBetweenParams(bool noBlanksBetweenParams)
01559 {
01560   myNoBlanksBetweenParams = noBlanksBetweenParams;
01561 }
01562 
01563 AREXPORT bool ArConfig::getNoBlanksBetweenParams(void)
01564 {
01565   return myNoBlanksBetweenParams;
01566 }
01567 
01573 AREXPORT void ArConfig::useArgumentParser(ArArgumentParser *parser)
01574 {
01575   myArgumentParser = parser;
01576 }
01577 
01578 AREXPORT bool ArConfig::parseArgumentParser(ArArgumentParser *parser,   
01579                         bool continueOnError,
01580                         char *errorBuffer,
01581                         size_t errorBufferLen)
01582 {
01583   std::list<ArConfigSection *>::iterator sectionIt;
01584   std::list<ArConfigArg>::iterator paramIt;
01585   ArConfigSection *section = NULL;
01586   ArConfigArg *param = NULL;
01587   std::list<ArConfigArg> *params = NULL;
01588 
01589   bool ret;
01590   size_t i;
01591   std::string strArg;
01592   std::string strUndashArg;
01593   ArArgumentBuilder builder;
01594   bool plainMatch;
01595 
01596   for (i = 0; i < parser->getArgc(); i++)
01597   {
01598     if (parser->getArg(i) == NULL)
01599     {
01600       ArLog::log(ArLog::Terse, "%sset up wrong (parseArgumentParser broken).",
01601                  myLogPrefix.c_str());
01602       if (errorBuffer != NULL)
01603         strncpy(errorBuffer, 
01604         "ArConfig set up wrong (parseArgumentParser broken).", 
01605         errorBufferLen);
01606       return false;
01607     }
01608     strArg = parser->getArg(i); 
01609     if (parser->getArg(i)[0] == '-')
01610       strUndashArg += &parser->getArg(i)[1]; 
01611     else
01612       strUndashArg = "";
01613     //printf("normal %s undash %s\n", strArg.c_str(), strUndashArg.c_str());
01614     for (sectionIt = mySections.begin(); 
01615          sectionIt != mySections.end(); 
01616          sectionIt++)
01617     {
01618       section = (*sectionIt);
01619       params = section->getParams();
01620 
01621       for (paramIt = params->begin(); paramIt != params->end(); paramIt++)
01622       {
01623         param = &(*paramIt);
01624         /*
01625         printf("### normal %s undash %s %d %d\n", strArg.c_str(), 
01626         strUndashArg.c_str(),
01627         ArUtil::strcasecmp(param->getName(), strArg),
01628         ArUtil::strcasecmp(param->getName(), strUndashArg));
01629         */
01630         if (strlen(param->getName()) > 0 &&
01631           ((plainMatch = ArUtil::strcasecmp(param->getName(),strArg)) == 0 ||
01632           ArUtil::strcasecmp(param->getName(), strUndashArg) == 0))
01633         {
01634           if (plainMatch == 0)
01635             builder.setExtraString(strArg.c_str());
01636           else
01637             builder.setExtraString(strUndashArg.c_str());
01638           if (i+1 < parser->getArgc())
01639           {
01640             builder.add(parser->getArg(i+1));
01641             parser->removeArg(i+1);
01642           }
01643           parser->removeArg(i);
01644 
01645           // set us to use the section this is in and then parse the argument
01646           std::string oldSection = mySection;
01647           bool oldSectionBroken = mySectionBroken;
01648           bool oldSectionIgnored = mySectionIgnored;
01649           bool oldUsingSections = myUsingSections;
01650           bool oldDuplicateParams = myDuplicateParams;
01651           mySection = section->getName();
01652           mySectionBroken = false;
01653           mySectionIgnored = false; // ?? TODO
01654           myUsingSections = true;
01655           myDuplicateParams = false;
01656           ret = parseArgument(&builder, errorBuffer, errorBufferLen);
01657           mySection = oldSection;
01658           mySectionBroken = oldSectionBroken;
01659           mySectionIgnored = oldSectionIgnored;
01660           myUsingSections = oldUsingSections;
01661           myDuplicateParams = oldDuplicateParams;
01662 
01663           // if we parsed the argument right or are continuing on
01664           // errors call ourselves again (so we don't hose iterators up above)
01665           if (ret || continueOnError)
01666           {
01667             //printf("Ret %s\n", ArUtil::convertBool(ret));
01668             return ret && parseArgumentParser(parser, continueOnError, 
01669               errorBuffer, errorBufferLen);
01670           }
01671           else
01672             return false;
01673         }
01674       }
01675     }
01676   }
01677 
01678   return true;
01679 }
01680 
01681 AREXPORT ArConfigSection *ArConfig::findSection(const char *sectionName) const
01682 {
01683   ArConfigSection *section = NULL;
01684   ArConfigSection *tempSection = NULL;
01685 
01686   for (std::list<ArConfigSection *>::const_iterator sectionIt = mySections.begin(); 
01687        sectionIt != mySections.end(); 
01688        sectionIt++)
01689   {
01690     tempSection = (*sectionIt);
01691     if (ArUtil::strcasecmp(tempSection->getName(), sectionName) == 0)
01692     {
01693       section = tempSection;
01694     }
01695   }
01696   return section;
01697 
01698 } // end method findSection
01699 
01700 void ArConfig::copySectionsToParse(std::list<std::string> *from)
01701 {
01702   mySectionsToParse = NULL;
01703   if (from != NULL) {
01704     mySectionsToParse = new std::list<std::string>();
01705     for (std::list<std::string>::const_iterator spIter = from->begin();
01706          spIter != from->end();
01707          spIter++) {
01708       mySectionsToParse->push_back(*spIter);
01709     } // end for each section to parse
01710   } // end if copy sections to parse
01711 
01712 } // end method copySectionsToParse
01713 
01714 
01715 
01716 AREXPORT void ArConfig::clearAllValueSet(void)
01717 {
01718   std::list<ArConfigSection *> *sections;
01719   ArConfigSection *section;
01720   std::list<ArConfigSection *>::iterator sectionIt;
01721   
01722   std::list<ArConfigArg> *params;
01723   ArConfigArg *param;
01724   std::list<ArConfigArg>::iterator paramIt;
01725 
01726   sections = getSections();
01727   for (sectionIt = sections->begin(); 
01728        sectionIt != sections->end(); 
01729        sectionIt++)
01730   {
01731     section = (*sectionIt);
01732     params = section->getParams();
01733     for (paramIt = params->begin(); paramIt != params->end(); paramIt++)
01734     {
01735       param = &(*paramIt);
01736       param->clearValueSet();
01737     }
01738   }
01739 }
01740 
01741 AREXPORT void ArConfig::removeAllUnsetValues(void)
01742 {
01743   std::list<ArConfigSection *> *sections;
01744   ArConfigSection *section;
01745   std::list<ArConfigSection *>::iterator sectionIt;
01746   
01747   std::list<ArConfigArg> *params;
01748   ArConfigArg *param;
01749   std::list<ArConfigArg>::iterator paramIt;
01750   std::list<std::list<ArConfigArg>::iterator> removeParams;
01751   std::list<std::list<ArConfigArg>::iterator>::iterator removeParamsIt;
01752 
01753   sections = getSections();
01754   for (sectionIt = sections->begin(); 
01755        sectionIt != sections->end(); 
01756        sectionIt++)
01757   {
01758     section = (*sectionIt);
01759     params = section->getParams();
01760     for (paramIt = params->begin(); paramIt != params->end(); paramIt++)
01761     {
01762       param = &(*paramIt);
01763       if (!param->isValueSet() && 
01764       param->getType() != ArConfigArg::SEPARATOR && 
01765       param->getType() != ArConfigArg::STRING_HOLDER && 
01766       param->getType() != ArConfigArg:: DESCRIPTION_HOLDER)
01767       {
01768     removeParams.push_back(paramIt);
01769       }
01770     }
01771     while ((removeParamsIt = removeParams.begin()) != removeParams.end())
01772     {
01773       ArLog::log(ArLog::Verbose, 
01774          "%s:removeAllUnsetValues: Removing %s:%s", 
01775      myLogPrefix.c_str(),
01776          section->getName(), (*(*removeParamsIt)).getName());
01777       section->getParams()->erase((*removeParamsIt));
01778       removeParams.pop_front();      
01779     }
01780   }
01781 }
01782 
01783 
01784 AREXPORT ArConfigSection::ArConfigSection(const char *name, 
01785                       const char *comment) 
01786 {
01787   myName = name;
01788   if (comment != NULL)
01789     myComment = comment;
01790   else
01791     myComment = "";
01792   myFlags = new ArArgumentBuilder(512, '|');
01793 }
01794 
01795 
01796 AREXPORT ArConfigSection::ArConfigSection(const ArConfigSection &section) 
01797 {
01798   myName = section.myName;
01799   myComment = section.myComment;
01800   myFlags = new ArArgumentBuilder(512, '|');
01801   myFlags->add(section.myFlags->getFullString());
01802 
01803   for (std::list<ArConfigArg>::const_iterator it = section.myParams.begin(); 
01804        it != section.myParams.end(); 
01805        it++) 
01806   {
01807     myParams.push_back(*it);
01808   }
01809 }
01810 
01811 AREXPORT ArConfigSection &ArConfigSection::operator=(const ArConfigSection &section) 
01812 {
01813   if (this != &section) 
01814   {
01815     
01816     myName = section.getName();
01817     myComment = section.getComment();
01818     delete myFlags;
01819     myFlags = new ArArgumentBuilder(512, '|');
01820     myFlags->add(section.myFlags->getFullString());
01821     
01822     for (std::list<ArConfigArg>::const_iterator it = section.myParams.begin(); 
01823      it != section.myParams.end(); 
01824      it++) 
01825     {
01826       myParams.push_back(*it);
01827     }
01828   }
01829   return *this;
01830 }
01831 
01832 
01833 
01834 AREXPORT ArConfigSection::~ArConfigSection()
01835 {
01836   delete myFlags;
01837 }
01838 
01839 
01840 
01841 AREXPORT ArConfigArg *ArConfigSection::findParam(const char *paramName)
01842 {
01843   ArConfigArg *param = NULL;
01844   ArConfigArg *tempParam = NULL;
01845 
01846   for (std::list<ArConfigArg>::iterator pIter = myParams.begin(); 
01847        pIter != myParams.end(); 
01848        pIter++)
01849   {
01850     // TODO: Does this do what I'm hoping it does?
01851     tempParam = &(*pIter);
01852     // ignore string holders 
01853     if (tempParam->getType() == ArConfigArg::STRING_HOLDER)
01854       continue;
01855     if (ArUtil::strcasecmp(tempParam->getName(), paramName) == 0)
01856     {
01857       param = tempParam;
01858     }
01859   }
01860   return param;
01861 
01862 } // end method findParam
01863 
01864 
01865 AREXPORT bool ArConfigSection::remStringHolder(const char *paramName)
01866 {
01867   ArConfigArg *tempParam = NULL;
01868   
01869   for (std::list<ArConfigArg>::iterator pIter = myParams.begin(); 
01870        pIter != myParams.end(); 
01871        pIter++)
01872   {
01873     // TODO: Does this do what I'm hoping it does?
01874     tempParam = &(*pIter);
01875     // pay attention to only string holders
01876     if (tempParam->getType() != ArConfigArg::STRING_HOLDER ||
01877     paramName == NULL || paramName[0] == '\0')
01878       continue;
01879     if (ArUtil::strcasecmp(tempParam->getName(), paramName) == 0)
01880     {
01881       myParams.erase(pIter);
01882       remStringHolder(paramName);
01883       return true;
01884     }
01885   }
01886   return false;
01887 }
01888 
01889 AREXPORT bool ArConfigSection::hasFlag(const char *flag) const
01890 {
01891   size_t i;
01892   for (i = 0; i < myFlags->getArgc(); i++)
01893   {
01894     if (strcmp(myFlags->getArg(i), flag) == 0)
01895     {
01896       return true;
01897     }
01898   }
01899   return false;
01900 }
01901 
01902 AREXPORT bool ArConfigSection::remFlag(const char *flag)
01903 {
01904   size_t i;
01905   for (i = myFlags->getArgc(); i < myFlags->getArgc(); i++)
01906   {
01907     if (strcmp(myFlags->getArg(i), flag) == 0)
01908     {
01909       myFlags->removeArg(i);
01910       return true;
01911     }
01912   }
01913 
01914   return false;
01915 }
01916 

Generated on Tue Feb 20 10:51:39 2007 for Aria by  doxygen 1.4.0