xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/cli/cli-utils.c (revision 627f7eb200a4419d89b531d55fccd2ee3ffdcde0)
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       *args = skip_spaces (*args);
143       *regexp = *args;
144       *args = NULL;
145       return true;
146     }
147 
148   if (check_for_argument (args, "-t", 2))
149     {
150       *t_regexp = extract_arg_maybe_quoted (args);
151       *args = skip_spaces (*args);
152       return true;
153     }
154 
155   if (check_for_argument (args, "-q", 2))
156     {
157       *quiet = true;
158       *args = skip_spaces (*args);
159       return true;
160     }
161 
162   return false;
163 }
164 
165 /* See documentation in cli-utils.h.  */
166 
167 void
168 report_unrecognized_option_error (const char *command, const char *args)
169 {
170   std::string option = extract_arg (&args);
171 
172   error (_("Unrecognized option '%s' to %s command.  "
173 	   "Try \"help %s\"."), option.c_str (),
174 	 command, command);
175 }
176 
177 /* See documentation in cli-utils.h.  */
178 
179 const char *
180 info_print_args_help (const char *prefix,
181 		      const char *entity_kind)
182 {
183   return xstrprintf (_("\
184 %sIf NAMEREGEXP is provided, only prints the %s whose name\n\
185 matches NAMEREGEXP.\n\
186 If -t TYPEREGEXP is provided, only prints the %s whose type\n\
187 matches TYPEREGEXP.  Note that the matching is done with the type\n\
188 printed by the 'whatis' command.\n\
189 By default, the command might produce headers and/or messages indicating\n\
190 why no %s can be printed.\n\
191 The flag -q disables the production of these headers and messages."),
192 		     prefix, entity_kind, entity_kind, entity_kind);
193 }
194 
195 /* See documentation in cli-utils.h.  */
196 
197 number_or_range_parser::number_or_range_parser (const char *string)
198 {
199   init (string);
200 }
201 
202 /* See documentation in cli-utils.h.  */
203 
204 void
205 number_or_range_parser::init (const char *string)
206 {
207   m_cur_tok = string;
208   m_last_retval = 0;
209   m_end_value = 0;
210   m_end_ptr = NULL;
211   m_in_range = false;
212 }
213 
214 /* See documentation in cli-utils.h.  */
215 
216 int
217 number_or_range_parser::get_number ()
218 {
219   if (m_in_range)
220     {
221       /* All number-parsing has already been done.  Return the next
222 	 integer value (one greater than the saved previous value).
223 	 Do not advance the token pointer until the end of range is
224 	 reached.  */
225 
226       if (++m_last_retval == m_end_value)
227 	{
228 	  /* End of range reached; advance token pointer.  */
229 	  m_cur_tok = m_end_ptr;
230 	  m_in_range = false;
231 	}
232     }
233   else if (*m_cur_tok != '-')
234     {
235       /* Default case: state->m_cur_tok is pointing either to a solo
236 	 number, or to the first number of a range.  */
237       m_last_retval = get_number_trailer (&m_cur_tok, '-');
238       /* If get_number_trailer has found a -, it might be the start
239 	 of a command option.  So, do not parse a range if the - is
240 	 followed by an alpha.  */
241       if (*m_cur_tok == '-' && !isalpha (*(m_cur_tok + 1)))
242 	{
243 	  const char **temp;
244 
245 	  /* This is the start of a range (<number1> - <number2>).
246 	     Skip the '-', parse and remember the second number,
247 	     and also remember the end of the final token.  */
248 
249 	  temp = &m_end_ptr;
250 	  m_end_ptr = skip_spaces (m_cur_tok + 1);
251 	  m_end_value = ::get_number (temp);
252 	  if (m_end_value < m_last_retval)
253 	    {
254 	      error (_("inverted range"));
255 	    }
256 	  else if (m_end_value == m_last_retval)
257 	    {
258 	      /* Degenerate range (number1 == number2).  Advance the
259 		 token pointer so that the range will be treated as a
260 		 single number.  */
261 	      m_cur_tok = m_end_ptr;
262 	    }
263 	  else
264 	    m_in_range = true;
265 	}
266     }
267   else
268     {
269       if (isdigit (*(m_cur_tok + 1)))
270 	error (_("negative value"));
271       if (*(m_cur_tok + 1) == '$')
272 	{
273 	  /* Convenience variable.  */
274 	  m_last_retval = ::get_number (&m_cur_tok);
275 	  if (m_last_retval < 0)
276 	    error (_("negative value"));
277 	}
278     }
279   return m_last_retval;
280 }
281 
282 /* See documentation in cli-utils.h.  */
283 
284 void
285 number_or_range_parser::setup_range (int start_value, int end_value,
286 				     const char *end_ptr)
287 {
288   gdb_assert (start_value > 0);
289 
290   m_in_range = true;
291   m_end_ptr = end_ptr;
292   m_last_retval = start_value - 1;
293   m_end_value = end_value;
294 }
295 
296 /* See documentation in cli-utils.h.  */
297 
298 bool
299 number_or_range_parser::finished () const
300 {
301   /* Parsing is finished when at end of string or null string,
302      or we are not in a range and not in front of an integer, negative
303      integer, convenience var or negative convenience var.  */
304   return (m_cur_tok == NULL || *m_cur_tok == '\0'
305 	  || (!m_in_range
306 	      && !(isdigit (*m_cur_tok) || *m_cur_tok == '$')
307 	      && !(*m_cur_tok == '-'
308 		   && (isdigit (m_cur_tok[1]) || m_cur_tok[1] == '$'))));
309 }
310 
311 /* Accept a number and a string-form list of numbers such as is
312    accepted by get_number_or_range.  Return TRUE if the number is
313    in the list.
314 
315    By definition, an empty list includes all numbers.  This is to
316    be interpreted as typing a command such as "delete break" with
317    no arguments.  */
318 
319 int
320 number_is_in_list (const char *list, int number)
321 {
322   if (list == NULL || *list == '\0')
323     return 1;
324 
325   number_or_range_parser parser (list);
326 
327   if (parser.finished ())
328     error (_("Arguments must be numbers or '$' variables."));
329   while (!parser.finished ())
330     {
331       int gotnum = parser.get_number ();
332 
333       if (gotnum == 0)
334 	error (_("Arguments must be numbers or '$' variables."));
335       if (gotnum == number)
336 	return 1;
337     }
338   return 0;
339 }
340 
341 /* See documentation in cli-utils.h.  */
342 
343 const char *
344 remove_trailing_whitespace (const char *start, const char *s)
345 {
346   while (s > start && isspace (*(s - 1)))
347     --s;
348 
349   return s;
350 }
351 
352 /* A helper function to extract an argument from *ARG.  An argument is
353    delimited by whitespace, but it can also be optionally quoted.
354    The quoting and special characters are handled similarly to
355    the parsing done by gdb_argv.
356    The return value is empty if no argument was found.  */
357 
358 static std::string
359 extract_arg_maybe_quoted (const char **arg)
360 {
361   bool squote = false;
362   bool dquote = false;
363   bool bsquote = false;
364   std::string result;
365   const char *p = *arg;
366 
367   /* Find the start of the argument.  */
368   p = skip_spaces (p);
369 
370   /* Parse p similarly to gdb_argv buildargv function.  */
371   while (*p != '\0')
372     {
373       if (isspace (*p) && !squote && !dquote && !bsquote)
374 	  break;
375       else
376 	{
377 	  if (bsquote)
378 	    {
379 	      bsquote = false;
380 	      result += *p;
381 	    }
382 	  else if (*p == '\\')
383 	      bsquote = true;
384 	  else if (squote)
385 	    {
386 	      if (*p == '\'')
387 		  squote = false;
388 	      else
389 		  result += *p;
390 	    }
391 	  else if (dquote)
392 	    {
393 	      if (*p == '"')
394 		  dquote = false;
395 	      else
396 		  result += *p;
397 	    }
398 	  else
399 	    {
400 	      if (*p == '\'')
401 		  squote = true;
402 	      else if (*p == '"')
403 		  dquote = true;
404 	      else
405 		  result += *p;
406 	    }
407 	  p++;
408 	}
409     }
410 
411   *arg = p;
412   return result;
413 }
414 
415 /* See documentation in cli-utils.h.  */
416 
417 std::string
418 extract_arg (const char **arg)
419 {
420   const char *result;
421 
422   if (!*arg)
423     return std::string ();
424 
425   /* Find the start of the argument.  */
426   *arg = skip_spaces (*arg);
427   if (!**arg)
428     return std::string ();
429   result = *arg;
430 
431   /* Find the end of the argument.  */
432   *arg = skip_to_space (*arg + 1);
433 
434   if (result == *arg)
435     return std::string ();
436 
437   return std::string (result, *arg - result);
438 }
439 
440 /* See documentation in cli-utils.h.  */
441 
442 std::string
443 extract_arg (char **arg)
444 {
445   const char *arg_const = *arg;
446   std::string result;
447 
448   result = extract_arg (&arg_const);
449   *arg += arg_const - *arg;
450   return result;
451 }
452 
453 /* See documentation in cli-utils.h.  */
454 
455 int
456 check_for_argument (const char **str, const char *arg, int arg_len)
457 {
458   if (strncmp (*str, arg, arg_len) == 0
459       && ((*str)[arg_len] == '\0' || isspace ((*str)[arg_len])))
460     {
461       *str += arg_len;
462       return 1;
463     }
464   return 0;
465 }
466 
467 /* See documentation in cli-utils.h.  */
468 
469 int
470 parse_flags (const char **str, const char *flags)
471 {
472   const char *p = skip_spaces (*str);
473 
474   if (p[0] == '-'
475       && isalpha (p[1])
476       && (p[2] == '\0' || isspace (p[2])))
477     {
478       const char pf = p[1];
479       const char *f = flags;
480 
481       while (*f != '\0')
482 	{
483 	  if (*f == pf)
484 	    {
485 	      *str = skip_spaces (p + 2);
486 	      return f - flags + 1;
487 	    }
488 	  f++;
489 	}
490     }
491 
492   return 0;
493 }
494 
495 /* See documentation in cli-utils.h.  */
496 
497 bool
498 parse_flags_qcs (const char *which_command, const char **str,
499 		 qcs_flags *flags)
500 {
501   switch (parse_flags (str, "qcs"))
502     {
503     case 0:
504       return false;
505     case 1:
506       flags->quiet = true;
507       break;
508     case 2:
509       flags->cont = true;
510       break;
511     case 3:
512       flags->silent = true;
513       break;
514     default:
515       gdb_assert_not_reached ("int qcs flag out of bound");
516     }
517 
518   if (flags->cont && flags->silent)
519     error (_("%s: -c and -s are mutually exclusive"), which_command);
520 
521   return true;
522 }
523