瀏覽代碼

cmake: Use shared parsing code for all cmake argv parsing

Robert Maynard 4 年之前
父節點
當前提交
0fb78576b0
共有 3 個文件被更改,包括 235 次插入164 次删除
  1. 133 0
      Source/cmCommandLineArgument.h
  2. 4 121
      Source/cmake.cxx
  3. 98 43
      Source/cmakemain.cxx

+ 133 - 0
Source/cmCommandLineArgument.h

@@ -0,0 +1,133 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#pragma once
+
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+template <typename FunctionSignature>
+struct cmCommandLineArgument
+{
+  enum class Values
+  {
+    Zero,
+    One,
+    Two,
+  };
+
+  std::string InvalidSyntaxMessage;
+  std::string InvalidValueMessage;
+  std::string Name;
+  Values Type;
+  std::function<FunctionSignature> StoreCall;
+
+  template <typename FunctionType>
+  cmCommandLineArgument(std::string n, Values t, FunctionType&& func)
+    : InvalidSyntaxMessage(cmStrCat("Invalid syntax used with ", n))
+    , InvalidValueMessage(cmStrCat("Invalid value used with ", n))
+    , Name(std::move(n))
+    , Type(t)
+    , StoreCall(std::forward<FunctionType>(func))
+  {
+  }
+
+  template <typename FunctionType>
+  cmCommandLineArgument(std::string n, std::string failedMsg, Values t,
+                        FunctionType&& func)
+    : InvalidSyntaxMessage(cmStrCat("Invalid syntax used with ", n))
+    , InvalidValueMessage(std::move(failedMsg))
+    , Name(std::move(n))
+    , Type(t)
+    , StoreCall(std::forward<FunctionType>(func))
+  {
+  }
+
+  bool matches(std::string const& input) const
+  {
+    return (this->Type == Values::Zero) ? (input == this->Name)
+                                        : cmHasPrefix(input, this->Name);
+  }
+
+  template <typename T, typename... CallState>
+  bool parse(std::string const& input, T& index,
+             std::vector<std::string> const& allArgs,
+             CallState&&... state) const
+  {
+    enum class ParseMode
+    {
+      Valid,
+      Invalid,
+      SyntaxError,
+      ValueError
+    };
+    ParseMode parseState = ParseMode::Valid;
+
+    if (this->Type == Values::Zero) {
+      if (input.size() == this->Name.size()) {
+        parseState =
+          this->StoreCall(std::string{}, std::forward<CallState>(state)...)
+          ? ParseMode::Valid
+          : ParseMode::Invalid;
+      } else {
+        parseState = ParseMode::SyntaxError;
+      }
+
+    } else if (this->Type == Values::One) {
+      if (input.size() == this->Name.size()) {
+        ++index;
+        if (index >= allArgs.size() || allArgs[index][0] == '-') {
+          parseState = ParseMode::ValueError;
+        } else {
+          parseState =
+            this->StoreCall(allArgs[index], std::forward<CallState>(state)...)
+            ? ParseMode::Valid
+            : ParseMode::Invalid;
+        }
+      } else {
+        // parse the string to get the value
+        auto possible_value = cm::string_view(input).substr(this->Name.size());
+        if (possible_value.empty()) {
+          parseState = ParseMode::SyntaxError;
+          parseState = ParseMode::ValueError;
+        } else if (possible_value[0] == '=') {
+          possible_value.remove_prefix(1);
+          if (possible_value.empty()) {
+            parseState = ParseMode::ValueError;
+          } else {
+            parseState = this->StoreCall(std::string(possible_value),
+                                         std::forward<CallState>(state)...)
+              ? ParseMode::Valid
+              : ParseMode::Invalid;
+          }
+        }
+        if (parseState == ParseMode::Valid) {
+          parseState = this->StoreCall(std::string(possible_value),
+                                       std::forward<CallState>(state)...)
+            ? ParseMode::Valid
+            : ParseMode::Invalid;
+        }
+      }
+    } else if (this->Type == Values::Two) {
+      if (input.size() == this->Name.size()) {
+        if (index + 2 >= allArgs.size() || allArgs[index + 1][0] == '-' ||
+            allArgs[index + 2][0] == '-') {
+          parseState = ParseMode::ValueError;
+        } else {
+          index += 2;
+          parseState =
+            this->StoreCall(cmStrCat(allArgs[index - 1], ";", allArgs[index]),
+                            std::forward<CallState>(state)...)
+            ? ParseMode::Valid
+            : ParseMode::Invalid;
+        }
+      }
+    }
+
+    if (parseState == ParseMode::SyntaxError) {
+      cmSystemTools::Error(this->InvalidSyntaxMessage);
+    } else if (parseState == ParseMode::ValueError) {
+      cmSystemTools::Error(this->InvalidValueMessage);
+    }
+    return (parseState == ParseMode::Valid);
+  }
+};

