2011-02-24 Michael Snyder <msnyder@vmware.com>
[platform/upstream/binutils.git] / gdb / cli / cli-utils.c
1 /* CLI utilities.
2
3    Copyright (c) 2011 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 int
121 get_number_or_range (char **pp)
122 {
123   static int last_retval, end_value;
124   static char *end_ptr;
125   static int in_range = 0;
126
127   if (**pp != '-')
128     {
129       /* Default case: pp is pointing either to a solo number, 
130          or to the first number of a range.  */
131       last_retval = get_number_trailer (pp, '-');
132       if (**pp == '-')
133         {
134           char **temp;
135
136           /* This is the start of a range (<number1> - <number2>).
137              Skip the '-', parse and remember the second number,
138              and also remember the end of the final token.  */
139
140           temp = &end_ptr; 
141           end_ptr = *pp + 1; 
142           while (isspace ((int) *end_ptr))
143             end_ptr++;  /* skip white space */
144           end_value = get_number (temp);
145           if (end_value < last_retval) 
146             {
147               error (_("inverted range"));
148             }
149           else if (end_value == last_retval)
150             {
151               /* Degenerate range (number1 == number2).  Advance the
152                  token pointer so that the range will be treated as a
153                  single number.  */ 
154               *pp = end_ptr;
155             }
156           else
157             in_range = 1;
158         }
159     }
160   else if (! in_range)
161     error (_("negative value"));
162   else
163     {
164       /* pp points to the '-' that betokens a range.  All
165          number-parsing has already been done.  Return the next
166          integer value (one greater than the saved previous value).
167          Do not advance the token pointer 'pp' until the end of range
168          is reached.  */
169
170       if (++last_retval == end_value)
171         {
172           /* End of range reached; advance token pointer.  */
173           *pp = end_ptr;
174           in_range = 0;
175         }
176     }
177   return last_retval;
178 }
179
180 /* Accept a number and a string-form list of numbers such as is 
181    accepted by get_number_or_range.  Return TRUE if the number is
182    in the list.
183
184    By definition, an empty list includes all numbers.  This is to 
185    be interpreted as typing a command such as "delete break" with 
186    no arguments.  */
187
188 int
189 number_is_in_list (char *list, int number)
190 {
191   if (list == NULL || *list == '\0')
192     return 1;
193
194   while (*list != '\0')
195     {
196       int gotnum = get_number_or_range (&list);
197
198       if (gotnum == 0)
199         error (_("Args must be numbers or '$' variables."));
200       if (gotnum == number)
201         return 1;
202     }
203   return 0;
204 }
205
206 /* See documentation in cli-utils.h.  */
207
208 char *
209 skip_spaces (char *chp)
210 {
211   if (chp == NULL)
212     return NULL;
213   while (*chp && isspace (*chp))
214     chp++;
215   return chp;
216 }
217
218 /* See documentation in cli-utils.h.  */
219
220 char *
221 skip_to_space (char *chp)
222 {
223   if (chp == NULL)
224     return NULL;
225   while (*chp && !isspace (*chp))
226     chp++;
227   return chp;
228 }