Diff for /embedaddon/readline/histexpand.c between versions 1.1.1.1 and 1.1.1.2

version 1.1.1.1, 2014/07/30 08:16:45 version 1.1.1.2, 2021/03/17 01:01:01
Line 1 Line 1
 /* histexpand.c -- history expansion. */  /* histexpand.c -- history expansion. */
   
/* Copyright (C) 1989-2012 Free Software Foundation, Inc./* Copyright (C) 1989-2018 Free Software Foundation, Inc.
   
    This file contains the GNU History Library (History), a set of     This file contains the GNU History Library (History), a set of
    routines for managing the text of previously typed lines.     routines for managing the text of previously typed lines.
Line 44 Line 44
   
 #include "history.h"  #include "history.h"
 #include "histlib.h"  #include "histlib.h"
   #include "chardefs.h"
   
 #include "rlshell.h"  #include "rlshell.h"
 #include "xmalloc.h"  #include "xmalloc.h"
   
 #define HISTORY_WORD_DELIMITERS         " \t\n;&()|<>"  #define HISTORY_WORD_DELIMITERS         " \t\n;&()|<>"
 #define HISTORY_QUOTE_CHARACTERS        "\"'`"  #define HISTORY_QUOTE_CHARACTERS        "\"'`"
   #define HISTORY_EVENT_DELIMITERS        "^$*%-"
   
 #define slashify_in_quotes "\\`\"$"  #define slashify_in_quotes "\\`\"$"
   
   #define fielddelim(c)   (whitespace(c) || (c) == '\n')
   
 typedef int _hist_search_func_t PARAMS((const char *, int));  typedef int _hist_search_func_t PARAMS((const char *, int));
   
 static char error_pointer;  static char error_pointer;
Line 62  static char *subst_rhs; Line 66  static char *subst_rhs;
 static int subst_lhs_len;  static int subst_lhs_len;
 static int subst_rhs_len;  static int subst_rhs_len;
   
   /* Characters that delimit history event specifications and separate event
      specifications from word designators.  Static for now */
   static char *history_event_delimiter_chars = HISTORY_EVENT_DELIMITERS;
   
 static char *get_history_word_specifier PARAMS((char *, char *, int *));  static char *get_history_word_specifier PARAMS((char *, char *, int *));
 static int history_tokenize_word PARAMS((const char *, int));  static int history_tokenize_word PARAMS((const char *, int));
 static char **history_tokenize_internal PARAMS((const char *, int, int *));  static char **history_tokenize_internal PARAMS((const char *, int, int *));
Line 81  char history_expansion_char = '!'; Line 89  char history_expansion_char = '!';
 char history_subst_char = '^';  char history_subst_char = '^';
   
 /* During tokenization, if this character is seen as the first character  /* During tokenization, if this character is seen as the first character
   of a word, then it, and all subsequent characters upto a newline are   of a word, then it, and all subsequent characters up to a newline are
    ignored.  For a Bourne shell, this should be '#'.  Bash special cases     ignored.  For a Bourne shell, this should be '#'.  Bash special cases
    the interactive comment character to not be a comment delimiter. */     the interactive comment character to not be a comment delimiter. */
 char history_comment_char = '\0';  char history_comment_char = '\0';
Line 101  char *history_word_delimiters = HISTORY_WORD_DELIMITER Line 109  char *history_word_delimiters = HISTORY_WORD_DELIMITER
    particular history expansion should be performed. */     particular history expansion should be performed. */
 rl_linebuf_func_t *history_inhibit_expansion_function;  rl_linebuf_func_t *history_inhibit_expansion_function;
   
   int history_quoting_state = 0;
   
 /* **************************************************************** */  /* **************************************************************** */
 /*                                                                  */  /*                                                                  */
 /*                      History Expansion                           */  /*                      History Expansion                           */
Line 112  rl_linebuf_func_t *history_inhibit_expansion_function; Line 122  rl_linebuf_func_t *history_inhibit_expansion_function;
   
 /* The last string searched for by a !?string? search. */  /* The last string searched for by a !?string? search. */
 static char *search_string;  static char *search_string;
   
 /* The last string matched by a !?string? search. */  /* The last string matched by a !?string? search. */
 static char *search_match;  static char *search_match;
   
