GDB (API)
|
00001 /* CLI utilities. 00002 00003 Copyright (C) 2011-2013 Free Software Foundation, Inc. 00004 00005 This file is part of GDB. 00006 00007 This program is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation; either version 3 of the License, or 00010 (at your option) any later version. 00011 00012 This program is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 00019 00020 #include "defs.h" 00021 #include "cli/cli-utils.h" 00022 #include "gdb_string.h" 00023 #include "value.h" 00024 #include "gdb_assert.h" 00025 00026 #include <ctype.h> 00027 00028 /* *PP is a string denoting a number. Get the number of the. Advance 00029 *PP after the string and any trailing whitespace. 00030 00031 Currently the string can either be a number, or "$" followed by the 00032 name of a convenience variable, or ("$" or "$$") followed by digits. 00033 00034 TRAILER is a character which can be found after the number; most 00035 commonly this is `-'. If you don't want a trailer, use \0. */ 00036 00037 static int 00038 get_number_trailer (char **pp, int trailer) 00039 { 00040 int retval = 0; /* default */ 00041 char *p = *pp; 00042 00043 if (*p == '$') 00044 { 00045 struct value *val = value_from_history_ref (p, &p); 00046 00047 if (val) /* Value history reference */ 00048 { 00049 if (TYPE_CODE (value_type (val)) == TYPE_CODE_INT) 00050 retval = value_as_long (val); 00051 else 00052 { 00053 printf_filtered (_("History value must have integer type.")); 00054 retval = 0; 00055 } 00056 } 00057 else /* Convenience variable */ 00058 { 00059 /* Internal variable. Make a copy of the name, so we can 00060 null-terminate it to pass to lookup_internalvar(). */ 00061 char *varname; 00062 char *start = ++p; 00063 LONGEST val; 00064 00065 while (isalnum (*p) || *p == '_') 00066 p++; 00067 varname = (char *) alloca (p - start + 1); 00068 strncpy (varname, start, p - start); 00069 varname[p - start] = '\0'; 00070 if (get_internalvar_integer (lookup_internalvar (varname), &val)) 00071 retval = (int) val; 00072 else 00073 { 00074 printf_filtered (_("Convenience variable must " 00075 "have integer value.\n")); 00076 retval = 0; 00077 } 00078 } 00079 } 00080 else 00081 { 00082 if (*p == '-') 00083 ++p; 00084 while (*p >= '0' && *p <= '9') 00085 ++p; 00086 if (p == *pp) 00087 /* There is no number here. (e.g. "cond a == b"). */ 00088 { 00089 /* Skip non-numeric token. */ 00090 while (*p && !isspace((int) *p)) 00091 ++p; 00092 /* Return zero, which caller must interpret as error. */ 00093 retval = 0; 00094 } 00095 else 00096 retval = atoi (*pp); 00097 } 00098 if (!(isspace (*p) || *p == '\0' || *p == trailer)) 00099 { 00100 /* Trailing junk: return 0 and let caller print error msg. */ 00101 while (!(isspace (*p) || *p == '\0' || *p == trailer)) 00102 ++p; 00103 retval = 0; 00104 } 00105 p = skip_spaces (p); 00106 *pp = p; 00107 return retval; 00108 } 00109 00110 /* See documentation in cli-utils.h. */ 00111 00112 int 00113 get_number (char **pp) 00114 { 00115 return get_number_trailer (pp, '\0'); 00116 } 00117 00118 /* See documentation in cli-utils.h. */ 00119 00120 void 00121 init_number_or_range (struct get_number_or_range_state *state, 00122 char *string) 00123 { 00124 memset (state, 0, sizeof (*state)); 00125 state->string = string; 00126 } 00127 00128 /* See documentation in cli-utils.h. */ 00129 00130 int 00131 get_number_or_range (struct get_number_or_range_state *state) 00132 { 00133 if (*state->string != '-') 00134 { 00135 /* Default case: state->string is pointing either to a solo 00136 number, or to the first number of a range. */ 00137 state->last_retval = get_number_trailer (&state->string, '-'); 00138 if (*state->string == '-') 00139 { 00140 char **temp; 00141 00142 /* This is the start of a range (<number1> - <number2>). 00143 Skip the '-', parse and remember the second number, 00144 and also remember the end of the final token. */ 00145 00146 temp = &state->end_ptr; 00147 state->end_ptr = skip_spaces (state->string + 1); 00148 state->end_value = get_number (temp); 00149 if (state->end_value < state->last_retval) 00150 { 00151 error (_("inverted range")); 00152 } 00153 else if (state->end_value == state->last_retval) 00154 { 00155 /* Degenerate range (number1 == number2). Advance the 00156 token pointer so that the range will be treated as a 00157 single number. */ 00158 state->string = state->end_ptr; 00159 } 00160 else 00161 state->in_range = 1; 00162 } 00163 } 00164 else if (! state->in_range) 00165 error (_("negative value")); 00166 else 00167 { 00168 /* state->string points to the '-' that betokens a range. All 00169 number-parsing has already been done. Return the next 00170 integer value (one greater than the saved previous value). 00171 Do not advance the token pointer until the end of range 00172 is reached. */ 00173 00174 if (++state->last_retval == state->end_value) 00175 { 00176 /* End of range reached; advance token pointer. */ 00177 state->string = state->end_ptr; 00178 state->in_range = 0; 00179 } 00180 } 00181 state->finished = *state->string == '\0'; 00182 return state->last_retval; 00183 } 00184 00185 /* Accept a number and a string-form list of numbers such as is 00186 accepted by get_number_or_range. Return TRUE if the number is 00187 in the list. 00188 00189 By definition, an empty list includes all numbers. This is to 00190 be interpreted as typing a command such as "delete break" with 00191 no arguments. */ 00192 00193 int 00194 number_is_in_list (char *list, int number) 00195 { 00196 struct get_number_or_range_state state; 00197 00198 if (list == NULL || *list == '\0') 00199 return 1; 00200 00201 init_number_or_range (&state, list); 00202 while (!state.finished) 00203 { 00204 int gotnum = get_number_or_range (&state); 00205 00206 if (gotnum == 0) 00207 error (_("Args must be numbers or '$' variables.")); 00208 if (gotnum == number) 00209 return 1; 00210 } 00211 return 0; 00212 } 00213 00214 /* See documentation in cli-utils.h. */ 00215 00216 char * 00217 skip_spaces (char *chp) 00218 { 00219 if (chp == NULL) 00220 return NULL; 00221 while (*chp && isspace (*chp)) 00222 chp++; 00223 return chp; 00224 } 00225 00226 /* A const-correct version of the above. */ 00227 00228 const char * 00229 skip_spaces_const (const char *chp) 00230 { 00231 if (chp == NULL) 00232 return NULL; 00233 while (*chp && isspace (*chp)) 00234 chp++; 00235 return chp; 00236 } 00237 00238 /* See documentation in cli-utils.h. */ 00239 00240 const char * 00241 skip_to_space_const (const char *chp) 00242 { 00243 if (chp == NULL) 00244 return NULL; 00245 while (*chp && !isspace (*chp)) 00246 chp++; 00247 return chp; 00248 } 00249 00250 /* See documentation in cli-utils.h. */ 00251 00252 char * 00253 remove_trailing_whitespace (const char *start, char *s) 00254 { 00255 while (s > start && isspace (*(s - 1))) 00256 --s; 00257 00258 return s; 00259 } 00260 00261 /* See documentation in cli-utils.h. */ 00262 00263 char * 00264 extract_arg (char **arg) 00265 { 00266 char *result, *copy; 00267 00268 if (!*arg) 00269 return NULL; 00270 00271 /* Find the start of the argument. */ 00272 *arg = skip_spaces (*arg); 00273 if (!**arg) 00274 return NULL; 00275 result = *arg; 00276 00277 /* Find the end of the argument. */ 00278 *arg = skip_to_space (*arg + 1); 00279 00280 if (result == *arg) 00281 return NULL; 00282 00283 copy = xmalloc (*arg - result + 1); 00284 memcpy (copy, result, *arg - result); 00285 copy[*arg - result] = '\0'; 00286 00287 return copy; 00288 } 00289 00290 /* See documentation in cli-utils.h. */ 00291 00292 int 00293 check_for_argument (char **str, char *arg, int arg_len) 00294 { 00295 if (strncmp (*str, arg, arg_len) == 0 00296 && ((*str)[arg_len] == '\0' || isspace ((*str)[arg_len]))) 00297 { 00298 *str += arg_len; 00299 return 1; 00300 } 00301 return 0; 00302 }