cmdline.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright 2015 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 #include "test/core/util/cmdline.h"
20 
21 #include <limits.h>
22 #include <stdio.h>
23 #include <string.h>
24 
25 #include <vector>
26 
27 #include "absl/strings/str_cat.h"
28 #include "absl/strings/str_format.h"
29 #include "absl/strings/str_join.h"
30 
31 #include <grpc/support/alloc.h>
32 #include <grpc/support/log.h>
34 
37 
39 
40 typedef struct arg {
41  const char* name;
42  const char* help;
44  void* value;
45  struct arg* next;
46 } arg;
47 
48 struct gpr_cmdline {
49  const char* description;
51  const char* argv0;
52 
53  const char* extra_arg_name;
54  const char* extra_arg_help;
55  void (*extra_arg)(void* user_data, const char* arg);
57 
58  int (*state)(gpr_cmdline* cl, char* arg);
60 
62 };
63 
64 static int normal_state(gpr_cmdline* cl, char* str);
65 
67  gpr_cmdline* cl = grpc_core::Zalloc<gpr_cmdline>();
68 
70  cl->state = normal_state;
71 
72  return cl;
73 }
74 
76  cl->survive_failure = 1;
77 }
78 
80  while (cl->args) {
81  arg* a = cl->args;
82  cl->args = a->next;
83  gpr_free(a);
84  }
85  gpr_free(cl);
86 }
87 
88 static void add_arg(gpr_cmdline* cl, const char* name, const char* help,
89  argtype type, void* value) {
90  arg* a;
91 
92  for (a = cl->args; a; a = a->next) {
93  GPR_ASSERT(0 != strcmp(a->name, name));
94  }
95 
96  a = static_cast<arg*>(gpr_zalloc(sizeof(arg)));
97  a->name = name;
98  a->help = help;
99  a->type = type;
100  a->value = value;
101  a->next = cl->args;
102  cl->args = a;
103 }
104 
105 void gpr_cmdline_add_int(gpr_cmdline* cl, const char* name, const char* help,
106  int* value) {
108 }
109 
110 void gpr_cmdline_add_flag(gpr_cmdline* cl, const char* name, const char* help,
111  int* value) {
113 }
114 
115 void gpr_cmdline_add_string(gpr_cmdline* cl, const char* name, const char* help,
116  const char** value) {
118 }
119 
121  gpr_cmdline* cl, const char* name, const char* help,
122  void (*on_extra_arg)(void* user_data, const char* arg), void* user_data) {
123  GPR_ASSERT(!cl->extra_arg);
124  GPR_ASSERT(on_extra_arg);
125 
126  cl->extra_arg = on_extra_arg;
127  cl->extra_arg_user_data = user_data;
128  cl->extra_arg_name = name;
129  cl->extra_arg_help = help;
130 }
131 
132 /* recursively descend argument list, adding the last element
133  to s first - so that arguments are added in the order they were
134  added to the list by api calls */
135 static void add_args_to_usage(arg* a, std::vector<std::string>* s) {
136  if (a == nullptr) return;
137  add_args_to_usage(a->next, s);
138  switch (a->type) {
139  case ARGTYPE_BOOL:
140  s->push_back(absl::StrFormat(" [--%s|--no-%s]", a->name, a->name));
141  break;
142  case ARGTYPE_STRING:
143  s->push_back(absl::StrFormat(" [--%s=string]", a->name));
144  break;
145  case ARGTYPE_INT:
146  s->push_back(absl::StrFormat(" [--%s=int]", a->name));
147  break;
148  }
149 }
150 
152  const char* name = strrchr(argv0, '/');
153  if (name != nullptr) {
154  name++;
155  } else {
156  name = argv0;
157  }
158 
159  std::vector<std::string> s;
160  s.push_back(absl::StrCat("Usage: ", name));
161  add_args_to_usage(cl->args, &s);
162  if (cl->extra_arg) {
163  s.push_back(absl::StrFormat(" [%s...]", cl->extra_arg_name));
164  }
165  s.push_back("\n");
166  return absl::StrJoin(s, "");
167 }
168 
170  fprintf(stderr, "%s", gpr_cmdline_usage_string(cl, cl->argv0).c_str());
171  if (!cl->survive_failure) {
172  exit(1);
173  }
174  return 0;
175 }
176 
177 static int extra_state(gpr_cmdline* cl, char* str) {
178  if (!cl->extra_arg) {
179  return print_usage_and_die(cl);
180  }
182  return 1;
183 }
184 
185 static arg* find_arg(gpr_cmdline* cl, char* name) {
186  arg* a;
187 
188  for (a = cl->args; a; a = a->next) {
189  if (0 == strcmp(a->name, name)) {
190  break;
191  }
192  }
193 
194  if (!a) {
195  fprintf(stderr, "Unknown argument: %s\n", name);
196  return nullptr;
197  }
198 
199  return a;
200 }
201 
202 static int value_state(gpr_cmdline* cl, char* str) {
203  long intval;
204  char* end;
205 
206  GPR_ASSERT(cl->cur_arg);
207 
208  switch (cl->cur_arg->type) {
209  case ARGTYPE_INT:
210  intval = strtol(str, &end, 0);
211  if (*end || intval < INT_MIN || intval > INT_MAX) {
212  fprintf(stderr, "expected integer, got '%s' for %s\n", str,
213  cl->cur_arg->name);
214  return print_usage_and_die(cl);
215  }
216  *static_cast<int*>(cl->cur_arg->value) = static_cast<int>(intval);
217  break;
218  case ARGTYPE_BOOL:
219  if (0 == strcmp(str, "1") || 0 == strcmp(str, "true")) {
220  *static_cast<int*>(cl->cur_arg->value) = 1;
221  } else if (0 == strcmp(str, "0") || 0 == strcmp(str, "false")) {
222  *static_cast<int*>(cl->cur_arg->value) = 0;
223  } else {
224  fprintf(stderr, "expected boolean, got '%s' for %s\n", str,
225  cl->cur_arg->name);
226  return print_usage_and_die(cl);
227  }
228  break;
229  case ARGTYPE_STRING:
230  *static_cast<char**>(cl->cur_arg->value) = str;
231  break;
232  }
233 
234  cl->state = normal_state;
235  return 1;
236 }
237 
238 static int normal_state(gpr_cmdline* cl, char* str) {
239  char* eq = nullptr;
240  char* tmp = nullptr;
241  char* arg_name = nullptr;
242  int r = 1;
243 
244  if (0 == strcmp(str, "-help") || 0 == strcmp(str, "--help") ||
245  0 == strcmp(str, "-h")) {
246  return print_usage_and_die(cl);
247  }
248 
249  cl->cur_arg = nullptr;
250 
251  if (str[0] == '-') {
252  if (str[1] == '-') {
253  if (str[2] == 0) {
254  /* handle '--' to move to just extra args */
255  cl->state = extra_state;
256  return 1;
257  }
258  str += 2;
259  } else {
260  str += 1;
261  }
262  /* first byte of str is now past the leading '-' or '--' */
263  if (str[0] == 'n' && str[1] == 'o' && str[2] == '-') {
264  /* str is of the form '--no-foo' - it's a flag disable */
265  str += 3;
266  cl->cur_arg = find_arg(cl, str);
267  if (cl->cur_arg == nullptr) {
268  return print_usage_and_die(cl);
269  }
270  if (cl->cur_arg->type != ARGTYPE_BOOL) {
271  fprintf(stderr, "%s is not a flag argument\n", str);
272  return print_usage_and_die(cl);
273  }
274  *static_cast<int*>(cl->cur_arg->value) = 0;
275  return 1; /* early out */
276  }
277  eq = strchr(str, '=');
278  if (eq != nullptr) {
279  /* copy the string into a temp buffer and extract the name */
280  tmp = arg_name =
281  static_cast<char*>(gpr_malloc(static_cast<size_t>(eq - str + 1)));
282  memcpy(arg_name, str, static_cast<size_t>(eq - str));
283  arg_name[eq - str] = 0;
284  } else {
285  arg_name = str;
286  }
287  cl->cur_arg = find_arg(cl, arg_name);
288  if (cl->cur_arg == nullptr) {
289  return print_usage_and_die(cl);
290  }
291  if (eq != nullptr) {
292  /* str was of the type --foo=value, parse the value */
293  r = value_state(cl, eq + 1);
294  } else if (cl->cur_arg->type != ARGTYPE_BOOL) {
295  /* flag types don't have a '--foo value' variant, other types do */
296  cl->state = value_state;
297  } else {
298  /* flag parameter: just set the value */
299  *static_cast<int*>(cl->cur_arg->value) = 1;
300  }
301  } else {
302  r = extra_state(cl, str);
303  }
304 
305  gpr_free(tmp);
306  return r;
307 }
308 
309 int gpr_cmdline_parse(gpr_cmdline* cl, int argc, char** argv) {
310  int i;
311 
312  GPR_ASSERT(argc >= 1);
313  cl->argv0 = argv[0];
314 
315  for (i = 1; i < argc; i++) {
316  if (!cl->state(cl, argv[i])) {
317  return 0;
318  }
319  }
320  return 1;
321 }
gpr_cmdline_set_survive_failure
void gpr_cmdline_set_survive_failure(gpr_cmdline *cl)
Definition: cmdline.cc:75
xds_interop_client.str
str
Definition: xds_interop_client.py:487
extra_state
static int extra_state(gpr_cmdline *cl, char *str)
Definition: cmdline.cc:177
gpr_cmdline::extra_arg_name
const char * extra_arg_name
Definition: cmdline.cc:53
log.h
absl::StrCat
std::string StrCat(const AlphaNum &a, const AlphaNum &b)
Definition: abseil-cpp/absl/strings/str_cat.cc:98
gpr_cmdline::extra_arg_user_data
void * extra_arg_user_data
Definition: cmdline.cc:56
gpr_cmdline_usage_string
std::string gpr_cmdline_usage_string(gpr_cmdline *cl, const char *argv0)
Definition: cmdline.cc:151
absl::StrFormat
ABSL_MUST_USE_RESULT std::string StrFormat(const FormatSpec< Args... > &format, const Args &... args)
Definition: abseil-cpp/absl/strings/str_format.h:338
gpr_cmdline::description
const char * description
Definition: cmdline.cc:49
setup.description
description
Definition: setup.py:544
gpr_cmdline::args
arg * args
Definition: cmdline.cc:50
string.h
gpr_free
GPRAPI void gpr_free(void *ptr)
Definition: alloc.cc:51
gpr_cmdline_destroy
void gpr_cmdline_destroy(gpr_cmdline *cl)
Definition: cmdline.cc:79
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
arg::value
void * value
Definition: cmdline.cc:44
gpr_malloc
GPRAPI void * gpr_malloc(size_t size)
Definition: alloc.cc:29
setup.name
name
Definition: setup.py:542
a
int a
Definition: abseil-cpp/absl/container/internal/hash_policy_traits_test.cc:88
gpr_cmdline_add_flag
void gpr_cmdline_add_flag(gpr_cmdline *cl, const char *name, const char *help, int *value)
Definition: cmdline.cc:110
arg::next
struct arg * next
Definition: cmdline.cc:45
value_state
static int value_state(gpr_cmdline *cl, char *str)
Definition: cmdline.cc:202
python_utils.port_server.stderr
stderr
Definition: port_server.py:51
ARGTYPE_INT
@ ARGTYPE_INT
Definition: cmdline.cc:38
arg::help
const char * help
Definition: cmdline.cc:42
print_usage_and_die
static int print_usage_and_die(gpr_cmdline *cl)
Definition: cmdline.cc:169
gpr_zalloc
GPRAPI void * gpr_zalloc(size_t size)
Definition: alloc.cc:40
add_arg
static void add_arg(gpr_cmdline *cl, const char *name, const char *help, argtype type, void *value)
Definition: cmdline.cc:88
memory.h
add_args_to_usage
static void add_args_to_usage(arg *a, std::vector< std::string > *s)
Definition: cmdline.cc:135
string_util.h
memcpy
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
arg::type
argtype type
Definition: cmdline.cc:43
xds_interop_client.int
int
Definition: xds_interop_client.py:113
GPR_ASSERT
#define GPR_ASSERT(x)
Definition: include/grpc/impl/codegen/log.h:94
end
char * end
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1008
absl::StrJoin
std::string StrJoin(Iterator start, Iterator end, absl::string_view sep, Formatter &&fmt)
Definition: abseil-cpp/absl/strings/str_join.h:239
arg::name
const char * name
Definition: cmdline.cc:41
gpr_cmdline_add_string
void gpr_cmdline_add_string(gpr_cmdline *cl, const char *name, const char *help, const char **value)
Definition: cmdline.cc:115
gpr_cmdline::survive_failure
int survive_failure
Definition: cmdline.cc:61
ARGTYPE_BOOL
@ ARGTYPE_BOOL
Definition: cmdline.cc:38
arg
Definition: cmdline.cc:40
ARGTYPE_STRING
@ ARGTYPE_STRING
Definition: cmdline.cc:38
asyncio_get_stats.help
help
Definition: asyncio_get_stats.py:39
gpr_cmdline::cur_arg
arg * cur_arg
Definition: cmdline.cc:59
argtype
argtype
Definition: cmdline.cc:38
value
const char * value
Definition: hpack_parser_table.cc:165
absl::compare_internal::eq
eq
Definition: abseil-cpp/absl/types/compare.h:72
gpr_cmdline_add_int
void gpr_cmdline_add_int(gpr_cmdline *cl, const char *name, const char *help, int *value)
Definition: cmdline.cc:105
alloc.h
cmdline.h
fix_build_deps.r
r
Definition: fix_build_deps.py:491
normal_state
static int normal_state(gpr_cmdline *cl, char *str)
Definition: cmdline.cc:238
gpr_cmdline_create
gpr_cmdline * gpr_cmdline_create(const char *description)
Definition: cmdline.cc:66
gpr_cmdline::argv0
const char * argv0
Definition: cmdline.cc:51
arg
struct arg arg
state
Definition: bloaty/third_party/zlib/contrib/blast/blast.c:41
gpr_cmdline
Definition: cmdline.cc:48
gpr_cmdline::extra_arg_help
const char * extra_arg_help
Definition: cmdline.cc:54
gpr_cmdline::extra_arg
void(* extra_arg)(void *user_data, const char *arg)
Definition: cmdline.cc:55
asyncio_get_stats.type
type
Definition: asyncio_get_stats.py:37
autogen_x86imm.tmp
tmp
Definition: autogen_x86imm.py:12
find_arg
static arg * find_arg(gpr_cmdline *cl, char *name)
Definition: cmdline.cc:185
gpr_cmdline::state
int(* state)(gpr_cmdline *cl, char *arg)
Definition: cmdline.cc:58
gpr_cmdline_on_extra_arg
void gpr_cmdline_on_extra_arg(gpr_cmdline *cl, const char *name, const char *help, void(*on_extra_arg)(void *user_data, const char *arg), void *user_data)
Definition: cmdline.cc:120
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
gpr_cmdline_parse
int gpr_cmdline_parse(gpr_cmdline *cl, int argc, char **argv)
Definition: cmdline.cc:309


grpc
Author(s):
autogenerated on Thu Mar 13 2025 02:58:48