Browse Source

cmFileCommand: Use cm::optional for keyword argument presence

Brad King 3 years ago
parent
commit
bff468c988

+ 61 - 83
Source/cmFileCommand.cxx

@@ -1254,7 +1254,7 @@ bool HandleRealPathCommand(std::vector<std::string> const& args,
 
   struct Arguments
   {
-    std::string BaseDirectory;
+    cm::optional<std::string> BaseDirectory;
     bool ExpandTilde = false;
   };
   static auto const parser =
@@ -1264,10 +1264,8 @@ bool HandleRealPathCommand(std::vector<std::string> const& args,
 
   std::vector<std::string> unparsedArguments;
   std::vector<cm::string_view> keywordsMissingValue;
-  std::vector<cm::string_view> parsedKeywords;
-  auto arguments =
-    parser.Parse(cmMakeRange(args).advance(3), &unparsedArguments,
-                 &keywordsMissingValue, &parsedKeywords);
+  auto arguments = parser.Parse(cmMakeRange(args).advance(3),
+                                &unparsedArguments, &keywordsMissingValue);
 
   if (!unparsedArguments.empty()) {
     status.SetError("REAL_PATH called with unexpected arguments");
@@ -1278,7 +1276,7 @@ bool HandleRealPathCommand(std::vector<std::string> const& args,
     return false;
   }
 
-  if (parsedKeywords.empty()) {
+  if (!arguments.BaseDirectory) {
     arguments.BaseDirectory = status.GetMakefile().GetCurrentSourceDirectory();
   }
 
@@ -1297,7 +1295,7 @@ bool HandleRealPathCommand(std::vector<std::string> const& args,
   }
 
   cmCMakePath path(input, cmCMakePath::auto_format);
-  path = path.Absolute(arguments.BaseDirectory).Normal();
+  path = path.Absolute(*arguments.BaseDirectory).Normal();
   auto realPath = cmSystemTools::GetRealPath(path.GenericString());
 
   status.GetMakefile().AddDefinition(args[2], realPath);
@@ -2499,12 +2497,12 @@ bool HandleGenerateCommand(std::vector<std::string> const& args,
 
   struct Arguments
   {
-    std::string Output;
-    std::string Input;
-    std::string Content;
-    std::string Condition;
-    std::string Target;
-    std::string NewLineStyle;
+    cm::optional<std::string> Output;
+    cm::optional<std::string> Input;
+    cm::optional<std::string> Content;
+    cm::optional<std::string> Condition;
+    cm::optional<std::string> Target;
+    cm::optional<std::string> NewLineStyle;
     bool NoSourcePermissions = false;
     bool UseSourcePermissions = false;
     std::vector<std::string> FilePermissions;
@@ -2530,7 +2528,9 @@ bool HandleGenerateCommand(std::vector<std::string> const& args,
                  &keywordsMissingValues, &parsedKeywords);
 
   if (!keywordsMissingValues.empty()) {
-    status.SetError("Incorrect arguments to GENERATE subcommand.");
+    status.SetError(
+      cmStrCat("GENERATE keywords missing values:\n  ",
+               cmJoin(cmMakeRange(keywordsMissingValues), "\n  ")));
     return false;
   }
 
@@ -2539,56 +2539,41 @@ bool HandleGenerateCommand(std::vector<std::string> const& args,
     return false;
   }
 
-  bool mandatoryOptionsSpecified = false;
-  if (parsedKeywords.size() > 1) {
-    const bool outputOprionSpecified = parsedKeywords[0] == "OUTPUT"_s;
-    const bool inputOrContentSpecified =
-      parsedKeywords[1] == "INPUT"_s || parsedKeywords[1] == "CONTENT"_s;
-    if (outputOprionSpecified && inputOrContentSpecified) {
-      mandatoryOptionsSpecified = true;
-    }
+  if (!arguments.Output || parsedKeywords[0] != "OUTPUT"_s) {
+    status.SetError("GENERATE requires OUTPUT as first option.");
+    return false;
   }
-  if (!mandatoryOptionsSpecified) {
-    status.SetError("Incorrect arguments to GENERATE subcommand.");
+  std::string const& output = *arguments.Output;
+
+  if (!arguments.Input && !arguments.Content) {
+    status.SetError("GENERATE requires INPUT or CONTENT option.");
     return false;
   }
+  const bool inputIsContent = parsedKeywords[1] == "CONTENT"_s;
+  if (!inputIsContent && parsedKeywords[1] == "INPUT") {
+    status.SetError("Unknown argument to GENERATE subcommand.");
+  }
+  std::string const& input =
+    inputIsContent ? *arguments.Content : *arguments.Input;
 
-  const bool conditionOptionSpecified =
-    std::find(parsedKeywords.begin(), parsedKeywords.end(), "CONDITION"_s) !=
-    parsedKeywords.end();
-  if (conditionOptionSpecified && arguments.Condition.empty()) {
+  if (arguments.Condition && arguments.Condition->empty()) {
     status.SetError("CONDITION of sub-command GENERATE must not be empty "
                     "if specified.");
     return false;
   }
+  std::string const& condition =
+    arguments.Condition ? *arguments.Condition : std::string();
 
-  const bool targetOptionSpecified =
-    std::find(parsedKeywords.begin(), parsedKeywords.end(), "TARGET"_s) !=
-    parsedKeywords.end();
-  if (targetOptionSpecified && arguments.Target.empty()) {
+  if (arguments.Target && arguments.Target->empty()) {
     status.SetError("TARGET of sub-command GENERATE must not be empty "
                     "if specified.");
     return false;
   }
+  std::string const& target =
+    arguments.Target ? *arguments.Target : std::string();
 
-  const bool outputOptionSpecified =
-    std::find(parsedKeywords.begin(), parsedKeywords.end(), "OUTPUT"_s) !=
-    parsedKeywords.end();
-  if (outputOptionSpecified && parsedKeywords[0] != "OUTPUT"_s) {
-    status.SetError("Incorrect arguments to GENERATE subcommand.");
-    return false;
-  }
-
-  const bool inputIsContent = parsedKeywords[1] != "INPUT"_s;
-  if (inputIsContent && parsedKeywords[1] != "CONTENT"_s) {
-    status.SetError("Unknown argument to GENERATE subcommand.");
-  }
-
-  const bool newLineStyleSpecified =
-    std::find(parsedKeywords.begin(), parsedKeywords.end(),
-              "NEWLINE_STYLE"_s) != parsedKeywords.end();
   cmNewLineStyle newLineStyle;
-  if (newLineStyleSpecified) {
+  if (arguments.NewLineStyle) {
     std::string errorMessage;
     if (!newLineStyle.ReadFromArguments(args, errorMessage)) {
       status.SetError(cmStrCat("GENERATE ", errorMessage));
@@ -2596,11 +2581,6 @@ bool HandleGenerateCommand(std::vector<std::string> const& args,
     }
   }
 
-  std::string input = arguments.Input;
-  if (inputIsContent) {
-    input = arguments.Content;
-  }
-
   if (arguments.NoSourcePermissions && arguments.UseSourcePermissions) {
     status.SetError("given both NO_SOURCE_PERMISSIONS and "
                     "USE_SOURCE_PERMISSIONS. Only one option allowed.");
@@ -2658,8 +2638,7 @@ bool HandleGenerateCommand(std::vector<std::string> const& args,
     }
   }
 
-  AddEvaluationFile(input, arguments.Target, arguments.Output,
-                    arguments.Condition, inputIsContent,
+  AddEvaluationFile(input, target, output, condition, inputIsContent,
                     newLineStyle.GetCharacters(), permissions, status);
   return true;
 }
@@ -3237,8 +3216,8 @@ bool HandleConfigureCommand(std::vector<std::string> const& args,
 {
   struct Arguments
   {
-    std::string Output;
-    std::string Content;
+    cm::optional<std::string> Output;
+    cm::optional<std::string> Content;
     bool EscapeQuotes = false;
     bool AtOnly = false;
     std::string NewlineStyle;
@@ -3253,11 +3232,10 @@ bool HandleConfigureCommand(std::vector<std::string> const& args,
       .Bind("NEWLINE_STYLE"_s, &Arguments::NewlineStyle);
 
   std::vector<std::string> unrecognizedArguments;
-  std::vector<cm::string_view> keywordsMissingArguments;
-  std::vector<cm::string_view> parsedKeywords;
+  std::vector<cm::string_view> keywordsMissingValues;
   auto parsedArgs =
     parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments,
-                 &keywordsMissingArguments, &parsedKeywords);
+                 &keywordsMissingValues);
 
   auto argIt = unrecognizedArguments.begin();
   if (argIt != unrecognizedArguments.end()) {
@@ -3267,28 +3245,28 @@ bool HandleConfigureCommand(std::vector<std::string> const& args,
     return false;
   }
 
-  std::vector<cm::string_view> mandatoryOptions{ "OUTPUT"_s, "CONTENT"_s };
-  for (auto const& e : mandatoryOptions) {
-    const bool optionHasNoValue =
-      std::find(keywordsMissingArguments.begin(),
-                keywordsMissingArguments.end(),
-                e) != keywordsMissingArguments.end();
-    if (optionHasNoValue) {
-      status.SetError(cmStrCat("CONFIGURE ", e, " option needs a value."));
-      cmSystemTools::SetFatalErrorOccurred();
-      return false;
-    }
+  // Arguments that are allowed to be empty lists.  Keep entries sorted!
+  static const std::vector<cm::string_view> LIST_ARGS = {
+    "NEWLINE_STYLE"_s, // Filter here so we can issue a custom error below.
+  };
+  auto kwbegin = keywordsMissingValues.cbegin();
+  auto kwend = cmRemoveMatching(keywordsMissingValues, LIST_ARGS);
+  if (kwend != kwbegin) {
+    status.SetError(cmStrCat("CONFIGURE keywords missing values:\n  ",
+                             cmJoin(cmMakeRange(kwbegin, kwend), "\n  ")));
+    cmSystemTools::SetFatalErrorOccurred();
+    return false;
   }
 
-  for (auto const& e : mandatoryOptions) {
-    const bool optionGiven =
-      std::find(parsedKeywords.begin(), parsedKeywords.end(), e) !=
-      parsedKeywords.end();
-    if (!optionGiven) {
-      status.SetError(cmStrCat("CONFIGURE ", e, " option is mandatory."));
-      cmSystemTools::SetFatalErrorOccurred();
-      return false;
-    }
+  if (!parsedArgs.Output) {
+    status.SetError("CONFIGURE OUTPUT option is mandatory.");
+    cmSystemTools::SetFatalErrorOccurred();
+    return false;
+  }
+  if (!parsedArgs.Content) {
+    status.SetError("CONFIGURE CONTENT option is mandatory.");
+    cmSystemTools::SetFatalErrorOccurred();
+    return false;
   }
 
   std::string errorMessage;
@@ -3300,7 +3278,7 @@ bool HandleConfigureCommand(std::vector<std::string> const& args,
 
   // Check for generator expressions
   std::string outputFile = cmSystemTools::CollapseFullPath(
-    parsedArgs.Output, status.GetMakefile().GetCurrentBinaryDirectory());
+    *parsedArgs.Output, status.GetMakefile().GetCurrentBinaryDirectory());
 
   std::string::size_type pos = outputFile.find_first_of("<>");
   if (pos != std::string::npos) {
@@ -3349,7 +3327,7 @@ bool HandleConfigureCommand(std::vector<std::string> const& args,
   fout.SetCopyIfDifferent(true);
 
   // copy input to output and expand variables from input at the same time
-  std::stringstream sin(parsedArgs.Content, std::ios::in);
+  std::stringstream sin(*parsedArgs.Content, std::ios::in);
   std::string inLine;
   std::string outLine;
   bool hasNewLine = false;

+ 3 - 1
Tests/RunCMake/File_Configure/BadArgContent-stderr.txt

@@ -1,4 +1,6 @@
 CMake Error at BadArgContent.cmake:[0-9]+ \(file\):
-  file CONFIGURE CONTENT option needs a value.
+  file CONFIGURE keywords missing values:
+
+    CONTENT
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)

+ 3 - 1
Tests/RunCMake/File_Configure/BadArgOutput-stderr.txt

@@ -1,4 +1,6 @@
 CMake Error at BadArgOutput.cmake:[0-9]+ \(file\):
-  file CONFIGURE OUTPUT option needs a value.
+  file CONFIGURE keywords missing values:
+
+    OUTPUT
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)

+ 3 - 1
Tests/RunCMake/File_Generate/EmptyCondition1-stderr.txt

@@ -1,4 +1,6 @@
 CMake Error at EmptyCondition1.cmake:2 \(file\):
-  file Incorrect arguments to GENERATE subcommand.
+  file GENERATE keywords missing values:
+
+    CONDITION
 Call Stack \(most recent call first\):
   CMakeLists.txt:[0-9]+ \(include\)

+ 3 - 1
Tests/RunCMake/File_Generate/NewLineStyle-NoArg-stderr.txt

@@ -1,4 +1,6 @@
 CMake Error at NewLineStyle-NoArg.cmake:[0-9]+ \(file\):
-  file Incorrect arguments to GENERATE subcommand.
+  file GENERATE keywords missing values:
+
+    NEWLINE_STYLE
 Call Stack \(most recent call first\):
   CMakeLists.txt:[0-9]+ \(include\)