Make check_for_argument skip whitespace after arg itself
[external/binutils.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 -, it might be the start
237          of a command option.  So, do not parse a range if the - is
238          followed by an alpha.  */
239       if (*m_cur_tok == '-' && !isalpha (*(m_cur_tok + 1)))
240         {
241           const char **temp;
242
243           /* This is the start of a range (<number1> - <number2>).
244              Skip the '-', parse and remember the second number,
245              and also remember the end of the final token.  */
246
247           temp = &m_end_ptr;
248           m_end_ptr = skip_spaces (m_cur_tok + 1);
249           m_end_value = ::get_number (temp);
250           if (m_end_value < m_last_retval)
251             {
252               error (_("inverted range"));
253             }
254           else if (m_end_value == m_last_retval)
255             {
256               /* Degenerate range (number1 == number2).  Advance the
257                  token pointer so that the range will be treated as a
258                  single number.  */
259               m_cur_tok = m_end_ptr;
260             }
261           else
262             m_in_range = true;
263         }
264     }
265   else
266     {
267       if (isdigit (*(m_cur_tok + 1)))
268         error (_("negative value"));
269       if (*(m_cur_tok + 1) == '$')
270         {
271           /* Convenience variable.  */
272           m_last_retval = ::get_number (&m_cur_tok);
273           if (m_last_retval < 0)
274             error (_("negative value"));
275         }
276     }
277   return m_last_retval;
278 }
279
280 /* See documentation in cli-utils.h.  */
281
282 void
283 number_or_range_parser::setup_range (int start_value, int end_value,
284                                      const char *end_ptr)
285 {
286   gdb_assert (start_value > 0);
287
288   m_in_range = true;
289   m_end_ptr = end_ptr;
290   m_last_retval = start_value - 1;
291   m_end_value = end_value;
292 }
293
294 /* See documentation in cli-utils.h.  */
295
296 bool
297 number_or_range_parser::finished () const
298 {
299   /* Parsing is finished when at end of string or null string,
300      or we are not in a range and not in front of an integer, negative
301      integer, convenience var or negative convenience var.  */
302   return (m_cur_tok == NULL || *m_cur_tok == '\0'
303           || (!m_in_range
304               && !(isdigit (*m_cur_tok) || *m_cur_tok == '$')
305               && !(*m_cur_tok == '-'
306                    && (isdigit (m_cur_tok[1]) || m_cur_tok[1] == '$'))));
307 }
308
309 /* Accept a number and a string-form list of numbers such as is 
310    accepted by get_number_or_range.  Return TRUE if the number is
311    in the list.
312
313    By definition, an empty list includes all numbers.  This is to 
314    be interpreted as typing a command such as "delete break" with 
315    no arguments.  */
316
317 int
318 number_is_in_list (const char *list, int number)
319 {
320   if (list == NULL || *list == '\0')
321     return 1;
322
323   number_or_range_parser parser (list);
324
325   if (parser.finished ())
326     error (_("Arguments must be numbers or '$' variables."));
327   while (!parser.finished ())
328     {
329       int gotnum = parser.get_number ();
330
331       if (gotnum == 0)
332         error (_("Arguments must be numbers or '$' variables."));
333       if (gotnum == number)
334         return 1;
335     }
336   return 0;
337 }
338
339 /* See documentation in cli-utils.h.  */
340
341 const char *
342 remove_trailing_whitespace (const char *start, const char *s)
343 {
344   while (s > start && isspace (*(s - 1)))
345     --s;
346
347   return s;
348 }
349
350 /* A helper function to extract an argument from *ARG.  An argument is
351    delimited by whitespace, but it can also be optionally quoted.
352    The quoting and special characters are handled similarly to
353    the parsing done by gdb_argv.
354    The return value is empty if no argument was found.  */
355
356 static std::string
357 extract_arg_maybe_quoted (const char **arg)
358 {
359   bool squote = false;
360   bool dquote = false;
361   bool bsquote = false;
362   std::string result;
363   const char *p = *arg;
364
365   /* Find the start of the argument.  */
366   p = skip_spaces (p);
367
368   /* Parse p similarly to gdb_argv buildargv function.  */
369   while (*p != '\0')
370     {
371       if (isspace (*p) && !squote && !dquote && !bsquote)
372           break;
373       else
374         {
375           if (bsquote)
376             {
377               bsquote = false;
378               result += *p;
379             }
380           else if (*p == '\\')
381               bsquote = true;
382           else if (squote)
383             {
384               if (*p == '\'')
385                   squote = false;
386               else
387                   result += *p;
388             }
389           else if (dquote)
390             {
391               if (*p == '"')
392                   dquote = false;
393               else
394                   result += *p;
395             }
396           else
397             {
398               if (*p == '\'')
399                   squote = true;
400               else if (*p == '"')
401                   dquote = true;
402               else
403                   result += *p;
404             }
405           p++;
406         }
407     }
408
409   *arg = p;
410   return result;
411 }
412
413 /* See documentation in cli-utils.h.  */
414
415 std::string
416 extract_arg (const char **arg)
417 {
418   const char *result;
419
420   if (!*arg)
421     return std::string ();
422
423   /* Find the start of the argument.  */
424   *arg = skip_spaces (*arg);
425   if (!**arg)
426     return std::string ();
427   result = *arg;
428
429   /* Find the end of the argument.  */
430   *arg = skip_to_space (*arg + 1);
431
432   if (result == *arg)
433     return std::string ();
434
435   return std::string (result, *arg - result);
436 }
437
438 /* See documentation in cli-utils.h.  */
439
440 std::string
441 extract_arg (char **arg)
442 {
443   const char *arg_const = *arg;
444   std::string result;
445
446   result = extract_arg (&arg_const);
447   *arg += arg_const - *arg;
448   return result;
449 }
450
451 /* See documentation in cli-utils.h.  */
452
453 int
454 check_for_argument (const char **str, const char *arg, int arg_len)
455 {
456   if (strncmp (*str, arg, arg_len) == 0
457       && ((*str)[arg_len] == '\0' || isspace ((*str)[arg_len])))
458     {
459       *str += arg_len;
460       *str = skip_spaces (*str);
461       return 1;
462     }
463   return 0;
464 }
465
466 /* See documentation in cli-utils.h.  */
467
468 int
469 parse_flags (const char **str, const char *flags)
470 {
471   const char *p = skip_spaces (*str);
472
473   if (p[0] == '-'
474       && isalpha (p[1])
475       && (p[2] == '\0' || isspace (p[2])))
476     {
477       const char pf = p[1];
478       const char *f = flags;
479
480       while (*f != '\0')
481         {
482           if (*f == pf)
483             {
484               *str = skip_spaces (p + 2);
485               return f - flags + 1;
486             }
487           f++;
488         }
489     }
490
491   return 0;
492 }
493
494 /* See documentation in cli-utils.h.  */
495
496 bool
497 parse_flags_qcs (const char *which_command, const char **str,
498                  qcs_flags *flags)
499 {
500   switch (parse_flags (str, "qcs"))
501     {
502     case 0:
503       return false;
504     case 1:
505       flags->quiet = true;
506       break;
507     case 2:
508       flags->cont = true;
509       break;
510     case 3:
511       flags->silent = true;
512       break;
513     default:
514       gdb_assert_not_reached ("int qcs flag out of bound");
515     }
516
517   if (flags->cont && flags->silent)
518     error (_("%s: -c and -s are mutually exclusive"), which_command);
519
520   return true;
521 }