Import readline 7.0 (patch 5)
[deliverable/binutils-gdb.git] / readline / bind.c
index a939528862ff194c2c9999ccd9ae3cd3435440e0..f1098c48b17ef910b18edea72c4d36926bb362c4 100644 (file)
@@ -1,6 +1,6 @@
 /* bind.c -- key binding and startup file support for the readline library. */
 
-/* Copyright (C) 1987-2010 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2016 Free Software Foundation, Inc.
 
    This file is part of the GNU Readline Library (Readline), a library
    for reading lines of text with interactive input and history editing.
@@ -72,11 +72,20 @@ extern char *strchr (), *strrchr ();
 /* Variables exported by this file. */
 Keymap rl_binding_keymap;
 
+static int _rl_skip_to_delim PARAMS((char *, int, int));
+
+#if defined (USE_VARARGS) && defined (PREFER_STDARG)
+static void _rl_init_file_error (const char *, ...)  __attribute__((__format__ (printf, 1, 2)));
+#else
+static void _rl_init_file_error ();
+#endif
+
 static char *_rl_read_file PARAMS((char *, size_t *));
-static void _rl_init_file_error PARAMS((const char *));
 static int _rl_read_init_file PARAMS((const char *, int));
 static int glean_key_from_name PARAMS((char *));
+
 static int find_boolean_var PARAMS((const char *));
+static int find_string_var PARAMS((const char *));
 
 static char *_rl_get_string_variable_value PARAMS((const char *));
 static int substring_member_of_array PARAMS((const char *, const char * const *));
@@ -113,6 +122,9 @@ rl_bind_key (key, function)
      int key;
      rl_command_func_t *function;
 {
+  char keyseq[3];
+  int l;
+
   if (key < 0)
     return (key);
 
@@ -131,8 +143,24 @@ rl_bind_key (key, function)
       return (key);
     }
 
-  _rl_keymap[key].type = ISFUNC;
-  _rl_keymap[key].function = function;
+  /* If it's bound to a function or macro, just overwrite.  Otherwise we have
+     to treat it as a key sequence so rl_generic_bind handles shadow keymaps
+     for us.  If we are binding '\' make sure to escape it so it makes it
+     through the call to rl_translate_keyseq. */
+  if (_rl_keymap[key].type != ISKMAP)
+    {
+      _rl_keymap[key].type = ISFUNC;
+      _rl_keymap[key].function = function;
+    }
+  else
+    {
+      l = 0;
+      if (key == '\\')
+       keyseq[l++] = '\\';
+      keyseq[l++] = key;
+      keyseq[l] = '\0';
+      rl_bind_keyseq (keyseq, function);
+    }
   rl_binding_keymap = _rl_keymap;
   return (0);
 }
@@ -538,7 +566,7 @@ rl_translate_keyseq (seq, array, len)
            case '0': case '1': case '2': case '3':
            case '4': case '5': case '6': case '7':
              i++;
-             for (temp = 2, c -= '0'; ISOCTAL (seq[i]) && temp--; i++)
+             for (temp = 2, c -= '0'; ISOCTAL ((unsigned char)seq[i]) && temp--; i++)
                c = (c * 8) + OCTVALUE (seq[i]);
              i--;      /* auto-increment in for loop */
              array[l++] = c & largest_char;
@@ -567,6 +595,40 @@ rl_translate_keyseq (seq, array, len)
   return (0);
 }
 
+static int
+_rl_isescape (c)
+     int c;
+{
+  switch (c)
+    {
+    case '\007':
+    case '\b':
+    case '\f':
+    case '\n':
+    case '\r':
+    case TAB:
+    case 0x0b:  return (1);
+    default: return (0);
+    }
+}
+
+static int
+_rl_escchar (c)
+     int c;
+{
+  switch (c)
+    {
+    case '\007':  return ('a');
+    case '\b':  return ('b');
+    case '\f':  return ('f');
+    case '\n':  return ('n');
+    case '\r':  return ('r');
+    case TAB:  return ('t');
+    case 0x0b:  return ('v');
+    default: return (c);
+    }
+}
+
 char *
 rl_untranslate_keyseq (seq)
      int seq;
