gdb: Make use of gdb::option framework for some info commands
[deliverable/binutils-gdb.git] / gdb / cli / cli-utils.c
1 /* CLI utilities.
2
3 Copyright (C) 2011-2019 Free Software Foundation, Inc.
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19
20 #include "defs.h"
21 #include "cli/cli-utils.h"
22 #include "value.h"
23
24 #include <ctype.h>
25
26 /* See documentation in cli-utils.h. */
27
28 ULONGEST
29 get_ulongest (const char **pp, int trailer)
30 {
31 LONGEST retval = 0; /* default */
32 const char *p = *pp;
33
34 if (*p == '$')
35 {
36 value *val = value_from_history_ref (p, &p);
37
38 if (val != NULL) /* Value history reference */
39 {
40 if (TYPE_CODE (value_type (val)) == TYPE_CODE_INT)
41 retval = value_as_long (val);
42 else
43 error (_("History value must have integer type."));
44 }
45 else /* Convenience variable */
46 {
47 /* Internal variable. Make a copy of the name, so we can
48 null-terminate it to pass to lookup_internalvar(). */
49 const char *start = ++p;
50 while (isalnum (*p) || *p == '_')
51 p++;
52 std::string varname (start, p - start);
53 if (!get_internalvar_integer (lookup_internalvar (varname.c_str ()),
54 &retval))
55 error (_("Convenience variable $%s does not have integer value."),
56 varname.c_str ());
57 }
58 }
59 else
60 {
61 const char *end = p;
62 retval = strtoulst (p, &end, 0);
63 if (p == end)
64 {
65 /* There is no number here. (e.g. "cond a == b"). */
66 error (_("Expected integer at: %s"), p);
67 }
68 p = end;
69 }
70
71 if (!(isspace (*p) || *p == '\0' || *p == trailer))
72 error (_("Trailing junk at: %s"), p);
73 p = skip_spaces (p);
74 *pp = p;
75 return retval;
76 }
77
78 /* See documentation in cli-utils.h. */
79
80 int
81 get_number_trailer (const char **pp, int trailer)
82 {
83 int retval = 0; /* default */
84 const char *p = *pp;
85 bool negative = false;
86
87 if (*p == '-')
88 {
89 ++p;
90 negative = true;
91 }
92
93 if (*p == '$')
94 {
95 struct value *val = value_from_history_ref (p, &p);
96
97 if (val) /* Value history reference */
98 {
99 if (TYPE_CODE (value_type (val)) == TYPE_CODE_INT)
100 retval = value_as_long (val);
101 else
102 {
103 printf_filtered (_("History value must have integer type.\n"));
104 retval = 0;
105 }
106 }
107 else /* Convenience variable */
108 {
109 /* Internal variable. Make a copy of the name, so we can
110 null-terminate it to pass to lookup_internalvar(). */
111 char *varname;
112 const char *start = ++p;
113 LONGEST longest_val;
114
115 while (isalnum (*p) || *p == '_')
116 p++;
117 varname = (char *) alloca (p - start + 1);
118 strncpy (varname, start, p - start);
119 varname[p - start] = '\0';
120 if (get_internalvar_integer (lookup_internalvar (varname),
121 &longest_val))
122 retval = (int) longest_val;
123 else
124 {
125 printf_filtered (_("Convenience variable must "
126 "have integer value.\n"));
127 retval = 0;
128 }
129 }
130 }
131 else
132 {
133 const char *p1 = p;
134 while (*p >= '0' && *p <= '9')
135 ++p;
136 if (p == p1)
137 /* There is no number here. (e.g. "cond a == b"). */
138 {
139 /* Skip non-numeric token. */
140 while (*p && !isspace((int) *p))
141 ++p;
142 /* Return zero, which caller must interpret as error. */
143 retval = 0;
144 }
145 else
146 retval = atoi (p1);
147 }
148 if (!(isspace (*p) || *p == '\0' || *p == trailer))
149 {
150 /* Trailing junk: return 0 and let caller print error msg. */
151 while (!(isspace (*p) || *p == '\0' || *p == trailer))
152 ++p;
153 retval = 0;
154 }
155 p = skip_spaces (p);
156 *pp = p;
157 return negative ? -retval : retval;
158 }
159
160 /* See documentation in cli-utils.h. */
161
162 int
163 get_number (const char **pp)
164 {
165 return get_number_trailer (pp, '\0');
166 }
167
168 /* See documentation in cli-utils.h. */
169
170 int
171 get_number (char **pp)
172 {
173 int result;
174 const char *p = *pp;
175
176 result = get_number_trailer (&p, '\0');
177 *pp = (char *) p;
178 return result;
179 }
180
181 /* See documentation in cli-utils.h. */
182
183 void
184 report_unrecognized_option_error (const char *command, const char *args)
185 {
186 std::string option = extract_arg (&args);
187
188 error (_("Unrecognized option '%s' to %s command. "
189 "Try \"help %s\"."), option.c_str (),
190 command, command);
191 }
192
193 /* See documentation in cli-utils.h. */
194
195 const char *
196 info_print_args_help (const char *prefix,
197 const char *entity_kind)
198 {
199 return xstrprintf (_("\
200 %sIf NAMEREGEXP is provided, only prints the %s whose name\n\
201 matches NAMEREGEXP.\n\
202 If -t TYPEREGEXP is provided, only prints the %s whose type\n\
203 matches TYPEREGEXP. Note that the matching is done with the type\n\
204 printed by the 'whatis' command.\n\
205 By default, the command might produce headers and/or messages indicating\n\
206 why no %s can be printed.\n\
207 The flag -q disables the production of these headers and messages."),
208 prefix, entity_kind, entity_kind, entity_kind);
209 }
210
211 /* See documentation in cli-utils.h. */
212
213 number_or_range_parser::number_or_range_parser (const char *string)
214 {
215 init (string);
216 }
217
218 /* See documentation in cli-utils.h. */
219
220 void
221 number_or_range_parser::init (const char *string)
222 {
223 m_cur_tok = string;
224 m_last_retval = 0;
225 m_end_value = 0;
226 m_end_ptr = NULL;
227 m_in_range = false;
228 }
229
230 /* See documentation in cli-utils.h. */
231
232 int
233 number_or_range_parser::get_number ()
234 {
235 if (m_in_range)
236 {
237 /* All number-parsing has already been done. Return the next
238 integer value (one greater than the saved previous value).
239 Do not advance the token pointer until the end of range is
240 reached. */
241
242 if (++m_last_retval == m_end_value)
243 {
244 /* End of range reached; advance token pointer. */
245 m_cur_tok = m_end_ptr;
246 m_in_range = false;
247 }
248 }
249 else if (*m_cur_tok != '-')
250 {
251 /* Default case: state->m_cur_tok is pointing either to a solo
252 number, or to the first number of a range. */
253 m_last_retval = get_number_trailer (&m_cur_tok, '-');
254 /* If get_number_trailer has found a '-' preceded by a space, it
255 might be the start of a command option. So, do not parse a
256 range if the '-' is followed by an alpha or another '-'. We
257 might also be completing something like
258 "frame apply level 0 -" and we prefer treating that "-" as an
259 option rather than an incomplete range, so check for end of
260 string as well. */
261 if (m_cur_tok[0] == '-'
262 && !(isspace (m_cur_tok[-1])
263 && (isalpha (m_cur_tok[1])
264 || m_cur_tok[1] == '-'
265 || m_cur_tok[1] == '\0')))
266 {
267 const char **temp;
268
269 /* This is the start of a range (<number1> - <number2>).
270 Skip the '-', parse and remember the second number,
271 and also remember the end of the final token. */
272
273 temp = &m_end_ptr;
274 m_end_ptr = skip_spaces (m_cur_tok + 1);
275 m_end_value = ::get_number (temp);
276 if (m_end_value < m_last_retval)
277 {
278 error (_("inverted range"));
279 }
280 else if (m_end_value == m_last_retval)
281 {
282 /* Degenerate range (number1 == number2). Advance the
283 token pointer so that the range will be treated as a
284 single number. */
285 m_cur_tok = m_end_ptr;
286 }
287 else
288 m_in_range = true;
289 }
290 }
291 else
292 {
293 if (isdigit (*(m_cur_tok + 1)))
294 error (_("negative value"));
295 if (*(m_cur_tok + 1) == '$')
296 {
297 /* Convenience variable. */
298 m_last_retval = ::get_number (&m_cur_tok);
299 if (m_last_retval < 0)
300 error (_("negative value"));
301 }
302 }
303 return m_last_retval;
304 }
305
306 /* See documentation in cli-utils.h. */
307
308 void
309 number_or_range_parser::setup_range (int start_value, int end_value,
310 const char *end_ptr)
311 {
312 gdb_assert (start_value > 0);
313
314 m_in_range = true;
315 m_end_ptr = end_ptr;
316 m_last_retval = start_value - 1;
317 m_end_value = end_value;
318 }
319
320 /* See documentation in cli-utils.h. */
321
322 bool
323 number_or_range_parser::finished () const
324 {
325 /* Parsing is finished when at end of string or null string,
326 or we are not in a range and not in front of an integer, negative
327 integer, convenience var or negative convenience var. */
328 return (m_cur_tok == NULL || *m_cur_tok == '\0'
329 || (!m_in_range
330 && !(isdigit (*m_cur_tok) || *m_cur_tok == '$')
331 && !(*m_cur_tok == '-'
332 && (isdigit (m_cur_tok[1]) || m_cur_tok[1] == '$'))));
333 }
334
335 /* Accept a number and a string-form list of numbers such as is
336 accepted by get_number_or_range. Return TRUE if the number is
337 in the list.
338
339 By definition, an empty list includes all numbers. This is to
340 be interpreted as typing a command such as "delete break" with
341 no arguments. */
342
343 int
344 number_is_in_list (const char *list, int number)
345 {
346 if (list == NULL || *list == '\0')
347 return 1;
348
349 number_or_range_parser parser (list);
350
351 if (parser.finished ())
352 error (_("Arguments must be numbers or '$' variables."));
353 while (!parser.finished ())
354 {
355 int gotnum = parser.get_number ();
356
357 if (gotnum == 0)
358 error (_("Arguments must be numbers or '$' variables."));
359 if (gotnum == number)
360 return 1;
361 }
362 return 0;
363 }
364
365 /* See documentation in cli-utils.h. */
366
367 const char *
368 remove_trailing_whitespace (const char *start, const char *s)
369 {
370 while (s > start && isspace (*(s - 1)))
371 --s;
372
373 return s;
374 }
375
376 /* See documentation in cli-utils.h. */
377
378 std::string
379 extract_arg (const char **arg)
380 {
381 const char *result;
382
383 if (!*arg)
384 return std::string ();
385
386 /* Find the start of the argument. */
387 *arg = skip_spaces (*arg);
388 if (!**arg)
389 return std::string ();
390 result = *arg;
391
392 /* Find the end of the argument. */
393 *arg = skip_to_space (*arg + 1);
394
395 if (result == *arg)
396 return std::string ();
397
398 return std::string (result, *arg - result);
399 }
400
401 /* See documentation in cli-utils.h. */
402
403 std::string
404 extract_arg (char **arg)
405 {
406 const char *arg_const = *arg;
407 std::string result;
408
409 result = extract_arg (&arg_const);
410 *arg += arg_const - *arg;
411 return result;
412 }
413
414 /* See documentation in cli-utils.h. */
415
416 int
417 check_for_argument (const char **str, const char *arg, int arg_len)
418 {
419 if (strncmp (*str, arg, arg_len) == 0
420 && ((*str)[arg_len] == '\0' || isspace ((*str)[arg_len])))
421 {
422 *str += arg_len;
423 *str = skip_spaces (*str);
424 return 1;
425 }
426 return 0;
427 }
428
429 /* See documentation in cli-utils.h. */
430
431 void
432 validate_flags_qcs (const char *which_command, qcs_flags *flags)
433 {
434 if (flags->cont && flags->silent)
435 error (_("%s: -c and -s are mutually exclusive"), which_command);
436 }
437
438 /* The options used by the 'info variables' commands and similar. */
439
440 static const gdb::option::option_def info_print_options_defs[] = {
441 gdb::option::boolean_option_def<info_print_options> {
442 "q",
443 [] (info_print_options *opt) { return &opt->quiet; },
444 nullptr, /* show_cmd_cb */
445 nullptr /* set_doc */
446 },
447
448 gdb::option::string_option_def<info_print_options> {
449 "t",
450 [] (info_print_options *opt) { return &opt->type_regexp; },
451 nullptr, /* show_cmd_cb */
452 nullptr /* set_doc */
453 }
454 };
455
456 /* Returns the option group used by 'info variables' and similar. */
457
458 static gdb::option::option_def_group
459 make_info_print_options_def_group (info_print_options *opts)
460 {
461 return {{info_print_options_defs}, opts};
462 }
463
464 /* See documentation in cli-utils.h. */
465
466 void
467 extract_info_print_options (info_print_options *opts,
468 const char **args)
469 {
470 auto grp = make_info_print_options_def_group (opts);
471 gdb::option::process_options
472 (args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, grp);
473 if (*args != nullptr && **args == '\0')
474 *args = nullptr;
475 }
This page took 0.1071 seconds and 5 git commands to generate.