xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/cli/cli-utils.c (revision c34236556bea94afcaca1782d7d228301edc3ea0)
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 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 }
287