Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

JobCommand.cxx

Go to the documentation of this file.
00001 
00002 // $Id: JobCommand.cxx,v 1.24 2009/07/24 07:52:19 nwest Exp $
00003 //
00004 // Convert text strings to command paths and options and provide easy
00005 // access to the command path and options to clients
00006 //
00007 // messier@huhepl.harvard.edu
00009 #include <cstdlib> // atoi(), atof(), strtod()
00010 
00011 #include "JobControl/JobCommand.h"
00012 #include "MessageService/MsgService.h"
00013 #include "Registry/Registry.h"
00014 
00015 CVSID("$Id: JobCommand.cxx,v 1.24 2009/07/24 07:52:19 nwest Exp $");
00016 
00017 //......................................................................
00018 
00019 ostream& operator<<(ostream& os, const JobCommand& jc) 
00020 {
00021   vector<string>::const_iterator itrend(jc.fCmdList.end());
00022   vector<string>::const_iterator itr;
00023   bool ifirst = true;
00024   for (itr = jc.fCmdList.begin(); itr!= itrend; ++itr) {
00025     if (ifirst) { os << (*itr); ifirst = false; }
00026     else os << "/" << (*itr);
00027   }
00028   itrend = jc.fOptList.end();
00029   for (itr = jc.fOptList.begin(); itr!= itrend; ++itr) {
00030     os << " " << (*itr);
00031   }
00032   return os;
00033 }
00034 
00035 //......................................................................
00036 
00037 JobCommand::JobCommand() 
00038 {
00039 //======================================================================
00040 // Purpose: Create an empty command
00041 //======================================================================
00042   // Flag these as empty
00043   fItrCmdList = fCmdList.end();
00044   fItrOptList = fOptList.end();
00045 }
00046 
00047 //......................................................................
00048 
00049 JobCommand::JobCommand(const char *cmd) 
00050 {
00051   this->Parse(cmd);
00052 }
00053 
00054 //......................................................................
00055 
00056 void JobCommand::Parse(const char *cmd) 
00057 {
00058 //======================================================================
00059 // Purpose: Parse a command line
00060 //
00061 // For example the command:
00062 //
00063 // /Path/Module/Set a 10
00064 //
00065 // Has fCmdList = {"Path","Module","Set"} and
00066 //     fOptList = {"a", "10"}
00067 //
00068 // Any command starting as "#" is taken to be a comment. Also,
00069 // standard C and C++ commenting styles are supported. However,
00070 // multi-line comments are *not* supported.
00071 //======================================================================
00072   int len;       // Number of characters in the command
00073   bool procCmd;  // Are we working on the command?
00074   bool procOpt;  // Are we handling options?
00075   bool inQuotes; // Are we inside a quoted string?
00076   bool expectSpecial; // Expect a special character?
00077   string word;   // The current word in the command line
00078   // MsgStream& msgDebug = MSGSTREAM("JobC",Msg::kDebug); // Debug stream
00079   
00080   word          = "";
00081   len           = strlen(cmd);
00082   procCmd       = true;
00083   procOpt       = false;
00084   inQuotes      = false;
00085   expectSpecial = false;
00086   // msgDebug << "Parse: ";
00087   for (int i=0; i<len; ++i) {
00088     // If we've been told not to treat this character as a token, just
00089     // and it to the word
00090     if (expectSpecial) {
00091       word += cmd[i];
00092       expectSpecial = false;
00093       continue; // next character
00094     }
00095 
00096     // See if we have a \ which flags that the next character is not a token
00097     if (cmd[i] == '\\') {
00098       expectSpecial = true;
00099       continue; // next character;
00100     }
00101 
00102     // Check if we are entering/leaving a quoted passage
00103     if (cmd[i] == '"' || cmd[i] == '\'') {
00104       inQuotes = !inQuotes;
00105       continue; // next character
00106     }
00107     if (inQuotes) {
00108       // Use every character inside quotes
00109       word += cmd[i];
00110       continue; // next character
00111     }
00112 
00113     // Skip extra white space
00114     if (i>0 && cmd[i]==' ' && cmd[i-1]==' ') {
00115       continue; // next character
00116     }
00117 
00118     // Check for command separator
00119     if (procCmd && cmd[i] == '/') {
00120       // Place the previous word (if there is one) in the command list
00121       if (word.length()>0) fCmdList.push_back(word);
00122       // msgDebug << '/' << word;
00123       word = "";
00124       continue; // next character
00125     }
00126 
00127     // White space is used to separate commands from options and
00128     // options from each other
00129     if (cmd[i] == ' ' || cmd[i] == '=') {
00130       if (procCmd) {
00131         // Place the previous work in the command list
00132         // msgDebug << '/' << word;
00133         if (word.length()>0) fCmdList.push_back(word);
00134         word = "";
00135         // Switch from processing commands to options
00136         procCmd = false;
00137         procOpt = true;
00138       }
00139       else if (procOpt) {
00140         // msgDebug << '|' << word;
00141         if (word.length()>0) fOptList.push_back(word);
00142         word = "";
00143       }
00144       continue; // next character
00145     }
00146     
00147     // Character triggered no special action -- add it to word
00148     word += cmd[i];
00149   } // End loop over characters
00150 
00151 
00152   if (procCmd) {
00153     // msgDebug << '/' << word;
00154     if (word.length()) fCmdList.push_back(word);
00155   }
00156   if (procOpt) {
00157     // msgDebug << '|' << word;
00158     if (word.length()) fOptList.push_back(word);
00159   }
00160   // msgDebug << "\n";
00161 
00162   // Point the iterators at the begining of the lists
00163   fItrCmdList = fCmdList.begin();
00164   fItrOptList = fOptList.begin();
00165 }
00166 
00167 //......................................................................
00168 
00169 JobCommand::~JobCommand() {}
00170 
00171 //......................................................................
00172 
00173 bool JobCommand::HaveCmd() const
00174 {
00175 //======================================================================
00176 // Purpose: Are there parts of the command that need processing?
00177 //
00178 // Returns: true  - there are more parts of the command to parse
00179 //          false - there are no more parts of the command to parse
00180 //======================================================================
00181   if (fItrCmdList == fCmdList.end()) return false;
00182   return true;
00183 }
00184 
00185 //......................................................................
00186 
00187 bool JobCommand::HaveOpt() const
00188 {
00189 //======================================================================
00190 // Purpose: Are there options that need processing?
00191 //
00192 // Returns: true  - options remain, 
00193 //          false - no more options left
00194 //======================================================================
00195   if (fItrOptList == fOptList.end()) return false;
00196   return true;
00197 }
00198 
00199 //......................................................................
00200 
00201 const char *JobCommand::PopCmd()
00202 {
00203 //======================================================================
00204 // Purpose: Return the current option parameter as a character string
00205 //
00206 // Returns: A pointer to the start of the option character string
00207 //          If the list of options has been exhausted this returns ""
00208 //======================================================================
00209   if (this->HaveCmd()) {
00210     const char *val = 0;
00211     val = (*fItrCmdList).c_str();
00212     ++fItrCmdList;
00213     return val;
00214   }
00215   return 0;
00216 }
00217 
00218 //......................................................................
00219 
00220 const char *JobCommand::PushCmd()
00221 {
00222 //======================================================================
00223 // Purpose: Return the current option parameter as a character string
00224 //
00225 // Returns: A pointer to the start of the option character string
00226 //          If the list of options has been exhausted this returns ""
00227 //======================================================================
00228   if (fItrCmdList != fCmdList.begin()) {
00229     const char *val = 0;
00230     --fItrCmdList;
00231     val = (*fItrCmdList).c_str();
00232     return val;
00233   }
00234   return 0;
00235 }
00236 
00237 const char *JobCommand::PushOpt()
00238 {
00239 //======================================================================
00240 // Purpose: Return the current option parameter as a character string
00241 //
00242 // Returns: A pointer to the start of the option character string
00243 //          If the list of options has been exhausted this returns ""
00244 //======================================================================
00245   if (fItrOptList != fOptList.begin()) {
00246     const char *val = 0;
00247     --fItrOptList;
00248     val = (*fItrOptList).c_str();
00249     return val;
00250   }
00251   return 0;
00252 }
00253 
00254 //......................................................................
00255 
00256 const char *JobCommand::PopOpt()
00257 {
00258 //======================================================================
00259 // Purpose: Return the current option parameter as a character string
00260 //
00261 // Returns: A pointer to the start of the option character string
00262 //          If the list of options has been exhausted this returns ""
00263 //======================================================================
00264   if (this->HaveOpt()) {
00265     const char *val = 0;
00266     val = (*fItrOptList).c_str();
00267     ++fItrOptList;
00268     return val;
00269   }
00270   return 0;
00271 }
00272 
00273 //......................................................................
00274 
00275 int JobCommand::PopIntOpt()
00276 {
00277 //======================================================================
00278 // Purpose: Return the current option parameter as an integer number
00279 //          and advance the counter.
00280 //
00281 // Returns: The current option interpreted as an integer number
00282 //          If the list of options has been exhausted this returns 0
00283 //======================================================================
00284   if (this->HaveOpt()) {
00285     int val;
00286     val = atoi((*fItrOptList).c_str());
00287     ++fItrOptList;
00288     return val;
00289   }
00290   return 0;
00291 }
00292 
00293 //......................................................................
00294 
00295 double JobCommand::PopFloatOpt()
00296 {
00297 //======================================================================
00298 // Purpose: Return the current option parameter as a floating point
00299 //          number and advance the counter.
00300 //
00301 // Returns: The current option interpreted as a floating point number
00302 //          If the list of options has been exhausted this returns 0.0
00303 //======================================================================
00304   if (this->HaveOpt()) {
00305     double val = 0.0;
00306     val = atof((*fItrOptList).c_str());
00307     ++fItrOptList;
00308     return val;
00309   }
00310   return 0.0;
00311 }
00312 
00313 //......................................................................
00314 
00315 void JobCommand::SplitLine(const char *line, char sep, string& a, string& b)
00316 {
00317 //======================================================================
00318 // Purpose: Split a character string into two pieces given a
00319 //          separator.  Example peas::carots into peas and carrots
00320 //
00321 // Inputs: line - the text to split
00322 //         sep  - the separation character (':' in the example above)
00323 //         a    - text before the separator
00324 //         b    - text after separator
00325 //======================================================================
00326   // Clear a and b strings
00327   a = "";
00328   b = "";
00329   bool doFront = true;
00330   for (const char* c = line; *c != '\0'; ++c) {
00331     if (*c == ' ') continue;
00332     if (*c == sep) {
00333       doFront = false;
00334       continue;
00335     }
00336     if (doFront) a += (*c);
00337     else         b += (*c);
00338   }
00339 
00340   MSG("JobC",Msg::kVerbose) << 
00341     "Split " << line << " into " << a << " " << b << ".\n";
00342 }
00343 
00344 
00345 //......................................................................
00346 
00347 void JobCommand::StringTok(std::vector<std::string>& ls,
00348                            const std::string& str,
00349                            const std::string& tok)
00350 {
00351 //======================================================================
00352 // Split a long string into a set of shorter strings spliting along
00353 // divisions makers by the characters listed in the token string
00354 //======================================================================
00355   const string::size_type S     = str.size();
00356   const string::size_type toksz = tok.size();
00357   string::size_type  i = 0;
00358   
00359   while (i < S) {
00360     // eat leading whitespace
00361     while ( (i<S) && (tok.find(str[i])<=toksz) ) {
00362       ++i;
00363     }
00364     if (i == S)  return;  // nothing left but WS
00365     
00366     // find end of word
00367     string::size_type  j = i+1;
00368     while ( (j<S) && !(tok.find(str[j])<=toksz) ) {
00369       ++j;
00370     }
00371 
00372     // add word
00373     ls.push_back(str.substr(i,j-i));
00374     
00375     // set up for next loop
00376     i = j+1;
00377   }  
00378 }
00379 
00380 //......................................................................
00381 
00382 bool JobCommand::IsInt(const char* s) 
00383 {
00384 //======================================================================
00385 // Does the string s represent an integer?
00386 //======================================================================
00387   char* endptr;
00388   strtol(s, &endptr,0);
00389 // Consider this a failure if the entire string does not convert to a long
00390   if (endptr != (s + strlen(s))) return false;
00391   
00392   // All checks for "intness" passed
00393   return true;
00394 }
00395 
00396 
00397 //......................................................................
00398 
00399 bool JobCommand::IsFloat(const char* s)
00400 {
00401 //======================================================================
00402 // Does the string s represent a float?
00403 //======================================================================
00404   char* endptr;
00405   strtod(s, &endptr);
00406 // Consider this a failure if the entire string does not convert to a  double
00407   if (endptr != (s + strlen(s))) return false;
00408   
00409   // All checks for "floatness" passed
00410   return true;
00411 }
00412 
00413 //......................................................................
00414 
00415 void JobCommand::StringToRegistry(Registry& r, const char* s) 
00416 {
00417 //======================================================================
00418 // Convert a string like "a=1 b=2.0 name=Mark" to a registry
00419 //======================================================================
00420   // JobCommand's expect format Command option1 option2...  so cast
00421   // the string into this form by prepending a bogus command string
00422   string cmd("Set "); // Set is as good a command name as any...
00423   cmd += s;           // Append the registry string
00424   JobCommand c(cmd.c_str());
00425 
00426   // Use the command to build a registry
00427   r.UnLockValues();
00428   while (c.HaveOpt()) {
00429     const char* key;
00430     const char* value;
00431 
00432     // Extract key/value pair
00433     key = c.PopOpt();
00434     if (c.HaveOpt() == false) {
00435       MSG("JobC",Msg::kWarning) << "Missing value for key \"" 
00436                                 << key << "\"!" << endl;
00437       return;
00438     }
00439     value = c.PopOpt();
00440     
00441     // Guess type of value and build registry
00442     if (JobCommand::IsInt(value)) {
00443       // Intergers are floats so check them next
00444       int i = atoi(value);
00445       r.Set(key, i);
00446     }
00447     else if (JobCommand::IsFloat(value)) {
00448       // Check float as it is the smallest set
00449       double d = atof(value);
00450       r.Set(key, d);
00451     }
00452     else if (JobCommand::IsBool(value)) {
00453       bool b = JobCommand::atob(value);
00454       r.Set(key, b); // Which Set is this?? char? int? Dunno...
00455     }
00456     else {
00457       // Everything is a string so check that last
00458       r.Set(key, value);
00459     }
00460   }
00461 
00462   r.LockValues();
00463 }
00464 
00465 //......................................................................
00466 
00467 bool JobCommand::IsBool(const char* value)
00468 {
00469 //======================================================================
00470 // Can the string value be interpreted as a bool value?
00471 //======================================================================
00472   std::string v(value);
00473   if (v == "true")   return true; // C++ style
00474   if (v == "false")  return true;
00475   if (v == "kTRUE")  return true; // ROOT style
00476   if (v == "kFALSE") return true;
00477   if (v == "TRUE")   return true; // Some other reasonable variations...
00478   if (v == "FALSE")  return true;
00479   if (v == "True")   return true;
00480   if (v == "False")  return true;
00481   if (v == "on")     return true;
00482   if (v == "off")    return true;
00483   if (v == "On")     return true;
00484   if (v == "Off")    return true;
00485   if (v == "ON")     return true;
00486   if (v == "OFF")    return true;
00487   return false;
00488 }
00489 
00490 //......................................................................
00491 
00492 bool JobCommand::atob(const char* value)
00493 {
00494 //======================================================================
00495 // Convert the text string to its bool equivalent No error checking is
00496 // done. Returns "false" if the contents of value are not regognized
00497 //======================================================================
00498   std::string v(value);
00499   if (v == "true")   return true;  // C++ style
00500   if (v == "false")  return false;
00501   if (v == "kTRUE")  return true;  // ROOT style
00502   if (v == "kFALSE") return false;
00503   if (v == "TRUE")   return true;  // Some other reasonable variations...
00504   if (v == "FALSE")  return false;
00505   if (v == "True")   return true;
00506   if (v == "False")  return false;
00507   if (v == "on")     return true;
00508   if (v == "off")    return false;
00509   if (v == "On")     return true;
00510   if (v == "Off")    return false;
00511   if (v == "ON")     return true;
00512   if (v == "OFF")    return false;
00513 
00514   // Oops, what have we here?
00515   MSG("JobC",Msg::kWarning) << 
00516     "Attmept to convert string '" << value << "' to bool. Result is 'false'\n";
00517   return false;
00518 }
00519 
00521 

Generated on Mon Feb 15 11:06:49 2010 for loon by  doxygen 1.3.9.1