@@ -618,9 +680,10 @@ rl_untranslate_keyseq (seq)
   return kseq;
 }
 
-static char *
-_rl_untranslate_macro_value (seq)
+char *
+_rl_untranslate_macro_value (seq, use_escapes)
      char *seq;
+     int use_escapes;
 {
   char *ret, *r, *s;
   int c;
@@ -644,9 +707,14 @@ _rl_untranslate_macro_value (seq)
       else if (CTRL_CHAR (c))
        {
          *r++ = '\\';
-         *r++ = 'C';
-         *r++ = '-';
-         c = _rl_to_lower (UNCTRL (c));
+         if (use_escapes && _rl_isescape (c))
+           c = _rl_escchar (c);
+         else
+           {
+             *r++ = 'C';
+             *r++ = '-';
+             c = _rl_to_lower (UNCTRL (c));
+           }
        }
       else if (c == RUBOUT)
        {
@@ -926,14 +994,35 @@ _rl_read_init_file (filename, include_level)
 }
 
 static void
-_rl_init_file_error (msg)
-     const char *msg;
+#if defined (PREFER_STDARG)
+_rl_init_file_error (const char *format, ...)
+#else
+_rl_init_file_error (va_alist)
+     va_dcl
+#endif
 {
+  va_list args;
+#if defined (PREFER_VARARGS)
+  char *format;
+#endif
+
+#if defined (PREFER_STDARG)
+  va_start (args, format);
+#else
+  va_start (args);
+  format = va_arg (args, char *);
+#endif
+
+  fprintf (stderr, "readline: ");
   if (currently_reading_init_file)
-    _rl_errmsg ("%s: line %d: %s\n", current_readline_init_file,
-                    current_readline_init_lineno, msg);
-  else
-    _rl_errmsg ("%s", msg);
+    fprintf (stderr, "%s: line %d: ", current_readline_init_file,
+                    current_readline_init_lineno);
+
+  vfprintf (stderr, format, args);
+  fprintf (stderr, "\n");
+  fflush (stderr);
+
+  va_end (args);
 }
 
 /* **************************************************************** */
@@ -1153,10 +1242,42 @@ handle_parser_directive (statement)
       }
 
   /* display an error message about the unknown parser directive */
-  _rl_init_file_error ("unknown parser directive");
+  _rl_init_file_error ("%s: unknown parser directive", directive);
   return (1);
 }
 
+/* Start at STRING[START] and look for DELIM.  Return I where STRING[I] ==
+   DELIM or STRING[I] == 0.  DELIM is usually a double quote. */
+static int
+_rl_skip_to_delim (string, start, delim)
+     char *string;
+     int start, delim;
+{
+  int i, c, passc;
+
+  for (i = start,passc = 0; c = string[i]; i++)
+    {
+      if (passc)
+       {
+         passc = 0;
+         if (c == 0)
+           break;
+         continue;
+       }
+
+      if (c == '\\')
+       {
+         passc = 1;
+         continue;
+       }
+
+      if (c == delim)
+       break;
+    }
+
+  return i;
+}
+
 /* Read the binding command from STRING and perform it.
    A key binding command looks like: Keyname: function-name\0,
    a variable binding command looks like: set variable value.
@@ -1167,12 +1288,12 @@ rl_parse_and_bind (string)
 {
   char *funname, *kname;
   register int c, i;
-  int key, equivalency;
+  int key, equivalency, foundmod, foundsep;
 
   while (string && whitespace (*string))
     string++;
 
-  if (!string || !*string || *string == '#')
+  if (string == 0 || *string == 0 || *string == '#')
     return 0;
 
   /* If this is a parser directive, act on it. */
@@ -1192,31 +1313,16 @@ rl_parse_and_bind (string)
      backslash to quote characters in the key expression. */
   if (*string == '"')
     {
-      int passc = 0;
-
-      for (i = 1; c = string[i]; i++)
-       {
-         if (passc)
-           {
-             passc = 0;
-             continue;
-           }
-
-         if (c == '\\')
-           {
-             passc++;
-             continue;
-           }
+      i = _rl_skip_to_delim (string, 1, '"');
 
-         if (c == '"')
-           break;
-       }
       /* If we didn't find a closing quote, abort the line. */
       if (string[i] == '\0')
         {
-          _rl_init_file_error ("no closing `\"' in key binding");
+          _rl_init_file_error ("%s: no closing `\"' in key binding", string);
           return 1;
         }
+      else
+        i++;   /* skip past closing double quote */
     }
 
   /* Advance to the colon (:) or whitespace which separates the two objects. */
