]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/cli/cli-utils.c
Update copyright year range in all GDB files
[thirdparty/binutils-gdb.git] / gdb / cli / cli-utils.c
1 /* CLI utilities.
2
3 Copyright (C) 2011-2018 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 /* See documentation in cli-utils.h. */
27
28 int
29 get_number_trailer (const char **pp, int trailer)
30 {
31 int retval = 0; /* default */
32 const char *p = *pp;
33 bool negative = false;
34
35 if (*p == '-')
36 {
37 ++p;
38 negative = true;
39 }
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 const char *p1 = p;
81 while (*p >= '0' && *p <= '9')
82 ++p;
83 if (p == p1)
84 /* There is no number here. (e.g. "cond a == b"). */
85 {
86 /* Skip non-numeric token. */
87 while (*p && !isspace((int) *p))
88 ++p;
89 /* Return zero, which caller must interpret as error. */
90 retval = 0;
91 }
92 else
93 retval = atoi (p1);
94 }
95 if (!(isspace (*p) || *p == '\0' || *p == trailer))
96 {
97 /* Trailing junk: return 0 and let caller print error msg. */
98 while (!(isspace (*p) || *p == '\0' || *p == trailer))
99 ++p;
100 retval = 0;
101 }
102 p = skip_spaces (p);
103 *pp = p;
104 return negative ? -retval : retval;
105 }
106
107 /* See documentation in cli-utils.h. */
108
109 int
110 get_number (const char **pp)
111 {
112 return get_number_trailer (pp, '\0');
113 }
114
115 /* See documentation in cli-utils.h. */
116
117 int
118 get_number (char **pp)
119 {
120 int result;
121 const char *p = *pp;
122
123 result = get_number_trailer (&p, '\0');
124 *pp = (char *) p;
125 return result;
126 }
127
128 /* See documentation in cli-utils.h. */
129
130 number_or_range_parser::number_or_range_parser (const char *string)
131 {
132 init (string);
133 }
134
135 /* See documentation in cli-utils.h. */
136
137 void
138 number_or_range_parser::init (const char *string)
139 {
140 m_finished = false;
141 m_cur_tok = string;
142 m_last_retval = 0;
143 m_end_value = 0;
144 m_end_ptr = NULL;
145 m_in_range = false;
146 }
147
148 /* See documentation in cli-utils.h. */
149
150 int
151 number_or_range_parser::get_number ()
152 {
153 if (m_in_range)
154 {
155 /* All number-parsing has already been done. Return the next
156 integer value (one greater than the saved previous value).
157 Do not advance the token pointer until the end of range is
158 reached. */
159
160 if (++m_last_retval == m_end_value)
161 {
162 /* End of range reached; advance token pointer. */
163 m_cur_tok = m_end_ptr;
164 m_in_range = false;
165 }
166 }
167 else if (*m_cur_tok != '-')
168 {
169 /* Default case: state->m_cur_tok is pointing either to a solo
170 number, or to the first number of a range. */
171 m_last_retval = get_number_trailer (&m_cur_tok, '-');
172 if (*m_cur_tok == '-')
173 {
174 const char **temp;
175
176 /* This is the start of a range (<number1> - <number2>).
177 Skip the '-', parse and remember the second number,
178 and also remember the end of the final token. */
179
180 temp = &m_end_ptr;
181 m_end_ptr = skip_spaces (m_cur_tok + 1);
182 m_end_value = ::get_number (temp);
183 if (m_end_value < m_last_retval)
184 {
185 error (_("inverted range"));
186 }
187 else if (m_end_value == m_last_retval)
188 {
189 /* Degenerate range (number1 == number2). Advance the
190 token pointer so that the range will be treated as a
191 single number. */
192 m_cur_tok = m_end_ptr;
193 }
194 else
195 m_in_range = true;
196 }
197 }
198 else
199 error (_("negative value"));
200 m_finished = *m_cur_tok == '\0';
201 return m_last_retval;
202 }
203
204 /* See documentation in cli-utils.h. */
205
206 void
207 number_or_range_parser::setup_range (int start_value, int end_value,
208 const char *end_ptr)
209 {
210 gdb_assert (start_value > 0);
211
212 m_in_range = true;
213 m_end_ptr = end_ptr;
214 m_last_retval = start_value - 1;
215 m_end_value = end_value;
216 }
217
218 /* Accept a number and a string-form list of numbers such as is
219 accepted by get_number_or_range. Return TRUE if the number is
220 in the list.
221
222 By definition, an empty list includes all numbers. This is to
223 be interpreted as typing a command such as "delete break" with
224 no arguments. */
225
226 int
227 number_is_in_list (const char *list, int number)
228 {
229 if (list == NULL || *list == '\0')
230 return 1;
231
232 number_or_range_parser parser (list);
233 while (!parser.finished ())
234 {
235 int gotnum = parser.get_number ();
236
237 if (gotnum == 0)
238 error (_("Args must be numbers or '$' variables."));
239 if (gotnum == number)
240 return 1;
241 }
242 return 0;
243 }
244
245 /* See documentation in cli-utils.h. */
246
247 const char *
248 remove_trailing_whitespace (const char *start, const char *s)
249 {
250 while (s > start && isspace (*(s - 1)))
251 --s;
252
253 return s;
254 }
255
256 /* See documentation in cli-utils.h. */
257
258 std::string
259 extract_arg (const char **arg)
260 {
261 const char *result;
262
263 if (!*arg)
264 return std::string ();
265
266 /* Find the start of the argument. */
267 *arg = skip_spaces (*arg);
268 if (!**arg)
269 return std::string ();
270 result = *arg;
271
272 /* Find the end of the argument. */
273 *arg = skip_to_space (*arg + 1);
274
275 if (result == *arg)
276 return std::string ();
277
278 return std::string (result, *arg - result);
279 }
280
281 /* See documentation in cli-utils.h. */
282
283 std::string
284 extract_arg (char **arg)
285 {
286 const char *arg_const = *arg;
287 std::string result;
288
289 result = extract_arg (&arg_const);
290 *arg += arg_const - *arg;
291 return result;
292 }
293
294 /* See documentation in cli-utils.h. */
295
296 int
297 check_for_argument (const char **str, const char *arg, int arg_len)
298 {
299 if (strncmp (*str, arg, arg_len) == 0
300 && ((*str)[arg_len] == '\0' || isspace ((*str)[arg_len])))
301 {
302 *str += arg_len;
303 return 1;
304 }
305 return 0;
306 }