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