Readline 5.1 import for HEAD.
[deliverable/binutils-gdb.git] / readline / complete.c
index a4ff24e8720b7ebf4e7e92d0a88bf30c32d9b0e6..d93c15ae55d2602bdc75fa9360d378830cfeb636 100644 (file)
@@ -1,6 +1,6 @@
 /* complete.c -- filename completion for readline. */
 
-/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
 
    This file is part of the GNU Readline Library, a library for
    reading lines of text with interactive input and history editing.
@@ -28,7 +28,7 @@
 #include <sys/types.h>
 #include <fcntl.h>
 #if defined (HAVE_SYS_FILE_H)
-#include <sys/file.h>
+#  include <sys/file.h>
 #endif
 
 #if defined (HAVE_UNISTD_H)
@@ -48,7 +48,7 @@
 extern int errno;
 #endif /* !errno */
 
-#ifdef HAVE_PWD_H
+#if defined (HAVE_PWD_H)
 #include <pwd.h>
 #endif
 
@@ -81,10 +81,9 @@ typedef int QSFUNC ();
 
 /* Most systems don't declare getpwent in <pwd.h> if _POSIX_SOURCE is
    defined. */
-#if defined(HAVE_GETPWENT) && \
-    (!defined (HAVE_GETPW_DECLS) || defined (_POSIX_SOURCE))
+#if defined (HAVE_GETPWENT) && (!defined (HAVE_GETPW_DECLS) || defined (_POSIX_SOURCE))
 extern struct passwd *getpwent PARAMS((void));
-#endif /* defiend (HAVE_GETPWENT) && (!HAVE_GETPW_DECLS || _POSIX_SOURCE) */
+#endif /* HAVE_GETPWENT && (!HAVE_GETPW_DECLS || _POSIX_SOURCE) */
 
 /* If non-zero, then this is the address of a function to call when
    completing a word would normally display the list of possible matches.
@@ -102,12 +101,16 @@ rl_compdisp_func_t *rl_completion_display_matches_hook = (rl_compdisp_func_t *)N
 static int stat_char PARAMS((char *));
 #endif
 
+static int path_isdir PARAMS((const char *));
+
 static char *rl_quote_filename PARAMS((char *, int, char *));
 
 static void set_completion_defaults PARAMS((int));
 static int get_y_or_n PARAMS((int));
 static int _rl_internal_pager PARAMS((int));
 static char *printable_part PARAMS((char *));
+static int fnwidth PARAMS((const char *));
+static int fnprint PARAMS((const char *));
 static int print_filename PARAMS((char *, char *));
 
 static char **gen_completion_matches PARAMS((char *, int, int, rl_compentry_func_t *, int, int));
@@ -133,6 +136,10 @@ static char *make_quoted_replacement PARAMS((char *, int, char *));
 /* If non-zero, non-unique completions always show the list of matches. */
 int _rl_complete_show_all = 0;
 
+/* If non-zero, non-unique completions show the list of matches, unless it
+   is not possible to do partial completion and modify the line. */
+int _rl_complete_show_unmodified = 0;
+
 /* If non-zero, completed directory names have a slash appended. */
 int _rl_complete_mark_directories = 1;
 
@@ -201,7 +208,8 @@ int rl_completion_type = 0;
 
 /* Up to this many items will be displayed in response to a
    possible-completions call.  After that, we ask the user if
-   she is sure she wants to see them all. */
+   she is sure she wants to see them all.  A negative value means
+   don't ask. */
 int rl_completion_query_items = 100;
 
 int _rl_page_completions = 1;
@@ -217,7 +225,12 @@ const char *rl_basic_quote_characters = "\"'";
 /* The list of characters that signal a break between words for
    rl_complete_internal.  The default list is the contents of
    rl_basic_word_break_characters.  */
-const char *rl_completer_word_break_characters = (const char *)NULL;
+/*const*/ char *rl_completer_word_break_characters = (/*const*/ char *)NULL;
+
+/* Hook function to allow an application to set the completion word
+   break characters before readline breaks up the line.  Allows
+   position-dependent word break characters. */
+rl_cpvfunc_t *rl_completion_word_break_hook = (rl_cpvfunc_t *)NULL;
 
 /* List of characters which can be used to quote a substring of the line.
    Completion occurs on the entire substring, and within the substring
@@ -285,6 +298,19 @@ int rl_completion_suppress_append = 0;
    default is a space. */
 int rl_completion_append_character = ' ';
 
