Upgrade GDB from 7.4.1 to 7.6.1 on the vendor branch
[dragonfly.git] / contrib / gdb-7 / gdb / cli / cli-utils.c
1 /* CLI utilities.
2
3    Copyright (C) 2011-2013 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 "gdb_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 (char **pp, int trailer)
39 {
40   int retval = 0;       /* default */
41   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."));
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           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 (p);
106   *pp = p;
107   return retval;
108 }
109
110 /* See documentation in cli-utils.h.  */
111
112 int
113 get_number (char **pp)
114 {
115   return get_number_trailer (pp, '\0');
116 }
117
118 /* See documentation in cli-utils.h.  */
119
120 void
121 init_number_or_range (struct get_number_or_range_state *state,
122                       char *string)
123 {
124   memset (state, 0, sizeof (*state));
125   state->string = string;
126 }
127
128 /* See documentation in cli-utils.h.  */
129
130 int
131 get_number_or_range (struct get_number_or_range_state *state)
132 {
133   if (*state->string != '-')
134     {
135       /* Default case: state->string is pointing either to a solo
136          number, or to the first number of a range.  */
137       state->last_retval = get_number_trailer (&state->string, '-');
138       if (*state->string == '-')
139         {
140           char **temp;
141
142           /* This is the start of a range (<number1> - <number2>).
143              Skip the '-', parse and remember the second number,
144              and also remember the end of the final token.  */
145
146           temp = &state->end_ptr; 
147           state->end_ptr = skip_spaces (state->string + 1);
148           state->end_value = get_number (temp);
149           if (state->end_value < state->last_retval) 
150             {
151               error (_("inverted range"));
152             }
153           else if (state->end_value == state->last_retval)
154             {
155               /* Degenerate range (number1 == number2).  Advance the
156                  token pointer so that the range will be treated as a
157                  single number.  */ 
158               state->string = state->end_ptr;
159             }
160           else
161             state->in_range = 1;
162         }
163     }
164   else if (! state->in_range)
165     error (_("negative value"));
166   else
167     {
168       /* state->string points to the '-' that betokens a range.  All
169          number-parsing has already been done.  Return the next
170          integer value (one greater than the saved previous value).
171          Do not advance the token pointer until the end of range
172          is reached.  */
173
174       if (++state->last_retval == state->end_value)
175         {
176           /* End of range reached; advance token pointer.  */
177           state->string = state->end_ptr;
178           state->in_range = 0;
179         }
180     }
181   state->finished = *state->string == '\0';
182   return state->last_retval;
183 }
184
185 /* Accept a number and a string-form list of numbers such as is 
186    accepted by get_number_or_range.  Return TRUE if the number is
187    in the list.
188
189    By definition, an empty list includes all numbers.  This is to 
190    be interpreted as typing a command such as "delete break" with 
191    no arguments.  */
192
193 int
194 number_is_in_list (char *list, int number)
195 {
196   struct get_number_or_range_state state;
197
198   if (list == NULL || *list == '\0')
199     return 1;
200
201   init_number_or_range (&state, list);
202   while (!state.finished)
203     {
204       int gotnum = get_number_or_range (&state);
205
206       if (gotnum == 0)
207         error (_("Args must be numbers or '$' variables."));
208       if (gotnum == number)
209         return 1;
210     }
211   return 0;
212 }
213
214 /* See documentation in cli-utils.h.  */
215
216 char *
217 skip_spaces (char *chp)
218 {
219   if (chp == NULL)
220     return NULL;
221   while (*chp && isspace (*chp))
222     chp++;
223   return chp;
224 }
225
226 /* A const-correct version of the above.  */
227
228 const char *
229 skip_spaces_const (const char *chp)
230 {
231   if (chp == NULL)
232     return NULL;
233   while (*chp && isspace (*chp))
234     chp++;
235   return chp;
236 }
237
238 /* See documentation in cli-utils.h.  */
239
240 const char *
241 skip_to_space_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 char *
253 remove_trailing_whitespace (const char *start, char *s)
254 {
255   while (s > start && isspace (*(s - 1)))
256     --s;
257
258   return s;
259 }
260
261 /* See documentation in cli-utils.h.  */
262
263 char *
264 extract_arg (char **arg)
265 {
266   char *result, *copy;
267
268   if (!*arg)
269     return NULL;
270
271   /* Find the start of the argument.  */
272   *arg = skip_spaces (*arg);
273   if (!**arg)
274     return NULL;
275   result = *arg;
276
277   /* Find the end of the argument.  */
278   *arg = skip_to_space (*arg + 1);
279
280   if (result == *arg)
281     return NULL;
282
283   copy = xmalloc (*arg - result + 1);
284   memcpy (copy, result, *arg - result);
285   copy[*arg - result] = '\0';
286
287   return copy;
288 }
289
290 /* See documentation in cli-utils.h.  */
291
292 int
293 check_for_argument (char **str, char *arg, int arg_len)
294 {
295   if (strncmp (*str, arg, arg_len) == 0
296       && ((*str)[arg_len] == '\0' || isspace ((*str)[arg_len])))
297     {
298       *str += arg_len;
299       return 1;
300     }
301   return 0;
302 }