1 /* CLI utilities. 2 3 Copyright (C) 2011-2013 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 /* A const-correct version of the above. */ 227 228 const char * 229 skip_spaces_const (const 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 const char * 241 skip_to_space_const (const char *chp) 242 { 243 if (chp == NULL) 244 return NULL; 245 while (*chp && !isspace (*chp)) 246 chp++; 247 return chp; 248 } 249 250 /* See documentation in cli-utils.h. */ 251 252 char * 253 remove_trailing_whitespace (const char *start, char *s) 254 { 255 while (s > start && isspace (*(s - 1))) 256 --s; 257 258 return s; 259 } 260 261 /* See documentation in cli-utils.h. */ 262 263 char * 264 extract_arg (char **arg) 265 { 266 char *result, *copy; 267 268 if (!*arg) 269 return NULL; 270 271 /* Find the start of the argument. */ 272 *arg = skip_spaces (*arg); 273 if (!**arg) 274 return NULL; 275 result = *arg; 276 277 /* Find the end of the argument. */ 278 *arg = skip_to_space (*arg + 1); 279 280 if (result == *arg) 281 return NULL; 282 283 copy = xmalloc (*arg - result + 1); 284 memcpy (copy, result, *arg - result); 285 copy[*arg - result] = '\0'; 286 287 return copy; 288 } 289 290 /* See documentation in cli-utils.h. */ 291 292 int 293 check_for_argument (char **str, char *arg, int arg_len) 294 { 295 if (strncmp (*str, arg, arg_len) == 0 296 && ((*str)[arg_len] == '\0' || isspace ((*str)[arg_len]))) 297 { 298 *str += arg_len; 299 return 1; 300 } 301 return 0; 302 } 303