+/* If non-zero, the completion functions don't append any closing quote.
+   This is set to 0 by rl_complete_internal and may be changed by an
+   application-specific completion function. */
+int rl_completion_suppress_quote = 0;
+
+/* Set to any quote character readline thinks it finds before any application
+   completion function is called. */
+int rl_completion_quote_character;
+
+/* Set to a non-zero value if readline found quoting anywhere in the word to
+   be completed; set before any application completion function is called. */
+int rl_completion_found_quote;
+
 /* If non-zero, a slash will be appended to completed filenames that are
    symbolic links to directory names, subject to the value of the
    mark-directories variable (which is user-settable).  This exists so
@@ -323,6 +349,8 @@ rl_complete (ignore, invoking_key)
     return (rl_complete_internal ('?'));
   else if (_rl_complete_show_all)
     return (rl_complete_internal ('!'));
+  else if (_rl_complete_show_unmodified)
+    return (rl_complete_internal ('@'));
   else
     return (rl_complete_internal (TAB));
 }
@@ -355,6 +383,8 @@ rl_completion_mode (cfunc)
     return '?';
   else if (_rl_complete_show_all)
     return '!';
+  else if (_rl_complete_show_unmodified)
+    return '@';
   else
     return TAB;
 }
@@ -375,7 +405,7 @@ set_completion_defaults (what_to_do)
   rl_filename_completion_desired = 0;
   rl_filename_quoting_desired = 1;
   rl_completion_type = what_to_do;
-  rl_completion_suppress_append = 0;
+  rl_completion_suppress_append = rl_completion_suppress_quote = 0;
 
   /* The completion entry function may optionally change this. */
   rl_completion_mark_symlink_dirs = _rl_complete_mark_symlink_dirs;
@@ -426,6 +456,15 @@ _rl_internal_pager (lines)
     return 0;
 }
 
+static int
+path_isdir (filename)
+     const char *filename;
+{
+  struct stat finfo;
+
+  return (stat (filename, &finfo) == 0 && S_ISDIR (finfo.st_mode));
+}
+
 #if defined (VISIBLE_STATS)
 /* Return the character which best describes FILENAME.
      `@' for symbolic links
@@ -523,53 +562,149 @@ printable_part (pathname)
     return ++temp;
 }
 
+/* Compute width of STRING when displayed on screen by print_filename */
+static int
+fnwidth (string)
+     const char *string;
+{
+  int width, pos;
+#if defined (HANDLE_MULTIBYTE)
+  mbstate_t ps;
+  int left, w;
+  size_t clen;
+  wchar_t wc;
+
+  left = strlen (string) + 1;
+  memset (&ps, 0, sizeof (mbstate_t));
+#endif
+
+  width = pos = 0;
+  while (string[pos])
+    {
+      if (CTRL_CHAR (*string) || *string == RUBOUT)
+       {
+         width += 2;
+         pos++;
+       }
+      else
+       {
+#if defined (HANDLE_MULTIBYTE)
+         clen = mbrtowc (&wc, string + pos, left - pos, &ps);
+         if (MB_INVALIDCH (clen))
+           {
+             width++;
+             pos++;
+             memset (&ps, 0, sizeof (mbstate_t));
+           }
+         else if (MB_NULLWCH (clen))
+           break;
+         else
+           {
+             pos += clen;
+             w = wcwidth (wc);
+             width += (w >= 0) ? w : 1;
+           }
+#else
+         width++;
+         pos++;
+#endif
+       }
+    }
+
+  return width;
+}
+
+static int
+fnprint (to_print)
+     const char *to_print;
+{
+  int printed_len;
+  const char *s;
+#if defined (HANDLE_MULTIBYTE)
+  mbstate_t ps;
+  const char *end;
+  size_t tlen;
+  int width, w;
+  wchar_t wc;
+
+  end = to_print + strlen (to_print) + 1;
+  memset (&ps, 0, sizeof (mbstate_t));
+#endif
+
+  printed_len = 0;
+  s = to_print;
+  while (*s)
+    {
+      if (CTRL_CHAR (*s))
+        {
+          putc ('^', rl_outstream);
+          putc (UNCTRL (*s), rl_outstream);
+          printed_len += 2;
+          s++;
+#if defined (HANDLE_MULTIBYTE)
+         memset (&ps, 0, sizeof (mbstate_t));
+#endif
+        }
+      else if (*s == RUBOUT)
+       {
+         putc ('^', rl_outstream);
+         putc ('?', rl_outstream);
+         printed_len += 2;
+         s++;
+#if defined (HANDLE_MULTIBYTE)
+         memset (&ps, 0, sizeof (mbstate_t));
+#endif
+       }
+      else
+       {
+#if defined (HANDLE_MULTIBYTE)
+         tlen = mbrtowc (&wc, s, end - s, &ps);
+         if (MB_INVALIDCH (tlen))
+           {
+             tlen = 1;
+             width = 1;
+             memset (&ps, 0, sizeof (mbstate_t));
+           }
+         else if (MB_NULLWCH (tlen))
+           break;
+         else
+           {
+             w = wcwidth (wc);
+             width = (w >= 0) ? w : 1;
+           }
+         fwrite (s, 1, tlen, rl_outstream);
+         s += tlen;
+         printed_len += width;
+#else
+         putc (*s, rl_outstream);
+         s++;
+         printed_len++;
+#endif
+       }
+    }
+
+  return printed_len;
+}
+
 /* Output TO_PRINT to rl_outstream.  If VISIBLE_STATS is defined and we
    are using it, check for and output a single character for `special'
    filenames.  Return the number of characters we output. */
 
