[llvm-commits] [llvm] r50355 - in /llvm/trunk: docs/CommandLine.html include/llvm/Support/CommandLine.h lib/Support/CommandLine.cpp

Mikhail Glushenkov foldr at codedgers.com
Mon Apr 28 09:44:25 PDT 2008


Author: foldr
Date: Mon Apr 28 11:44:25 2008
New Revision: 50355

URL: http://llvm.org/viewvc/llvm-project?rev=50355&view=rev
Log:
Add support for response files to the CommandLine library.

Modified:
    llvm/trunk/docs/CommandLine.html
    llvm/trunk/include/llvm/Support/CommandLine.h
    llvm/trunk/lib/Support/CommandLine.cpp

Modified: llvm/trunk/docs/CommandLine.html
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/CommandLine.html?rev=50355&r1=50354&r2=50355&view=diff

==============================================================================
--- llvm/trunk/docs/CommandLine.html (original)
+++ llvm/trunk/docs/CommandLine.html Mon Apr 28 11:44:25 2008
@@ -52,6 +52,7 @@
                                    specified</a></li>
         <li><a href="#formatting">Controlling other formatting options</a></li>
         <li><a href="#misc">Miscellaneous option modifiers</a></li>
+        <li><a href="#response">Response files</a></li>
         </ul></li>
 
       <li><a href="#toplevel">Top-Level Classes and Functions</a>
@@ -1442,6 +1443,29 @@
 
 </div>
 
+<!-- _______________________________________________________________________ -->
+<div class="doc_subsubsection">
+  <a name="response">Response files</a>
+</div>
+
+<div class="doc_text">
+
+<p>Some systems, such as certain variants of Microsoft Windows and
+some older Unices have a relatively low limit on command-line
+length. It is therefore customary to use the so-called 'response
+files' to circumvent this restriction. These files are mentioned on
+the command-line (using the "@file") syntax. The program reads these
+files and inserts the contents into argv, thereby working around the
+command-line length limits. Response files are enabled by an optional
+fourth argument to
+<a href="#cl::ParseEnvironmentOptions"><tt>cl::ParseEnvironmentOptions</tt></a>
+and
+<a href="#cl::ParseCommandLineOptions"><tt>cl::ParseCommandLineOptions</tt></a>.
+</p>
+
+</div>
+
+
 <!-- ======================================================================= -->
 <div class="doc_subsection">
   <a name="toplevel">Top-Level Classes and Functions</a>
@@ -1475,7 +1499,8 @@
 <p>The <tt>cl::ParseCommandLineOptions</tt> function requires two parameters
 (<tt>argc</tt> and <tt>argv</tt>), but may also take an optional third parameter
 which holds <a href="#description">additional extra text</a> to emit when the
-<tt>--help</tt> option is invoked.</p>
+<tt>--help</tt> option is invoked, and a fourth boolean parameter that enables
+<a href="#response">response files</a>.</p>
 
 </div>
 
@@ -1497,11 +1522,13 @@
 href="#cl::ParseCommandLineOptions"><tt>cl::ParseCommandLineOptions</tt></a>
 does.</p>
 
-<p>It takes three parameters: the name of the program (since <tt>argv</tt> may
+<p>It takes four parameters: the name of the program (since <tt>argv</tt> may
 not be available, it can't just look in <tt>argv[0]</tt>), the name of the
-environment variable to examine, and the optional
+environment variable to examine, the optional
 <a href="#description">additional extra text</a> to emit when the
-<tt>--help</tt> option is invoked.</p>
+<tt>--help</tt> option is invoked, and the boolean
+switch that controls whether <a href="#response">reponse files</a>
+should be read.</p>
 
 <p><tt>cl::ParseEnvironmentOptions</tt> will break the environment
 variable's value up into words and then process them using

Modified: llvm/trunk/include/llvm/Support/CommandLine.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/CommandLine.h?rev=50355&r1=50354&r2=50355&view=diff

==============================================================================
--- llvm/trunk/include/llvm/Support/CommandLine.h (original)
+++ llvm/trunk/include/llvm/Support/CommandLine.h Mon Apr 28 11:44:25 2008
@@ -41,14 +41,16 @@
 // ParseCommandLineOptions - Command line option processing entry point.
 //
 void ParseCommandLineOptions(int argc, char **argv,
-                             const char *Overview = 0);
+                             const char *Overview = 0,
+                             bool ReadResponseFiles = false);
 
 //===----------------------------------------------------------------------===//
 // ParseEnvironmentOptions - Environment variable option processing alternate
 //                           entry point.
 //
 void ParseEnvironmentOptions(const char *progName, const char *envvar,
-                             const char *Overview = 0);
+                             const char *Overview = 0,
+                             bool ReadResponseFiles = false);
 
 ///===---------------------------------------------------------------------===//
 /// SetVersionPrinter - Override the default (LLVM specific) version printer
