1 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2    file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
3 #include "kwsysPrivate.h"
4 #include KWSYS_HEADER(CommandLineArguments.hxx)
5 
6 // Work-around CMake dependency scanning limitation.  This must
7 // duplicate the above list of headers.
8 #if 0
9 #  include "CommandLineArguments.hxx.in"
10 #endif
11 
12 #include <iostream>
13 #include <vector>
14 
15 #include <cstddef> /* size_t */
16 #include <cstring> /* strcmp */
17 
18 static void* random_ptr = reinterpret_cast<void*>(0x123);
19 
argument(const char * arg,const char * value,void * call_data)20 static int argument(const char* arg, const char* value, void* call_data)
21 {
22   std::cout << "Got argument: \"" << arg << "\" value: \""
23             << (value ? value : "(null)") << "\"" << std::endl;
24   if (call_data != random_ptr) {
25     std::cerr << "Problem processing call_data" << std::endl;
26     return 0;
27   }
28   return 1;
29 }
30 
unknown_argument(const char * argument,void * call_data)31 static int unknown_argument(const char* argument, void* call_data)
32 {
33   std::cout << "Got unknown argument: \"" << argument << "\"" << std::endl;
34   if (call_data != random_ptr) {
35     std::cerr << "Problem processing call_data" << std::endl;
36     return 0;
37   }
38   return 1;
39 }
40 
CompareTwoItemsOnList(bool i1,bool i2)41 static bool CompareTwoItemsOnList(bool i1, bool i2)
42 {
43   return i1 == i2;
44 }
CompareTwoItemsOnList(int i1,int i2)45 static bool CompareTwoItemsOnList(int i1, int i2)
46 {
47   return i1 == i2;
48 }
CompareTwoItemsOnList(double i1,double i2)49 static bool CompareTwoItemsOnList(double i1, double i2)
50 {
51   return i1 == i2;
52 }
CompareTwoItemsOnList(const char * i1,const char * i2)53 static bool CompareTwoItemsOnList(const char* i1, const char* i2)
54 {
55   return strcmp(i1, i2) == 0;
56 }
CompareTwoItemsOnList(const std::string & i1,const std::string & i2)57 static bool CompareTwoItemsOnList(const std::string& i1, const std::string& i2)
58 {
59   return i1 == i2;
60 }
61 
testCommandLineArguments(int argc,char * argv[])62 int testCommandLineArguments(int argc, char* argv[])
63 {
64   // Example run: ./testCommandLineArguments --some-int-variable 4
65   // --another-bool-variable --some-bool-variable=yes
66   // --some-stl-string-variable=foobar --set-bool-arg1 --set-bool-arg2
67   // --some-string-variable=hello
68 
69   int res = 0;
70   kwsys::CommandLineArguments arg;
71   arg.Initialize(argc, argv);
72 
73   // For error handling
74   arg.SetClientData(random_ptr);
75   arg.SetUnknownArgumentCallback(unknown_argument);
76 
77   int some_int_variable = 10;
78   double some_double_variable = 10.10;
79   char* some_string_variable = nullptr;
80   std::string some_stl_string_variable;
81   bool some_bool_variable = false;
82   bool some_bool_variable1 = false;
83   bool bool_arg1 = false;
84   int bool_arg2 = 0;
85 
86   std::vector<int> numbers_argument;
87   int valid_numbers[] = { 5, 1, 8, 3, 7, 1, 3, 9, 7, 1 };
88 
89   std::vector<double> doubles_argument;
90   double valid_doubles[] = { 12.5, 1.31, 22 };
91 
92   std::vector<bool> bools_argument;
93   bool valid_bools[] = { true, true, false };
94 
95   std::vector<char*> strings_argument;
96   const char* valid_strings[] = { "andy", "bill", "brad", "ken" };
97 
98   std::vector<std::string> stl_strings_argument;
99   std::string valid_stl_strings[] = { "ken", "brad", "bill", "andy" };
100 
101   using argT = kwsys::CommandLineArguments;
102 
103   arg.AddArgument("--some-int-variable", argT::SPACE_ARGUMENT,
104                   &some_int_variable, "Set some random int variable");
105   arg.AddArgument("--some-double-variable", argT::CONCAT_ARGUMENT,
106                   &some_double_variable, "Set some random double variable");
107   arg.AddArgument("--some-string-variable", argT::EQUAL_ARGUMENT,
108                   &some_string_variable, "Set some random string variable");
109   arg.AddArgument("--some-stl-string-variable", argT::EQUAL_ARGUMENT,
110                   &some_stl_string_variable,
111                   "Set some random stl string variable");
112   arg.AddArgument("--some-bool-variable", argT::EQUAL_ARGUMENT,
113                   &some_bool_variable, "Set some random bool variable");
114   arg.AddArgument("--another-bool-variable", argT::NO_ARGUMENT,
115                   &some_bool_variable1, "Set some random bool variable 1");
116   arg.AddBooleanArgument("--set-bool-arg1", &bool_arg1,
117                          "Test AddBooleanArgument 1");
118   arg.AddBooleanArgument("--set-bool-arg2", &bool_arg2,
119                          "Test AddBooleanArgument 2");
120   arg.AddArgument("--some-multi-argument", argT::MULTI_ARGUMENT,
121                   &numbers_argument, "Some multiple values variable");
122   arg.AddArgument("-N", argT::SPACE_ARGUMENT, &doubles_argument,
123                   "Some explicit multiple values variable");
124   arg.AddArgument("-BB", argT::CONCAT_ARGUMENT, &bools_argument,
125                   "Some explicit multiple values variable");
126   arg.AddArgument("-SS", argT::EQUAL_ARGUMENT, &strings_argument,
127                   "Some explicit multiple values variable");
128   arg.AddArgument("-SSS", argT::MULTI_ARGUMENT, &stl_strings_argument,
129                   "Some explicit multiple values variable");
130 
131   arg.AddCallback("-A", argT::NO_ARGUMENT, argument, random_ptr,
132                   "Some option -A. This option has a multiline comment. It "
133                   "should demonstrate how the code splits lines.");
134   arg.AddCallback("-B", argT::SPACE_ARGUMENT, argument, random_ptr,
135                   "Option -B takes argument with space");
136   arg.AddCallback("-C", argT::EQUAL_ARGUMENT, argument, random_ptr,
137                   "Option -C takes argument after =");
138   arg.AddCallback("-D", argT::CONCAT_ARGUMENT, argument, random_ptr,
139                   "This option takes concatenated argument");
140   arg.AddCallback("--long1", argT::NO_ARGUMENT, argument, random_ptr, "-A");
141   arg.AddCallback("--long2", argT::SPACE_ARGUMENT, argument, random_ptr, "-B");
142   arg.AddCallback("--long3", argT::EQUAL_ARGUMENT, argument, random_ptr,
143                   "Same as -C but a bit different");
144   arg.AddCallback("--long4", argT::CONCAT_ARGUMENT, argument, random_ptr,
145                   "-C");
146 
147   if (!arg.Parse()) {
148     std::cerr << "Problem parsing arguments" << std::endl;
149     res = 1;
150   }
151   std::cout << "Help: " << arg.GetHelp() << std::endl;
152 
153   std::cout << "Some int variable was set to: " << some_int_variable
154             << std::endl;
155   std::cout << "Some double variable was set to: " << some_double_variable
156             << std::endl;
157   if (some_string_variable &&
158       strcmp(some_string_variable, "test string with space") == 0) {
159     std::cout << "Some string variable was set to: " << some_string_variable
160               << std::endl;
161     delete[] some_string_variable;
162   } else {
163     std::cerr << "Problem setting string variable" << std::endl;
164     res = 1;
165   }
166   size_t cc;
167 #define CompareTwoLists(list1, list_valid, lsize)                             \
168   do {                                                                        \
169     if (list1.size() != lsize) {                                              \
170       std::cerr << "Problem setting " #list1 ". Size is: " << list1.size()    \
171                 << " should be: " << lsize << std::endl;                      \
172       res = 1;                                                                \
173     } else {                                                                  \
174       std::cout << #list1 " argument set:";                                   \
175       for (cc = 0; cc < lsize; ++cc) {                                        \
176         std::cout << " " << list1[cc];                                        \
177         if (!CompareTwoItemsOnList(list1[cc], list_valid[cc])) {              \
178           std::cerr << "Problem setting " #list1 ". Value of " << cc          \
179                     << " is: [" << list1[cc] << "] <> [" << list_valid[cc]    \
180                     << "]" << std::endl;                                      \
181           res = 1;                                                            \
182           break;                                                              \
183         }                                                                     \
184       }                                                                       \
185       std::cout << std::endl;                                                 \
186     }                                                                         \
187   } while (0)
188   CompareTwoLists(numbers_argument, valid_numbers, 10);
189   CompareTwoLists(doubles_argument, valid_doubles, 3);
190   CompareTwoLists(bools_argument, valid_bools, 3);
191   CompareTwoLists(strings_argument, valid_strings, 4);
192   CompareTwoLists(stl_strings_argument, valid_stl_strings, 4);
193 
194   std::cout << "Some STL String variable was set to: "
195             << some_stl_string_variable << std::endl;
196   std::cout << "Some bool variable was set to: " << some_bool_variable
197             << std::endl;
198   std::cout << "Some bool variable was set to: " << some_bool_variable1
199             << std::endl;
200   std::cout << "bool_arg1 variable was set to: " << bool_arg1 << std::endl;
201   std::cout << "bool_arg2 variable was set to: " << bool_arg2 << std::endl;
202   std::cout << std::endl;
203 
204   for (cc = 0; cc < strings_argument.size(); ++cc) {
205     delete[] strings_argument[cc];
206     strings_argument[cc] = nullptr;
207   }
208   return res;
209 }
210