@@ -1224,6 +1330,8 @@ rl_parse_and_bind (string)
 
   equivalency = (c == ':' && string[i + 1] == '=');
 
+  foundsep = c != 0;
+
   /* Mark the end of the command (or keyname). */
   if (string[i])
     string[i++] = '\0';
@@ -1236,6 +1344,7 @@ rl_parse_and_bind (string)
   if (_rl_stricmp (string, "set") == 0)
     {
       char *var, *value, *e;
+      int s;
 
       var = string + i;
       /* Make VAR point to start of variable name. */
@@ -1243,25 +1352,37 @@ rl_parse_and_bind (string)
 
       /* Make VALUE point to start of value string. */
       value = var;
-      while (*value && !whitespace (*value)) value++;
+      while (*value && whitespace (*value) == 0) value++;
       if (*value)
        *value++ = '\0';
       while (*value && whitespace (*value)) value++;
 
-      /* Strip trailing whitespace from values to boolean variables.  Temp
-        fix until I get a real quoted-string parser here. */
-      i = find_boolean_var (var);
-      if (i >= 0)
+      /* Strip trailing whitespace from values of boolean variables. */
+      if (find_boolean_var (var) >= 0)
        {
          /* remove trailing whitespace */
+remove_trailing:
          e = value + strlen (value) - 1;
          while (e >= value && whitespace (*e))
            e--;
          e++;          /* skip back to whitespace or EOS */
+         
          if (*e && e >= value)
            *e = '\0';
        }
-
+      else if ((i = find_string_var (var)) >= 0)
+       {
+         /* Allow quoted strings in variable values */
+         if (*value == '"')
+           {
+             i = _rl_skip_to_delim (value, 1, *value);
+             value[i] = '\0';
+             value++;  /* skip past the quote */
+           }
+         else
+           goto remove_trailing;
+       }
+       
       rl_variable_bind (var, value);
       return 0;
     }
@@ -1282,32 +1403,13 @@ rl_parse_and_bind (string)
      the quoted string delimiter, like the shell. */
   if (*funname == '\'' || *funname == '"')
     {
-      int delimiter, passc;
-
-      delimiter = string[i++];
-      for (passc = 0; c = string[i]; i++)
-       {
-         if (passc)
-           {
-             passc = 0;
-             continue;
-           }
-
-         if (c == '\\')
-           {
-             passc = 1;
-             continue;
-           }
-
-         if (c == delimiter)
-           break;
-       }
-      if (c)
+      i = _rl_skip_to_delim (string, i+1, *funname);
+      if (string[i])
        i++;
     }
 
   /* Advance to the end of the string.  */
-  for (; string[i] && !whitespace (string[i]); i++);
+  for (; string[i] && whitespace (string[i]) == 0; i++);
 
   /* No extra whitespace at the end of the string. */
   string[i] = '\0';
@@ -1319,6 +1421,12 @@ rl_parse_and_bind (string)
       return 0;
     }
 
+  if (foundsep == 0)
+    {
+      _rl_init_file_error ("%s: no key sequence terminator", string);
+      return 1;
+    }
+
   /* If this is a new-style key-binding, then do the binding with
      rl_bind_keyseq ().  Otherwise, let the older code deal with it. */
   if (*string == '"')
@@ -1367,7 +1475,7 @@ rl_parse_and_bind (string)
 
   /* Get the actual character we want to deal with. */
   kname = strrchr (string, '-');
-  if (!kname)
+  if (kname == 0)
     kname = string;
   else
     kname++;
@@ -1375,11 +1483,24 @@ rl_parse_and_bind (string)
   key = glean_key_from_name (kname);
 
   /* Add in control and meta bits. */
+  foundmod = 0;
   if (substring_member_of_array (string, _rl_possible_control_prefixes))