+ 4 - 121
Source/cmake.cxx

@@ -29,6 +29,7 @@
 #include "cm_sys_stat.h"
 
 #include "cmCMakePresetsFile.h"
+#include "cmCommandLineArgument.h"
 #include "cmCommands.h"
 #include "cmDocumentation.h"
 #include "cmDocumentationEntry.h"
@@ -132,131 +133,13 @@ namespace {
 using JsonValueMapType = std::unordered_map<std::string, Json::Value>;
 #endif
 
-struct CommandArgument
-{
-  enum struct Values
-  {
-    Zero,
-    One,
-    Two,
-  };
-
-  std::string InvalidSyntaxMessage;
-  std::string InvalidValueMessage;
-  std::string Name;
-  CommandArgument::Values Type;
-  std::function<bool(std::string const& value, cmake* state)> StoreCall;
-
-  template <typename FunctionType>
-  CommandArgument(std::string n, CommandArgument::Values t,
-                  FunctionType&& func)
-    : InvalidSyntaxMessage(cmStrCat("Invalid syntax used with ", n))
-    , InvalidValueMessage(cmStrCat("Invalid value used with ", n))
-    , Name(std::move(n))
-    , Type(t)
-    , StoreCall(std::forward<FunctionType>(func))
-  {
-  }
-
-  template <typename FunctionType>
-  CommandArgument(std::string n, std::string failedMsg,
-                  CommandArgument::Values t, FunctionType&& func)
-    : InvalidSyntaxMessage(cmStrCat("Invalid syntax used with ", n))
-    , InvalidValueMessage(std::move(failedMsg))
-    , Name(std::move(n))
-    , Type(t)
-    , StoreCall(std::forward<FunctionType>(func))
-  {
-  }
-
-  bool matches(std::string const& input) const
-  {
-    return cmHasPrefix(input, this->Name);
-  }
-
-  template <typename T>
-  bool parse(std::string const& input, T& index,
-             std::vector<std::string> const& allArgs, cmake* state) const
-  {
-    enum struct ParseMode
-    {
-      Valid,
-      Invalid,
-      SyntaxError,
-      ValueError
-    };
-    ParseMode parseState = ParseMode::Valid;
-
-    // argument is the next parameter
-    if (this->Type == CommandArgument::Values::Zero) {
-      if (input.size() == this->Name.size()) {
-        parseState = this->StoreCall(input, state) ? ParseMode::Valid
-                                                   : ParseMode::Invalid;
-      } else {
-        parseState = ParseMode::SyntaxError;
-      }
-
-    } else if (this->Type == CommandArgument::Values::One) {
-      if (input.size() == this->Name.size()) {
-        ++index;
-        if (index >= allArgs.size() || allArgs[index][0] == '-') {
-          parseState = ParseMode::ValueError;
-        } else {
-          parseState = this->StoreCall(allArgs[index], state)
-            ? ParseMode::Valid
-            : ParseMode::Invalid;
-        }
-      } else {
-        // parse the string to get the value
-        auto possible_value = cm::string_view(input).substr(this->Name.size());
-        if (possible_value.empty()) {
-          parseState = ParseMode::SyntaxError;
-          parseState = ParseMode::ValueError;
-        } else if (possible_value[0] == '=') {
-          possible_value.remove_prefix(1);
-          if (possible_value.empty()) {
-            parseState = ParseMode::ValueError;
-          } else {
-            parseState = this->StoreCall(std::string(possible_value), state)
-              ? ParseMode::Valid
-              : ParseMode::Invalid;
-          }
-        }
-        if (parseState == ParseMode::Valid) {
-          parseState = this->StoreCall(std::string(possible_value), state)
-            ? ParseMode::Valid
-            : ParseMode::Invalid;
-        }
-      }
-    } else if (this->Type == CommandArgument::Values::Two) {
-      if (input.size() == this->Name.size()) {
-        if (index + 2 >= allArgs.size() || allArgs[index + 1][0] == '-' ||
-            allArgs[index + 2][0] == '-') {
-          parseState = ParseMode::ValueError;
-        } else {
-          index += 2;
-          parseState =
-            this->StoreCall(cmStrCat(allArgs[index - 1], ";", allArgs[index]),
-                            state)
-            ? ParseMode::Valid
-            : ParseMode::Invalid;
-        }
-      }
-    }
-
-    if (parseState == ParseMode::SyntaxError) {
-      cmSystemTools::Error(this->InvalidSyntaxMessage);
-    } else if (parseState == ParseMode::ValueError) {
-      cmSystemTools::Error(this->InvalidValueMessage);
-    }
-    return (parseState == ParseMode::Valid);
-  }
-};
-
 auto IgnoreAndTrueLambda = [](std::string const&, cmake*) -> bool {
   return true;
 };
 
+using CommandArgument =
+  cmCommandLineArgument<bool(std::string const& value, cmake* state)>;
+
 } // namespace
 
 static bool cmakeCheckStampFile(const std::string& stampName);

