Fix PR cli/23785: Check if file exists when invoking "restore FILE binary"
[external/binutils.git] / gdb / cli / cli-utils.c
1 /* CLI utilities.
2
3    Copyright (C) 2011-2018 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   bool negative = false;
34
35   if (*p == '-')
36     {
37       ++p;
38       negative = true;
39     }
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 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),
69                                        &longest_val))
70             retval = (int) longest_val;
71           else
72             {
73               printf_filtered (_("Convenience variable must "
74                                  "have integer value.\n"));
75               retval = 0;
76             }
77         }
78     }
79   else
80     {
81       const char *p1 = p;
82       while (*p >= '0' && *p <= '9')
83         ++p;
84       if (p == p1)
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 (p1);
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 (p);
104   *pp = p;
105   return negative ? -retval : retval;
106 }
107
108 /* See documentation in cli-utils.h.  */
109
110 int
111 get_number (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 number_or_range_parser::number_or_range_parser (const char *string)
132 {
133   init (string);
134 }
135
136 /* See documentation in cli-utils.h.  */
137
138 void
139 number_or_range_parser::init (const char *string)
140 {
141   m_cur_tok = string;
142   m_last_retval = 0;
143   m_end_value = 0;
144   m_end_ptr = NULL;
145   m_in_range = false;
146 }
147
148 /* See documentation in cli-utils.h.  */
149
150 int
151 number_or_range_parser::get_number ()
152 {
153   if (m_in_range)
154     {
155       /* All number-parsing has already been done.  Return the next
156          integer value (one greater than the saved previous value).
157          Do not advance the token pointer until the end of range is
158          reached.  */
159
160       if (++m_last_retval == m_end_value)
161         {
162           /* End of range reached; advance token pointer.  */
163           m_cur_tok = m_end_ptr;
164           m_in_range = false;
165         }
166     }
167   else if (*m_cur_tok != '-')
168     {
169       /* Default case: state->m_cur_tok is pointing either to a solo
170          number, or to the first number of a range.  */
171       m_last_retval = get_number_trailer (&m_cur_tok, '-');
172       /* If get_number_trailer has found a -, it might be the start
173          of a command option.  So, do not parse a range if the - is
174          followed by an alpha.  */
175       if (*m_cur_tok == '-' && !isalpha (*(m_cur_tok + 1)))
176         {
177           const char **temp;
178
179           /* This is the start of a range (<number1> - <number2>).
180              Skip the '-', parse and remember the second number,
181              and also remember the end of the final token.  */
182
183           temp = &m_end_ptr;
184           m_end_ptr = skip_spaces (m_cur_tok + 1);
185           m_end_value = ::get_number (temp);
186           if (m_end_value < m_last_retval)
187             {
188               error (_("inverted range"));
189             }
190           else if (m_end_value == m_last_retval)
191             {
192               /* Degenerate range (number1 == number2).  Advance the
193                  token pointer so that the range will be treated as a
194                  single number.  */
195               m_cur_tok = m_end_ptr;
196             }
197           else
198             m_in_range = true;
199         }
200     }
201   else
202     {
203       if (isdigit (*(m_cur_tok + 1)))
204         error (_("negative value"));
205       if (*(m_cur_tok + 1) == '$')
206         {
207           /* Convenience variable.  */
208           m_last_retval = ::get_number (&m_cur_tok);
209           if (m_last_retval < 0)
210             error (_("negative value"));
211         }
212     }
213   return m_last_retval;
214 }
215
216 /* See documentation in cli-utils.h.  */
217
218 void
219 number_or_range_parser::setup_range (int start_value, int end_value,
220                                      const char *end_ptr)
221 {
222   gdb_assert (start_value > 0);
223
224   m_in_range = true;
225   m_end_ptr = end_ptr;
226   m_last_retval = start_value - 1;
227   m_end_value = end_value;
228 }
229
230 /* See documentation in cli-utils.h.  */
231
232 bool
233 number_or_range_parser::finished () const
234 {
235   /* Parsing is finished when at end of string or null string,
236      or we are not in a range and not in front of an integer, negative
237      integer, convenience var or negative convenience var.  */
238   return (m_cur_tok == NULL || *m_cur_tok == '\0'
239           || (!m_in_range
240               && !(isdigit (*m_cur_tok) || *m_cur_tok == '$')
241               && !(*m_cur_tok == '-'
242                    && (isdigit (m_cur_tok[1]) || m_cur_tok[1] == '$'))));
243 }
244
245 /* Accept a number and a string-form list of numbers such as is 
246    accepted by get_number_or_range.  Return TRUE if the number is
247    in the list.
248
249    By definition, an empty list includes all numbers.  This is to 
250    be interpreted as typing a command such as "delete break" with 
251    no arguments.  */
252
253 int
254 number_is_in_list (const char *list, int number)
255 {
256   if (list == NULL || *list == '\0')
257     return 1;
258
259   number_or_range_parser parser (list);
260
261   if (parser.finished ())
262     error (_("Arguments must be numbers or '$' variables."));
263   while (!parser.finished ())
264     {
265       int gotnum = parser.get_number ();
266
267       if (gotnum == 0)
268         error (_("Arguments must be numbers or '$' variables."));
269       if (gotnum == number)
270         return 1;
271     }
272   return 0;
273 }
274
275 /* See documentation in cli-utils.h.  */
276
277 const char *
278 remove_trailing_whitespace (const char *start, const char *s)
279 {
280   while (s > start && isspace (*(s - 1)))
281     --s;
282
283   return s;
284 }
285
286 /* See documentation in cli-utils.h.  */
287
288 std::string
289 extract_arg (const char **arg)
290 {
291   const char *result;
292
293   if (!*arg)
294     return std::string ();
295
296   /* Find the start of the argument.  */
297   *arg = skip_spaces (*arg);
298   if (!**arg)
299     return std::string ();
300   result = *arg;
301
302   /* Find the end of the argument.  */
303   *arg = skip_to_space (*arg + 1);
304
305   if (result == *arg)
306     return std::string ();
307
308   return std::string (result, *arg - result);
309 }
310
311 /* See documentation in cli-utils.h.  */
312
313 std::string
314 extract_arg (char **arg)
315 {
316   const char *arg_const = *arg;
317   std::string result;
318
319   result = extract_arg (&arg_const);
320   *arg += arg_const - *arg;
321   return result;
322 }
323
324 /* See documentation in cli-utils.h.  */
325
326 int
327 check_for_argument (const char **str, const char *arg, int arg_len)
328 {
329   if (strncmp (*str, arg, arg_len) == 0
330       && ((*str)[arg_len] == '\0' || isspace ((*str)[arg_len])))
331     {
332       *str += arg_len;
333       return 1;
334     }
335   return 0;
336 }
337
338 /* See documentation in cli-utils.h.  */
339
340 int
341 parse_flags (const char **str, const char *flags)
342 {
343   const char *p = skip_spaces (*str);
344
345   if (p[0] == '-'
346       && isalpha (p[1])
347       && (p[2] == '\0' || isspace (p[2])))
348     {
349       const char pf = p[1];
350       const char *f = flags;
351
352       while (*f != '\0')
353         {
354           if (*f == pf)
355             {
356               *str = skip_spaces (p + 2);
357               return f - flags + 1;
358             }
359           f++;
360         }
361     }
362
363   return 0;
364 }
365
366 /* See documentation in cli-utils.h.  */
367
368 bool
369 parse_flags_qcs (const char *which_command, const char **str,
370                  qcs_flags *flags)
371 {
372   switch (parse_flags (str, "qcs"))
373     {
374     case 0:
375       return false;
376     case 1:
377       flags->quiet = true;
378       break;
379     case 2:
380       flags->cont = true;
381       break;
382     case 3:
383       flags->silent = true;
384       break;
385     default:
386       gdb_assert_not_reached ("int qcs flag out of bound");
387     }
388
389   if (flags->cont && flags->silent)
390     error (_("%s: -c and -s are mutually exclusive"), which_command);
391
392   return true;
393 }