gdb/cli/cli-utils.c - gdb

Functions defined

Source code

  1. /* CLI utilities.

  2.    Copyright (C) 2011-2015 Free Software Foundation, Inc.

  3.    This file is part of GDB.

  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 3 of the License, or
  7.    (at your option) any later version.

  8.    This program is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.    GNU General Public License for more details.

  12.    You should have received a copy of the GNU General Public License
  13.    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

  14. #include "defs.h"
  15. #include "cli/cli-utils.h"
  16. #include "value.h"

  17. #include <ctype.h>

  18. /* *PP is a string denoting a number.  Get the number of the.  Advance
  19.    *PP after the string and any trailing whitespace.

  20.    Currently the string can either be a number, or "$" followed by the
  21.    name of a convenience variable, or ("$" or "$$") followed by digits.

  22.    TRAILER is a character which can be found after the number; most
  23.    commonly this is `-'.  If you don't want a trailer, use \0.  */

  24. static int
  25. get_number_trailer (const char **pp, int trailer)
  26. {
  27.   int retval = 0;        /* default */
  28.   const char *p = *pp;

  29.   if (*p == '$')
  30.     {
  31.       struct value *val = value_from_history_ref (p, &p);

  32.       if (val)        /* Value history reference */
  33.         {
  34.           if (TYPE_CODE (value_type (val)) == TYPE_CODE_INT)
  35.             retval = value_as_long (val);
  36.           else
  37.             {
  38.               printf_filtered (_("History value must have integer type.\n"));
  39.               retval = 0;
  40.             }
  41.         }
  42.       else        /* Convenience variable */
  43.         {
  44.           /* Internal variable.  Make a copy of the name, so we can
  45.              null-terminate it to pass to lookup_internalvar().  */
  46.           char *varname;
  47.           const char *start = ++p;
  48.           LONGEST val;

  49.           while (isalnum (*p) || *p == '_')
  50.             p++;
  51.           varname = (char *) alloca (p - start + 1);
  52.           strncpy (varname, start, p - start);
  53.           varname[p - start] = '\0';
  54.           if (get_internalvar_integer (lookup_internalvar (varname), &val))
  55.             retval = (int) val;
  56.           else
  57.             {
  58.               printf_filtered (_("Convenience variable must "
  59.                                  "have integer value.\n"));
  60.               retval = 0;
  61.             }
  62.         }
  63.     }
  64.   else
  65.     {
  66.       if (*p == '-')
  67.         ++p;
  68.       while (*p >= '0' && *p <= '9')
  69.         ++p;
  70.       if (p == *pp)
  71.         /* There is no number here.  (e.g. "cond a == b").  */
  72.         {
  73.           /* Skip non-numeric token.  */
  74.           while (*p && !isspace((int) *p))
  75.             ++p;
  76.           /* Return zero, which caller must interpret as error.  */
  77.           retval = 0;
  78.         }
  79.       else
  80.         retval = atoi (*pp);
  81.     }
  82.   if (!(isspace (*p) || *p == '\0' || *p == trailer))
  83.     {
  84.       /* Trailing junk: return 0 and let caller print error msg.  */
  85.       while (!(isspace (*p) || *p == '\0' || *p == trailer))
  86.         ++p;
  87.       retval = 0;
  88.     }
  89.   p = skip_spaces_const (p);
  90.   *pp = p;
  91.   return retval;
  92. }

  93. /* See documentation in cli-utils.h.  */

  94. int
  95. get_number_const (const char **pp)
  96. {
  97.   return get_number_trailer (pp, '\0');
  98. }

  99. /* See documentation in cli-utils.h.  */

  100. int
  101. get_number (char **pp)
  102. {
  103.   int result;
  104.   const char *p = *pp;

  105.   result = get_number_trailer (&p, '\0');
  106.   *pp = (char *) p;
  107.   return result;
  108. }

  109. /* See documentation in cli-utils.h.  */

  110. void
  111. init_number_or_range (struct get_number_or_range_state *state,
  112.                       const char *string)
  113. {
  114.   memset (state, 0, sizeof (*state));
  115.   state->string = string;
  116. }

  117. /* See documentation in cli-utils.h.  */

  118. int
  119. get_number_or_range (struct get_number_or_range_state *state)
  120. {
  121.   if (*state->string != '-')
  122.     {
  123.       /* Default case: state->string is pointing either to a solo
  124.          number, or to the first number of a range.  */
  125.       state->last_retval = get_number_trailer (&state->string, '-');
  126.       if (*state->string == '-')
  127.         {
  128.           const char **temp;

  129.           /* This is the start of a range (<number1> - <number2>).
  130.              Skip the '-', parse and remember the second number,
  131.              and also remember the end of the final token.  */

  132.           temp = &state->end_ptr;
  133.           state->end_ptr = skip_spaces_const (state->string + 1);
  134.           state->end_value = get_number_const (temp);
  135.           if (state->end_value < state->last_retval)
  136.             {
  137.               error (_("inverted range"));
  138.             }
  139.           else if (state->end_value == state->last_retval)
  140.             {
  141.               /* Degenerate range (number1 == number2).  Advance the
  142.                  token pointer so that the range will be treated as a
  143.                  single number.  */
  144.               state->string = state->end_ptr;
  145.             }
  146.           else
  147.             state->in_range = 1;
  148.         }
  149.     }
  150.   else if (! state->in_range)
  151.     error (_("negative value"));
  152.   else
  153.     {
  154.       /* state->string points to the '-' that betokens a range.  All
  155.          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
  158.          is reached.  */

  159.       if (++state->last_retval == state->end_value)
  160.         {
  161.           /* End of range reached; advance token pointer.  */
  162.           state->string = state->end_ptr;
  163.           state->in_range = 0;
  164.         }
  165.     }
  166.   state->finished = *state->string == '\0';
  167.   return state->last_retval;
  168. }

  169. /* Accept a number and a string-form list of numbers such as is
  170.    accepted by get_number_or_range.  Return TRUE if the number is
  171.    in the list.

  172.    By definition, an empty list includes all numbers.  This is to
  173.    be interpreted as typing a command such as "delete break" with
  174.    no arguments.  */

  175. int
  176. number_is_in_list (const char *list, int number)
  177. {
  178.   struct get_number_or_range_state state;

  179.   if (list == NULL || *list == '\0')
  180.     return 1;

  181.   init_number_or_range (&state, list);
  182.   while (!state.finished)
  183.     {
  184.       int gotnum = get_number_or_range (&state);

  185.       if (gotnum == 0)
  186.         error (_("Args must be numbers or '$' variables."));
  187.       if (gotnum == number)
  188.         return 1;
  189.     }
  190.   return 0;
  191. }

  192. /* See documentation in cli-utils.h.  */

  193. char *
  194. skip_spaces (char *chp)
  195. {
  196.   if (chp == NULL)
  197.     return NULL;
  198.   while (*chp && isspace (*chp))
  199.     chp++;
  200.   return chp;
  201. }

  202. /* A const-correct version of the above.  */

  203. const char *
  204. skip_spaces_const (const char *chp)
  205. {
  206.   if (chp == NULL)
  207.     return NULL;
  208.   while (*chp && isspace (*chp))
  209.     chp++;
  210.   return chp;
  211. }

  212. /* See documentation in cli-utils.h.  */

  213. const char *
  214. skip_to_space_const (const char *chp)
  215. {
  216.   if (chp == NULL)
  217.     return NULL;
  218.   while (*chp && !isspace (*chp))
  219.     chp++;
  220.   return chp;
  221. }

  222. /* See documentation in cli-utils.h.  */

  223. char *
  224. remove_trailing_whitespace (const char *start, char *s)
  225. {
  226.   while (s > start && isspace (*(s - 1)))
  227.     --s;

  228.   return s;
  229. }

  230. /* See documentation in cli-utils.h.  */

  231. char *
  232. extract_arg_const (const char **arg)
  233. {
  234.   const char *result;

  235.   if (!*arg)
  236.     return NULL;

  237.   /* Find the start of the argument.  */
  238.   *arg = skip_spaces_const (*arg);
  239.   if (!**arg)
  240.     return NULL;
  241.   result = *arg;

  242.   /* Find the end of the argument.  */
  243.   *arg = skip_to_space_const (*arg + 1);

  244.   if (result == *arg)
  245.     return NULL;

  246.   return savestring (result, *arg - result);
  247. }

  248. /* See documentation in cli-utils.h.  */

  249. char *
  250. extract_arg (char **arg)
  251. {
  252.   const char *arg_const = *arg;
  253.   char *result;

  254.   result = extract_arg_const (&arg_const);
  255.   *arg += arg_const - *arg;
  256.   return result;
  257. }

  258. /* See documentation in cli-utils.h.  */

  259. int
  260. check_for_argument (char **str, char *arg, int arg_len)
  261. {
  262.   if (strncmp (*str, arg, arg_len) == 0
  263.       && ((*str)[arg_len] == '\0' || isspace ((*str)[arg_len])))
  264.     {
  265.       *str += arg_len;
  266.       return 1;
  267.     }
  268.   return 0;
  269. }