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