Pass argc by value, not by reference, since it isn't modified.
[oota-llvm.git] / lib / Support / CommandLine.cpp
index 5fa65d82ba5b73d4b7810ef18264675240809a81..eed780437bb0b97416c42eb59e0c9990c1534a6d 100644 (file)
@@ -36,6 +36,7 @@ using namespace cl;
 // Template instantiations and anchors.
 //
 TEMPLATE_INSTANTIATION(class basic_parser<bool>);
+TEMPLATE_INSTANTIATION(class basic_parser<boolOrDefault>);
 TEMPLATE_INSTANTIATION(class basic_parser<int>);
 TEMPLATE_INSTANTIATION(class basic_parser<unsigned>);
 TEMPLATE_INSTANTIATION(class basic_parser<double>);
@@ -50,6 +51,7 @@ TEMPLATE_INSTANTIATION(class opt<bool>);
 void Option::anchor() {}
 void basic_parser_impl::anchor() {}
 void parser<bool>::anchor() {}
+void parser<boolOrDefault>::anchor() {}
 void parser<int>::anchor() {}
 void parser<unsigned>::anchor() {}
 void parser<double>::anchor() {}
@@ -71,32 +73,78 @@ extrahelp::extrahelp(const char *Help)
   MoreHelp->push_back(Help);
 }
 
-//===----------------------------------------------------------------------===//
-// Basic, shared command line option processing machinery.
-//
+static bool OptionListChanged = false;
 
-static ManagedStatic<std::map<std::string, Option*> > OptionsMap;
-static ManagedStatic<std::vector<Option*> > PositionalOptions;
+// MarkOptionsChanged - Internal helper function.
+void cl::MarkOptionsChanged() {
+  OptionListChanged = true;
+}
+
+/// RegisteredOptionList - This is the list of the command line options that
+/// have statically constructed themselves.
+static Option *RegisteredOptionList = 0;
 
