Upgrade GDB from 7.4.1 to 7.6.1 on the vendor branch
[dragonfly.git] / contrib / gdb-7 / gdb / cli / cli-utils.c
CommitLineData
c50c785c
JM
1/* CLI utilities.
2
ef5ccd6c 3 Copyright (C) 2011-2013 Free Software Foundation, Inc.
c50c785c
JM
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
37static int
38get_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
112int
113get_number (char **pp)
114{
115 return get_number_trailer (pp, '\0');
116}
117
118/* See documentation in cli-utils.h. */
119
120void
121init_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
130int
131get_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
193int
194number_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
216char *
217skip_spaces (char *chp)
218{
219 if (chp == NULL)
220 return NULL;
221 while (*chp && isspace (*chp))
222 chp++;
223 return chp;
224}
225
ef5ccd6c
JM
226/* A const-correct version of the above. */
227
228const char *
229skip_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
c50c785c
JM
238/* See documentation in cli-utils.h. */
239
ef5ccd6c
JM
240const char *
241skip_to_space_const (const char *chp)
c50c785c
JM
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
252char *
253remove_trailing_whitespace (const char *start, char *s)
254{
255 while (s > start && isspace (*(s - 1)))
256 --s;
257
258 return s;
259}
ef5ccd6c
JM
260
261/* See documentation in cli-utils.h. */
262
263char *
264extract_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
292int
293check_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}