+ 98 - 43
Source/cmakemain.cxx

@@ -19,6 +19,7 @@
 
 #include <cm3p/uv.h>
 
+#include "cmCommandLineArgument.h"
 #include "cmConsoleBuf.h"
 #include "cmDocumentationEntry.h" // IWYU pragma: keep
 #include "cmGlobalGenerator.h"
@@ -213,61 +214,115 @@ int do_cmake(int ac, char const* const* av)
   }
 #endif
 
+  bool wizard_mode = false;
   bool sysinfo = false;
   bool list_cached = false;
   bool list_all_cached = false;
   bool list_help = false;
   bool view_only = false;
   cmake::WorkingMode workingMode = cmake::NORMAL_MODE;
-  std::vector<std::string> args;
-  for (int i = 0; i < ac; ++i) {
-    if (strcmp(av[i], "-i") == 0) {
-      /* clang-format off */
-      std::cerr <<
-        "The \"cmake -i\" wizard mode is no longer supported.\n"
-        "Use the -D option to set cache values on the command line.\n"
-        "Use cmake-gui or ccmake for an interactive dialog.\n";
-      /* clang-format on */
-      return 1;
-    }
-    if (strcmp(av[i], "--system-information") == 0) {
-      sysinfo = true;
-    } else if (strcmp(av[i], "-N") == 0) {
-      view_only = true;
-    } else if (strcmp(av[i], "-L") == 0) {
-      list_cached = true;
-    } else if (strcmp(av[i], "-LA") == 0) {
-      list_all_cached = true;
-    } else if (strcmp(av[i], "-LH") == 0) {
-      list_cached = true;
-      list_help = true;
-    } else if (strcmp(av[i], "-LAH") == 0) {
-      list_all_cached = true;
-      list_help = true;
-    } else if (cmHasLiteralPrefix(av[i], "-P")) {
-      if (i == ac - 1) {
-        cmSystemTools::Error("No script specified for argument -P");
-        return 1;
+  std::vector<std::string> parsedArgs;
+
+  using CommandArgument =
+    cmCommandLineArgument<bool(std::string const& value)>;
+  std::vector<CommandArgument> arguments = {
+    CommandArgument{
+      "-i", CommandArgument::Values::Zero,
+      [&wizard_mode](std::string const&) -> bool {
+        /* clang-format off */
+        std::cerr <<
+          "The \"cmake -i\" wizard mode is no longer supported.\n"
+          "Use the -D option to set cache values on the command line.\n"
+          "Use cmake-gui or ccmake for an interactive dialog.\n";
+        /* clang-format on */
+        wizard_mode = true;
+        return true;
+      } },
+    CommandArgument{ "--system-information", CommandArgument::Values::Zero,
+                     [&](std::string const&) -> bool {
+                       sysinfo = true;
+                       return true;
+                     } },
+    CommandArgument{ "-N", CommandArgument::Values::Zero,
+                     [&](std::string const&) -> bool {
+                       view_only = true;
+                       return true;
+                     } },
+    CommandArgument{ "-LAH", CommandArgument::Values::Zero,
+                     [&](std::string const&) -> bool {
+                       list_all_cached = true;
+                       list_help = true;
+                       return true;
+                     } },
+    CommandArgument{ "-LA", CommandArgument::Values::Zero,
+                     [&](std::string const&) -> bool {
+                       list_all_cached = true;
+                       return true;
+                     } },
+    CommandArgument{ "-LH", CommandArgument::Values::Zero,
+                     [&](std::string const&) -> bool {
+                       list_cached = true;
+                       list_help = true;
+                       return true;
+                     } },
+    CommandArgument{ "-L", CommandArgument::Values::Zero,
+                     [&](std::string const&) -> bool {
+                       list_cached = true;
+                       return true;
+                     } },
+    CommandArgument{ "-P", "No script specified for argument -P",
+                     CommandArgument::Values::One,
+                     [&](std::string const& value) -> bool {
+                       workingMode = cmake::SCRIPT_MODE;
+                       parsedArgs.emplace_back("-P");
+                       parsedArgs.push_back(std::move(value));
+                       return true;
+                     } },
+    CommandArgument{ "--find-package", CommandArgument::Values::Zero,
+                     [&](std::string const&) -> bool {
+                       workingMode = cmake::FIND_PACKAGE_MODE;
+                       parsedArgs.emplace_back("--find-package");
+                       return true;
+                     } },
+    CommandArgument{ "--list-presets", CommandArgument::Values::Zero,
+                     [&](std::string const&) -> bool {
+                       workingMode = cmake::HELP_MODE;
+                       parsedArgs.emplace_back("--list-presets");
+                       return true;
+                     } },
+  };
+
+  std::vector<std::string> inputArgs;
+  inputArgs.reserve(ac);
+  cm::append(inputArgs, av, av + ac);
+
+  for (decltype(inputArgs.size()) i = 0; i < inputArgs.size(); ++i) {
+    std::string const& arg = inputArgs[i];
+    bool matched = false;
+    for (auto const& m : arguments) {
+      if (m.matches(arg)) {
+        matched = true;
+        if (m.parse(arg, i, inputArgs)) {
+          break;
+        } else {
+          return 1;
+        }
       }
-      workingMode = cmake::SCRIPT_MODE;
-      args.emplace_back(av[i]);
-      i++;
-      args.emplace_back(av[i]);
-    } else if (cmHasLiteralPrefix(av[i], "--find-package")) {
-      workingMode = cmake::FIND_PACKAGE_MODE;
-      args.emplace_back(av[i]);
-    } else if (strcmp(av[i], "--list-presets") == 0) {
-      workingMode = cmake::HELP_MODE;
-      args.emplace_back(av[i]);
-    } else {
-      args.emplace_back(av[i]);
+    }
+    if (!matched) {
+      parsedArgs.emplace_back(av[i]);
     }
   }
+
+  if (wizard_mode) {
+    return 1;
+  }
+
   if (sysinfo) {
     cmake cm(cmake::RoleProject, cmState::Project);
     cm.SetHomeDirectory("");
     cm.SetHomeOutputDirectory("");
-    int ret = cm.GetSystemInformation(args);
+    int ret = cm.GetSystemInformation(parsedArgs);
     return ret;
   }
   cmake::Role const role =
@@ -297,7 +352,7 @@ int do_cmake(int ac, char const* const* av)
   });
   cm.SetWorkingMode(workingMode);
 
-  int res = cm.Run(args, view_only);
+  int res = cm.Run(parsedArgs, view_only);
   if (list_cached || list_all_cached) {
     std::cout << "-- Cache values" << std::endl;
     std::vector<std::string> keys = cm.GetState()->GetCacheEntryKeys();