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 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