cmMathCommand.cxx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmMathCommand.h"
  4. #include <cstdio>
  5. #include <cm3p/kwiml/int.h>
  6. #include "cmExecutionStatus.h"
  7. #include "cmExprParserHelper.h"
  8. #include "cmMakefile.h"
  9. #include "cmMessageType.h"
  10. namespace {
  11. bool HandleExprCommand(std::vector<std::string> const& args,
  12. cmExecutionStatus& status);
  13. }
  14. bool cmMathCommand(std::vector<std::string> const& args,
  15. cmExecutionStatus& status)
  16. {
  17. if (args.empty()) {
  18. status.SetError("must be called with at least one argument.");
  19. return false;
  20. }
  21. const std::string& subCommand = args[0];
  22. if (subCommand == "EXPR") {
  23. return HandleExprCommand(args, status);
  24. }
  25. std::string e = "does not recognize sub-command " + subCommand;
  26. status.SetError(e);
  27. return false;
  28. }
  29. namespace {
  30. bool HandleExprCommand(std::vector<std::string> const& args,
  31. cmExecutionStatus& status)
  32. {
  33. if ((args.size() != 3) && (args.size() != 5)) {
  34. status.SetError("EXPR called with incorrect arguments.");
  35. return false;
  36. }
  37. enum class NumericFormat
  38. {
  39. UNINITIALIZED,
  40. DECIMAL,
  41. HEXADECIMAL,
  42. };
  43. const std::string& outputVariable = args[1];
  44. const std::string& expression = args[2];
  45. size_t argumentIndex = 3;
  46. NumericFormat outputFormat = NumericFormat::UNINITIALIZED;
  47. status.GetMakefile().AddDefinition(outputVariable, "ERROR");
  48. if (argumentIndex < args.size()) {
  49. const std::string messageHint = "sub-command EXPR ";
  50. std::string const& option = args[argumentIndex++];
  51. if (option == "OUTPUT_FORMAT") {
  52. if (argumentIndex < args.size()) {
  53. std::string const& argument = args[argumentIndex++];
  54. if (argument == "DECIMAL") {
  55. outputFormat = NumericFormat::DECIMAL;
  56. } else if (argument == "HEXADECIMAL") {
  57. outputFormat = NumericFormat::HEXADECIMAL;
  58. } else {
  59. std::string error = messageHint + "value \"" + argument +
  60. "\" for option \"" + option + "\" is invalid.";
  61. status.SetError(error);
  62. return false;
  63. }
  64. } else {
  65. std::string error =
  66. messageHint + "missing argument for option \"" + option + "\".";
  67. status.SetError(error);
  68. return false;
  69. }
  70. } else {
  71. std::string error =
  72. messageHint + "option \"" + option + "\" is unknown.";
  73. status.SetError(error);
  74. return false;
  75. }
  76. }
  77. if (outputFormat == NumericFormat::UNINITIALIZED) {
  78. outputFormat = NumericFormat::DECIMAL;
  79. }
  80. cmExprParserHelper helper;
  81. if (!helper.ParseString(expression.c_str(), 0)) {
  82. status.SetError(helper.GetError());
  83. return false;
  84. }
  85. char buffer[1024];
  86. const char* fmt;
  87. switch (outputFormat) {
  88. case NumericFormat::HEXADECIMAL:
  89. fmt = "0x%" KWIML_INT_PRIx64;
  90. break;
  91. case NumericFormat::DECIMAL:
  92. CM_FALLTHROUGH;
  93. default:
  94. fmt = "%" KWIML_INT_PRId64;
  95. break;
  96. }
  97. snprintf(buffer, sizeof(buffer), fmt, helper.GetResult());
  98. std::string const& w = helper.GetWarning();
  99. if (!w.empty()) {
  100. status.GetMakefile().IssueMessage(MessageType::AUTHOR_WARNING, w);
  101. }
  102. status.GetMakefile().AddDefinition(outputVariable, buffer);
  103. return true;
  104. }
  105. }