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