-static Option *getOption(const std::string &Str) {
-  std::map<std::string,Option*>::iterator I = OptionsMap->find(Str);
-  return I != OptionsMap->end() ? I->second : 0;
+void Option::addArgument() {
+  assert(NextRegistered == 0 && "argument multiply registered!");
+  
+  NextRegistered = RegisteredOptionList;
+  RegisteredOptionList = this;
+  MarkOptionsChanged();
 }
 
-static void AddArgument(const char *ArgName, Option *Opt) {
-  if (getOption(ArgName)) {
-    cerr << ProgramName << ": CommandLine Error: Argument '"
-         << ArgName << "' defined more than once!\n";
-  } else {
-    // Add argument to the argument map!
-    (*OptionsMap)[ArgName] = Opt;
+
+//===----------------------------------------------------------------------===//
+// Basic, shared command line option processing machinery.
+//
+
+/// GetOptionInfo - Scan the list of registered options, turning them into data
+/// structures that are easier to handle.
+static void GetOptionInfo(std::vector<Option*> &PositionalOpts,
+                          std::map<std::string, Option*> &OptionsMap) {
+  std::vector<const char*> OptionNames;
+  Option *CAOpt = 0;  // The ConsumeAfter option if it exists.
+  for (Option *O = RegisteredOptionList; O; O = O->getNextRegisteredOption()) {
+    // If this option wants to handle multiple option names, get the full set.
+    // This handles enum options like "-O1 -O2" etc.
+    O->getExtraOptionNames(OptionNames);
+    if (O->ArgStr[0])
+      OptionNames.push_back(O->ArgStr);
+    
+    // Handle named options.
+    for (unsigned i = 0, e = OptionNames.size(); i != e; ++i) {
+      // Add argument to the argument map!
+      if (!OptionsMap.insert(std::pair<std::string,Option*>(OptionNames[i],
+                                                            O)).second) {
+        cerr << ProgramName << ": CommandLine Error: Argument '"
+             << OptionNames[0] << "' defined more than once!\n";
+      }
+    }
+    
+    OptionNames.clear();
+    
+    // Remember information about positional options.
+    if (O->getFormattingFlag() == cl::Positional)
+      PositionalOpts.push_back(O);
+    else if (O->getNumOccurrencesFlag() == cl::ConsumeAfter) {
+      if (CAOpt)
+        O->error("Cannot specify more than one option with cl::ConsumeAfter!");
+      CAOpt = O;
+    }
   }
+  
+  if (CAOpt)
+    PositionalOpts.push_back(CAOpt);
+  
+  // Make sure that they are in order of registration not backwards.
+  std::reverse(PositionalOpts.begin(), PositionalOpts.end());
 }
 
+
 /// LookupOption - Lookup the option specified by the specified option on the
 /// command line.  If there is a value specified (after an equal sign) return
 /// that as well.
-static Option *LookupOption(const char *&Arg, const char *&Value) {
+static Option *LookupOption(const char *&Arg, const char *&Value,
+                            std::map<std::string, Option*> &OptionsMap) {
   while (*Arg == '-') ++Arg;  // Eat leading dashes
   
   const char *ArgEnd = Arg;
@@ -110,10 +158,9 @@ static Option *LookupOption(const char *&Arg, const char *&Value) {
   if (*Arg == 0) return 0;
   
   // Look up the option.
-  std::map<std::string, Option*> &Opts = *OptionsMap;
   std::map<std::string, Option*>::iterator I =
-    Opts.find(std::string(Arg, ArgEnd));
-  return (I != Opts.end()) ? I->second : 0;
+    OptionsMap.find(std::string(Arg, ArgEnd));
+  return I != OptionsMap.end() ? I->second : 0;
 }
 
 static inline bool ProvideOption(Option *Handler, const char *ArgName,
@@ -171,27 +218,28 @@ static inline bool isPrefixedOrGrouping(const Option *O) {
 // otherwise return null.
 //
 static Option *getOptionPred(std::string Name, unsigned &Length,
-                             bool (*Pred)(const Option*)) {
+                             bool (*Pred)(const Option*),
+                             std::map<std::string, Option*> &OptionsMap) {
 
-  Option *Op = getOption(Name);
-  if (Op && Pred(Op)) {
+  std::map<std::string, Option*>::iterator OMI = OptionsMap.find(Name);
+  if (OMI != OptionsMap.end() && Pred(OMI->second)) {
     Length = Name.length();
-    return Op;
+    return OMI->second;
   }
 
   if (Name.size() == 1) return 0;
   do {
     Name.erase(Name.end()-1, Name.end());   // Chop off the last character...
-    Op = getOption(Name);
+    OMI = OptionsMap.find(Name);
 
     // Loop while we haven't found an option and Name still has at least two
     // characters in it (so that the next iteration will not be the empty
     // string...
-  } while ((Op == 0 || !Pred(Op)) && Name.size() > 1);
+  } while ((OMI == OptionsMap.end() || !Pred(OMI->second)) && Name.size() > 1);
 
-  if (Op && Pred(Op)) {
+  if (OMI != OptionsMap.end() && Pred(OMI->second)) {
     Length = Name.length();
-    return Op;             // Found one!
+    return OMI->second;    // Found one!
   }
   return 0;                // No option found!
 }
@@ -284,11 +332,15 @@ void cl::ParseEnvironmentOptions(const char *progName, const char *envVar,
     free (*i);
 }
 
-void cl::ParseCommandLineOptions(int &argc, char **argv,
+void cl::ParseCommandLineOptions(int argc, char **argv,
                                  const char *Overview) {
-  assert((!OptionsMap->empty() || !PositionalOptions->empty()) &&
-         "No options specified, or ParseCommandLineOptions called more"
-         " than once!");
+  // Process all registered options.
+  std::vector<Option*> PositionalOpts;
+  std::map<std::string, Option*> Opts;
+  GetOptionInfo(PositionalOpts, Opts);
+  
+  assert((!Opts.empty() || !PositionalOpts.empty()) &&
+         "No options specified!");
   sys::Path progname(argv[0]);
 
   // Copy the program name into ProgName, making sure not to overflow it.
@@ -299,9 +351,6 @@ void cl::ParseCommandLineOptions(int &argc, char **argv,
   ProgramOverview = Overview;
   bool ErrorParsing = false;
 
-  std::map<std::string, Option*> &Opts = *OptionsMap;
-  std::vector<Option*> &PositionalOpts = *PositionalOptions;
-
   // Check out the positional arguments to collect information about them.
   unsigned NumPositionalRequired = 0;
   
@@ -363,6 +412,16 @@ void cl::ParseCommandLineOptions(int &argc, char **argv,
     const char *Value = 0;
     const char *ArgName = "";
 
+    // If the option list changed, this means that some command line
+    // option has just been registered or deregistered.  This can occur in
+    // response to things like -load, etc.  If this happens, rescan the options.
+    if (OptionListChanged) {
+      PositionalOpts.clear();
+      Opts.clear();
+      GetOptionInfo(PositionalOpts, Opts);
+      OptionListChanged = false;
+    }
+    
     // Check to see if this is a positional argument.  This argument is
     // considered to be positional if it doesn't start with '-', if it is "-"
     // itself, or if we have seen "--" already.
@@ -398,7 +457,7 @@ void cl::ParseCommandLineOptions(int &argc, char **argv,
       // option is another positional argument.  If so, treat it as an argument,
       // otherwise feed it to the eating positional.
       ArgName = argv[i]+1;
-      Handler = LookupOption(ArgName, Value);
+      Handler = LookupOption(ArgName, Value, Opts);
       if (!Handler || Handler->getFormattingFlag() != cl::Positional) {
         ProvidePositionalOption(ActivePositionalArg, argv[i], i);
         continue;  // We are done!
@@ -406,14 +465,15 @@ void cl::ParseCommandLineOptions(int &argc, char **argv,
 
     } else {     // We start with a '-', must be an argument...
       ArgName = argv[i]+1;
-      Handler = LookupOption(ArgName, Value);
+      Handler = LookupOption(ArgName, Value, Opts);
 
       // Check to see if this "option" is really a prefixed or grouped argument.
       if (Handler == 0) {
         std::string RealName(ArgName);
         if (RealName.size() > 1) {
           unsigned Length = 0;
-          Option *PGOpt = getOptionPred(RealName, Length, isPrefixedOrGrouping);
+          Option *PGOpt = getOptionPred(RealName, Length, isPrefixedOrGrouping,
+                                        Opts);
 
           // If the option is a prefixed option, then the value is simply the
           // rest of the name...  so fall through to later processing, by
@@ -444,7 +504,7 @@ void cl::ParseCommandLineOptions(int &argc, char **argv,
                                             0, 0, 0, Dummy);
 
               // Get the next grouping option...
-              PGOpt = getOptionPred(RealName, Length, isGrouping);
+              PGOpt = getOptionPred(RealName, Length, isGrouping, Opts);
             } while (PGOpt && Length != RealName.size());
 
             Handler = PGOpt; // Ate all of the options.
@@ -633,23 +693,6 @@ bool Option::addOccurrence(unsigned pos, const char *ArgName,
   return handleOccurrence(pos, ArgName, Value);
 }
 
-// addArgument - Tell the system that this Option subclass will handle all
-// occurrences of -ArgStr on the command line.
-//
-void Option::addArgument(const char *ArgStr) {
-  if (ArgStr[0])
-    AddArgument(ArgStr, this);
-
-  if (getFormattingFlag() == Positional)
-    PositionalOptions->push_back(this);
-  else if (getNumOccurrencesFlag() == ConsumeAfter) {
-    if (!PositionalOptions->empty() &&
-        PositionalOptions->front()->getNumOccurrencesFlag() == ConsumeAfter)
-      error("Cannot specify more than one option with cl::ConsumeAfter!");
-    PositionalOptions->insert(PositionalOptions->begin(), this);
-  }
-}
-
 
 // getValueStr - Get the value description string, using "DefaultMsg" if nothing
 // has been specified yet.
@@ -726,6 +769,22 @@ bool parser<bool>::parse(Option &O, const char *ArgName,
   return false;
 }
 
+// parser<boolOrDefault> implementation
+//
+bool parser<boolOrDefault>::parse(Option &O, const char *ArgName,
+                         const std::string &Arg, boolOrDefault &Value) {
+  if (Arg == "" || Arg == "true" || Arg == "TRUE" || Arg == "True" ||
+      Arg == "1") {
+    Value = BOU_TRUE;
+  } else if (Arg == "false" || Arg == "FALSE" || Arg == "False" || Arg == "0") {
+    Value = BOU_FALSE;
+  } else {
+    return O.error(": '" + Arg +
+                   "' is invalid value for boolean argument! Try 0 or 1");
+  }
+  return false;
+}
+
 // parser<int> implementation
 //
 bool parser<int>::parse(Option &O, const char *ArgName,
@@ -867,9 +926,14 @@ public:
   void operator=(bool Value) {
     if (Value == false) return;
 
+    // Get all the options.
+    std::vector<Option*> PositionalOpts;
+    std::map<std::string, Option*> OptMap;
+    GetOptionInfo(PositionalOpts, OptMap);
+    
     // Copy Options into a vector so we can sort them as we like...
     std::vector<std::pair<std::string, Option*> > Opts;
-    copy(OptionsMap->begin(), OptionsMap->end(), std::back_inserter(Opts));
+    copy(OptMap.begin(), OptMap.end(), std::back_inserter(Opts));
 
     // Eliminate Hidden or ReallyHidden arguments, depending on ShowHidden
     Opts.erase(std::remove_if(Opts.begin(), Opts.end(),
@@ -887,20 +951,20 @@ public:
     }
 
     if (ProgramOverview)
-      cout << "OVERVIEW:" << ProgramOverview << "\n";
+      cout << "OVERVIEW: " << ProgramOverview << "\n";
 
     cout << "USAGE: " << ProgramName << " [options]";
 
     // Print out the positional options.
-    std::vector<Option*> &PosOpts = *PositionalOptions;
     Option *CAOpt = 0;   // The cl::ConsumeAfter option, if it exists...
-    if (!PosOpts.empty() && PosOpts[0]->getNumOccurrencesFlag() == ConsumeAfter)
-      CAOpt = PosOpts[0];
-
-    for (unsigned i = CAOpt != 0, e = PosOpts.size(); i != e; ++i) {
-      if (PosOpts[i]->ArgStr[0])
-        cout << " --" << PosOpts[i]->ArgStr;
-      cout << " " << PosOpts[i]->HelpStr;
+    if (!PositionalOpts.empty() && 
+        PositionalOpts[0]->getNumOccurrencesFlag() == ConsumeAfter)
+      CAOpt = PositionalOpts[0];
+
+    for (unsigned i = CAOpt != 0, e = PositionalOpts.size(); i != e; ++i) {
+      if (PositionalOpts[i]->ArgStr[0])
+        cout << " --" << PositionalOpts[i]->ArgStr;
+      cout << " " << PositionalOpts[i]->HelpStr;
     }
 
     // Print the consume after option info if it exists...
@@ -924,7 +988,6 @@ public:
     MoreHelp->clear();
 
     // Halt the program since help information was printed
-    OptionsMap->clear();  // Don't bother making option dtors remove from map.
     exit(1);
   }
 };
@@ -970,7 +1033,6 @@ public:
     if (OptionWasSpecified) {
       if (OverrideVersionPrinter == 0) {
         print();
-        OptionsMap->clear();// Don't bother making option dtors remove from map.
         exit(1);
       } else {
         (*OverrideVersionPrinter)();