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