Include gdb_assert.h in common-defs.h
[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
25 #include <ctype.h>
26
27 /* *PP is a string denoting a number.  Get the number of the.  Advance
28    *PP after the string and any trailing whitespace.
29
30    Currently the string can either be a number, or "$" followed by the
31    name of a convenience variable, or ("$" or "$$") followed by digits.
32
33    TRAILER is a character which can be found after the number; most
34    commonly this is `-'.  If you don't want a trailer, use \0.  */
35
36 static int
37 get_number_trailer (const char **pp, int trailer)
38 {
39   int retval = 0;       /* default */
40   const char *p = *pp;
41
42   if (*p == '$')
43     {
44       struct value *val = value_from_history_ref (p, &p);
45
46       if (val)  /* Value history reference */
47         {
48           if (TYPE_CODE (value_type (val)) == TYPE_CODE_INT)
49             retval = value_as_long (val);
50           else
51             {
52               printf_filtered (_("History value must have integer type.\n"));
53               retval = 0;
54             }
55         }
56       else      /* Convenience variable */
57         {
58           /* Internal variable.  Make a copy of the name, so we can
59              null-terminate it to pass to lookup_internalvar().  */
60           char *varname;
61           const char *start = ++p;
62           LONGEST val;
63
64           while (isalnum (*p) || *p == '_')
65             p++;
66           varname = (char *) alloca (p - start + 1);
67           strncpy (varname, start, p - start);
68           varname[p - start] = '\0';
69           if (get_internalvar_integer (lookup_internalvar (varname), &val))
70             retval = (int) val;
71           else
72             {
73               printf_filtered (_("Convenience variable must "
74                                  "have integer value.\n"));
75               retval = 0;
76             }
77         }
78     }
79   else
80     {
81       if (*p == '-')
82         ++p;
83       while (*p >= '0' && *p <= '9')
84         ++p;
85       if (p == *pp)
86         /* There is no number here.  (e.g. "cond a == b").  */
87         {
88           /* Skip non-numeric token.  */
89           while (*p && !isspace((int) *p))
90             ++p;
91           /* Return zero, which caller must interpret as error.  */
92           retval = 0;
93         }
94       else
95         retval = atoi (*pp);
96     }
97   if (!(isspace (*p) || *p == '\0' || *p == trailer))
98     {
99       /* Trailing junk: return 0 and let caller print error msg.  */
100       while (!(isspace (*p) || *p == '\0' || *p == trailer))
101         ++p;
102       retval = 0;
103     }
104   p = skip_spaces_const (p);
105   *pp = p;
106   return retval;
107 }
108
109 /* See documentation in cli-utils.h.  */
110
111 int
112 get_number_const (const char **pp)
113 {
114   return get_number_trailer (pp, '\0');
115 }
116
117 /* See documentation in cli-utils.h.  */
118
119 int
120 get_number (char **pp)
121 {
122   int result;
123   const char *p = *pp;
124
125   result = get_number_trailer (&p, '\0');
126   *pp = (char *) p;
127   return result;
128 }
129
130 /* See documentation in cli-utils.h.  */
131
132 void
133 init_number_or_range (struct get_number_or_range_state *state,
134                       const char *string)
135 {
136   memset (state, 0, sizeof (*state));
137   state->string = string;
138 }
139
140 /* See documentation in cli-utils.h.  */
141
142 int
143 get_number_or_range (struct get_number_or_range_state *state)
144 {
145   if (*state->string != '-')
146     {
147       /* Default case: state->string is pointing either to a solo
148          number, or to the first number of a range.  */
149       state->last_retval = get_number_trailer (&state->string, '-');
150       if (*state->string == '-')
151         {
152           const char **temp;
153
154           /* This is the start of a range (<number1> - <number2>).
155              Skip the '-', parse and remember the second number,
156              and also remember the end of the final token.  */
157
158           temp = &state->end_ptr; 
159           state->end_ptr = skip_spaces_const (state->string + 1);
160           state->end_value = get_number_const (temp);
161           if (state->end_value < state->last_retval) 
162             {
163               error (_("inverted range"));
164             }
165           else if (state->end_value == state->last_retval)
166             {
167               /* Degenerate range (number1 == number2).  Advance the
168                  token pointer so that the range will be treated as a
169                  single number.  */ 
170               state->string = state->end_ptr;
171             }
172           else
173             state->in_range = 1;
174         }
175     }
176   else if (! state->in_range)
177     error (_("negative value"));
178   else
179     {
180       /* state->string points to the '-' that betokens a range.  All
181          number-parsing has already been done.  Return the next
182          integer value (one greater than the saved previous value).
183          Do not advance the token pointer until the end of range
184          is reached.  */
185
186       if (++state->last_retval == state->end_value)
187         {
188           /* End of range reached; advance token pointer.  */
189           state->string = state->end_ptr;
190           state->in_range = 0;
191         }
192     }
193   state->finished = *state->string == '\0';
194   return state->last_retval;
195 }
196
197 /* Accept a number and a string-form list of numbers such as is 
198    accepted by get_number_or_range.  Return TRUE if the number is
199    in the list.
200
201    By definition, an empty list includes all numbers.  This is to 
202    be interpreted as typing a command such as "delete break" with 
203    no arguments.  */
204
205 int
206 number_is_in_list (const char *list, int number)
207 {
208   struct get_number_or_range_state state;
209
210   if (list == NULL || *list == '\0')
211     return 1;
212
213   init_number_or_range (&state, list);
214   while (!state.finished)
215     {
216       int gotnum = get_number_or_range (&state);
217
218       if (gotnum == 0)
219         error (_("Args must be numbers or '$' variables."));
220       if (gotnum == number)
221         return 1;
222     }
223   return 0;
224 }
225
226 /* See documentation in cli-utils.h.  */
227
228 char *
229 skip_spaces (char *chp)
230 {
231   if (chp == NULL)
232     return NULL;
233   while (*chp && isspace (*chp))
234     chp++;
235   return chp;
236 }
237
238 /* A const-correct version of the above.  */
239
240 const char *
241 skip_spaces_const (const char *chp)
242 {
243   if (chp == NULL)
244     return NULL;
245   while (*chp && isspace (*chp))
246     chp++;
247   return chp;
248 }
249
250 /* See documentation in cli-utils.h.  */
251
252 const char *
253 skip_to_space_const (const char *chp)
254 {
255   if (chp == NULL)
256     return NULL;
257   while (*chp && !isspace (*chp))
258     chp++;
259   return chp;
260 }
261
262 /* See documentation in cli-utils.h.  */
263
264 char *
265 remove_trailing_whitespace (const char *start, char *s)
266 {
267   while (s > start && isspace (*(s - 1)))
268     --s;
269
270   return s;
271 }
272
273 /* See documentation in cli-utils.h.  */
274
275 char *
276 extract_arg_const (const char **arg)
277 {
278   const char *result;
279
280   if (!*arg)
281     return NULL;
282
283   /* Find the start of the argument.  */
284   *arg = skip_spaces_const (*arg);
285   if (!**arg)
286     return NULL;
287   result = *arg;
288
289   /* Find the end of the argument.  */
290   *arg = skip_to_space_const (*arg + 1);
291
292   if (result == *arg)
293     return NULL;
294
295   return savestring (result, *arg - result);
296 }
297
298 /* See documentation in cli-utils.h.  */
299
300 char *
301 extract_arg (char **arg)
302 {
303   const char *arg_const = *arg;
304   char *result;
305
306   result = extract_arg_const (&arg_const);
307   *arg += arg_const - *arg;
308   return result;
309 }
310
311 /* See documentation in cli-utils.h.  */
312
313 int
314 check_for_argument (char **str, char *arg, int arg_len)
315 {
316   if (strncmp (*str, arg, arg_len) == 0
317       && ((*str)[arg_len] == '\0' || isspace ((*str)[arg_len])))
318     {
319       *str += arg_len;
320       return 1;
321     }
322   return 0;
323 }