-    key = CTRL (_rl_to_upper (key));
+    {
+      key = CTRL (_rl_to_upper (key));
+      foundmod = 1;
+    }
 
   if (substring_member_of_array (string, _rl_possible_meta_prefixes))
-    key = META (key);
+    {
+      key = META (key);
+      foundmod = 1;
+    }
+
+  if (foundmod == 0 && kname != string)
+    {
+      _rl_init_file_error ("%s: unknown key modifier", string);
+      return 1;
+    }
 
   /* Temporary.  Handle old-style keyname with macro-binding. */
   if (*funname == '\'' || *funname == '"')
@@ -1406,6 +1527,7 @@ rl_parse_and_bind (string)
 #endif /* PREFIX_META_HACK */
   else
     rl_bind_key (key, rl_named_function (funname));
+
   return 0;
 }
 
@@ -1423,11 +1545,16 @@ static const struct {
   { "bind-tty-special-chars",  &_rl_bind_stty_chars,           0 },
   { "blink-matching-paren",    &rl_blink_matching_paren,       V_SPECIAL },
   { "byte-oriented",           &rl_byte_oriented,              0 },
+#if defined (COLOR_SUPPORT)
+  { "colored-completion-prefix",&_rl_colored_completion_prefix,        0 },
+  { "colored-stats",           &_rl_colored_stats,             0 },
+#endif
   { "completion-ignore-case",  &_rl_completion_case_fold,      0 },
   { "completion-map-case",     &_rl_completion_case_map,       0 },
   { "convert-meta",            &_rl_convert_meta_chars_to_ascii, 0 },
   { "disable-completion",      &rl_inhibit_completion,         0 },
   { "echo-control-characters", &_rl_echo_control_chars,        0 },
+  { "enable-bracketed-paste",  &_rl_enable_bracketed_paste,    0 },
   { "enable-keypad",           &_rl_enable_keypad,             0 },
   { "enable-meta-key",         &_rl_enable_meta,               0 },
   { "expand-tilde",            &rl_complete_with_tilde_expansion, 0 },
@@ -1447,6 +1574,7 @@ static const struct {
   { "revert-all-at-newline",   &_rl_revert_all_at_newline,     0 },
   { "show-all-if-ambiguous",   &_rl_complete_show_all,         0 },
   { "show-all-if-unmodified",  &_rl_complete_show_unmodified,  0 },
+  { "show-mode-in-prompt",     &_rl_show_mode_in_prompt,       0 },
   { "skip-completed-text",     &_rl_skip_completed_text,       0 },
 #if defined (VISIBLE_STATS)
   { "visible-stats",           &rl_visible_stats,              0 },
@@ -1486,6 +1614,8 @@ hack_special_boolean_var (i)
       else
        _rl_bell_preference = AUDIBLE_BELL;
     }
+  else if (_rl_stricmp (name, "show-mode-in-prompt") == 0)
+    _rl_reset_prompt ();
 }
 
 typedef int _rl_sv_func_t PARAMS((const char *));
@@ -1508,9 +1638,13 @@ static int sv_dispprefix PARAMS((const char *));
 static int sv_compquery PARAMS((const char *));
 static int sv_compwidth PARAMS((const char *));
 static int sv_editmode PARAMS((const char *));
+static int sv_emacs_modestr PARAMS((const char *));
 static int sv_histsize PARAMS((const char *));
 static int sv_isrchterm PARAMS((const char *));
 static int sv_keymap PARAMS((const char *));