-#define PUTX(c) \
-    do { \
-      if (CTRL_CHAR (c)) \
-        { \
-          putc ('^', rl_outstream); \
-          putc (UNCTRL (c), rl_outstream); \
-          printed_len += 2; \
-        } \
-      else if (c == RUBOUT) \
-       { \
-         putc ('^', rl_outstream); \
-         putc ('?', rl_outstream); \
-         printed_len += 2; \
-       } \
-      else \
-       { \
-         putc (c, rl_outstream); \
-         printed_len++; \
-       } \
-    } while (0)
-
 static int
 print_filename (to_print, full_pathname)
      char *to_print, *full_pathname;
 {
-  int printed_len = 0;
-#if !defined (VISIBLE_STATS)
-  char *s;
+  int printed_len, extension_char, slen, tlen;
+  char *s, c, *new_full_pathname, *dn;
 
-  for (s = to_print; *s; s++)
-    {
-      PUTX (*s);
-    }
-#else  
-  char *s, c, *new_full_pathname;
-  int extension_char, slen, tlen;
+  extension_char = 0;
+  printed_len = fnprint (to_print);
 
-  for (s = to_print; *s; s++)
-    {
-      PUTX (*s);
-    }
-
- if (rl_filename_completion_desired && rl_visible_stats)
+#if defined (VISIBLE_STATS)
+ if (rl_filename_completion_desired && (rl_visible_stats || _rl_complete_mark_directories))
+#else
+ if (rl_filename_completion_desired && _rl_complete_mark_directories)
+#endif
     {
       /* If to_print != full_pathname, to_print is the basename of the
         path passed.  In this case, we try to expand the directory
@@ -585,7 +720,17 @@ print_filename (to_print, full_pathname)
             files in the root directory.  If we pass a null string to the
             bash directory completion hook, for example, it will expand it
             to the current directory.  We just want the `/'. */
-         s = tilde_expand (full_pathname && *full_pathname ? full_pathname : "/");
+         if (full_pathname == 0 || *full_pathname == 0)
+           dn = "/";
+         else if (full_pathname[0] != '/')
+           dn = full_pathname;
+         else if (full_pathname[1] == 0)
+           dn = "//";          /* restore trailing slash to `//' */
+         else if (full_pathname[1] == '/' && full_pathname[2] == 0)
+           dn = "/";           /* don't turn /// into // */
+         else
+           dn = full_pathname;
+         s = tilde_expand (dn);
          if (rl_directory_completion_hook)
            (*rl_directory_completion_hook) (&s);
 
@@ -593,10 +738,20 @@ print_filename (to_print, full_pathname)
          tlen = strlen (to_print);
          new_full_pathname = (char *)xmalloc (slen + tlen + 2);
          strcpy (new_full_pathname, s);
+         if (s[slen - 1] == '/')
+           slen--;
+         else
+           new_full_pathname[slen] = '/';
          new_full_pathname[slen] = '/';
          strcpy (new_full_pathname + slen + 1, to_print);
 
-         extension_char = stat_char (new_full_pathname);
+#if defined (VISIBLE_STATS)
+         if (rl_visible_stats)
+           extension_char = stat_char (new_full_pathname);
+         else
+#endif
+         if (path_isdir (new_full_pathname))
+           extension_char = '/';
 
          free (new_full_pathname);
          to_print[-1] = c;
@@ -604,7 +759,13 @@ print_filename (to_print, full_pathname)
       else
        {
          s = tilde_expand (full_pathname);
-         extension_char = stat_char (s);
+#if defined (VISIBLE_STATS)
+         if (rl_visible_stats)
+           extension_char = stat_char (s);
+         else
+#endif
+           if (path_isdir (s))
+             extension_char = '/';
        }
 
       free (s);
@@ -614,7 +775,7 @@ print_filename (to_print, full_pathname)
          printed_len++;
        }
     }
