Imported from ../bash-2.04.tar.gz.
[platform/upstream/bash.git] / lib / readline / histexpand.c
index d916c74..78da3e5 100644 (file)
@@ -7,7 +7,7 @@
 
    The Library is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 1, or (at your option)
+   the Free Software Foundation; either version 2, or (at your option)
    any later version.
 
    The Library is distributed in the hope that it will be useful, but
@@ -18,7 +18,7 @@
    The GNU General Public License is often shipped with GNU software, and
    is generally kept in a file called COPYING or LICENSE.  If you do not
    have a copy of the license, write to the Free Software Foundation,
-   675 Mass Ave, Cambridge, MA 02139, USA. */
+   59 Temple Place, Suite 330, Boston, MA 02111 USA. */
 
 #define READLINE_LIBRARY
 
@@ -35,6 +35,9 @@
 #endif /* HAVE_STDLIB_H */
 
 #if defined (HAVE_UNISTD_H)
+#  ifndef _MINIX
+#    include <sys/types.h>
+#  endif
 #  include <unistd.h>
 #endif
 
 #include "history.h"
 #include "histlib.h"
 
+#include "rlshell.h"
+#include "xmalloc.h"
+
+#define HISTORY_WORD_DELIMITERS                " \t\n;&()|<>"
+#define HISTORY_QUOTE_CHARACTERS       "\"'`"
+
 static char error_pointer;
 
 static char *subst_lhs;
@@ -54,19 +63,10 @@ static char *subst_rhs;
 static int subst_lhs_len;
 static int subst_rhs_len;
 
-static char *get_history_word_specifier ();
-static char *history_find_word ();
-
-extern int history_offset;
+static char *get_history_word_specifier __P((char *, char *, int *));
+static char *history_find_word __P((char *, int));
 
-#if defined (SHELL)
-extern char *single_quote ();
-#else
-static char *single_quote ();
-#endif /* !SHELL */
-static char *quote_breaks ();
-
-extern char *xmalloc (), *xrealloc ();
+static char *quote_breaks __P((char *));
 
 /* Variables exported by this file. */
 /* The character that represents the start of a history expansion
@@ -91,6 +91,10 @@ char *history_no_expand_chars = " \t\n\r=";
    The default is 0. */
 int history_quotes_inhibit_expansion = 0;
 
+/* If set, this points to a function that is called to verify that a
+   particular history expansion should be performed. */
+Function *history_inhibit_expansion_function;
+
 /* **************************************************************** */
 /*                                                                 */
 /*                     History Expansion                           */
@@ -289,38 +293,6 @@ hist_string_extract_single_quoted (string, sindex)
   *sindex = i;
 }
 
-#if !defined (SHELL)
-/* Does shell-like quoting using single quotes. */
-static char *
-single_quote (string)
-     char *string;
-{
-  register int c;
-  char *result, *r, *s;
-
-  result = (char *)xmalloc (3 + (3 * strlen (string)));
-  r = result;
-  *r++ = '\'';
-
-  for (s = string; s && (c = *s); s++)
-    {
-      *r++ = c;
-
-      if (c == '\'')
-       {
-         *r++ = '\\';  /* insert escaped single quote */
-         *r++ = '\'';
-         *r++ = '\'';  /* start new quoted string */
-       }
-    }
-
-  *r++ = '\'';
-  *r = '\0';
-
-  return (result);
-}
-#endif /* !SHELL */
-
 static char *
 quote_breaks (s)
      char *s;
@@ -391,6 +363,10 @@ hist_error(s, start, current, errtype)
       emsg = "unrecognized history modifier";
       elen = 29;
       break;
+    case NO_PREV_SUBST:
+      emsg = "no previous substitution";
+      elen = 24;
+      break;
     default:
       emsg = "unknown expansion error";
       elen = 23;
@@ -680,15 +656,6 @@ history_expand_internal (string, start, end_index_ptr, ret_string, current_line)
                      }
                  }
 
-               /* If there is no lhs, the substitution can't succeed. */
-               if (subst_lhs_len == 0)
-                 {
-                   *ret_string = hist_error (string, starting_index, i, SUBST_FAILED);
-                   free (result);
-                   free (temp);
-                   return -1;
-                 }
-
                FREE (subst_rhs);
                subst_rhs = get_subst_pattern (string, &i, delimiter, 1, &subst_rhs_len);
 
