gdb: Make use of gdb::option framework for some info commands
[deliverable/binutils-gdb.git] / gdb / cli / cli-utils.c
CommitLineData
e9cafbcc
TT
1/* CLI utilities.
2
42a4f53d 3 Copyright (C) 2011-2019 Free Software Foundation, Inc.
e9cafbcc
TT
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"
e9cafbcc
TT
22#include "value.h"
23
24#include <ctype.h>
25
5d5658a1 26/* See documentation in cli-utils.h. */
e9cafbcc 27
9d0faba9
PA
28ULONGEST
29get_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 {
41fc454c
PA
61 const char *end = p;
62 retval = strtoulst (p, &end, 0);
63 if (p == end)
9d0faba9
PA
64 {
65 /* There is no number here. (e.g. "cond a == b"). */
66 error (_("Expected integer at: %s"), p);
67 }
41fc454c 68 p = end;
9d0faba9
PA
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
5d5658a1 80int
e799154c 81get_number_trailer (const char **pp, int trailer)
e9cafbcc
TT
82{
83 int retval = 0; /* default */
e799154c 84 const char *p = *pp;
95e95a6d
PA
85 bool negative = false;
86
87 if (*p == '-')
88 {
89 ++p;
90 negative = true;
91 }
e9cafbcc
TT
92
93 if (*p == '$')
94 {
3bd0f5ef 95 struct value *val = value_from_history_ref (p, &p);
e9cafbcc 96
3bd0f5ef 97 if (val) /* Value history reference */
e9cafbcc 98 {
3bd0f5ef
MS
99 if (TYPE_CODE (value_type (val)) == TYPE_CODE_INT)
100 retval = value_as_long (val);
101 else
102 {
2217da06 103 printf_filtered (_("History value must have integer type.\n"));
3bd0f5ef
MS
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;
e799154c 112 const char *start = ++p;
b926417a 113 LONGEST longest_val;
3bd0f5ef
MS
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';
b926417a
TT
120 if (get_internalvar_integer (lookup_internalvar (varname),
121 &longest_val))
122 retval = (int) longest_val;
3bd0f5ef
MS
123 else
124 {
125 printf_filtered (_("Convenience variable must "
126 "have integer value.\n"));
127 retval = 0;
128 }
e9cafbcc
TT
129 }
130 }
131 else
132 {
95e95a6d 133 const char *p1 = p;
e9cafbcc
TT
134 while (*p >= '0' && *p <= '9')
135 ++p;
95e95a6d 136 if (p == p1)
e9cafbcc
TT
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
95e95a6d 146 retval = atoi (p1);
e9cafbcc
TT
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 }
f1735a53 155 p = skip_spaces (p);
e9cafbcc 156 *pp = p;
95e95a6d 157 return negative ? -retval : retval;
e9cafbcc
TT
158}
159
160/* See documentation in cli-utils.h. */
161
162int
f1735a53 163get_number (const char **pp)
e9cafbcc
TT
164{
165 return get_number_trailer (pp, '\0');
166}
167
168/* See documentation in cli-utils.h. */
169
e799154c
TT
170int
171get_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
0d4cad90
PW
183void
184report_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
195const char *
196info_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\
201matches NAMEREGEXP.\n\
202If -t TYPEREGEXP is provided, only prints the %s whose type\n\
203matches TYPEREGEXP. Note that the matching is done with the type\n\
204printed by the 'whatis' command.\n\
205By default, the command might produce headers and/or messages indicating\n\
206why no %s can be printed.\n\
207The 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
bfd28288
PA
213number_or_range_parser::number_or_range_parser (const char *string)
214{
215 init (string);
216}
217
218/* See documentation in cli-utils.h. */
219
197f0a60 220void
bfd28288 221number_or_range_parser::init (const char *string)
e9cafbcc 222{
bfd28288
PA
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;
197f0a60
TT
228}
229
230/* See documentation in cli-utils.h. */
e9cafbcc 231
197f0a60 232int
bfd28288 233number_or_range_parser::get_number ()
197f0a60 234{
bfd28288 235 if (m_in_range)
71ef29a8
PA
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
bfd28288 242 if (++m_last_retval == m_end_value)
71ef29a8
PA
243 {
244 /* End of range reached; advance token pointer. */
bfd28288
PA
245 m_cur_tok = m_end_ptr;
246 m_in_range = false;
71ef29a8
PA
247 }
248 }
bfd28288 249 else if (*m_cur_tok != '-')
e9cafbcc 250 {
bfd28288 251 /* Default case: state->m_cur_tok is pointing either to a solo
197f0a60 252 number, or to the first number of a range. */
bfd28288 253 m_last_retval = get_number_trailer (&m_cur_tok, '-');
2c722807
PA
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')))
e9cafbcc 266 {
e799154c 267 const char **temp;
e9cafbcc
TT
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
bfd28288 273 temp = &m_end_ptr;
f1735a53
TT
274 m_end_ptr = skip_spaces (m_cur_tok + 1);
275 m_end_value = ::get_number (temp);
bfd28288 276 if (m_end_value < m_last_retval)
e9cafbcc
TT
277 {
278 error (_("inverted range"));
279 }
bfd28288 280 else if (m_end_value == m_last_retval)
e9cafbcc
TT
281 {
282 /* Degenerate range (number1 == number2). Advance the
283 token pointer so that the range will be treated as a
bfd28288
PA
284 single number. */
285 m_cur_tok = m_end_ptr;
e9cafbcc
TT
286 }
287 else
bfd28288 288 m_in_range = true;
e9cafbcc
TT
289 }
290 }
e9cafbcc 291 else
529c08b2
PW
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 }
bfd28288 303 return m_last_retval;
e9cafbcc
TT
304}
305
71ef29a8
PA
306/* See documentation in cli-utils.h. */
307
308void
bfd28288
PA
309number_or_range_parser::setup_range (int start_value, int end_value,
310 const char *end_ptr)
71ef29a8
PA
311{
312 gdb_assert (start_value > 0);
313
bfd28288
PA
314 m_in_range = true;
315 m_end_ptr = end_ptr;
316 m_last_retval = start_value - 1;
317 m_end_value = end_value;
71ef29a8
PA
318}
319
529c08b2
PW
320/* See documentation in cli-utils.h. */
321
322bool
323number_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
aea5b279
MS
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
343int
e799154c 344number_is_in_list (const char *list, int number)
aea5b279
MS
345{
346 if (list == NULL || *list == '\0')
347 return 1;
348
bfd28288 349 number_or_range_parser parser (list);
529c08b2
PW
350
351 if (parser.finished ())
352 error (_("Arguments must be numbers or '$' variables."));
bfd28288 353 while (!parser.finished ())
298f437a 354 {
bfd28288 355 int gotnum = parser.get_number ();
aea5b279 356
298f437a 357 if (gotnum == 0)
529c08b2 358 error (_("Arguments must be numbers or '$' variables."));
298f437a
MS
359 if (gotnum == number)
360 return 1;
361 }
aea5b279
MS
362 return 0;
363}
364
e9cafbcc
TT
365/* See documentation in cli-utils.h. */
366
63160a43
PA
367const char *
368remove_trailing_whitespace (const char *start, const char *s)
c00f8484
KS
369{
370 while (s > start && isspace (*(s - 1)))
371 --s;
372
373 return s;
374}
55aa24fb
SDJ
375
376/* See documentation in cli-utils.h. */
377
cb791d59 378std::string
f1735a53 379extract_arg (const char **arg)
55aa24fb 380{
b5be8ce0 381 const char *result;
55aa24fb
SDJ
382
383 if (!*arg)
cb791d59 384 return std::string ();
55aa24fb
SDJ
385
386 /* Find the start of the argument. */
f1735a53 387 *arg = skip_spaces (*arg);
55aa24fb 388 if (!**arg)
cb791d59 389 return std::string ();
55aa24fb
SDJ
390 result = *arg;
391
392 /* Find the end of the argument. */
f1735a53 393 *arg = skip_to_space (*arg + 1);
55aa24fb
SDJ
394
395 if (result == *arg)
cb791d59 396 return std::string ();
55aa24fb 397
cb791d59 398 return std::string (result, *arg - result);
b5be8ce0
JB
399}
400
401/* See documentation in cli-utils.h. */
402
cb791d59 403std::string
b5be8ce0
JB
404extract_arg (char **arg)
405{
406 const char *arg_const = *arg;
cb791d59 407 std::string result;
55aa24fb 408
f1735a53 409 result = extract_arg (&arg_const);
b5be8ce0
JB
410 *arg += arg_const - *arg;
411 return result;
55aa24fb 412}
e6f0bce7
HZ
413
414/* See documentation in cli-utils.h. */
415
416int
63160a43 417check_for_argument (const char **str, const char *arg, int arg_len)
e6f0bce7
HZ
418{
419 if (strncmp (*str, arg, arg_len) == 0
420 && ((*str)[arg_len] == '\0' || isspace ((*str)[arg_len])))
421 {
422 *str += arg_len;
cbba3ecd 423 *str = skip_spaces (*str);
e6f0bce7
HZ
424 return 1;
425 }
426 return 0;
427}
529c08b2
PW
428
429/* See documentation in cli-utils.h. */
430
5d707134
PA
431void
432validate_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
b16507e0
AB
438/* The options used by the 'info variables' commands and similar. */
439
440static 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
458static gdb::option::option_def_group
459make_info_print_options_def_group (info_print_options *opts)
460{
461 return {{info_print_options_defs}, opts};
462}
463
5d707134 464/* See documentation in cli-utils.h. */
b16507e0
AB
465
466void
467extract_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.601511 seconds and 4 git commands to generate.