-#endif /* VISIBLE_STATS */
+
   return printed_len;
 }
 
@@ -654,19 +815,25 @@ _rl_find_completion_word (fp, dp)
      int *fp, *dp;
 {
   int scan, end, found_quote, delimiter, pass_next, isbrk;
-  char quote_char;
+  char quote_char, *brkchars;
 
   end = rl_point;
   found_quote = delimiter = 0;
   quote_char = '\0';
 
+  brkchars = 0;
+  if (rl_completion_word_break_hook)
+    brkchars = (*rl_completion_word_break_hook) ();
+  if (brkchars == 0)
+    brkchars = rl_completer_word_break_characters;
+
   if (rl_completer_quote_characters)
     {
       /* We have a list of characters which can be used in pairs to
         quote substrings for the completer.  Try to find the start
         of an unclosed quoted substring. */
       /* FOUND_QUOTE is set so we know what kind of quotes we found. */
-      for (scan = pass_next = 0; scan < end; scan++)
+      for (scan = pass_next = 0; scan < end; scan = MB_NEXTCHAR (rl_line_buffer, scan, 1, MB_FIND_ANY))
        {
          if (pass_next)
            {
@@ -716,15 +883,11 @@ _rl_find_completion_word (fp, dp)
       /* We didn't find an unclosed quoted substring upon which to do
          completion, so use the word break characters to find the
          substring on which to complete. */
-#if defined (HANDLE_MULTIBYTE)
-      while (rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_ANY))
-#else
-      while (--rl_point)
-#endif
+      while (rl_point = MB_PREVCHAR (rl_line_buffer, rl_point, MB_FIND_ANY))
        {
          scan = rl_line_buffer[rl_point];
 
-         if (strchr (rl_completer_word_break_characters, scan) == 0)
+         if (strchr (brkchars, scan) == 0)
            continue;
 
          /* Call the application-specific function to tell us whether
@@ -752,9 +915,9 @@ _rl_find_completion_word (fp, dp)
       if (rl_char_is_quoted_p)
        isbrk = (found_quote == 0 ||
                (*rl_char_is_quoted_p) (rl_line_buffer, rl_point) == 0) &&
-               strchr (rl_completer_word_break_characters, scan) != 0;
+               strchr (brkchars, scan) != 0;
       else
-       isbrk = strchr (rl_completer_word_break_characters, scan) != 0;
+       isbrk = strchr (brkchars, scan) != 0;
 
       if (isbrk)
        {
@@ -789,6 +952,9 @@ gen_completion_matches (text, start, end, our_func, found_quote, quote_char)
 {
   char **matches, *temp;
 
+  rl_completion_found_quote = found_quote;
+  rl_completion_quote_character = quote_char;
+
   /* If the user wants to TRY to complete, but then wants to give
      up and use the default completion function, they set the
      variable rl_attempted_completion_function. */
@@ -892,6 +1058,7 @@ compute_lcd_of_matches (match_list, matches, text)
 {
   register int i, c1, c2, si;
   int low;             /* Count of max-matched characters. */
+  char *dtext;         /* dequoted TEXT, if needed */
 #if defined (HANDLE_MULTIBYTE)
   int v;
   mbstate_t ps1, ps2;
@@ -983,6 +1150,26 @@ compute_lcd_of_matches (match_list, matches, text)
         the user typed in the face of multiple matches differing in case. */
       if (_rl_completion_case_fold)
        {
+         /* We're making an assumption here:
+               IF we're completing filenames AND
+                  the application has defined a filename dequoting function AND
+                  we found a quote character AND
+                  the application has requested filename quoting
+               THEN
+                  we assume that TEXT was dequoted before checking against
+                  the file system and needs to be dequoted here before we
+                  check against the list of matches
+               FI */
+         dtext = (char *)NULL;
+         if (rl_filename_completion_desired &&
+             rl_filename_dequoting_function &&
+             rl_completion_found_quote &&
+             rl_filename_quoting_desired)
+           {
+             dtext = (*rl_filename_dequoting_function) ((char *)text, rl_completion_quote_character);
+             text = dtext;
+           }
+
          /* sort the list to get consistent answers. */
          qsort (match_list+1, matches, sizeof(char *), (QSFUNC *)_rl_qsort_string_compare);
 
@@ -1002,6 +1189,8 @@ compute_lcd_of_matches (match_list, matches, text)
          else
            /* otherwise, just use the text the user typed. */
            strncpy (match_list[0], text, low);
+
+         FREE (dtext);
        }
       else
         strncpy (match_list[0], match_list[1], low);
@@ -1206,7 +1395,7 @@ display_matches (matches)
   for (max = 0, i = 1; matches[i]; i++)
     {
       temp = printable_part (matches[i]);
-      len = strlen (temp);
+      len = fnwidth (temp);
 
       if (len > max)
        max = len;
@@ -1223,7 +1412,7 @@ display_matches (matches)
        
   /* If there are many items, then ask the user if she really wants to
      see them all. */
-  if (len >= rl_completion_query_items)
+  if (rl_completion_query_items > 0 && len >= rl_completion_query_items)
     {
       rl_crlf ();
       fprintf (rl_outstream, "Display all %d possibilities? (y or n)", len);
@@ -1341,7 +1530,8 @@ append_to_match (text, delimiter, quote_char, nontrivial_match)
   struct stat finfo;
 
   temp_string_index = 0;
-  if (quote_char && rl_point && rl_line_buffer[rl_point - 1] != quote_char)
+  if (quote_char && rl_point && rl_completion_suppress_quote == 0 &&
+      rl_line_buffer[rl_point - 1] != quote_char)
     temp_string[temp_string_index++] = quote_char;
 
   if (delimiter)
@@ -1359,7 +1549,7 @@ append_to_match (text, delimiter, quote_char, nontrivial_match)
                : stat (filename, &finfo);
       if (s == 0 && S_ISDIR (finfo.st_mode))
        {
-         if (_rl_complete_mark_directories)
+         if (_rl_complete_mark_directories /* && rl_completion_suppress_append == 0 */)
            {
              /* This is clumsy.  Avoid putting in a double slash if point
                 is at the end of the line and the previous character is a
@@ -1452,7 +1642,9 @@ _rl_free_match_list (matches)
    TAB means do standard completion.
    `*' means insert all of the possible completions.
    `!' means to do standard completion, and list all possible completions if
-   there is more than one. */
+   there is more than one.
+   `@' means to do standard completion, and list all possible completions if
+   there is more than one and partial completion is not possible. */
 int
 rl_complete_internal (what_to_do)
      int what_to_do;
@@ -1471,7 +1663,6 @@ rl_complete_internal (what_to_do)
   our_func = rl_completion_entry_function
                ? rl_completion_entry_function
                : rl_filename_completion_function;
-
   /* We now look backwards for the start of a filename/variable word. */
   end = rl_point;
   found_quote = delimiter = 0;
@@ -1519,6 +1710,7 @@ rl_complete_internal (what_to_do)
     {
     case TAB:
     case '!':
+    case '@':
       /* Insert the first match with proper quoting. */
       if (*matches[0])
        insert_match (matches[0], start, matches[1] ? MULT_MATCH : SINGLE_MATCH, &quote_char);
@@ -1538,6 +1730,12 @@ rl_complete_internal (what_to_do)
              display_matches (matches);
              break;
            }
+         else if (what_to_do == '@')
+           {
+             if (nontrivial_lcd == 0)
+               display_matches (matches);
+             break;
+           }
          else if (rl_editing_mode != vi_mode)
            rl_ding (); /* There are other matches remaining. */
        }
@@ -1665,7 +1863,7 @@ rl_username_completion_function (text, state)
       setpwent ();
     }
 
-#ifdef HAVE_GETPWENT
+#if defined (HAVE_GETPWENT)
   while (entry = getpwent ())
     {
       /* Null usernames should result in all users as possible completions. */
@@ -1676,7 +1874,7 @@ rl_username_completion_function (text, state)
 
   if (entry == 0)
     {
-#ifdef HAVE_GETPWENT
+#if defined (HAVE_GETPWENT)
       endpwent ();
 #endif
       return ((char *)NULL);
@@ -1990,9 +2188,11 @@ rl_menu_complete (count, ignore)
       return (0);
     }
 
-  match_list_index = (match_list_index + count) % match_list_size;
+  match_list_index += count;
   if (match_list_index < 0)
     match_list_index += match_list_size;
+  else
+    match_list_index %= match_list_size;
 
   if (match_list_index == 0 && match_list_size > 1)
     {
This page took 0.029315 seconds and 4 git commands to generate.