@@ -146,10 +148,10 @@
   virtual enum ValueExpected getValueExpectedFlagDefault() const {
     return ValueOptional;
   }
-  
+
   // Out of line virtual function to provide home for the class.
   virtual void anchor();
-  
+
   int NumOccurrences;     // The number of times specified
   int Flags;              // Flags for the argument
   unsigned Position;      // Position of last occurrence of the option
@@ -213,7 +215,7 @@
   // addArgument - Register this argument with the commandline system.
   //
   void addArgument();
-  
+
   Option *getNextRegisteredOption() const { return NextRegistered; }
 
   // Return the width of the option tag for printing...
@@ -225,7 +227,7 @@
   virtual void printOptionInfo(unsigned GlobalWidth) const = 0;
 
   virtual void getExtraOptionNames(std::vector<const char*> &OptionNames) {}
-  
+
   // addOccurrence - Wrapper around handleOccurrence that enforces Flags
   //
   bool addOccurrence(unsigned pos, const char *ArgName,
@@ -339,7 +341,7 @@
 };
 
 template<class DataType>
-ValuesClass<DataType> END_WITH_NULL values(const char *Arg, DataType Val, 
+ValuesClass<DataType> END_WITH_NULL values(const char *Arg, DataType Val,
                                            const char *Desc, ...) {
     va_list ValueArgs;
     va_start(ValueArgs, Desc);
@@ -389,7 +391,7 @@
     //
     hasArgStr = O.hasArgStr();
   }
-  
+
   void getExtraOptionNames(std::vector<const char*> &OptionNames) {
     // If there has been no argstr specified, that means that we need to add an
     // argument for every possible option.  This ensures that our options are
@@ -537,7 +539,7 @@
 
   // getValueName - Do not print =<value> at all.
   virtual const char *getValueName() const { return 0; }
-  
+
   // An out-of-line virtual method to provide a 'home' for this class.
   virtual void anchor();
 };
@@ -551,7 +553,7 @@
 class parser<boolOrDefault> : public basic_parser<boolOrDefault> {
 public:
   // parse - Return true on error.
-  bool parse(Option &O, const char *ArgName, const std::string &Arg, 
+  bool parse(Option &O, const char *ArgName, const std::string &Arg,
              boolOrDefault &Val);
 
   enum ValueExpected getValueExpectedFlagDefault() const {
@@ -560,7 +562,7 @@
 
   // getValueName - Do not print =<value> at all.
   virtual const char *getValueName() const { return 0; }
-  
+
   // An out-of-line virtual method to provide a 'home' for this class.
   virtual void anchor();
 };
@@ -965,7 +967,7 @@
   virtual void getExtraOptionNames(std::vector<const char*> &OptionNames) {
     return Parser.getExtraOptionNames(OptionNames);
   }
-  
+
   virtual bool handleOccurrence(unsigned pos, const char *ArgName,
                                 const std::string &Arg) {
     typename ParserClass::parser_data_type Val =
@@ -1071,7 +1073,7 @@
 template<class DataType, class StorageClass>
 class bits_storage {
   unsigned *Location;   // Where to store the bits...
-  
+
   template<class T>
   static unsigned Bit(const T &V) {
     unsigned BitPos = reinterpret_cast<unsigned>(V);
@@ -1096,9 +1098,9 @@
            "line option with external storage!");
     *Location |= Bit(V);
   }
-  
+
   unsigned getBits() { return *Location; }
-  
+
   template<class T>
   bool isSet(const T &V) {
     return (*Location & Bit(V)) != 0;
@@ -1106,13 +1108,13 @@
 };
 
 
-// Define how to hold bits.  Since we can inherit from a class, we do so. 
+// Define how to hold bits.  Since we can inherit from a class, we do so.
 // This makes us exactly compatible with the bits in all cases that it is used.
 //
 template<class DataType>
 class bits_storage<DataType, bool> {
   unsigned Bits;   // Where to store the bits...
-  
+
   template<class T>
   static unsigned Bit(const T &V) {
     unsigned BitPos = reinterpret_cast<unsigned>(V);
@@ -1120,15 +1122,15 @@
           "enum exceeds width of bit vector!");
     return 1 << BitPos;
   }
-  
+
 public:
   template<class T>
   void addValue(const T &V) {
     Bits |=  Bit(V);
   }
-  
+
   unsigned getBits() { return Bits; }
-  
+
   template<class T>
   bool isSet(const T &V) {
     return (Bits & Bit(V)) != 0;
@@ -1151,7 +1153,7 @@
   virtual void getExtraOptionNames(std::vector<const char*> &OptionNames) {
     return Parser.getExtraOptionNames(OptionNames);
   }
-  
+
   virtual bool handleOccurrence(unsigned pos, const char *ArgName,
                                 const std::string &Arg) {
     typename ParserClass::parser_data_type Val =

Modified: llvm/trunk/lib/Support/CommandLine.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/CommandLine.cpp?rev=50355&r1=50354&r2=50355&view=diff

==============================================================================
--- llvm/trunk/lib/Support/CommandLine.cpp (original)
+++ llvm/trunk/lib/Support/CommandLine.cpp Mon Apr 28 11:44:25 2008
@@ -17,7 +17,9 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/Config/config.h"
+#include "llvm/ADT/OwningPtr.h"
 #include "llvm/Support/CommandLine.h"
+#include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/ManagedStatic.h"
 #include "llvm/Support/Streams.h"
 #include "llvm/System/Path.h"
@@ -87,7 +89,7 @@
 
 void Option::addArgument() {
   assert(NextRegistered == 0 && "argument multiply registered!");
-  
+
   NextRegistered = RegisteredOptionList;
   RegisteredOptionList = this;
   MarkOptionsChanged();
@@ -111,7 +113,7 @@
     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!
@@ -121,9 +123,9 @@
              << OptionNames[0] << "' defined more than once!\n";
       }
     }
-    
+
     OptionNames.clear();
-    
+
     // Remember information about positional options.
     if (O->getFormattingFlag() == cl::Positional)
       PositionalOpts.push_back(O);
@@ -135,10 +137,10 @@
       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());
 }
@@ -150,17 +152,17 @@
 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;
   while (*ArgEnd && *ArgEnd != '=')
     ++ArgEnd; // Scan till end of argument name.
-  
+
   if (*ArgEnd == '=')  // If we have an equals sign...
     Value = ArgEnd+1;  // Get the value, not the equals
-  
-  
+
+
   if (*Arg == 0) return 0;
-  
+
   // Look up the option.
   std::map<std::string, Option*>::iterator I =
     OptionsMap.find(std::string(Arg, ArgEnd));
@@ -309,7 +311,7 @@
 /// an environment variable (whose name is given in ENVVAR).
 ///
 void cl::ParseEnvironmentOptions(const char *progName, const char *envVar,
-                                 const char *Overview) {
+                                 const char *Overview, bool ReadResponseFiles) {
   // Check args.
   assert(progName && "Program name not specified");
   assert(envVar && "Environment variable name missing");
@@ -328,7 +330,7 @@
   // and hand it off to ParseCommandLineOptions().
   ParseCStringVector(newArgv, envValue);
   int newArgc = newArgv.size();
-  ParseCommandLineOptions(newArgc, &newArgv[0], Overview);
+  ParseCommandLineOptions(newArgc, &newArgv[0], Overview, ReadResponseFiles);
 
   // Free all the strdup()ed strings.
   for (std::vector<char*>::iterator i = newArgv.begin(), e = newArgv.end();
@@ -336,32 +338,78 @@
     free (*i);
 }
 
+
+/// ExpandResponseFiles - Copy the contents of argv into newArgv,
+/// substituting the contents of the response files for the arguments
+/// of type @file.
+static void ExpandResponseFiles(int argc, char** argv,
+                                std::vector<char*>& newArgv) {
+  for (int i = 1; i != argc; ++i) {
+    char* arg = argv[i];
+
+    if (arg[0] == '@') {
+
+      sys::PathWithStatus respFile(++arg);
+
+      // Check that the response file is not empty (mmap'ing empty
+      // files can be problematic).
+      const sys::FileStatus *FileStat = respFile.getFileStatus();
+      if (!FileStat)
+        continue;
+      if (FileStat->getSize() == 0)
+        continue;
+
+      // Mmap the response file into memory.
+      OwningPtr<MemoryBuffer>
+        respFilePtr(MemoryBuffer::getFile(respFile.c_str()));
+
+      if (respFilePtr == 0)
+        continue;
+
+      ParseCStringVector(newArgv, respFilePtr->getBufferStart());
+    }
+    else {
+      newArgv.push_back(strdup(arg));
+    }
+  }
+}
+
 void cl::ParseCommandLineOptions(int argc, char **argv,
-                                 const char *Overview) {
+                                 const char *Overview, bool ReadResponseFiles) {
   // Process all registered options.
   std::vector<Option*> PositionalOpts;
   std::vector<Option*> SinkOpts;
   std::map<std::string, Option*> Opts;
   GetOptionInfo(PositionalOpts, SinkOpts, Opts);
-  
+
   assert((!Opts.empty() || !PositionalOpts.empty()) &&
          "No options specified!");
+
+  // Expand response files.
+  std::vector<char*> newArgv;
+  if (ReadResponseFiles) {
+    newArgv.push_back(strdup(argv[0]));
+    ExpandResponseFiles(argc, argv, newArgv);
+    argv = &newArgv[0];
+    argc = newArgv.size();
+  }
+
   sys::Path progname(argv[0]);
 
   // Copy the program name into ProgName, making sure not to overflow it.
   std::string ProgName = sys::Path(argv[0]).getLast();
   if (ProgName.size() > 79) ProgName.resize(79);
   strcpy(ProgramName, ProgName.c_str());
-  
+
   ProgramOverview = Overview;
   bool ErrorParsing = false;
 
   // Check out the positional arguments to collect information about them.
   unsigned NumPositionalRequired = 0;
-  
+
   // Determine whether or not there are an unlimited number of positionals
   bool HasUnlimitedPositionals = false;
-  
+
   Option *ConsumeAfterOpt = 0;
   if (!PositionalOpts.empty()) {
     if (PositionalOpts[0]->getNumOccurrencesFlag() == cl::ConsumeAfter) {
@@ -427,7 +475,7 @@
       GetOptionInfo(PositionalOpts, SinkOpts, 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.
@@ -567,7 +615,7 @@
          << ": Not enough positional command line arguments specified!\n"
          << "Must specify at least " << NumPositionalRequired
          << " positional arguments: See: " << argv[0] << " --help\n";
-    
+
     ErrorParsing = true;
   } else if (!HasUnlimitedPositionals
              && PositionalVals.size() > PositionalOpts.size()) {
@@ -664,6 +712,14 @@
   PositionalOpts.clear();
   MoreHelp->clear();
 
+  // Free the memory allocated by ExpandResponseFiles.
+  if (ReadResponseFiles) {
+    // Free all the strdup()ed strings.
+    for (std::vector<char*>::iterator i = newArgv.begin(), e = newArgv.end();
+         i != e; ++i)
+      free (*i);
+  }
+
   // If we had an error processing our arguments, don't let the program execute
   if (ErrorParsing) exit(1);
 }
@@ -678,7 +734,7 @@
     cerr << HelpStr;  // Be nice for positional arguments
   else
     cerr << ProgramName << ": for the -" << ArgName;
-  
+
   cerr << " option: " << Message << "\n";
   return true;
 }
@@ -943,7 +999,7 @@
     std::vector<Option*> SinkOpts;
     std::map<std::string, Option*> OptMap;
     GetOptionInfo(PositionalOpts, SinkOpts, OptMap);
-    
+
     // Copy Options into a vector so we can sort them as we like...
     std::vector<std::pair<std::string, Option*> > Opts;
     copy(OptMap.begin(), OptMap.end(), std::back_inserter(Opts));
@@ -970,7 +1026,7 @@
 
     // Print out the positional options.
     Option *CAOpt = 0;   // The cl::ConsumeAfter option, if it exists...
-    if (!PositionalOpts.empty() && 
+    if (!PositionalOpts.empty() &&
         PositionalOpts[0]->getNumOccurrencesFlag() == ConsumeAfter)
       CAOpt = PositionalOpts[0];
 





More information about the llvm-commits mailing list