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

ArConfig.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 "ArConfig.h"
00030 #include "ArArgumentBuilder.h"
00031 #include "ArLog.h"
00032 
00039 ArConfig::ArConfig(const char *baseDirectory,
00040                             bool noBlanksBetweenParams,
00041                             bool ignoreBounds, 
00042                             bool failOnBadSection) : 
00043   myProcessFileCBList(), 
00044   myNoBlanksBetweenParams(noBlanksBetweenParams),
00045   myBaseDirectory(),
00046   myParser(NULL),
00047   mySections(),
00048   myParserCB(this, &ArConfig::parseArgument),
00049   mySectionCB(this, &ArConfig::parseSection)
00050 {
00051   if (!myParser.addHandlerWithError("section", &mySectionCB))
00052   {
00053     ArLog::log(ArLog::Normal, "Could not add section to file parser, horrific failure");
00054   }
00055   myArgumentParser = NULL;
00056   setBaseDirectory(baseDirectory);
00057   myIgnoreBounds = ignoreBounds;
00058   myFailOnBadSection = failOnBadSection;
00059   myProcessFileCallbacksLogLevel = ArLog::Verbose;
00060   myUsingSections = false;
00061   mySectionBroken = false;
00062   myDuplicateParams = false;
00063   mySection = "";
00064 }
00065 
00066 ArConfig::~ArConfig()
00067 {
00068   clearSections();
00069 }
00070 
00071 
00072 ArConfig::ArConfig(const ArConfig &config) :
00073   myProcessFileCBList(),    // TODO: Copy? (don't think we need to)
00074   myNoBlanksBetweenParams(config.myNoBlanksBetweenParams),
00075   myBaseDirectory(),
00076   myParser(NULL),  
00077   mySections(),
00078   myParserCB(this, &ArConfig::parseArgument),
00079   mySectionCB(this, &ArConfig::parseSection) 
00080 {
00081   myArgumentParser = NULL;
00082   setBaseDirectory(config.getBaseDirectory());
00083   myIgnoreBounds = config.myIgnoreBounds;
00084   myFailOnBadSection = config.myFailOnBadSection;
00085   myProcessFileCallbacksLogLevel = config.myProcessFileCallbacksLogLevel;
00086   mySectionBroken = config.mySectionBroken;
00087   mySection = config.mySection;
00088   myUsingSections = config.myUsingSections;
00089   myDuplicateParams = config.myDuplicateParams;
00090 
00091   std::list<ArConfigSection *>::const_iterator it;
00092   for (it = config.mySections.begin(); 
00093        it != config.mySections.end(); 
00094        it++) 
00095   {
00096     mySections.push_back(new ArConfigSection(*(*it)));
00097   }
00098   myParser.remHandler(&myParserCB);
00099   myParser.remHandler(&mySectionCB);
00100   addParserHandlers();
00101 
00102 }
00103 
00104 
00105 ArConfig &ArConfig::operator=(const ArConfig &config)
00106 {
00107   if (this != &config) {
00108     
00109     // TODO: The following attributes also need to be copied (or 
00110     // something) -- ditto for copy ctor:
00111     //     myProcessFileCBList
00112     //     myParser
00113     //     myParserCB
00114     //     mySectionCB
00115     myArgumentParser = NULL;
00116     setBaseDirectory(config.getBaseDirectory());
00117     myNoBlanksBetweenParams = config.myNoBlanksBetweenParams;
00118     myIgnoreBounds = config.myIgnoreBounds;    
00119     myFailOnBadSection = config.myFailOnBadSection;
00120     mySection = config.mySection;
00121     mySectionBroken = config.mySectionBroken;
00122     myUsingSections = config.myUsingSections;
00123     myDuplicateParams = config.myDuplicateParams;
00124     mySections.clear();
00125     std::list<ArConfigSection *>::const_iterator it;
00126     for (it = config.mySections.begin(); 
00127          it != config.mySections.end(); 
00128          it++) 
00129     {
00130       mySections.push_back(new ArConfigSection(*(*it)));
00131     }
00132     myParser.remHandler(&myParserCB);
00133     myParser.remHandler(&mySectionCB);
00134     addParserHandlers();
00135     
00136   }
00137   return *this;
00138 
00139 }
00140 
00141 void ArConfig::clearSections(void)
00142 {
00143   while (mySections.begin() != mySections.end())
00144   {
00145     delete mySections.front();
00146     mySections.pop_front();
00147   }
00148 }
00149 
00150 void ArConfig::clearAll(void)
00151 {
00152   clearSections();
00153   myProcessFileCBList.clear();
00154 }
00155 
00156 void ArConfig::addParserHandlers(void)
00157 {
00158   std::list<ArConfigSection *>::const_iterator it;
00159   std::list<ArConfigArg> *params;
00160   std::list<ArConfigArg>::iterator pit;
00161 
00162   if (!myParser.addHandlerWithError("section", &mySectionCB))
00163     ArLog::log(ArLog::Verbose, 
00164               "ArConfig: Could not add section parser (probably unimportant)");
00165 
00166   for (it = mySections.begin(); 
00167        it != mySections.end(); 
00168        it++) 
00169   {
00170     params = (*it)->getParams();
00171     if (params == NULL)
00172       continue;
00173     for (pit = params->begin(); pit != params->end(); pit++)
00174     {
00175       if (!myParser.addHandlerWithError((*pit).getName(), &myParserCB))
00176         ArLog::log(ArLog::Verbose, 
00177                    "ArConfig: Could not add keyword %s (probably unimportant)",
00178                    (*pit).getName());
00179     }
00180   }
00181 
00182 }
00183 
00188 void ArConfig::setSectionComment(const char *sectionName, 
00189                                           const char *comment)
00190 {
00191   ArConfigSection *section = findSection(sectionName);
00192 
00193   if (section == NULL)
00194   {
00195     ArLog::log(ArLog::Verbose, "Making new section '%s'", sectionName);
00196     section = new ArConfigSection(sectionName, comment);
00197     mySections.push_back(section);
00198   }
00199   else
00200     section->setComment(comment);
00201 }
00202 
00203 bool ArConfig::addParam(const ArConfigArg &arg, const char *sectionName,
00204                                                  ArPriority::Priority priority)
00205 {
00206   ArConfigSection *section = findSection(sectionName);
00207 
00208   //printf("SECTION '%s' name '%s' desc '%s'\n", sectionName, arg.getName(), arg.getDescription());
00209   if (section == NULL)
00210   {
00211     ArLog::log(ArLog::Verbose, "Making new section '%s'", sectionName);
00212     section = new ArConfigSection(sectionName);
00213     mySections.push_back(section);
00214   }
00215    
00216   std::list<ArConfigArg> *params = section->getParams();
00217 
00218   if (params == NULL)
00219   {
00220     ArLog::log(ArLog::Terse, "Something has gone hideously wrong in ArConfig::addParam");
00221     return false;
00222   }
00223   
00224 
00225   // see if we have this parameter in another section so we can require sections
00226   std::list<ArConfigSection *>::iterator sectionIt;
00227   
00228   for (sectionIt = mySections.begin(); 
00229        sectionIt != mySections.end(); 
00230        sectionIt++)
00231   {
00232     // if we have an argument of this name but we don't have see if
00233     // this section is our own, if its not then note we have
00234     // duplicates
00235     if (strlen(arg.getName()) > 0 && 
00236         (*sectionIt)->findParam(arg.getName()) != NULL && 
00237         strcasecmp((*sectionIt)->getName(), section->getName()) != 0)
00238     {
00239       ArLog::log(ArLog::Normal, 
00240                  "Parameter %s duplicated in section %s and %s",
00241                  arg.getName(), (*sectionIt)->getName(), section->getName());
00242       myDuplicateParams = true;
00243     }
00244   }
00245   
00246   // now make sure we can add it to the file parser
00247   if (!myParser.addHandlerWithError(arg.getName(), &myParserCB))
00248   {
00249     ArLog::log(ArLog::Verbose, "Could not add parameter '%s' to file parser, probably already there.", 
00250                arg.getName());
00251     //return false;
00252   }
00253 
00254   // we didn't have a parameter with this name so add it
00255   params->push_back(arg);
00256   params->back().setConfigPriority(priority);
00257   params->back().setIgnoreBounds(myIgnoreBounds);
00258 
00259   ArLog::log(ArLog::Verbose, "Added parameter '%s'", arg.getName());
00260   //arg.log();
00261   return true;
00262 }
00263 
00267 bool ArConfig::addComment(const char *comment, const char *sectionName, 
00268                                    ArPriority::Priority priority)
00269 {
00270   return addParam(ArConfigArg(comment), sectionName, priority);
00271 }
00272 
00273 
00274 
00286 bool ArConfig::parseSection(ArArgumentBuilder *arg,
00287                                       char *errorBuffer,
00288                                       size_t errorBufferLen)
00289 {
00290   if (myFailOnBadSection && errorBuffer != NULL)
00291     errorBuffer[0] = '\0';
00292 
00293   std::list<ArConfigSection *>::iterator sectionIt;
00294   ArConfigSection *section = NULL;
00295   
00296   if (myFailOnBadSection && errorBuffer != NULL)
00297     errorBuffer[0] = '\0';
00298   for (sectionIt = mySections.begin(); 
00299        sectionIt != mySections.end(); 
00300        sectionIt++)
00301   {
00302     section = (*sectionIt);
00303     if (ArUtil::strcasecmp(section->getName(), arg->getFullString()) == 0)
00304     {
00305       ArLog::log(ArLog::Verbose, "Config switching to section '%s'", 
00306                  arg->getFullString());
00307       //printf("Config switching to section '%s'\n", 
00308       //arg->getFullString());
00309       mySection = arg->getFullString();
00310       mySectionBroken = false;
00311       myUsingSections = true;
00312       return true;
00313     }
00314   }
00315 
00316   mySection = "";
00317   mySectionBroken = true;
00318   
00319   if (myFailOnBadSection)
00320   {
00321     snprintf(errorBuffer, errorBufferLen,  "ArConfig: Could not find section '%s'", 
00322              arg->getFullString());
00323     
00324     ArLog::log(ArLog::Terse,  
00325                "ArConfig: Could not find section '%s', failing", 
00326                arg->getFullString());
00327     return false;
00328   }
00329   else
00330   {
00331     ArLog::log(ArLog::Normal,  
00332                "ArConfig: Ignoring section '%s'", 
00333                arg->getFullString());
00334     return true;
00335   }
00336 }
00337 
00349 bool ArConfig::parseArgument(ArArgumentBuilder *arg, 
00350                                       char *errorBuffer,
00351                                       size_t errorBufferLen)
00352 {
00353   std::list<ArConfigSection *>::iterator sectionIt;
00354   std::list<ArConfigArg>::iterator paramIt;
00355   ArConfigSection *section = NULL;
00356   std::list<ArConfigArg> *params = NULL;
00357   ArConfigArg *param = NULL;
00358   int valInt = 0;
00359   double valDouble = 0;
00360   bool valBool = false;
00361   bool ret = true;
00362 
00363   if (mySectionBroken)
00364   {
00365     ArLog::log(ArLog::Verbose, "Skipping parameter %s because section broken",
00366                arg->getExtraString());
00367     if (myFailOnBadSection)
00368     {
00369       snprintf(errorBuffer, errorBufferLen, 
00370                "Failed because broken config section");
00371       return false;
00372     }
00373     else
00374     {
00375       return true;
00376     }
00377   }
00378 
00379   // if we have duplicate params and don't have sections don't trash anything
00380   if (myDuplicateParams && myUsingSections && mySection.size() <= 0)
00381   {
00382     snprintf(errorBuffer, errorBufferLen, 
00383              "%s not in section, client needs an upgrade",
00384              arg->getExtraString());
00385 
00386     ArLog::log(ArLog::Normal, 
00387                "%s not in a section, client needs an upgrade",
00388                arg->getExtraString());
00389     return false;
00390   }
00391 
00392   if (errorBuffer != NULL)
00393     errorBuffer[0] = '\0';
00394   for (sectionIt = mySections.begin(); 
00395        sectionIt != mySections.end(); 
00396        sectionIt++)
00397   {
00398     section = (*sectionIt);
00399     // if we have a section make sure we're in it, otherwise do the
00400     // normal thing
00401     if (mySection.size() > 0 && 
00402         ArUtil::strcasecmp(mySection, section->getName()))
00403       continue;
00404     params = section->getParams();
00405     // find this parameter
00406     for (paramIt = params->begin(); paramIt != params->end(); paramIt++)
00407     {
00408       if (strcasecmp((*paramIt).getName(), arg->getExtraString()) == 0)
00409       {
00410         param = &(*paramIt);
00411         if (param->getType() != ArConfigArg::STRING &&
00412             param->getType() != ArConfigArg::FUNCTOR &&
00413             arg->getArg(0) == NULL)
00414         {
00415           ArLog::log(ArLog::Verbose, "ArConfig: parameter '%s' has no argument.",
00416                      param->getName());
00417           continue;
00418         }
00419         if (param->getType() == ArConfigArg::DESCRIPTION_HOLDER)
00420         {
00421 
00422         }
00423         // see if we're an int
00424         else if (param->getType() == ArConfigArg::INT)
00425         {
00426           // if the param isn't an int fail
00427           if (!arg->isArgInt(0))
00428           {
00429             ArLog::log(ArLog::Terse, "ArConfig: parameter '%s' is an integer parameterbut was given non-integer argument of '%s'", param->getName(), arg->getArg(0));
00430             ret = false;
00431             if (errorBuffer != NULL)
00432               snprintf(errorBuffer, errorBufferLen, "%s is an integer parameter but was given non-integer argument of '%s'", param->getName(), arg->getArg(0));
00433             continue;
00434           }
00435           valInt = arg->getArgInt(0);
00436           if (param->setInt(valInt, errorBuffer, errorBufferLen))
00437           {
00438             ArLog::log(ArLog::Verbose, "Set parameter '%s' to '%d'",
00439                        param->getName(), valInt);
00440             continue;
00441           }
00442           else
00443           {
00444             ArLog::log(ArLog::Verbose, "Could not parameter '%s' to '%d'",
00445                        param->getName(), valInt);
00446             ret = false;
00447             continue;
00448           }
00449         }
00450         else if (param->getType() == ArConfigArg::DOUBLE)
00451         {
00452           // if the param isn't an in tfail
00453           if (!arg->isArgDouble(0))
00454           {
00455             ArLog::log(ArLog::Terse, "ArConfig: parameter '%s' is a double parameter but was given non-double argument of '%s'", param->getName(), arg->getArg(0));
00456             if (errorBuffer != NULL)
00457               snprintf(errorBuffer, errorBufferLen, "%s is a double parameter but was given non-double argument of '%s'", param->getName(), arg->getArg(0));
00458 
00459             ret = false;
00460             continue;
00461           }
00462           valDouble = arg->getArgDouble(0);
00463           if (param->setDouble(valDouble, errorBuffer, errorBufferLen))
00464           {
00465             ArLog::log(ArLog::Verbose, "Set parameter '%s' to '%.10f'",
00466                        param->getName(), valDouble);
00467             continue;
00468           }
00469           else
00470           {
00471             ArLog::log(ArLog::Verbose, "Could not set parameter '%s' to '%.10f'",
00472                        param->getName(), valDouble);
00473             ret = false;
00474             continue;
00475           }
00476         }
00477         else if (param->getType() == ArConfigArg::BOOL)
00478         {
00479           // if the param isn't an in tfail
00480           if (!arg->isArgBool(0))
00481           {
00482             ArLog::log(ArLog::Terse, "ArConfig: parameter '%s' is a bool parameter but was given non-bool argument of '%s'", param->getName(), arg->getArg(0));
00483             ret = false;
00484             if (errorBuffer != NULL)
00485               snprintf(errorBuffer, errorBufferLen, "%s is a bool parameter but was given non-bool argument of '%s'", param->getName(), arg->getArg(0));
00486             continue;
00487           }
00488           valBool = arg->getArgBool(0);
00489           if (param->setBool(valBool, errorBuffer, errorBufferLen))
00490           {
00491             ArLog::log(ArLog::Verbose, "Set parameter '%s' to %s",
00492                        param->getName(), valBool ? "true" : "false" );
00493             continue;
00494           }
00495           else
00496           {
00497             ArLog::log(ArLog::Verbose, "Could not set parameter '%s' to %s",
00498                        param->getName(), valBool ? "true" : "false" );
00499             ret = false;
00500             continue;
00501           }
00502         }
00503         else if (param->getType() == ArConfigArg::STRING)
00504         {
00505           if (param->setString(arg->getFullString()))
00506           {
00507             ArLog::log(ArLog::Verbose, "Set parameter string '%s' to '%s'",
00508                        param->getName(), param->getString());
00509             continue;
00510           }
00511           else
00512           {
00513             ArLog::log(ArLog::Verbose, "Could not set string parameter '%s' to '%s'",
00514                        param->getName(), param->getString());
00515             if (errorBuffer != NULL && errorBuffer[0] == '\0')
00516               snprintf(errorBuffer, errorBufferLen, "%s could not be set to '%s'.", param->getName(), arg->getFullString());
00517 
00518             ret = false;
00519             continue;
00520           }
00521         }
00522         else if (param->getType() == ArConfigArg::FUNCTOR)
00523         {
00524           if (param->setArgWithFunctor(arg))
00525           {
00526             ArLog::log(ArLog::Verbose, "Set arg '%s' with '%s'",
00527                        param->getName(), arg->getFullString());
00528             continue;
00529           }
00530           else
00531           {
00532             ArLog::log(ArLog::Verbose, "Could not set parameter '%s' to '%s'",
00533                        param->getName(), arg->getFullString());
00534             // if it didn't put in an error message make one
00535             if (errorBuffer != NULL && errorBuffer[0] == '\0')
00536               snprintf(errorBuffer, errorBufferLen, "%s could not be set to '%s'.", param->getName(), arg->getFullString());
00537             ret = false;
00538             continue;
00539           }
00540         }
00541         else
00542         {
00543           ArLog::log(ArLog::Terse, "Have no argument type for config '%s', got string '%s'.\n", param->getName(), arg->getFullString());
00544         }
00545       }
00546     }
00547   }
00548   return ret;
00549 }
00550 
00564 bool ArConfig::parseFile(const char *fileName, bool continueOnErrors,
00565                                   bool noFileNotFoundMessage, 
00566                                   char *errorBuffer,
00567                                   size_t errorBufferLen)
00568 {
00569   bool ret = true;
00570 
00571   myFileName = fileName;
00572   if (errorBuffer != NULL)
00573     errorBuffer[0] = '\0';
00574 
00575   // parse the file (errors will go into myErrorBuffer from the functors)
00576   ret = myParser.parseFile(fileName, continueOnErrors, noFileNotFoundMessage);
00577   // set our pointers so we don't copy anymore into/over it
00578   if (errorBuffer != NULL && errorBuffer[0] != '\0')
00579   {
00580     errorBuffer = NULL;
00581     errorBufferLen = 0;
00582   }
00583   //printf("file %s\n", ArUtil::convertBool(ret));
00584 
00585   // if we have a parser and haven't failed (or we continue on errors)
00586   // then parse the arguments from the parser
00587   if (myArgumentParser != NULL && (ret || continueOnErrors))
00588     ret = ret && parseArgumentParser(myArgumentParser, continueOnErrors, 
00589                                      errorBuffer, errorBufferLen);
00590 
00591   // set our pointers so we don't copy anymore into/over it
00592   if (errorBuffer != NULL && errorBuffer[0] != '\0')
00593   {
00594     errorBuffer = NULL;
00595     errorBufferLen = 0;
00596   }
00597   //printf("parser %s\n", ArUtil::convertBool(ret));
00598   
00599   // if we haven't failed (or we continue on errors) then call the
00600   // process file callbacks
00601   if (ret || continueOnErrors)
00602     ret = ret && callProcessFileCallBacks(continueOnErrors, errorBuffer,
00603                                           errorBufferLen);
00604   // copy our error if we have one and haven't copied in yet
00605   // set our pointers so we don't copy anymore into/over it
00606   if (errorBuffer != NULL && errorBuffer[0] != '\0')
00607   {
00608     errorBuffer = NULL;
00609     errorBufferLen = 0;
00610   }
00611   //printf("callbacks %s\n", ArUtil::convertBool(ret));
00612   return ret;
00613 }
00614 
00627 bool ArConfig::writeFile(const char *fileName, bool append, 
00628                                   std::set<std::string> *alreadyWritten,
00629                                   bool writePriorities)
00630 {
00631   FILE *file;
00632 
00633   // holds each line
00634   char line[1024];
00635   // holds the fprintf
00636   char startLine[128];
00637 
00638   std::set<std::string> writtenSet;
00639   std::set<std::string> *written;
00640   if (alreadyWritten != NULL)
00641     written = alreadyWritten;
00642   else
00643     written = &writtenSet;
00644   //std::list<ArConfigArg>::iterator it;
00645   ArConfigArg *param = NULL;
00646 
00647   std::list<ArArgumentBuilder *>::const_iterator argIt;
00648   const std::list<ArArgumentBuilder *> *argList = NULL;
00649 
00650   bool commented = false;
00651   // later this'll have a prefix
00652   std::string realFileName;
00653   if (fileName[0] == '/' || fileName[0] == '\\')
00654   {
00655     realFileName = fileName;
00656   }
00657   else
00658   {
00659     realFileName = myBaseDirectory;
00660     realFileName += fileName;
00661   }
00662 
00663   unsigned int startCommentColumn = 25;
00664   std::string mode;
00665 
00666   if (append)
00667     mode = "a";
00668   else
00669     mode = "w";
00670 
00671   if ((file = fopen(realFileName.c_str(), mode.c_str())) == NULL)
00672   {
00673     ArLog::log(ArLog::Terse, "ArConfig: Cannot open file '%s' for writing",
00674                realFileName.c_str());
00675     return false;
00676   }
00677 
00678   bool firstSection = true;
00679   std::list<ArConfigSection *>::iterator sectionIt;
00680   std::list<ArConfigArg>::iterator paramIt;
00681   ArConfigSection *section = NULL;
00682   std::list<ArConfigArg> *params = NULL;
00683   for (sectionIt = mySections.begin(); 
00684        sectionIt != mySections.end(); 
00685        sectionIt++)
00686   {
00687     section = (*sectionIt);
00689     written->clear();
00690     //printf("Section '%s' %p\n", section->getName(), section);
00691     if (!firstSection)
00692       fprintf(file, "\n");
00693     firstSection = false;
00694     
00695     if (section->getName() != NULL && strlen(section->getName()) > 0)
00696     {
00697       //fprintf(file, "; %s\n", section->getName());
00698       fprintf(file, "Section %s\n", section->getName());
00699     }
00700     sprintf(line, "; ");
00701     if (section->getComment() != NULL && strlen(section->getComment()) > 0)
00702     {
00703       ArArgumentBuilder descr;
00704       descr.add(section->getComment());
00705       for (unsigned int i = 0; i < descr.getArgc(); i++)
00706       {
00707         // see if we're over, if we are write this line out and start
00708         // the next one
00709         if (strlen(line) + strlen(descr.getArg(i)) > 78)
00710         {
00711           fprintf(file, "%s\n", line);
00712           sprintf(line, "; ");
00713           sprintf(line, "%s %s", line, descr.getArg(i));
00714         }
00715         // if its not the end of the line toss this word in
00716         else
00717         {
00718           sprintf(line, "%s %s", line, descr.getArg(i));
00719         }
00720       }
00721       // put the last line into the file
00722       fprintf(file, "%s\n", line);
00723     }
00724 
00725     params = section->getParams();
00726     // find this parameter
00727     for (paramIt = params->begin(); paramIt != params->end(); paramIt++)
00728     {
00729       commented = false;
00730       param = &(*paramIt);
00731 
00732       if (written != NULL && 
00733           param->getType() != ArConfigArg::DESCRIPTION_HOLDER &&
00734           written->find(param->getName()) != written->end())
00735         continue;
00736       else if (written != NULL && 
00737                param->getType() != ArConfigArg::DESCRIPTION_HOLDER)
00738       {
00739         written->insert(param->getName());
00740       }
00741       
00742       // if the type is a functor then we need to handle all of it up
00743       // here since its a special case both in regards to comments and values
00744       if (param->getType() == ArConfigArg::FUNCTOR)
00745       {
00746         // put the comments in the file first
00747         sprintf(line, "; ");
00748         if (param->getDescription() != NULL && 
00749             strlen(param->getDescription()) > 0)
00750         {
00751           ArArgumentBuilder descr;
00752           descr.add(param->getDescription());
00753           for (unsigned int i = 0; i < descr.getArgc(); i++)
00754           {
00755             // see if we're over, if we are write this line out and start
00756             // the next one
00757             if (strlen(line) + strlen(descr.getArg(i)) > 78)
00758             {
00759               fprintf(file, "%s\n", line);
00760               sprintf(line, "; ");
00761               sprintf(line, "%s %s", line, descr.getArg(i));
00762             }
00763             // if its not the end of the line toss this word in
00764             else
00765             {
00766               sprintf(line, "%s %s", line, descr.getArg(i));
00767             }
00768           }
00769           // put the last line into the file
00770           fprintf(file, "%s\n", line);
00771         }
00772         // now put in the values
00773         argList = param->getArgsWithFunctor();
00774         if (argList != NULL)
00775           for (argIt = argList->begin(); argIt != argList->end(); argIt++)
00776             fprintf(file, "%s %s\n", param->getName(), (*argIt)->getFullString());
00777         
00778         // okay, we did it all, now continue
00779         continue;
00780       }
00781       
00782       sprintf(line, "%s", param->getName());
00783       if (param->getType() == ArConfigArg::INT)
00784       {
00785         sprintf(line, "%s %d", line, param->getInt());
00786       }
00787       else if (param->getType() == ArConfigArg::DOUBLE)
00788       {
00789         sprintf(line, "%s %g", line, param->getDouble());
00790       }
00791       else if (param->getType() == ArConfigArg::STRING)
00792       {
00793         sprintf(line, "%s %s", line, param->getString());
00794       }
00795       else if (param->getType() == ArConfigArg::BOOL)
00796       {
00797         sprintf(line, "%s %s", line, param->getBool() ? "true" : "false"); 
00798       }
00799       else if (param->getType() == ArConfigArg::FUNCTOR)
00800       {
00801       }
00802       else if (param->getType() == ArConfigArg::DESCRIPTION_HOLDER)
00803       {
00804         if (strlen(param->getDescription()) == 0)
00805         {
00806           fprintf(file, "\n");
00807           continue;
00808         }
00809       }
00810       else
00811       {
00812         ArLog::log(ArLog::Terse, "ArConfig no argument type");
00813       }
00814       // configure our start of line part
00815       if (param->getType() == ArConfigArg::DESCRIPTION_HOLDER)
00816         sprintf(startLine, "; ");
00817       else
00818         sprintf(startLine, "%%-%ds;", startCommentColumn);
00819       // if our line is already longer then where we want to go put in
00820       // an extra space
00821       if (strlen(line) >= startCommentColumn)
00822         sprintf(line, "%-s ;", line);
00823       // if its not then just put the start in
00824       else
00825         sprintf(line, startLine, line);
00826       // if its an int we want to put in ranges if there are any
00827       if (param->getType() == ArConfigArg::INT)
00828       {
00829         if (param->getMinInt() != INT_MIN && param->getMaxInt() != INT_MAX)
00830         {
00831           sprintf(line, "%s range [%d, %d], ", line, 
00832                   param->getMinInt(), param->getMaxInt());
00833         }
00834         else if (param->getMinInt() != INT_MIN)
00835           sprintf(line, "%s minumum %d, ", line, param->getMinInt());
00836         else if (param->getMaxInt() != INT_MAX)
00837           sprintf(line, "%s maximum %d, ", line, param->getMaxInt());
00838       }
00839       if (param->getType() == ArConfigArg::DOUBLE)
00840       {
00841         if (param->getMinDouble() != -HUGE_VAL && 
00842             param->getMaxDouble() != HUGE_VAL)
00843           sprintf(line, "%s range [%g, %g], ", line, param->getMinDouble(), 
00844                   param->getMaxDouble());
00845         else if (param->getMinDouble() != -HUGE_VAL)
00846           sprintf(line, "%s minimum %g, ", line, 
00847                   param->getMinDouble());
00848         else if (param->getMaxDouble() != HUGE_VAL)
00849           sprintf(line, "%s Maximum %g, ", line, 
00850                   param->getMaxDouble());
00851       }
00852       
00853       // if we have a description to put in, put it in with word wrap
00854       if (param->getDescription() != NULL && 
00855           strlen(param->getDescription()) > 0)
00856       {
00857         ArArgumentBuilder descr;
00858         descr.add(param->getDescription());
00859         for (unsigned int i = 0; i < descr.getArgc(); i++)
00860         {
00861           // see if we're over, if we are write this line out and start
00862           // the next one
00863           if (strlen(line) + strlen(descr.getArg(i)) > 78)
00864           {
00865             fprintf(file, "%s\n", line);
00866             sprintf(line, startLine, "");
00867             sprintf(line, "%s %s", line, descr.getArg(i));
00868           }
00869           // if its not the end of the line toss this word in
00870           else
00871           {
00872             sprintf(line, "%s %s", line, descr.getArg(i));
00873           }
00874         }
00875         // put the last line into the file
00876         fprintf(file, "%s\n", line);
00877       }
00878       // if they're no description just end the line
00879       else 
00880         fprintf(file, "%s\n", line);
00881       // if they have a config priority put that on its own line
00882       if (writePriorities)
00883       {
00884         sprintf(line, startLine, "");
00885         fprintf(file, "%s Priority: %s\n", line,
00886                 ArPriority::getPriorityName(param->getConfigPriority()));
00887       }
00888       // now put a blank line between params if we should
00889       if (!myNoBlanksBetweenParams)
00890         fprintf(file, "\n");
00891     }
00892   }
00893   fclose(file);
00894   return true;
00895 }
00896 
00897 const char *ArConfig::getBaseDirectory(void) const
00898 {
00899   return myBaseDirectory.c_str();
00900 }
00901 
00902 void ArConfig::setBaseDirectory(const char *baseDirectory)
00903 {
00904   if (baseDirectory != NULL && strlen(baseDirectory) > 0)
00905     myBaseDirectory = baseDirectory;
00906   else
00907     myBaseDirectory = "";
00908    
00909   myParser.setBaseDirectory(baseDirectory);
00910 }
00911 
00912 const char *ArConfig::getFileName(void) const
00913 {
00914   return myFileName.c_str();
00915 }
00916 
00933 void ArConfig::addProcessFileCB(ArRetFunctor<bool> *functor,
00934                                          int priority)
00935 {
00936   myProcessFileCBList.insert(
00937           std::pair<int, ProcessFileCBType *>(-priority, 
00938                                               new ProcessFileCBType(functor)));
00939 }
00940 
00944 void ArConfig::remProcessFileCB(ArRetFunctor<bool> *functor)
00945 {
00946   std::multimap<int, ProcessFileCBType *>::iterator it;
00947   ProcessFileCBType *cb;
00948 
00949   for (it = myProcessFileCBList.begin(); it != myProcessFileCBList.end(); ++it)
00950   {
00951     if ((*it).second->haveFunctor(functor))
00952     {
00953       cb = (*it).second;
00954       myProcessFileCBList.erase(it);
00955       delete cb;
00956       remProcessFileCB(functor);
00957     }
00958   }
00959 }
00960 
00984 void ArConfig::addProcessFileWithErrorCB(
00985         ArRetFunctor2<bool, char *, size_t> *functor,
00986         int priority)
00987 {
00988   myProcessFileCBList.insert(
00989           std::pair<int, ProcessFileCBType *>(-priority, 
00990                                       new ProcessFileCBType(functor)));
00991 }
00992 
00996 void ArConfig::remProcessFileCB(
00997         ArRetFunctor2<bool, char *, size_t> *functor)
00998 {
00999   std::multimap<int, ProcessFileCBType *>::iterator it;
01000   ProcessFileCBType *cb;
01001 
01002   for (it = myProcessFileCBList.begin(); it != myProcessFileCBList.end(); ++it)
01003   {
01004     if ((*it).second->haveFunctor(functor))
01005     {
01006       cb = (*it).second;
01007       myProcessFileCBList.erase(it);
01008       delete cb;
01009       remProcessFileCB(functor);
01010     }
01011   }
01012 }
01013 
01014 bool ArConfig::callProcessFileCallBacks(bool continueOnErrors,
01015                                                  char *errorBuffer,
01016                                                  size_t errorBufferLen)
01017 {
01018   bool ret = true;
01019   std::multimap<int, ProcessFileCBType *>::iterator it;
01020   ProcessFileCBType *callback;
01021   ArLog::LogLevel level = myProcessFileCallbacksLogLevel;
01022 
01023   // reset our section to nothing again
01024   mySection = "";
01025 
01026   // in windows, can't simply declare an array of errorBufferLen -- so
01027   // allocate one.
01028   
01029   // empty the buffer, we're only going to put the first error in it
01030   if (errorBuffer != NULL)
01031     errorBuffer[0] = '\0';
01032 
01033   ArLog::log(level, "ArConfig: Processing file");
01034   for (it = myProcessFileCBList.begin(); 
01035        it != myProcessFileCBList.end(); 
01036        ++it)
01037   {
01038     callback = (*it).second;
01039     if (callback->getName() != NULL && callback->getName()[0] != '\0')
01040       ArLog::log(level, "ArConfig: Processing functor '%s' (%d)", 
01041                  callback->getName(), -(*it).first);
01042     else
01043       ArLog::log(level, "ArConfig: Processing unnamed functor (%d)", -(*it).first);
01044     if (!(*it).second->call(errorBuffer, errorBufferLen))
01045     {
01046       //printf("# %s\n", scratchBuffer); 
01047 
01048       // if there is an error buffer and it got filled get rid of our
01049       // pointer to it
01050       if (errorBuffer != NULL && errorBuffer[0] != '\0')
01051       {
01052         errorBuffer = NULL;
01053         errorBufferLen = 0;
01054       }
01055       ret = false;
01056       if (!continueOnErrors)
01057       {
01058         if (callback->getName() != NULL && callback->getName()[0] != '\0')
01059           ArLog::log(ArLog::Normal, "ArConfig: Failed, stopping because the '%s' process file callback failed", 
01060                      callback->getName());
01061         else
01062           ArLog::log(ArLog::Normal, "ArConfig: Failed, stopping because unnamed process file callback failed");
01063         break;
01064       }
01065       else
01066       {
01067         if (callback->getName() != NULL && callback->getName()[0] != '\0')
01068           ArLog::log(ArLog::Normal, "ArConfig: Failed but continuing, the '%s' process file callback failed", 
01069                      callback->getName());
01070         else
01071           ArLog::log(ArLog::Normal, "ArConfig: Failed but continuing, an unnamed process file callback failed");
01072       }
01073 
01074     }
01075   }
01076   if (ret || continueOnErrors)
01077   {
01078     ArLog::log(level, "ArConfig: Processing with own processFile");
01079     if (!processFile())
01080       ret = false;
01081   }
01082   ArLog::log(level, "ArConfig: Done processing file, ret is %s", 
01083              ArUtil::convertBool(ret));
01084 
01085   return ret;
01086 }
01087 
01088 
01089 std::list<ArConfigSection *> *ArConfig::getSections(void)
01090 {
01091   return &mySections;
01092 }
01093 
01094 void ArConfig::setNoBlanksBetweenParams(bool noBlanksBetweenParams)
01095 {
01096   myNoBlanksBetweenParams = noBlanksBetweenParams;
01097 }
01098 
01099 bool ArConfig::getNoBlanksBetweenParams(void)
01100 {
01101   return myNoBlanksBetweenParams;
01102 }
01103 
01109 void ArConfig::useArgumentParser(ArArgumentParser *parser)
01110 {
01111   myArgumentParser = parser;
01112 }
01113 
01114 bool ArConfig::parseArgumentParser(ArArgumentParser *parser,    
01115                                             bool continueOnError,
01116                                             char *errorBuffer,
01117                                             size_t errorBufferLen)
01118 {
01119   std::list<ArConfigSection *>::iterator sectionIt;
01120   std::list<ArConfigArg>::iterator paramIt;
01121   ArConfigSection *section = NULL;
01122   ArConfigArg *param = NULL;
01123   std::list<ArConfigArg> *params = NULL;
01124 
01125   bool ret;
01126   size_t i;
01127   std::string strArg;
01128   std::string strUndashArg;
01129   ArArgumentBuilder builder;
01130   bool plainMatch;
01131   
01132   for (i = 0; i < parser->getArgc(); i++)
01133   {
01134     if (parser->getArg(i) == NULL)
01135     {
01136       ArLog::log(ArLog::Terse, "ArConfig set up wrong (parseArgumentParser broken).");
01137       if (errorBuffer != NULL)
01138         strncpy(errorBuffer, 
01139                 "ArConfig set up wrong (parseArgumentParser broken).", 
01140                 errorBufferLen);
01141       return false;
01142     }
01143     strArg = parser->getArg(i); 
01144     if (parser->getArg(i)[0] == '-')
01145       strUndashArg += &parser->getArg(i)[1]; 
01146     else
01147       strUndashArg = "";
01148     //printf("normal %s undash %s\n", strArg.c_str(), strUndashArg.c_str());
01149     for (sectionIt = mySections.begin(); 
01150          sectionIt != mySections.end(); 
01151          sectionIt++)
01152     {
01153       section = (*sectionIt);
01154       params = section->getParams();
01155       for (paramIt = params->begin(); paramIt != params->end(); paramIt++)
01156       {
01157         param = &(*paramIt);
01158         /*
01159         printf("### normal %s undash %s %d %d\n", strArg.c_str(), 
01160                strUndashArg.c_str(),
01161                ArUtil::strcasecmp(param->getName(), strArg),
01162                ArUtil::strcasecmp(param->getName(), strUndashArg));
01163         */
01164         if (strlen(param->getName()) > 0 &&
01165             ((plainMatch = ArUtil::strcasecmp(param->getName(),strArg)) == 0 ||
01166              ArUtil::strcasecmp(param->getName(), strUndashArg) == 0))
01167         {
01168           if (plainMatch == 0)
01169             builder.setExtraString(strArg.c_str());
01170           else
01171             builder.setExtraString(strUndashArg.c_str());
01172           if (i+1 < parser->getArgc())
01173           {
01174             builder.add(parser->getArg(i+1));
01175             parser->removeArg(i+1);
01176           }
01177           parser->removeArg(i);
01178 
01179           // set us to use the section this is in and then parse the argument
01180           std::string oldSection = mySection;
01181           bool oldSectionBroken = mySectionBroken;
01182           bool oldUsingSections = myUsingSections;
01183           bool oldDuplicateParams = myDuplicateParams;
01184           mySection = section->getName();
01185           mySectionBroken = false;
01186           myUsingSections = true;
01187           myDuplicateParams = false;
01188           ret = parseArgument(&builder, errorBuffer, errorBufferLen);
01189           mySection = oldSection;
01190           mySectionBroken = oldSectionBroken;
01191           myUsingSections = oldUsingSections;
01192           myDuplicateParams = oldDuplicateParams;
01193 
01194           // if we parsed the argument right or are continuing on
01195           // errors call ourselves again (so we don't hose iterators up above)
01196           if (ret || continueOnError)
01197           {
01198             //printf("Ret %s\n", ArUtil::convertBool(ret));
01199             return ret && parseArgumentParser(parser, continueOnError, 
01200                                              errorBuffer, errorBufferLen);
01201           }
01202           else
01203             return false;
01204         }
01205       }
01206     }
01207   }
01208 
01209   return true;
01210 }
01211 
01212 ArConfigSection::ArConfigSection(const char *name, 
01213                                           const char *comment)
01214 {
01215   myName = name;
01216   if (comment != NULL)
01217     myComment = comment;
01218   else
01219     myComment = "";
01220 }
01221 
01222 
01223 ArConfigSection::ArConfigSection(const ArConfigSection &section) 
01224 {
01225   myName = section.myName;
01226   myComment = section.myComment;
01227   for (std::list<ArConfigArg>::const_iterator it = section.myParams.begin(); 
01228        it != section.myParams.end(); 
01229        it++) 
01230   {
01231     myParams.push_back(*it);
01232   }
01233 }
01234 
01235 ArConfigSection &ArConfigSection::operator=(const ArConfigSection &section)
01236 {
01237   if (this != &section) 
01238   {
01239     
01240     myName = section.getName();
01241     myComment = section.getComment();
01242     
01243     myParams.clear();
01244     
01245     for (std::list<ArConfigArg>::const_iterator it = section.myParams.begin(); 
01246          it != section.myParams.end(); 
01247          it++) 
01248     {
01249       myParams.push_back(*it);
01250     }
01251   }
01252   return *this;
01253 }
01254 
01255 
01256 
01257 ArConfigSection::~ArConfigSection()
01258 {
01259 
01260 }
01261 
01262 
01263 ArConfigSection *ArConfig::findSection(const char *sectionName) const
01264 {
01265   ArConfigSection *section = NULL;
01266   ArConfigSection *tempSection = NULL;
01267 
01268   for (std::list<ArConfigSection *>::const_iterator sectionIt = mySections.begin(); 
01269        sectionIt != mySections.end(); 
01270        sectionIt++)
01271   {
01272     tempSection = (*sectionIt);
01273     if (ArUtil::strcasecmp(tempSection->getName(), sectionName) == 0)
01274     {
01275       section = tempSection;
01276     }
01277   }
01278   return section;
01279 
01280 } // end method findSection
01281 
01282 ArConfigArg *ArConfigSection::findParam(const char *paramName)
01283 {
01284   ArConfigArg *param = NULL;
01285   ArConfigArg *tempParam = NULL;
01286 
01287   for (std::list<ArConfigArg>::iterator pIter = myParams.begin(); 
01288        pIter != myParams.end(); 
01289        pIter++)
01290   {
01291     // TODO: Does this do what I'm hoping it does?
01292     tempParam = &(*pIter);
01293     if (ArUtil::strcasecmp(tempParam->getName(), paramName) == 0)
01294     {
01295       param = tempParam;
01296     }
01297   }
01298   return param;
01299 
01300 } // end method findParam
01301 
01302 
01303 

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