+static int sv_seqtimeout PARAMS((const char *));
+static int sv_viins_modestr PARAMS((const char *));
+static int sv_vicmd_modestr PARAMS((const char *));
 
 static const struct {
   const char * const name;
@@ -1523,9 +1657,13 @@ static const struct {
   { "completion-prefix-display-length", V_INT, sv_dispprefix },
   { "completion-query-items", V_INT,   sv_compquery },
   { "editing-mode",    V_STRING,       sv_editmode },
+  { "emacs-mode-string", V_STRING,     sv_emacs_modestr },  
   { "history-size",    V_INT,          sv_histsize },
   { "isearch-terminators", V_STRING,   sv_isrchterm },
   { "keymap",          V_STRING,       sv_keymap },
+  { "keyseq-timeout",  V_INT,          sv_seqtimeout },
+  { "vi-cmd-mode-string", V_STRING,    sv_vicmd_modestr }, 
+  { "vi-ins-mode-string", V_STRING,    sv_viins_modestr }, 
   { (char *)NULL,      0, (_rl_sv_func_t *)0 }
 };
 
@@ -1542,7 +1680,7 @@ find_string_var (name)
 }
 
 /* A boolean value that can appear in a `set variable' command is true if
-   the value is null or empty, `on' (case-insenstive), or "1".  Any other
+   the value is null or empty, `on' (case-insensitive), or "1".  Any other
    values result in 0 (false). */
 static int
 bool_to_int (value)
@@ -1591,10 +1729,14 @@ rl_variable_bind (name, value)
 
   i = find_string_var (name);
 
-  /* For the time being, unknown variable names or string names without a
-     handler function are simply ignored. */
+  /* For the time being, string names without a handler function are simply
+     ignored. */
   if (i < 0 || string_varlist[i].set_func == 0)
-    return 0;
+    {
+      if (i < 0)
+       _rl_init_file_error ("%s: unknown variable name", name);
+      return 0;
+    }
 
   v = (*string_varlist[i].set_func) (value);
   return v;
@@ -1683,13 +1825,17 @@ static int
 sv_histsize (value)
      const char *value;
 {
-  int nval = 500;
+  int nval;
 
+  nval = 500;
   if (value && *value)
     {
       nval = atoi (value);
       if (nval < 0)
-       return 1;
+       {
+         unstifle_history ();
+         return 0;
+       }
     }
   stifle_history (nval);
   return 0;
@@ -1710,6 +1856,23 @@ sv_keymap (value)
   return 1;
 }
 
+static int
+sv_seqtimeout (value)
+     const char *value;
+{
+  int nval;
+
+  nval = 0;
+  if (value && *value)
+    {
+      nval = atoi (value);
+      if (nval < 0)
+       nval = 0;
+    }
+  _rl_keyseq_timeout = nval;
+  return 0;
+}
+
 static int
 sv_bell_style (value)
      const char *value;
@@ -1748,7 +1911,7 @@ sv_isrchterm (value)
     }
   else
     {
-      for (beg = end = 0; whitespace (v[end]) == 0; end++)
+      for (beg = end = 0; v[end] && whitespace (v[end]) == 0; end++)
        ;
     }
 
@@ -1762,7 +1925,96 @@ sv_isrchterm (value)
   xfree (v);
   return 0;
 }