Line 127  static char *search_match; Line 136  static char *search_match;
    So you might call this function like:     So you might call this function like:
    line = get_history_event ("!echo:p", &index, 0);  */     line = get_history_event ("!echo:p", &index, 0);  */
 char *  char *
get_history_event (string, caller_index, delimiting_quote)get_history_event (const char *string, int *caller_index, int delimiting_quote)
     const char *string; 
     int *caller_index; 
     int delimiting_quote; 
 {  {
   register int i;    register int i;
   register char c;    register char c;
Line 174  get_history_event (string, caller_index, delimiting_qu Line 180  get_history_event (string, caller_index, delimiting_qu
     }      }
   
   /* Hack case of numeric line specification. */    /* Hack case of numeric line specification. */
  if (string[i] == '-')  if (string[i] == '-' && _rl_digit_p (string[i+1]))
     {      {
       sign = -1;        sign = -1;
       i++;        i++;
Line 224  get_history_event (string, caller_index, delimiting_qu Line 230  get_history_event (string, caller_index, delimiting_qu
         }          }
   
 #endif /* HANDLE_MULTIBYTE */  #endif /* HANDLE_MULTIBYTE */
      if ((!substring_okay && (whitespace (c) || c == ':' ||      if ((!substring_okay &&
          (history_search_delimiter_chars && member (c, history_search_delimiter_chars)) ||            (whitespace (c) || c == ':' ||
          string[i] == delimiting_quote)) ||            (i > local_index && history_event_delimiter_chars && c == '-') ||
             (c != '-' && history_event_delimiter_chars && member (c, history_event_delimiter_chars)) ||
             (history_search_delimiter_chars && member (c, history_search_delimiter_chars)) ||
             string[i] == delimiting_quote)) ||
           string[i] == '\n' ||            string[i] == '\n' ||
           (substring_okay && string[i] == '?'))            (substring_okay && string[i] == '?'))
         break;          break;
Line 310  get_history_event (string, caller_index, delimiting_qu Line 319  get_history_event (string, caller_index, delimiting_qu
    to the closing single quote.  FLAGS currently used to allow backslash     to the closing single quote.  FLAGS currently used to allow backslash
    to escape a single quote (e.g., for bash $'...'). */     to escape a single quote (e.g., for bash $'...'). */
 static void  static void
hist_string_extract_single_quoted (string, sindex, flags)hist_string_extract_single_quoted (char *string, int *sindex, int flags)
     char *string; 
     int *sindex, flags; 
 {  {
   register int i;    register int i;
   
Line 326  hist_string_extract_single_quoted (string, sindex, fla Line 333  hist_string_extract_single_quoted (string, sindex, fla
 }  }
   
 static char *  static char *
quote_breaks (s)quote_breaks (char *s)
     char *s; 
 {  {
   register char *p, *r;    register char *p, *r;
   char *ret;    char *ret;
Line 368  quote_breaks (s) Line 374  quote_breaks (s)
 }  }
   
 static char *  static char *
hist_error(s, start, current, errtype)hist_error(char *s, int start, int current, int errtype)
      char *s; 
      int start, current, errtype; 
 {  {
   char *temp;    char *temp;
   const char *emsg;    const char *emsg;
Line 407  hist_error(s, start, current, errtype) Line 411  hist_error(s, start, current, errtype)
     }      }
   
   temp = (char *)xmalloc (ll + elen + 3);    temp = (char *)xmalloc (ll + elen + 3);
  strncpy (temp, s + start, ll);  if (s[start])
     strncpy (temp, s + start, ll);
   else
     ll = 0;
   temp[ll] = ':';    temp[ll] = ':';
   temp[ll + 1] = ' ';    temp[ll + 1] = ' ';
   strcpy (temp + ll + 2, emsg);    strcpy (temp + ll + 2, emsg);
Line 427  hist_error(s, start, current, errtype) Line 434  hist_error(s, start, current, errtype)
    subst_rhs is allowed to be set to the empty string. */     subst_rhs is allowed to be set to the empty string. */
   
 static char *  static char *
get_subst_pattern (str, iptr, delimiter, is_rhs, lenptr)get_subst_pattern (char *str, int *iptr, int delimiter, int is_rhs, int *lenptr)
     char *str; 
     int *iptr, delimiter, is_rhs, *lenptr; 
 {  {
   register int si, i, j, k;    register int si, i, j, k;
   char *s;    char *s;
Line 484  get_subst_pattern (str, iptr, delimiter, is_rhs, lenpt Line 489  get_subst_pattern (str, iptr, delimiter, is_rhs, lenpt
 }  }
   
 static void  static void
postproc_subst_rhs ()postproc_subst_rhs (void)
 {  {
   char *new;    char *new;
   int i, j, new_size;    int i, j, new_size;
Line 520  postproc_subst_rhs () Line 525  postproc_subst_rhs ()
    if the `p' modifier was supplied and the caller should just print     if the `p' modifier was supplied and the caller should just print
    the returned string.  Returns the new index into string in     the returned string.  Returns the new index into string in
    *END_INDEX_PTR, and the expanded specifier in *RET_STRING. */     *END_INDEX_PTR, and the expanded specifier in *RET_STRING. */
   /* need current line for !# */
 static int  static int
history_expand_internal (string, start, qc, end_index_ptr, ret_string, current_line)history_expand_internal (char *string, int start, int qc, int *end_index_ptr, char **ret_string, char *current_line)
     char *string; 
     int start, qc, *end_index_ptr; 
     char **ret_string; 
     char *current_line;       /* for !# */ 
 {  {
   int i, n, starting_index;    int i, n, starting_index;
   int substitute_globally, subst_bywords, want_quotes, print_only;    int substitute_globally, subst_bywords, want_quotes, print_only;
Line 627  history_expand_internal (string, start, qc, end_index_ Line 629  history_expand_internal (string, start, qc, end_index_
              return an error state after adding this line to the               return an error state after adding this line to the
              history. */               history. */
         case 'p':          case 'p':
          print_only++;          print_only = 1;
           break;            break;
   
           /* :t discards all but the last part of the pathname. */            /* :t discards all but the last part of the pathname. */
Line 774  history_expand_internal (string, start, qc, end_index_ Line 776  history_expand_internal (string, start, qc, end_index_
                    the last time. */                     the last time. */
                 if (subst_bywords && si > we)                  if (subst_bywords && si > we)
                   {                    {
                    for (; temp[si] && whitespace (temp[si]); si++)                    for (; temp[si] && fielddelim (temp[si]); si++)
                       ;                        ;
                     ws = si;                      ws = si;
                     we = history_tokenize_word (temp, si);                      we = history_tokenize_word (temp, si);
Line 873  history_expand_internal (string, start, qc, end_index_ Line 875  history_expand_internal (string, start, qc, end_index_
    1) If expansions did take place     1) If expansions did take place
    2) If the `p' modifier was given and the caller should print the result     2) If the `p' modifier was given and the caller should print the result
   
  If an error ocurred in expansion, then OUTPUT contains a descriptive  If an error occurred in expansion, then OUTPUT contains a descriptive
   error message. */    error message. */
   
 #define ADD_STRING(s) \  #define ADD_STRING(s) \
Line 902  history_expand_internal (string, start, qc, end_index_ Line 904  history_expand_internal (string, start, qc, end_index_
         while (0)          while (0)
   
 int  int
history_expand (hstring, output)history_expand (char *hstring, char **output)
     char *hstring; 
     char **output; 
 {  {
   register int j;    register int j;
   int i, r, l, passc, cc, modified, eindex, only_printing, dquote, squote, flag;    int i, r, l, passc, cc, modified, eindex, only_printing, dquote, squote, flag;
Line 970  history_expand (hstring, output) Line 970  history_expand (hstring, output)
   
       /* `!' followed by one of the characters in history_no_expand_chars        /* `!' followed by one of the characters in history_no_expand_chars
          is NOT an expansion. */           is NOT an expansion. */
      for (i = dquote = squote = 0; string[i]; i++)      dquote = history_quoting_state == '"';
       squote = history_quoting_state == '\'';
 
       /* If the calling application tells us we are already reading a
          single-quoted string, consume the rest of the string right now
          and then go on. */
       i = 0;
       if (squote && history_quotes_inhibit_expansion)
         {          {
             hist_string_extract_single_quoted (string, &i, 0);
             squote = 0;
             if (string[i])
               i++;
           }
   
         for ( ; string[i]; i++)
           {
 #if defined (HANDLE_MULTIBYTE)  #if defined (HANDLE_MULTIBYTE)
           if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)            if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
             {              {
Line 991  history_expand (hstring, output) Line 1006  history_expand (hstring, output)
              history expansion performed on it.               history expansion performed on it.
              Skip the rest of the line and break out of the loop. */               Skip the rest of the line and break out of the loop. */
           if (history_comment_char && string[i] == history_comment_char &&            if (history_comment_char && string[i] == history_comment_char &&
                 dquote == 0 &&
               (i == 0 || member (string[i - 1], history_word_delimiters)))                (i == 0 || member (string[i - 1], history_word_delimiters)))
             {              {
               while (string[i])                while (string[i])
Line 1057  history_expand (hstring, output) Line 1073  history_expand (hstring, output)
     }      }
   
   /* Extract and perform the substitution. */    /* Extract and perform the substitution. */
  for (passc = dquote = squote = i = j = 0; i < l; i++)  dquote = history_quoting_state == '"';
   squote = history_quoting_state == '\'';
 
   /* If the calling application tells us we are already reading a
      single-quoted string, consume the rest of the string right now
      and then go on. */
   i = j = 0;
   if (squote && history_quotes_inhibit_expansion)
     {      {
         int c;
   
         hist_string_extract_single_quoted (string, &i, 0);
         squote = 0;
         for (c = 0; c < i; c++)
           ADD_CHAR (string[c]);      
         if (string[i])
           {
             ADD_CHAR (string[i]);
             i++;
           }
       }
   
     for (passc = 0; i < l; i++)
       {
       int qc, tchar = string[i];        int qc, tchar = string[i];
   
       if (passc)        if (passc)
Line 1149  history_expand (hstring, output) Line 1187  history_expand (hstring, output)
           }            }
   
         case -2:                /* history_comment_char */          case -2:                /* history_comment_char */
          if (i == 0 || member (string[i - 1], history_word_delimiters))          if ((dquote == 0 || history_quotes_inhibit_expansion == 0) &&
               (i == 0 || member (string[i - 1], history_word_delimiters)))
             {              {
               temp = (char *)xmalloc (l - i + 1);                temp = (char *)xmalloc (l - i + 1);
               strcpy (temp, string + i);                strcpy (temp, string + i);
Line 1213  history_expand (hstring, output) Line 1252  history_expand (hstring, output)
                     ADD_STRING (temp);                      ADD_STRING (temp);
                   xfree (temp);                    xfree (temp);
                 }                  }
              only_printing = r == 1;              only_printing += r == 1;
               i = eindex;                i = eindex;
             }              }
           break;            break;
Line 1241  history_expand (hstring, output) Line 1280  history_expand (hstring, output)
    CALLER_INDEX is the offset in SPEC to start looking; it is updated     CALLER_INDEX is the offset in SPEC to start looking; it is updated
    to point to just after the last character parsed. */     to point to just after the last character parsed. */
 static char *  static char *
get_history_word_specifier (spec, from, caller_index)get_history_word_specifier (char *spec, char *from, int *caller_index)
     char *spec, *from; 
     int *caller_index; 
 {  {
   register int i = *caller_index;    register int i = *caller_index;
   int first, last;    int first, last;
Line 1324  get_history_word_specifier (spec, from, caller_index) Line 1361  get_history_word_specifier (spec, from, caller_index)
           i++;            i++;
           last = '$';            last = '$';
         }          }
         else if (spec[i] == '^')
           {
             i++;
             last = 1;
           }
 #if 0  #if 0
       else if (!spec[i] || spec[i] == ':')        else if (!spec[i] || spec[i] == ':')
         /* check against `:' because there could be a modifier separator */          /* check against `:' because there could be a modifier separator */
Line 1349  get_history_word_specifier (spec, from, caller_index) Line 1391  get_history_word_specifier (spec, from, caller_index)
    tokens, so that FIRST = -1 means the next to last token on the line).     tokens, so that FIRST = -1 means the next to last token on the line).
    If LAST is `$' the last arg from STRING is used. */     If LAST is `$' the last arg from STRING is used. */
 char *  char *
history_arg_extract (first, last, string)history_arg_extract (int first, int last, const char *string)
     int first, last; 
     const char *string; 
 {  {
   register int i, len;    register int i, len;
   char *result;    char *result;
Line 1410  history_arg_extract (first, last, string) Line 1450  history_arg_extract (first, last, string)
 }  }
   
 static int  static int
history_tokenize_word (string, ind)history_tokenize_word (const char *string, int ind)
     const char *string; 
     int ind; 
 {  {
  register int i;  register int i, j;
   int delimiter, nestdelim, delimopen;    int delimiter, nestdelim, delimopen;
   
   i = ind;    i = ind;
   delimiter = nestdelim = 0;    delimiter = nestdelim = 0;
   
  if (member (string[i], "()\n"))  if (member (string[i], "()\n"))       /* XXX - included \n, but why? been here forever */
     {      {
       i++;        i++;
       return i;        return i;
     }      }
   
  if (member (string[i], "<>;&|$"))  if (ISDIGIT (string[i]))
     {      {
         j = i;
         while (string[j] && ISDIGIT (string[j]))
           j++;
         if (string[j] == 0)
           return (j);
         if (string[j] == '<' || string[j] == '>')
           i = j;                  /* digit sequence is a file descriptor */
         else
           {
             i = j;
             goto get_word;        /* digit sequence is part of a word */
           }
       }
   
     if (member (string[i], "<>;&|"))
       {
       int peek = string[i + 1];        int peek = string[i + 1];
   
      if (peek == string[i] && peek != '$')      if (peek == string[i])
         {          {
           if (peek == '<' && string[i + 2] == '-')            if (peek == '<' && string[i + 2] == '-')
             i++;              i++;
Line 1439  history_tokenize_word (string, ind) Line 1493  history_tokenize_word (string, ind)
           i += 2;            i += 2;
           return i;            return i;
         }          }
      else if ((peek == '&' && (string[i] == '>' || string[i] == '<')) ||      else if (peek == '&' && (string[i] == '>' || string[i] == '<'))
                (peek == '>' && string[i] == '&')) 
         {          {
             j = i + 2;
             while (string[j] && ISDIGIT (string[j]))      /* file descriptor */
               j++;
             if (string[j] =='-')          /* <&[digits]-, >&[digits]- */
               j++;
             return j;
           }
         else if ((peek == '>' && string[i] == '&') || (peek == '|' && string[i] == '>'))
           {
           i += 2;            i += 2;
           return i;            return i;
         }          }
      /* XXX - separated out for later -- bash-4.2 */      /* XXX - process substitution -- separated out for later -- bash-4.2 */
      else if ((peek == '(' && (string[i] == '>' || string[i] == '<')) || /* ) */      else if (peek == '(' && (string[i] == '>' || string[i] == '<')) /*)*/
               (peek == '(' && string[i] == '$')) /*)*/ 
         {          {
           i += 2;            i += 2;
           delimopen = '(';            delimopen = '(';
Line 1455  history_tokenize_word (string, ind) Line 1516  history_tokenize_word (string, ind)
           nestdelim = 1;            nestdelim = 1;
           goto get_word;            goto get_word;
         }          }
 #if 0  
       else if (peek == '\'' && string[i] == '$')  
         {  
           i += 2;       /* XXX */  
           return i;  
         }  
 #endif  
   
      if (string[i] != '$')      i++;
        {      return i;
          i++; 
          return i; 
        } 
     }      }
   
   /* same code also used for $(...)/<(...)/>(...) above */  
   if (member (string[i], "!@?+*"))  
     {  
       int peek = string[i + 1];  
   
       if (peek == '(')          /*)*/  
         {  
           /* Shell extended globbing patterns */  
           i += 2;  
           delimopen = '(';  
           delimiter = ')';      /* XXX - not perfect */  
           nestdelim = 1;  
         }  
     }  
   
 get_word:  get_word:
   /* Get word from string + i; */    /* Get word from string + i; */
   
Line 1527  get_word: Line 1563  get_word:
           continue;            continue;
         }          }
   
         /* Command and process substitution; shell extended globbing patterns */
         if (nestdelim == 0 && delimiter == 0 && member (string[i], "<>$!@?+*") && string[i+1] == '(') /*)*/
           {
             i += 2;
             delimopen = '(';
             delimiter = ')';
             nestdelim = 1;
             continue;
           }
         
       if (delimiter == 0 && (member (string[i], history_word_delimiters)))        if (delimiter == 0 && (member (string[i], history_word_delimiters)))
         break;          break;
   
Line 1538  get_word: Line 1584  get_word:
 }  }
   
 static char *  static char *
history_substring (string, start, end)history_substring (const char *string, int start, int end)
     const char *string; 
     int start, end; 
 {  {
   register int len;    register int len;
   register char *result;    register char *result;
Line 1557  history_substring (string, start, end) Line 1601  history_substring (string, start, end)
    WIND.  The position in the returned array of strings is returned in     WIND.  The position in the returned array of strings is returned in
    *INDP. */     *INDP. */
 static char **  static char **
history_tokenize_internal (string, wind, indp)history_tokenize_internal (const char *string, int wind, int *indp)
     const char *string; 
     int wind, *indp; 
 {  {
   char **result;    char **result;
   register int i, start, result_index, size;    register int i, start, result_index, size;
Line 1574  history_tokenize_internal (string, wind, indp) Line 1616  history_tokenize_internal (string, wind, indp)
   for (i = result_index = size = 0, result = (char **)NULL; string[i]; )    for (i = result_index = size = 0, result = (char **)NULL; string[i]; )
     {      {
       /* Skip leading whitespace. */        /* Skip leading whitespace. */
      for (; string[i] && whitespace (string[i]); i++)      for (; string[i] && fielddelim (string[i]); i++)
         ;          ;
       if (string[i] == 0 || string[i] == history_comment_char)        if (string[i] == 0 || string[i] == history_comment_char)
         return (result);          return (result);
Line 1612  history_tokenize_internal (string, wind, indp) Line 1654  history_tokenize_internal (string, wind, indp)
 /* Return an array of tokens, much as the shell might.  The tokens are  /* Return an array of tokens, much as the shell might.  The tokens are
    parsed out of STRING. */     parsed out of STRING. */
 char **  char **
history_tokenize (string)history_tokenize (const char *string)
     const char *string; 
 {  {
   return (history_tokenize_internal (string, -1, (int *)NULL));    return (history_tokenize_internal (string, -1, (int *)NULL));
 }  }
   
 /* Free members of WORDS from START to an empty string */  /* Free members of WORDS from START to an empty string */
 static void  static void
freewords (words, start)freewords (char **words, int start)
     char **words; 
     int start; 
 {  {
   register int i;    register int i;
   
Line 1634  freewords (words, start) Line 1673  freewords (words, start)
    in the history line LINE.  Used to save the word matched by the     in the history line LINE.  Used to save the word matched by the
    last history !?string? search. */     last history !?string? search. */
 static char *  static char *
history_find_word (line, ind)history_find_word (char *line, int ind)
     char *line; 
     int ind; 
 {  {
   char **words, *s;    char **words, *s;
   int i, wind;    int i, wind;

Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.2


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>