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