-      
+
+extern char *_rl_emacs_mode_str;
+
+static int
+sv_emacs_modestr (value)
+     const char *value;
+{
+  if (value && *value)
+    {
+      FREE (_rl_emacs_mode_str);
+      _rl_emacs_mode_str = (char *)xmalloc (2 * strlen (value) + 1);
+      rl_translate_keyseq (value, _rl_emacs_mode_str, &_rl_emacs_modestr_len);
+      _rl_emacs_mode_str[_rl_emacs_modestr_len] = '\0';
+      return 0;
+    }
+  else if (value)
+    {
+      FREE (_rl_emacs_mode_str);
+      _rl_emacs_mode_str = (char *)xmalloc (1);
+      _rl_emacs_mode_str[_rl_emacs_modestr_len = 0] = '\0';
+      return 0;
+    }
+  else if (value == 0)
+    {
+      FREE (_rl_emacs_mode_str);
+      _rl_emacs_mode_str = 0;  /* prompt_modestr does the right thing */
+      _rl_emacs_modestr_len = 0;
+      return 0;
+    }
+  return 1;
+}
+
+static int
+sv_viins_modestr (value)
+     const char *value;
+{
+  if (value && *value)
+    {
+      FREE (_rl_vi_ins_mode_str);
+      _rl_vi_ins_mode_str = (char *)xmalloc (2 * strlen (value) + 1);
+      rl_translate_keyseq (value, _rl_vi_ins_mode_str, &_rl_vi_ins_modestr_len);
+      _rl_vi_ins_mode_str[_rl_vi_ins_modestr_len] = '\0';
+      return 0;
+    }
+  else if (value)
+    {
+      FREE (_rl_vi_ins_mode_str);
+      _rl_vi_ins_mode_str = (char *)xmalloc (1);
+      _rl_vi_ins_mode_str[_rl_vi_ins_modestr_len = 0] = '\0';
+      return 0;
+    }
+  else if (value == 0)
+    {
+      FREE (_rl_vi_ins_mode_str);
+      _rl_vi_ins_mode_str = 0; /* prompt_modestr does the right thing */
+      _rl_vi_ins_modestr_len = 0;
+      return 0;
+    }
+  return 1;
+}
+
+static int
+sv_vicmd_modestr (value)
+     const char *value;
+{
+  if (value && *value)
+    {
+      FREE (_rl_vi_cmd_mode_str);
+      _rl_vi_cmd_mode_str = (char *)xmalloc (2 * strlen (value) + 1);
+      rl_translate_keyseq (value, _rl_vi_cmd_mode_str, &_rl_vi_cmd_modestr_len);
+      _rl_vi_cmd_mode_str[_rl_vi_cmd_modestr_len] = '\0';
+      return 0;
+    }
+  else if (value)
+    {
+      FREE (_rl_vi_cmd_mode_str);
+      _rl_vi_cmd_mode_str = (char *)xmalloc (1);
+      _rl_vi_cmd_mode_str[_rl_vi_cmd_modestr_len = 0] = '\0';
+      return 0;
+    }
+  else if (value == 0)
+    {
+      FREE (_rl_vi_cmd_mode_str);
+      _rl_vi_cmd_mode_str = 0; /* prompt_modestr does the right thing */
+      _rl_vi_cmd_modestr_len = 0;
+      return 0;
+    }
+  return 1;
+}
+
 /* Return the character which matches NAME.
    For example, `Space' returns ' '. */
 
@@ -2167,7 +2419,8 @@ rl_function_dumper (print_readably)
            }
        }
     }
-  free (names);
+
+  xfree (names);
 }
 
 /* Print all of the current functions and their bindings to
@@ -2200,7 +2453,7 @@ _rl_macro_dumper_internal (print_readably, map, prefix)
        {
        case ISMACR:
          keyname = _rl_get_keyname (key);
-         out = _rl_untranslate_macro_value ((char *)map[key].function);
+         out = _rl_untranslate_macro_value ((char *)map[key].function, 0);
 
          if (print_readably)
            fprintf (rl_outstream, "\"%s%s\": \"%s\"\n", prefix ? prefix : "",
@@ -2312,7 +2565,7 @@ _rl_get_string_variable_value (name)
     {
       if (_rl_isearch_terminators == 0)
        return 0;
-      ret = _rl_untranslate_macro_value (_rl_isearch_terminators);
+      ret = _rl_untranslate_macro_value (_rl_isearch_terminators, 0);
       if (ret)
        {
          strncpy (numbuf, ret, sizeof (numbuf) - 1);
@@ -2330,6 +2583,17 @@ _rl_get_string_variable_value (name)
        ret = rl_get_keymap_name_from_edit_mode ();
       return (ret ? ret : "none");
     }
+  else if (_rl_stricmp (name, "keyseq-timeout") == 0)
+    {
+      sprintf (numbuf, "%d", _rl_keyseq_timeout);    
+      return (numbuf);
+    }
+  else if (_rl_stricmp (name, "emacs-mode-string") == 0)
+    return (_rl_emacs_mode_str ? _rl_emacs_mode_str : RL_EMACS_MODESTR_DEFAULT);
+  else if (_rl_stricmp (name, "vi-cmd-mode-string") == 0)
+    return (_rl_vi_cmd_mode_str ? _rl_vi_cmd_mode_str : RL_VI_CMD_MODESTR_DEFAULT);
+  else if (_rl_stricmp (name, "vi-ins-mode-string") == 0)
+    return (_rl_vi_ins_mode_str ? _rl_vi_ins_mode_str : RL_VI_INS_MODESTR_DEFAULT);
   else
     return (0);
 }
This page took 0.032732 seconds and 4 git commands to generate.