1 /* CLI utilities. 2 3 Copyright (C) 2011-2016 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 /* See documentation in cli-utils.h. */ 27 28 int 29 get_number_trailer (const char **pp, int trailer) 30 { 31 int retval = 0; /* default */ 32 const char *p = *pp; 33 34 if (*p == '$') 35 { 36 struct value *val = value_from_history_ref (p, &p); 37 38 if (val) /* Value history reference */ 39 { 40 if (TYPE_CODE (value_type (val)) == TYPE_CODE_INT) 41 retval = value_as_long (val); 42 else 43 { 44 printf_filtered (_("History value must have integer type.\n")); 45 retval = 0; 46 } 47 } 48 else /* Convenience variable */ 49 { 50 /* Internal variable. Make a copy of the name, so we can 51 null-terminate it to pass to lookup_internalvar(). */ 52 char *varname; 53 const char *start = ++p; 54 LONGEST val; 55 56 while (isalnum (*p) || *p == '_') 57 p++; 58 varname = (char *) alloca (p - start + 1); 59 strncpy (varname, start, p - start); 60 varname[p - start] = '\0'; 61 if (get_internalvar_integer (lookup_internalvar (varname), &val)) 62 retval = (int) val; 63 else 64 { 65 printf_filtered (_("Convenience variable must " 66 "have integer value.\n")); 67 retval = 0; 68 } 69 } 70 } 71 else 72 { 73 if (*p == '-') 74 ++p; 75 while (*p >= '0' && *p <= '9') 76 ++p; 77 if (p == *pp) 78 /* There is no number here. (e.g. "cond a == b"). */ 79 { 80 /* Skip non-numeric token. */ 81 while (*p && !isspace((int) *p)) 82 ++p; 83 /* Return zero, which caller must interpret as error. */ 84 retval = 0; 85 } 86 else 87 retval = atoi (*pp); 88 } 89 if (!(isspace (*p) || *p == '\0' || *p == trailer)) 90 { 91 /* Trailing junk: return 0 and let caller print error msg. */ 92 while (!(isspace (*p) || *p == '\0' || *p == trailer)) 93 ++p; 94 retval = 0; 95 } 96 p = skip_spaces_const (p); 97 *pp = p; 98 return retval; 99 } 100 101 /* See documentation in cli-utils.h. */ 102 103 int 104 get_number_const (const char **pp) 105 { 106 return get_number_trailer (pp, '\0'); 107 } 108 109 /* See documentation in cli-utils.h. */ 110 111 int 112 get_number (char **pp) 113 { 114 int result; 115 const char *p = *pp; 116 117 result = get_number_trailer (&p, '\0'); 118 *pp = (char *) p; 119 return result; 120 } 121 122 /* See documentation in cli-utils.h. */ 123 124 void 125 init_number_or_range (struct get_number_or_range_state *state, 126 const char *string) 127 { 128 memset (state, 0, sizeof (*state)); 129 state->string = string; 130 } 131 132 /* See documentation in cli-utils.h. */ 133 134 int 135 get_number_or_range (struct get_number_or_range_state *state) 136 { 137 if (state->in_range) 138 { 139 /* All number-parsing has already been done. Return the next 140 integer value (one greater than the saved previous value). 141 Do not advance the token pointer until the end of range is 142 reached. */ 143 144 if (++state->last_retval == state->end_value) 145 { 146 /* End of range reached; advance token pointer. */ 147 state->string = state->end_ptr; 148 state->in_range = 0; 149 } 150 } 151 else if (*state->string != '-') 152 { 153 /* Default case: state->string is pointing either to a solo 154 number, or to the first number of a range. */ 155 state->last_retval = get_number_trailer (&state->string, '-'); 156 if (*state->string == '-') 157 { 158 const char **temp; 159 160 /* This is the start of a range (<number1> - <number2>). 161 Skip the '-', parse and remember the second number, 162 and also remember the end of the final token. */ 163 164 temp = &state->end_ptr; 165 state->end_ptr = skip_spaces_const (state->string + 1); 166 state->end_value = get_number_const (temp); 167 if (state->end_value < state->last_retval) 168 { 169 error (_("inverted range")); 170 } 171 else if (state->end_value == state->last_retval) 172 { 173 /* Degenerate range (number1 == number2). Advance the 174 token pointer so that the range will be treated as a 175 single number. */ 176 state->string = state->end_ptr; 177 } 178 else 179 state->in_range = 1; 180 } 181 } 182 else 183 error (_("negative value")); 184 state->finished = *state->string == '\0'; 185 return state->last_retval; 186 } 187 188 /* See documentation in cli-utils.h. */ 189 190 void 191 number_range_setup_range (struct get_number_or_range_state *state, 192 int start_value, int end_value, const char *end_ptr) 193 { 194 gdb_assert (start_value > 0); 195 196 state->in_range = 1; 197 state->end_ptr = end_ptr; 198 state->last_retval = start_value - 1; 199 state->end_value = end_value; 200 } 201 202 /* Accept a number and a string-form list of numbers such as is 203 accepted by get_number_or_range. Return TRUE if the number is 204 in the list. 205 206 By definition, an empty list includes all numbers. This is to 207 be interpreted as typing a command such as "delete break" with 208 no arguments. */ 209 210 int 211 number_is_in_list (const char *list, int number) 212 { 213 struct get_number_or_range_state state; 214 215 if (list == NULL || *list == '\0') 216 return 1; 217 218 init_number_or_range (&state, list); 219 while (!state.finished) 220 { 221 int gotnum = get_number_or_range (&state); 222 223 if (gotnum == 0) 224 error (_("Args must be numbers or '$' variables.")); 225 if (gotnum == number) 226 return 1; 227 } 228 return 0; 229 } 230 231 /* See documentation in cli-utils.h. */ 232 233 char * 234 remove_trailing_whitespace (const char *start, char *s) 235 { 236 while (s > start && isspace (*(s - 1))) 237 --s; 238 239 return s; 240 } 241 242 /* See documentation in cli-utils.h. */ 243 244 char * 245 extract_arg_const (const char **arg) 246 { 247 const char *result; 248 249 if (!*arg) 250 return NULL; 251 252 /* Find the start of the argument. */ 253 *arg = skip_spaces_const (*arg); 254 if (!**arg) 255 return NULL; 256 result = *arg; 257 258 /* Find the end of the argument. */ 259 *arg = skip_to_space_const (*arg + 1); 260 261 if (result == *arg) 262 return NULL; 263 264 return savestring (result, *arg - result); 265 } 266 267 /* See documentation in cli-utils.h. */ 268 269 char * 270 extract_arg (char **arg) 271 { 272 const char *arg_const = *arg; 273 char *result; 274 275 result = extract_arg_const (&arg_const); 276 *arg += arg_const - *arg; 277 return result; 278 } 279 280 /* See documentation in cli-utils.h. */ 281 282 int 283 check_for_argument (char **str, char *arg, int arg_len) 284 { 285 if (strncmp (*str, arg, arg_len) == 0 286 && ((*str)[arg_len] == '\0' || isspace ((*str)[arg_len]))) 287 { 288 *str += arg_len; 289 return 1; 290 } 291 return 0; 292 } 293