xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/cli/cli-utils.c (revision d909946ca08dceb44d7d0f22ec9488679695d976)
1 /* CLI utilities.
2 
3    Copyright (C) 2011-2015 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 }
323