xref: /dragonfly/contrib/gdb-7/gdb/cli/cli-utils.c (revision 3170ffd7)
1 /* CLI utilities.
2 
3    Copyright (c) 2011-2012 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 "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 
37 static int
38 get_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 
112 int
113 get_number (char **pp)
114 {
115   return get_number_trailer (pp, '\0');
116 }
117 
118 /* See documentation in cli-utils.h.  */
119 
120 void
121 init_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 
130 int
131 get_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 
193 int
194 number_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 
216 char *
217 skip_spaces (char *chp)
218 {
219   if (chp == NULL)
220     return NULL;
221   while (*chp && isspace (*chp))
222     chp++;
223   return chp;
224 }
225 
226 /* See documentation in cli-utils.h.  */
227 
228 char *
229 skip_to_space (char *chp)
230 {
231   if (chp == NULL)
232     return NULL;
233   while (*chp && !isspace (*chp))
234     chp++;
235   return chp;
236 }
237 
238 /* See documentation in cli-utils.h.  */
239 
240 char *
241 remove_trailing_whitespace (const char *start, char *s)
242 {
243   while (s > start && isspace (*(s - 1)))
244     --s;
245 
246   return s;
247 }
248