@@ -700,6 +667,15 @@ history_expand_internal (string, start, end_index_ptr, ret_string, current_line)
            else
              i += 2;
 
+           /* If there is no lhs, the substitution can't succeed. */
+           if (subst_lhs_len == 0)
+             {
+               *ret_string = hist_error (string, starting_index, i, NO_PREV_SUBST);
+               free (result);
+               free (temp);
+               return -1;
+             }
+
            l_temp = strlen (temp);
            /* Ignore impossible cases. */
            if (subst_lhs_len > l_temp)
@@ -855,8 +831,8 @@ history_expand (hstring, output)
   only_printing = modified = 0;
   l = strlen (hstring);
 
-  /* Grovel the string.  Only backslash can quote the history escape
-     character.  We also handle arg specifiers. */
+  /* Grovel the string.  Only backslash and single quotes can quote the
+     history escape character.  We also handle arg specifiers. */
 
   /* Before we grovel forever, see if the history_expansion_char appears
      anywhere within the text. */
@@ -884,26 +860,34 @@ history_expand (hstring, output)
       for (i = 0; string[i]; i++)
        {
          cc = string[i + 1];
-         if (string[i] == history_expansion_char)
+         /* The history_comment_char, if set, appearing that the beginning
+            of a word signifies that the rest of the line should not have
+            history expansion performed on it.
+            Skip the rest of the line and break out of the loop. */
+         if (history_comment_char && string[i] == history_comment_char &&
+             (i == 0 || member (string[i - 1], HISTORY_WORD_DELIMITERS)))
+           {
+             while (string[i])
+               i++;
+             break;
+           }
+         else if (string[i] == history_expansion_char)
            {
              if (!cc || member (cc, history_no_expand_chars))
                continue;
-#if defined (SHELL)
-             /* The shell uses ! as a pattern negation character
-                in globbing [...] expressions, so let those pass
-                without expansion. */
-             else if (i > 0 && (string[i - 1] == '[') &&
-                      member (']', string + i + 1))
-               continue;
-             /* The shell uses ! as the indirect expansion character, so
-                let those expansions pass as well. */
-             else if (i > 1 && string[i - 1] == '{' && string[i - 2] == '$' &&
-                      member ('}', string + i + 1))
+             /* If the calling application has set
+                history_inhibit_expansion_function to a function that checks
+                for special cases that should not be history expanded,
+                call the function and skip the expansion if it returns a
+                non-zero value. */
+             else if (history_inhibit_expansion_function &&
+                       (*history_inhibit_expansion_function) (string, i))
                continue;
-#endif /* SHELL */
              else
                break;
            }
+         /* XXX - at some point, might want to extend this to handle
+                  double quotes as well. */
          else if (history_quotes_inhibit_expansion && string[i] == '\'')
            {
              /* If this is bash, single quotes inhibit history expansion. */
@@ -941,6 +925,8 @@ history_expand (hstring, output)
 
       if (tchar == history_expansion_char)
        tchar = -3;
+      else if (tchar == history_comment_char)
+       tchar = -2;
 
       switch (tchar)
        {
@@ -976,6 +962,19 @@ history_expand (hstring, output)
            break;
          }
 
+       case -2:                /* history_comment_char */
+         if (i == 0 || member (string[i - 1], HISTORY_WORD_DELIMITERS))
+           {
+             temp = xmalloc (l - i + 1);
+             strcpy (temp, string + i);
+             ADD_STRING (temp);
+             free (temp);
+             i = l;
+           }
+         else
+           ADD_CHAR (string[i]);
+         break;
+
        case -3:                /* history_expansion_char */
          cc = string[i + 1];
 
@@ -1275,7 +1274,7 @@ history_tokenize_internal (string, wind, indp)
 
       /* Get word from string + i; */
 
-      if (member (string[i], "\"'`"))
+      if (member (string[i], HISTORY_QUOTE_CHARACTERS))
        delimiter = string[i++];
 
       for (; string[i]; i++)
@@ -1299,10 +1298,10 @@ history_tokenize_internal (string, wind, indp)
              continue;
            }
 
-         if (!delimiter && (member (string[i], " \t\n;&()|<>")))
+         if (!delimiter && (member (string[i], HISTORY_WORD_DELIMITERS)))
            break;
 
-         if (!delimiter && member (string[i], "\"'`"))
+         if (!delimiter && member (string[i], HISTORY_QUOTE_CHARACTERS))
            delimiter = string[i];
        }