constify some cli-utils stuff
[platform/upstream/binutils.git] / gdb / cli / cli-utils.c
1 /* CLI utilities.
2
3    Copyright (C) 2011-2014 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 <string.h>
23 #include "value.h"
24 #include "gdb_assert.h"
25
26 #include <ctype.h>
27
28 /* *PP is a string denoting a number.  Get the number of the.  Advance
29    *PP after the string and any trailing whitespace.
30
31    Currently the string can either be a number, or "$" followed by the
32    name of a convenience variable, or ("$" or "$$") followed by digits.
33
34    TRAILER is a character which can be found after the number; most
35    commonly this is `-'.  If you don't want a trailer, use \0.  */
36
37 static int
38 get_number_trailer (const char **pp, int trailer)
39 {
40   int retval = 0;       /* default */
41   const char *p = *pp;
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 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), &val))
71             retval = (int) val;
72           else
73             {
74               printf_filtered (_("Convenience variable must "
75                                  "have integer value.\n"));
76               retval = 0;
77             }
78         }
79     }
80   else
81     {
82       if (*p == '-')
83         ++p;
84       while (*p >= '0' && *p <= '9')
85         ++p;
86       if (p == *pp)
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 (*pp);
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_const (p);
106   *pp = p;
107   return retval;
108 }
109
110 /* See documentation in cli-utils.h.  */
111
112 int
113 get_number_const (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 void
134 init_number_or_range (struct get_number_or_range_state *state,
135                       const char *string)
136 {
137   memset (state, 0, sizeof (*state));
138   state->string = string;
139 }
140
141 /* See documentation in cli-utils.h.  */
142
143 int
144 get_number_or_range (struct get_number_or_range_state *state)
145 {
146   if (*state->string != '-')
147     {
148       /* Default case: state->string is pointing either to a solo
149          number, or to the first number of a range.  */
150       state->last_retval = get_number_trailer (&state->string, '-');
151       if (*state->string == '-')
152         {
153           const char **temp;
154
155           /* This is the start of a range (<number1> - <number2>).
156              Skip the '-', parse and remember the second number,
157              and also remember the end of the final token.  */
158
159           temp = &state->end_ptr; 
160           state->end_ptr = skip_spaces_const (state->string + 1);
161           state->end_value = get_number_const (temp);
162           if (state->end_value < state->last_retval) 
163             {
164               error (_("inverted range"));
165             }
166           else if (state->end_value == state->last_retval)
167             {
168               /* Degenerate range (number1 == number2).  Advance the
169                  token pointer so that the range will be treated as a
170                  single number.  */ 
171               state->string = state->end_ptr;
172             }
173           else
174             state->in_range = 1;
175         }
176     }
177   else if (! state->in_range)
178     error (_("negative value"));
179   else
180     {
181       /* state->string points to the '-' that betokens a range.  All
182          number-parsing has already been done.  Return the next
183          integer value (one greater than the saved previous value).
184          Do not advance the token pointer until the end of range
185          is reached.  */
186
187       if (++state->last_retval == state->end_value)
188         {
189           /* End of range reached; advance token pointer.  */
190           state->string = state->end_ptr;
191           state->in_range = 0;
192         }
193     }
194   state->finished = *state->string == '\0';
195   return state->last_retval;
196 }
197
198 /* Accept a number and a string-form list of numbers such as is 
199    accepted by get_number_or_range.  Return TRUE if the number is
200    in the list.
201
202    By definition, an empty list includes all numbers.  This is to 
203    be interpreted as typing a command such as "delete break" with 
204    no arguments.  */
205
206 int
207 number_is_in_list (const char *list, int number)
208 {
209   struct get_number_or_range_state state;
210
211   if (list == NULL || *list == '\0')
212     return 1;
213
214   init_number_or_range (&state, list);
215   while (!state.finished)
216     {
217       int gotnum = get_number_or_range (&state);
218
219       if (gotnum == 0)
220         error (_("Args must be numbers or '$' variables."));
221       if (gotnum == number)
222         return 1;
223     }
224   return 0;
225 }
226
227 /* See documentation in cli-utils.h.  */
228
229 char *
230 skip_spaces (char *chp)
231 {
232   if (chp == NULL)
233     return NULL;
234   while (*chp && isspace (*chp))
235     chp++;
236   return chp;
237 }
238
239 /* A const-correct version of the above.  */
240
241 const char *
242 skip_spaces_const (const char *chp)
243 {
244   if (chp == NULL)
245     return NULL;
246   while (*chp && isspace (*chp))
247     chp++;
248   return chp;
249 }
250
251 /* See documentation in cli-utils.h.  */
252
253 const char *
254 skip_to_space_const (const char *chp)
255 {
256   if (chp == NULL)
257     return NULL;
258   while (*chp && !isspace (*chp))
259     chp++;
260   return chp;
261 }
262
263 /* See documentation in cli-utils.h.  */
264
265 char *
266 remove_trailing_whitespace (const char *start, char *s)
267 {
268   while (s > start && isspace (*(s - 1)))
269     --s;
270
271   return s;
272 }
273
274 /* See documentation in cli-utils.h.  */
275
276 char *
277 extract_arg_const (const char **arg)
278 {
279   const char *result;
280
281   if (!*arg)
282     return NULL;
283
284   /* Find the start of the argument.  */
285   *arg = skip_spaces_const (*arg);
286   if (!**arg)
287     return NULL;
288   result = *arg;
289
290   /* Find the end of the argument.  */
291   *arg = skip_to_space_const (*arg + 1);
292
293   if (result == *arg)
294     return NULL;
295
296   return savestring (result, *arg - result);
297 }
298
299 /* See documentation in cli-utils.h.  */
300
301 char *
302 extract_arg (char **arg)
303 {
304   const char *arg_const = *arg;
305   char *result;
306
307   result = extract_arg_const (&arg_const);
308   *arg += arg_const - *arg;
309   return result;
310 }
311
312 /* See documentation in cli-utils.h.  */
313
314 int
315 check_for_argument (char **str, char *arg, int arg_len)
316 {
317   if (strncmp (*str, arg, arg_len) == 0
318       && ((*str)[arg_len] == '\0' || isspace ((*str)[arg_len])))
319     {
320       *str += arg_len;
321       return 1;
322     }
323   return 0;
324 }