1 /* CLI utilities. 2 3 Copyright (C) 2011-2017 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 number_or_range_parser::number_or_range_parser (const char *string) 125 { 126 init (string); 127 } 128 129 /* See documentation in cli-utils.h. */ 130 131 void 132 number_or_range_parser::init (const char *string) 133 { 134 m_finished = false; 135 m_cur_tok = string; 136 m_last_retval = 0; 137 m_end_value = 0; 138 m_end_ptr = NULL; 139 m_in_range = false; 140 } 141 142 /* See documentation in cli-utils.h. */ 143 144 int 145 number_or_range_parser::get_number () 146 { 147 if (m_in_range) 148 { 149 /* All number-parsing has already been done. Return the next 150 integer value (one greater than the saved previous value). 151 Do not advance the token pointer until the end of range is 152 reached. */ 153 154 if (++m_last_retval == m_end_value) 155 { 156 /* End of range reached; advance token pointer. */ 157 m_cur_tok = m_end_ptr; 158 m_in_range = false; 159 } 160 } 161 else if (*m_cur_tok != '-') 162 { 163 /* Default case: state->m_cur_tok is pointing either to a solo 164 number, or to the first number of a range. */ 165 m_last_retval = get_number_trailer (&m_cur_tok, '-'); 166 if (*m_cur_tok == '-') 167 { 168 const char **temp; 169 170 /* This is the start of a range (<number1> - <number2>). 171 Skip the '-', parse and remember the second number, 172 and also remember the end of the final token. */ 173 174 temp = &m_end_ptr; 175 m_end_ptr = skip_spaces_const (m_cur_tok + 1); 176 m_end_value = get_number_const (temp); 177 if (m_end_value < m_last_retval) 178 { 179 error (_("inverted range")); 180 } 181 else if (m_end_value == m_last_retval) 182 { 183 /* Degenerate range (number1 == number2). Advance the 184 token pointer so that the range will be treated as a 185 single number. */ 186 m_cur_tok = m_end_ptr; 187 } 188 else 189 m_in_range = true; 190 } 191 } 192 else 193 error (_("negative value")); 194 m_finished = *m_cur_tok == '\0'; 195 return m_last_retval; 196 } 197 198 /* See documentation in cli-utils.h. */ 199 200 void 201 number_or_range_parser::setup_range (int start_value, int end_value, 202 const char *end_ptr) 203 { 204 gdb_assert (start_value > 0); 205 206 m_in_range = true; 207 m_end_ptr = end_ptr; 208 m_last_retval = start_value - 1; 209 m_end_value = end_value; 210 } 211 212 /* Accept a number and a string-form list of numbers such as is 213 accepted by get_number_or_range. Return TRUE if the number is 214 in the list. 215 216 By definition, an empty list includes all numbers. This is to 217 be interpreted as typing a command such as "delete break" with 218 no arguments. */ 219 220 int 221 number_is_in_list (const char *list, int number) 222 { 223 if (list == NULL || *list == '\0') 224 return 1; 225 226 number_or_range_parser parser (list); 227 while (!parser.finished ()) 228 { 229 int gotnum = parser.get_number (); 230 231 if (gotnum == 0) 232 error (_("Args must be numbers or '$' variables.")); 233 if (gotnum == number) 234 return 1; 235 } 236 return 0; 237 } 238 239 /* See documentation in cli-utils.h. */ 240 241 const char * 242 remove_trailing_whitespace (const char *start, const char *s) 243 { 244 while (s > start && isspace (*(s - 1))) 245 --s; 246 247 return s; 248 } 249 250 /* See documentation in cli-utils.h. */ 251 252 char * 253 extract_arg_const (const char **arg) 254 { 255 const char *result; 256 257 if (!*arg) 258 return NULL; 259 260 /* Find the start of the argument. */ 261 *arg = skip_spaces_const (*arg); 262 if (!**arg) 263 return NULL; 264 result = *arg; 265 266 /* Find the end of the argument. */ 267 *arg = skip_to_space_const (*arg + 1); 268 269 if (result == *arg) 270 return NULL; 271 272 return savestring (result, *arg - result); 273 } 274 275 /* See documentation in cli-utils.h. */ 276 277 char * 278 extract_arg (char **arg) 279 { 280 const char *arg_const = *arg; 281 char *result; 282 283 result = extract_arg_const (&arg_const); 284 *arg += arg_const - *arg; 285 return result; 286 } 287 288 /* See documentation in cli-utils.h. */ 289 290 int 291 check_for_argument (const char **str, const char *arg, int arg_len) 292 { 293 if (strncmp (*str, arg, arg_len) == 0 294 && ((*str)[arg_len] == '\0' || isspace ((*str)[arg_len]))) 295 { 296 *str += arg_len; 297 return 1; 298 } 299 return 0; 300 } 301