]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/cli/cli-utils.c
GDB copyright headers update after running GDB's copyright.py script.
[thirdparty/binutils-gdb.git] / gdb / cli / cli-utils.c
1 /* CLI utilities.
2
3 Copyright (C) 2011-2016 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 remove_trailing_whitespace (const char *start, char *s)
229 {
230 while (s > start && isspace (*(s - 1)))
231 --s;
232
233 return s;
234 }
235
236 /* See documentation in cli-utils.h. */
237
238 char *
239 extract_arg_const (const char **arg)
240 {
241 const char *result;
242
243 if (!*arg)
244 return NULL;
245
246 /* Find the start of the argument. */
247 *arg = skip_spaces_const (*arg);
248 if (!**arg)
249 return NULL;
250 result = *arg;
251
252 /* Find the end of the argument. */
253 *arg = skip_to_space_const (*arg + 1);
254
255 if (result == *arg)
256 return NULL;
257
258 return savestring (result, *arg - result);
259 }
260
261 /* See documentation in cli-utils.h. */
262
263 char *
264 extract_arg (char **arg)
265 {
266 const char *arg_const = *arg;
267 char *result;
268
269 result = extract_arg_const (&arg_const);
270 *arg += arg_const - *arg;
271 return result;
272 }
273
274 /* See documentation in cli-utils.h. */
275
276 int
277 check_for_argument (char **str, char *arg, int arg_len)
278 {
279 if (strncmp (*str, arg, arg_len) == 0
280 && ((*str)[arg_len] == '\0' || isspace ((*str)[arg_len])))
281 {
282 *str += arg_len;
283 return 1;
284 }
285 return 0;
286 }