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