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