gdb: Allow quoting around string options in the gdb::option framework
[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
0d4cad90
PW
26static std::string extract_arg_maybe_quoted (const char **arg);
27
5d5658a1 28/* See documentation in cli-utils.h. */
e9cafbcc 29
9d0faba9
PA
30ULONGEST
31get_ulongest (const char **pp, int trailer)
32{
33 LONGEST retval = 0; /* default */
34 const char *p = *pp;
35
36 if (*p == '$')
37 {
38 value *val = value_from_history_ref (p, &p);
39
40 if (val != NULL) /* Value history reference */
41 {
42 if (TYPE_CODE (value_type (val)) == TYPE_CODE_INT)
43 retval = value_as_long (val);
44 else
45 error (_("History value must have integer type."));
46 }
47 else /* Convenience variable */
48 {
49 /* Internal variable. Make a copy of the name, so we can
50 null-terminate it to pass to lookup_internalvar(). */
51 const char *start = ++p;
52 while (isalnum (*p) || *p == '_')
53 p++;
54 std::string varname (start, p - start);
55 if (!get_internalvar_integer (lookup_internalvar (varname.c_str ()),
56 &retval))
57 error (_("Convenience variable $%s does not have integer value."),
58 varname.c_str ());
59 }
60 }
61 else
62 {
41fc454c
PA
63 const char *end = p;
64 retval = strtoulst (p, &end, 0);
65 if (p == end)
9d0faba9
PA
66 {
67 /* There is no number here. (e.g. "cond a == b"). */
68 error (_("Expected integer at: %s"), p);
69 }
41fc454c 70 p = end;
9d0faba9
PA
71 }
72
73 if (!(isspace (*p) || *p == '\0' || *p == trailer))
74 error (_("Trailing junk at: %s"), p);
75 p = skip_spaces (p);
76 *pp = p;
77 return retval;
78}
79
80/* See documentation in cli-utils.h. */
81
5d5658a1 82int
e799154c 83get_number_trailer (const char **pp, int trailer)
e9cafbcc
TT
84{
85 int retval = 0; /* default */
e799154c 86 const char *p = *pp;
95e95a6d
PA
87 bool negative = false;
88
89 if (*p == '-')
90 {
91 ++p;
92 negative = true;
93 }
e9cafbcc
TT
94
95 if (*p == '$')
96 {
3bd0f5ef 97 struct value *val = value_from_history_ref (p, &p);
e9cafbcc 98
3bd0f5ef 99 if (val) /* Value history reference */
e9cafbcc 100 {
3bd0f5ef
MS
101 if (TYPE_CODE (value_type (val)) == TYPE_CODE_INT)
102 retval = value_as_long (val);
103 else
104 {
2217da06 105 printf_filtered (_("History value must have integer type.\n"));
3bd0f5ef
MS
106 retval = 0;
107 }
108 }
109 else /* Convenience variable */
110 {
111 /* Internal variable. Make a copy of the name, so we can
112 null-terminate it to pass to lookup_internalvar(). */
113 char *varname;
e799154c 114 const char *start = ++p;
b926417a 115 LONGEST longest_val;
3bd0f5ef
MS
116
117 while (isalnum (*p) || *p == '_')
118 p++;
119 varname = (char *) alloca (p - start + 1);
120 strncpy (varname, start, p - start);
121 varname[p - start] = '\0';
b926417a
TT
122 if (get_internalvar_integer (lookup_internalvar (varname),
123 &longest_val))
124 retval = (int) longest_val;
3bd0f5ef
MS
125 else
126 {
127 printf_filtered (_("Convenience variable must "
128 "have integer value.\n"));
129 retval = 0;
130 }
e9cafbcc
TT
131 }
132 }
133 else
134 {
95e95a6d 135 const char *p1 = p;
e9cafbcc
TT
136 while (*p >= '0' && *p <= '9')
137 ++p;
95e95a6d 138 if (p == p1)
e9cafbcc
TT
139 /* There is no number here. (e.g. "cond a == b"). */
140 {
141 /* Skip non-numeric token. */
142 while (*p && !isspace((int) *p))
143 ++p;
144 /* Return zero, which caller must interpret as error. */
145 retval = 0;
146 }
147 else
95e95a6d 148 retval = atoi (p1);
e9cafbcc
TT
149 }
150 if (!(isspace (*p) || *p == '\0' || *p == trailer))
151 {
152 /* Trailing junk: return 0 and let caller print error msg. */
153 while (!(isspace (*p) || *p == '\0' || *p == trailer))
154 ++p;
155 retval = 0;
156 }
f1735a53 157 p = skip_spaces (p);
e9cafbcc 158 *pp = p;
95e95a6d 159 return negative ? -retval : retval;
e9cafbcc
TT
160}
161
162/* See documentation in cli-utils.h. */
163
164int
f1735a53 165get_number (const char **pp)
e9cafbcc
TT
166{
167 return get_number_trailer (pp, '\0');
168}
169
170/* See documentation in cli-utils.h. */
171
e799154c
TT
172int
173get_number (char **pp)
174{
175 int result;
176 const char *p = *pp;
177
178 result = get_number_trailer (&p, '\0');
179 *pp = (char *) p;
180 return result;
181}
182
183/* See documentation in cli-utils.h. */
184
0d4cad90
PW
185bool
186extract_info_print_args (const char **args,
187 bool *quiet,
188 std::string *regexp,
189 std::string *t_regexp)
190{
191 /* Check for NAMEREGEXP or -- NAMEREGEXP. */
192 if (**args != '-' || check_for_argument (args, "--", 2))
193 {
0d4cad90
PW
194 *regexp = *args;
195 *args = NULL;
196 return true;
197 }
198
199 if (check_for_argument (args, "-t", 2))
200 {
201 *t_regexp = extract_arg_maybe_quoted (args);
202 *args = skip_spaces (*args);
203 return true;
204 }
205
206 if (check_for_argument (args, "-q", 2))
207 {
208 *quiet = true;
0d4cad90
PW
209 return true;
210 }
211
212 return false;
213}
214
215/* See documentation in cli-utils.h. */
216
217void
218report_unrecognized_option_error (const char *command, const char *args)
219{
220 std::string option = extract_arg (&args);
221
222 error (_("Unrecognized option '%s' to %s command. "
223 "Try \"help %s\"."), option.c_str (),
224 command, command);
225}
226
227/* See documentation in cli-utils.h. */
228
229const char *
230info_print_args_help (const char *prefix,
231 const char *entity_kind)
232{
233 return xstrprintf (_("\
234%sIf NAMEREGEXP is provided, only prints the %s whose name\n\
235matches NAMEREGEXP.\n\
236If -t TYPEREGEXP is provided, only prints the %s whose type\n\
237matches TYPEREGEXP. Note that the matching is done with the type\n\
238printed by the 'whatis' command.\n\
239By default, the command might produce headers and/or messages indicating\n\
240why no %s can be printed.\n\
241The flag -q disables the production of these headers and messages."),
242 prefix, entity_kind, entity_kind, entity_kind);
243}
244
245/* See documentation in cli-utils.h. */
246
bfd28288
PA
247number_or_range_parser::number_or_range_parser (const char *string)
248{
249 init (string);
250}
251
252/* See documentation in cli-utils.h. */
253
197f0a60 254void
bfd28288 255number_or_range_parser::init (const char *string)
e9cafbcc 256{
bfd28288
PA
257 m_cur_tok = string;
258 m_last_retval = 0;
259 m_end_value = 0;
260 m_end_ptr = NULL;
261 m_in_range = false;
197f0a60
TT
262}
263
264/* See documentation in cli-utils.h. */
e9cafbcc 265
197f0a60 266int
bfd28288 267number_or_range_parser::get_number ()
197f0a60 268{
bfd28288 269 if (m_in_range)
71ef29a8
PA
270 {
271 /* All number-parsing has already been done. Return the next
272 integer value (one greater than the saved previous value).
273 Do not advance the token pointer until the end of range is
274 reached. */
275
bfd28288 276 if (++m_last_retval == m_end_value)
71ef29a8
PA
277 {
278 /* End of range reached; advance token pointer. */
bfd28288
PA
279 m_cur_tok = m_end_ptr;
280 m_in_range = false;
71ef29a8
PA
281 }
282 }
bfd28288 283 else if (*m_cur_tok != '-')
e9cafbcc 284 {
bfd28288 285 /* Default case: state->m_cur_tok is pointing either to a solo
197f0a60 286 number, or to the first number of a range. */
bfd28288 287 m_last_retval = get_number_trailer (&m_cur_tok, '-');
2c722807
PA
288 /* If get_number_trailer has found a '-' preceded by a space, it
289 might be the start of a command option. So, do not parse a
290 range if the '-' is followed by an alpha or another '-'. We
291 might also be completing something like
292 "frame apply level 0 -" and we prefer treating that "-" as an
293 option rather than an incomplete range, so check for end of
294 string as well. */
295 if (m_cur_tok[0] == '-'
296 && !(isspace (m_cur_tok[-1])
297 && (isalpha (m_cur_tok[1])
298 || m_cur_tok[1] == '-'
299 || m_cur_tok[1] == '\0')))
e9cafbcc 300 {
e799154c 301 const char **temp;
e9cafbcc
TT
302
303 /* This is the start of a range (<number1> - <number2>).
304 Skip the '-', parse and remember the second number,
305 and also remember the end of the final token. */
306
bfd28288 307 temp = &m_end_ptr;
f1735a53
TT
308 m_end_ptr = skip_spaces (m_cur_tok + 1);
309 m_end_value = ::get_number (temp);
bfd28288 310 if (m_end_value < m_last_retval)
e9cafbcc
TT
311 {
312 error (_("inverted range"));
313 }
bfd28288 314 else if (m_end_value == m_last_retval)
e9cafbcc
TT
315 {
316 /* Degenerate range (number1 == number2). Advance the
317 token pointer so that the range will be treated as a
bfd28288
PA
318 single number. */
319 m_cur_tok = m_end_ptr;
e9cafbcc
TT
320 }
321 else
bfd28288 322 m_in_range = true;
e9cafbcc
TT
323 }
324 }
e9cafbcc 325 else
529c08b2
PW
326 {
327 if (isdigit (*(m_cur_tok + 1)))
328 error (_("negative value"));
329 if (*(m_cur_tok + 1) == '$')
330 {
331 /* Convenience variable. */
332 m_last_retval = ::get_number (&m_cur_tok);
333 if (m_last_retval < 0)
334 error (_("negative value"));
335 }
336 }
bfd28288 337 return m_last_retval;
e9cafbcc
TT
338}
339
71ef29a8
PA
340/* See documentation in cli-utils.h. */
341
342void
bfd28288
PA
343number_or_range_parser::setup_range (int start_value, int end_value,
344 const char *end_ptr)
71ef29a8
PA
345{
346 gdb_assert (start_value > 0);
347
bfd28288
PA
348 m_in_range = true;
349 m_end_ptr = end_ptr;
350 m_last_retval = start_value - 1;
351 m_end_value = end_value;
71ef29a8
PA
352}
353
529c08b2
PW
354/* See documentation in cli-utils.h. */
355
356bool
357number_or_range_parser::finished () const
358{
359 /* Parsing is finished when at end of string or null string,
360 or we are not in a range and not in front of an integer, negative
361 integer, convenience var or negative convenience var. */
362 return (m_cur_tok == NULL || *m_cur_tok == '\0'
363 || (!m_in_range
364 && !(isdigit (*m_cur_tok) || *m_cur_tok == '$')
365 && !(*m_cur_tok == '-'
366 && (isdigit (m_cur_tok[1]) || m_cur_tok[1] == '$'))));
367}
368
aea5b279
MS
369/* Accept a number and a string-form list of numbers such as is
370 accepted by get_number_or_range. Return TRUE if the number is
371 in the list.
372
373 By definition, an empty list includes all numbers. This is to
374 be interpreted as typing a command such as "delete break" with
375 no arguments. */
376
377int
e799154c 378number_is_in_list (const char *list, int number)
aea5b279
MS
379{
380 if (list == NULL || *list == '\0')
381 return 1;
382
bfd28288 383 number_or_range_parser parser (list);
529c08b2
PW
384
385 if (parser.finished ())
386 error (_("Arguments must be numbers or '$' variables."));
bfd28288 387 while (!parser.finished ())
298f437a 388 {
bfd28288 389 int gotnum = parser.get_number ();
aea5b279 390
298f437a 391 if (gotnum == 0)
529c08b2 392 error (_("Arguments must be numbers or '$' variables."));
298f437a
MS
393 if (gotnum == number)
394 return 1;
395 }
aea5b279
MS
396 return 0;
397}
398
e9cafbcc
TT
399/* See documentation in cli-utils.h. */
400
63160a43
PA
401const char *
402remove_trailing_whitespace (const char *start, const char *s)
c00f8484
KS
403{
404 while (s > start && isspace (*(s - 1)))
405 --s;
406
407 return s;
408}
55aa24fb 409
0d4cad90
PW
410/* A helper function to extract an argument from *ARG. An argument is
411 delimited by whitespace, but it can also be optionally quoted.
412 The quoting and special characters are handled similarly to
413 the parsing done by gdb_argv.
414 The return value is empty if no argument was found. */
415
416static std::string
417extract_arg_maybe_quoted (const char **arg)
418{
419 bool squote = false;
420 bool dquote = false;
421 bool bsquote = false;
422 std::string result;
423 const char *p = *arg;
424
425 /* Find the start of the argument. */
426 p = skip_spaces (p);
427
428 /* Parse p similarly to gdb_argv buildargv function. */
429 while (*p != '\0')
430 {
431 if (isspace (*p) && !squote && !dquote && !bsquote)
432 break;
433 else
434 {
435 if (bsquote)
436 {
437 bsquote = false;
438 result += *p;
439 }
440 else if (*p == '\\')
441 bsquote = true;
442 else if (squote)
443 {
444 if (*p == '\'')
445 squote = false;
446 else
447 result += *p;
448 }
449 else if (dquote)
450 {
451 if (*p == '"')
452 dquote = false;
453 else
454 result += *p;
455 }
456 else
457 {
458 if (*p == '\'')
459 squote = true;
460 else if (*p == '"')
461 dquote = true;
462 else
463 result += *p;
464 }
465 p++;
466 }
467 }
468
469 *arg = p;
470 return result;
471}
472
55aa24fb
SDJ
473/* See documentation in cli-utils.h. */
474
cb791d59 475std::string
f1735a53 476extract_arg (const char **arg)
55aa24fb 477{
b5be8ce0 478 const char *result;
55aa24fb
SDJ
479
480 if (!*arg)
cb791d59 481 return std::string ();
55aa24fb
SDJ
482
483 /* Find the start of the argument. */
f1735a53 484 *arg = skip_spaces (*arg);
55aa24fb 485 if (!**arg)
cb791d59 486 return std::string ();
55aa24fb
SDJ
487 result = *arg;
488
489 /* Find the end of the argument. */
f1735a53 490 *arg = skip_to_space (*arg + 1);
55aa24fb
SDJ
491
492 if (result == *arg)
cb791d59 493 return std::string ();
55aa24fb 494
cb791d59 495 return std::string (result, *arg - result);
b5be8ce0
JB
496}
497
498/* See documentation in cli-utils.h. */
499
cb791d59 500std::string
b5be8ce0
JB
501extract_arg (char **arg)
502{
503 const char *arg_const = *arg;
cb791d59 504 std::string result;
55aa24fb 505
f1735a53 506 result = extract_arg (&arg_const);
b5be8ce0
JB
507 *arg += arg_const - *arg;
508 return result;
55aa24fb 509}
e6f0bce7
HZ
510
511/* See documentation in cli-utils.h. */
512
513int
63160a43 514check_for_argument (const char **str, const char *arg, int arg_len)
e6f0bce7
HZ
515{
516 if (strncmp (*str, arg, arg_len) == 0
517 && ((*str)[arg_len] == '\0' || isspace ((*str)[arg_len])))
518 {
519 *str += arg_len;
cbba3ecd 520 *str = skip_spaces (*str);
e6f0bce7
HZ
521 return 1;
522 }
523 return 0;
524}
529c08b2
PW
525
526/* See documentation in cli-utils.h. */
527
5d707134
PA
528void
529validate_flags_qcs (const char *which_command, qcs_flags *flags)
530{
531 if (flags->cont && flags->silent)
532 error (_("%s: -c and -s are mutually exclusive"), which_command);
533}
534
535/* See documentation in cli-utils.h. */
This page took 0.580854 seconds and 4 git commands to generate.