Imported from ../bash-3.0.tar.gz.
[platform/upstream/bash.git] / lib / readline / complete.c
index 21a9d70..d212f61 100644 (file)
@@ -1,6 +1,6 @@
 /* complete.c -- filename completion for readline. */
 
-/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2004 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)
@@ -99,12 +99,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));
@@ -130,6 +134,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;
 
@@ -214,7 +222,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
@@ -282,6 +295,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
@@ -320,6 +346,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));
 }
@@ -352,6 +380,8 @@ rl_completion_mode (cfunc)
     return '?';
   else if (_rl_complete_show_all)
     return '!';
+  else if (_rl_complete_show_unmodified)
+    return '@';
   else
     return TAB;
 }
@@ -372,7 +402,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;
@@ -423,6 +453,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
@@ -520,53 +559,140 @@ 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;
+
+  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 = mbrlen (s, end - s, &ps);
+         if (MB_INVALIDCH (tlen))
+           {
+             tlen = 1;
+             memset (&ps, 0, sizeof (mbstate_t));
+           }
+         else if (MB_NULLWCH (tlen))
+           break;
+         fwrite (s, 1, tlen, rl_outstream);
+         s += tlen;
+#else
+         putc (*s, rl_outstream);
+         s++;
+#endif
+         printed_len++;
+       }
+    }
+
+  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;
-
-  for (s = to_print; *s; s++)
-    {
-      PUTX (*s);
-    }
-#else  
+  int printed_len, extension_char, slen, tlen;
   char *s, c, *new_full_pathname;
-  int extension_char, slen, tlen;
 
-  for (s = to_print; *s; s++)
-    {
-      PUTX (*s);
-    }
+  extension_char = 0;
+  printed_len = fnprint (to_print);
 
- 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
@@ -593,7 +719,13 @@ print_filename (to_print, full_pathname)
          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;
@@ -601,7 +733,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);
@@ -611,7 +749,7 @@ print_filename (to_print, full_pathname)
          printed_len++;
        }
     }
-#endif /* VISIBLE_STATS */
+
   return printed_len;
 }
 
@@ -651,19 +789,32 @@ _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. */
+#if defined (HANDLE_MULTIBYTE)
+      for (scan = pass_next = 0; scan < end;
+               scan = ((MB_CUR_MAX == 1 || rl_byte_oriented)
+                       ? (scan + 1) 
+                       : _rl_find_next_mbchar (rl_line_buffer, scan, 1, MB_FIND_ANY)))
+#else
       for (scan = pass_next = 0; scan < end; scan++)
+#endif
        {
          if (pass_next)
            {
@@ -721,7 +872,7 @@ _rl_find_completion_word (fp, dp)
        {
          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
@@ -749,9 +900,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)
        {
@@ -786,6 +937,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. */
@@ -889,6 +1043,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;
@@ -980,6 +1135,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) (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);
 
@@ -999,6 +1174,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);
@@ -1203,7 +1380,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;
@@ -1338,7 +1515,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)
@@ -1449,7 +1627,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;
@@ -1468,7 +1648,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;
@@ -1516,6 +1695,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);
@@ -1535,6 +1715,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. */
        }