Make gdb::option::complete_options save processed arguments too
[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 static std::string extract_arg_maybe_quoted (const char **arg);
27
28 /* See documentation in cli-utils.h. */
29
30 ULONGEST
31 get_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 {
63 const char *end = p;
64 retval = strtoulst (p, &end, 0);
65 if (p == end)
66 {
67 /* There is no number here. (e.g. "cond a == b"). */
68 error (_("Expected integer at: %s"), p);
69 }
70 p = end;
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
82 int
83 get_number_trailer (const char **pp, int trailer)
84 {
85 int retval = 0; /* default */
86 const char *p = *pp;
87 bool negative = false;
88
89 if (*p == '-')
90 {
91 ++p;
92 negative = true;
93 }
94
95 if (*p == '$')
96 {
97 struct value *val = value_from_history_ref (p, &p);
98
99 if (val) /* Value history reference */
100 {
101 if (TYPE_CODE (value_type (val)) == TYPE_CODE_INT)
102 retval = value_as_long (val);
103 else
104 {
105 printf_filtered (_("History value must have integer type.\n"));
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;
114 const char *start = ++p;
115 LONGEST longest_val;
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';
122 if (get_internalvar_integer (lookup_internalvar (varname),
123 &longest_val))
124 retval = (int) longest_val;
125 else
126 {
127 printf_filtered (_("Convenience variable must "
128 "have integer value.\n"));
129 retval = 0;
130 }
131 }
132 }
133 else
134 {
135 const char *p1 = p;
136 while (*p >= '0' && *p <= '9')
137 ++p;
138 if (p == p1)
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
148 retval = atoi (p1);
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 }
157 p = skip_spaces (p);
158 *pp = p;
159 return negative ? -retval : retval;
160 }
161
162 /* See documentation in cli-utils.h. */
163
164 int
165 get_number (const char **pp)
166 {
167 return get_number_trailer (pp, '\0');
168 }
169
170 /* See documentation in cli-utils.h. */
171
172 int
173 get_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
185 bool
186 extract_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 {
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;
209 return true;
210 }
211
212 return false;
213 }
214
215 /* See documentation in cli-utils.h. */
216
217 void
218 report_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
229 const char *
230 info_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\
235 matches NAMEREGEXP.\n\
236 If -t TYPEREGEXP is provided, only prints the %s whose type\n\
237 matches TYPEREGEXP. Note that the matching is done with the type\n\
238 printed by the 'whatis' command.\n\
239 By default, the command might produce headers and/or messages indicating\n\
240 why no %s can be printed.\n\
241 The 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
247 number_or_range_parser::number_or_range_parser (const char *string)
248 {
249 init (string);
250 }
251
252 /* See documentation in cli-utils.h. */
253
254 void
255 number_or_range_parser::init (const char *string)
256 {
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;
262 }
263
264 /* See documentation in cli-utils.h. */
265
266 int
267 number_or_range_parser::get_number ()
268 {
269 if (m_in_range)
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
276 if (++m_last_retval == m_end_value)
277 {
278 /* End of range reached; advance token pointer. */
279 m_cur_tok = m_end_ptr;
280 m_in_range = false;
281 }
282 }
283 else if (*m_cur_tok != '-')
284 {
285 /* Default case: state->m_cur_tok is pointing either to a solo
286 number, or to the first number of a range. */
287 m_last_retval = get_number_trailer (&m_cur_tok, '-');
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')))
300 {
301 const char **temp;
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
307 temp = &m_end_ptr;
308 m_end_ptr = skip_spaces (m_cur_tok + 1);
309 m_end_value = ::get_number (temp);
310 if (m_end_value < m_last_retval)
311 {
312 error (_("inverted range"));
313 }
314 else if (m_end_value == m_last_retval)
315 {
316 /* Degenerate range (number1 == number2). Advance the
317 token pointer so that the range will be treated as a
318 single number. */
319 m_cur_tok = m_end_ptr;
320 }
321 else
322 m_in_range = true;
323 }
324 }
325 else
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 }
337 return m_last_retval;
338 }
339
340 /* See documentation in cli-utils.h. */
341
342 void
343 number_or_range_parser::setup_range (int start_value, int end_value,
344 const char *end_ptr)
345 {
346 gdb_assert (start_value > 0);
347
348 m_in_range = true;
349 m_end_ptr = end_ptr;
350 m_last_retval = start_value - 1;
351 m_end_value = end_value;
352 }
353
354 /* See documentation in cli-utils.h. */
355
356 bool
357 number_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
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
377 int
378 number_is_in_list (const char *list, int number)
379 {
380 if (list == NULL || *list == '\0')
381 return 1;
382
383 number_or_range_parser parser (list);
384
385 if (parser.finished ())
386 error (_("Arguments must be numbers or '$' variables."));
387 while (!parser.finished ())
388 {
389 int gotnum = parser.get_number ();
390
391 if (gotnum == 0)
392 error (_("Arguments must be numbers or '$' variables."));
393 if (gotnum == number)
394 return 1;
395 }
396 return 0;
397 }
398
399 /* See documentation in cli-utils.h. */
400
401 const char *
402 remove_trailing_whitespace (const char *start, const char *s)
403 {
404 while (s > start && isspace (*(s - 1)))
405 --s;
406
407 return s;
408 }
409
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
416 static std::string
417 extract_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
473 /* See documentation in cli-utils.h. */
474
475 std::string
476 extract_arg (const char **arg)
477 {
478 const char *result;
479
480 if (!*arg)
481 return std::string ();
482
483 /* Find the start of the argument. */
484 *arg = skip_spaces (*arg);
485 if (!**arg)
486 return std::string ();
487 result = *arg;
488
489 /* Find the end of the argument. */
490 *arg = skip_to_space (*arg + 1);
491
492 if (result == *arg)
493 return std::string ();
494
495 return std::string (result, *arg - result);
496 }
497
498 /* See documentation in cli-utils.h. */
499
500 std::string
501 extract_arg (char **arg)
502 {
503 const char *arg_const = *arg;
504 std::string result;
505
506 result = extract_arg (&arg_const);
507 *arg += arg_const - *arg;
508 return result;
509 }
510
511 /* See documentation in cli-utils.h. */
512
513 int
514 check_for_argument (const char **str, const char *arg, int arg_len)
515 {
516 if (strncmp (*str, arg, arg_len) == 0
517 && ((*str)[arg_len] == '\0' || isspace ((*str)[arg_len])))
518 {
519 *str += arg_len;
520 *str = skip_spaces (*str);
521 return 1;
522 }
523 return 0;
524 }
525
526 /* See documentation in cli-utils.h. */
527
528 void
529 validate_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.050037 seconds and 4 git commands to generate.