File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / readline / histexpand.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 01:01:01 2021 UTC (3 years, 3 months ago) by misho
Branches: readline, MAIN
CVS tags: v8_2p0, v8_1p0, HEAD
readline 8.1

    1: /* histexpand.c -- history expansion. */
    2: 
    3: /* Copyright (C) 1989-2018 Free Software Foundation, Inc.
    4: 
    5:    This file contains the GNU History Library (History), a set of
    6:    routines for managing the text of previously typed lines.
    7: 
    8:    History is free software: you can redistribute it and/or modify
    9:    it under the terms of the GNU General Public License as published by
   10:    the Free Software Foundation, either version 3 of the License, or
   11:    (at your option) any later version.
   12: 
   13:    History is distributed in the hope that it will be useful,
   14:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   15:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16:    GNU General Public License for more details.
   17: 
   18:    You should have received a copy of the GNU General Public License
   19:    along with History.  If not, see <http://www.gnu.org/licenses/>.
   20: */
   21: 
   22: #define READLINE_LIBRARY
   23: 
   24: #if defined (HAVE_CONFIG_H)
   25: #  include <config.h>
   26: #endif
   27: 
   28: #include <stdio.h>
   29: 
   30: #if defined (HAVE_STDLIB_H)
   31: #  include <stdlib.h>
   32: #else
   33: #  include "ansi_stdlib.h"
   34: #endif /* HAVE_STDLIB_H */
   35: 
   36: #if defined (HAVE_UNISTD_H)
   37: #  ifndef _MINIX
   38: #    include <sys/types.h>
   39: #  endif
   40: #  include <unistd.h>
   41: #endif
   42: 
   43: #include "rlmbutil.h"
   44: 
   45: #include "history.h"
   46: #include "histlib.h"
   47: #include "chardefs.h"
   48: 
   49: #include "rlshell.h"
   50: #include "xmalloc.h"
   51: 
   52: #define HISTORY_WORD_DELIMITERS		" \t\n;&()|<>"
   53: #define HISTORY_QUOTE_CHARACTERS	"\"'`"
   54: #define HISTORY_EVENT_DELIMITERS	"^$*%-"
   55: 
   56: #define slashify_in_quotes "\\`\"$"
   57: 
   58: #define fielddelim(c)	(whitespace(c) || (c) == '\n')
   59: 
   60: typedef int _hist_search_func_t PARAMS((const char *, int));
   61: 
   62: static char error_pointer;
   63: 
   64: static char *subst_lhs;
   65: static char *subst_rhs;
   66: static int subst_lhs_len;
   67: static int subst_rhs_len;
   68: 
   69: /* Characters that delimit history event specifications and separate event
   70:    specifications from word designators.  Static for now */
   71: static char *history_event_delimiter_chars = HISTORY_EVENT_DELIMITERS;
   72: 
   73: static char *get_history_word_specifier PARAMS((char *, char *, int *));
   74: static int history_tokenize_word PARAMS((const char *, int));
   75: static char **history_tokenize_internal PARAMS((const char *, int, int *));
   76: static char *history_substring PARAMS((const char *, int, int));
   77: static void freewords PARAMS((char **, int));
   78: static char *history_find_word PARAMS((char *, int));
   79: 
   80: static char *quote_breaks PARAMS((char *));
   81: 
   82: /* Variables exported by this file. */
   83: /* The character that represents the start of a history expansion
   84:    request.  This is usually `!'. */
   85: char history_expansion_char = '!';
   86: 
   87: /* The character that invokes word substitution if found at the start of
   88:    a line.  This is usually `^'. */
   89: char history_subst_char = '^';
   90: 
   91: /* During tokenization, if this character is seen as the first character
   92:    of a word, then it, and all subsequent characters up to a newline are
   93:    ignored.  For a Bourne shell, this should be '#'.  Bash special cases
   94:    the interactive comment character to not be a comment delimiter. */
   95: char history_comment_char = '\0';
   96: 
   97: /* The list of characters which inhibit the expansion of text if found
   98:    immediately following history_expansion_char. */
   99: char *history_no_expand_chars = " \t\n\r=";
  100: 
  101: /* If set to a non-zero value, single quotes inhibit history expansion.
  102:    The default is 0. */
  103: int history_quotes_inhibit_expansion = 0;
  104: 
  105: /* Used to split words by history_tokenize_internal. */
  106: char *history_word_delimiters = HISTORY_WORD_DELIMITERS;
  107: 
  108: /* If set, this points to a function that is called to verify that a
  109:    particular history expansion should be performed. */
  110: rl_linebuf_func_t *history_inhibit_expansion_function;
  111: 
  112: int history_quoting_state = 0;
  113: 
  114: /* **************************************************************** */
  115: /*								    */
  116: /*			History Expansion			    */
  117: /*								    */
  118: /* **************************************************************** */
  119: 
  120: /* Hairy history expansion on text, not tokens.  This is of general
  121:    use, and thus belongs in this library. */
  122: 
  123: /* The last string searched for by a !?string? search. */
  124: static char *search_string;
  125: /* The last string matched by a !?string? search. */
  126: static char *search_match;
  127: 
  128: /* Return the event specified at TEXT + OFFSET modifying OFFSET to
  129:    point to after the event specifier.  Just a pointer to the history
  130:    line is returned; NULL is returned in the event of a bad specifier.
  131:    You pass STRING with *INDEX equal to the history_expansion_char that
  132:    begins this specification.
  133:    DELIMITING_QUOTE is a character that is allowed to end the string
  134:    specification for what to search for in addition to the normal
  135:    characters `:', ` ', `\t', `\n', and sometimes `?'.
  136:    So you might call this function like:
  137:    line = get_history_event ("!echo:p", &index, 0);  */
  138: char *
  139: get_history_event (const char *string, int *caller_index, int delimiting_quote)
  140: {
  141:   register int i;
  142:   register char c;
  143:   HIST_ENTRY *entry;
  144:   int which, sign, local_index, substring_okay;
  145:   _hist_search_func_t *search_func;
  146:   char *temp;
  147: 
  148:   /* The event can be specified in a number of ways.
  149: 
  150:      !!   the previous command
  151:      !n   command line N
  152:      !-n  current command-line minus N
  153:      !str the most recent command starting with STR
  154:      !?str[?]
  155: 	  the most recent command containing STR
  156: 
  157:      All values N are determined via HISTORY_BASE. */
  158: 
  159:   i = *caller_index;
  160: 
  161:   if (string[i] != history_expansion_char)
  162:     return ((char *)NULL);
  163: 
  164:   /* Move on to the specification. */
  165:   i++;
  166: 
  167:   sign = 1;
  168:   substring_okay = 0;
  169: 
  170: #define RETURN_ENTRY(e, w) \
  171: 	return ((e = history_get (w)) ? e->line : (char *)NULL)
  172: 
  173:   /* Handle !! case. */
  174:   if (string[i] == history_expansion_char)
  175:     {
  176:       i++;
  177:       which = history_base + (history_length - 1);
  178:       *caller_index = i;
  179:       RETURN_ENTRY (entry, which);
  180:     }
  181: 
  182:   /* Hack case of numeric line specification. */
  183:   if (string[i] == '-' && _rl_digit_p (string[i+1]))
  184:     {
  185:       sign = -1;
  186:       i++;
  187:     }
  188: 
  189:   if (_rl_digit_p (string[i]))
  190:     {
  191:       /* Get the extent of the digits and compute the value. */
  192:       for (which = 0; _rl_digit_p (string[i]); i++)
  193: 	which = (which * 10) + _rl_digit_value (string[i]);
  194: 
  195:       *caller_index = i;
  196: 
  197:       if (sign < 0)
  198: 	which = (history_length + history_base) - which;
  199: 
  200:       RETURN_ENTRY (entry, which);
  201:     }
  202: 
  203:   /* This must be something to search for.  If the spec begins with
  204:      a '?', then the string may be anywhere on the line.  Otherwise,
  205:      the string must be found at the start of a line. */
  206:   if (string[i] == '?')
  207:     {
  208:       substring_okay++;
  209:       i++;
  210:     }
  211: 
  212:   /* Only a closing `?' or a newline delimit a substring search string. */
  213:   for (local_index = i; c = string[i]; i++)
  214:     {
  215: #if defined (HANDLE_MULTIBYTE)
  216:       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
  217: 	{
  218: 	  int v;
  219: 	  mbstate_t ps;
  220: 
  221: 	  memset (&ps, 0, sizeof (mbstate_t));
  222: 	  /* These produce warnings because we're passing a const string to a
  223: 	     function that takes a non-const string. */
  224: 	  _rl_adjust_point ((char *)string, i, &ps);
  225: 	  if ((v = _rl_get_char_len ((char *)string + i, &ps)) > 1)
  226: 	    {
  227: 	      i += v - 1;
  228: 	      continue;
  229: 	    }
  230:         }
  231: 
  232: #endif /* HANDLE_MULTIBYTE */
  233:       if ((!substring_okay &&
  234: 	    (whitespace (c) || c == ':' ||
  235: 	    (i > local_index && history_event_delimiter_chars && c == '-') ||
  236: 	    (c != '-' && history_event_delimiter_chars && member (c, history_event_delimiter_chars)) ||
  237: 	    (history_search_delimiter_chars && member (c, history_search_delimiter_chars)) ||
  238: 	    string[i] == delimiting_quote)) ||
  239: 	  string[i] == '\n' ||
  240: 	  (substring_okay && string[i] == '?'))
  241: 	break;
  242:     }
  243: 
  244:   which = i - local_index;
  245:   temp = (char *)xmalloc (1 + which);
  246:   if (which)
  247:     strncpy (temp, string + local_index, which);
  248:   temp[which] = '\0';
  249: 
  250:   if (substring_okay && string[i] == '?')
  251:     i++;
  252: 
  253:   *caller_index = i;
  254: 
  255: #define FAIL_SEARCH() \
  256:   do { \
  257:     history_offset = history_length; xfree (temp) ; return (char *)NULL; \
  258:   } while (0)
  259: 
  260:   /* If there is no search string, try to use the previous search string,
  261:      if one exists.  If not, fail immediately. */
  262:   if (*temp == '\0' && substring_okay)
  263:     {
  264:       if (search_string)
  265:         {
  266:           xfree (temp);
  267:           temp = savestring (search_string);
  268:         }
  269:       else
  270:         FAIL_SEARCH ();
  271:     }
  272: 
  273:   search_func = substring_okay ? history_search : history_search_prefix;
  274:   while (1)
  275:     {
  276:       local_index = (*search_func) (temp, -1);
  277: 
  278:       if (local_index < 0)
  279: 	FAIL_SEARCH ();
  280: 
  281:       if (local_index == 0 || substring_okay)
  282: 	{
  283: 	  entry = current_history ();
  284: 	  if (entry == 0)
  285: 	    FAIL_SEARCH ();
  286: 	  history_offset = history_length;
  287: 	
  288: 	  /* If this was a substring search, then remember the
  289: 	     string that we matched for word substitution. */
  290: 	  if (substring_okay)
  291: 	    {
  292: 	      FREE (search_string);
  293: 	      search_string = temp;
  294: 
  295: 	      FREE (search_match);
  296: 	      search_match = history_find_word (entry->line, local_index);
  297: 	    }
  298: 	  else
  299: 	    xfree (temp);
  300: 
  301: 	  return (entry->line);
  302: 	}
  303: 
  304:       if (history_offset)
  305: 	history_offset--;
  306:       else
  307: 	FAIL_SEARCH ();
  308:     }
  309: #undef FAIL_SEARCH
  310: #undef RETURN_ENTRY
  311: }
  312: 
  313: /* Function for extracting single-quoted strings.  Used for inhibiting
  314:    history expansion within single quotes. */
  315: 
  316: /* Extract the contents of STRING as if it is enclosed in single quotes.
  317:    SINDEX, when passed in, is the offset of the character immediately
  318:    following the opening single quote; on exit, SINDEX is left pointing
  319:    to the closing single quote.  FLAGS currently used to allow backslash
  320:    to escape a single quote (e.g., for bash $'...'). */
  321: static void
  322: hist_string_extract_single_quoted (char *string, int *sindex, int flags)
  323: {
  324:   register int i;
  325: 
  326:   for (i = *sindex; string[i] && string[i] != '\''; i++)
  327:     {
  328:       if ((flags & 1) && string[i] == '\\' && string[i+1])
  329:         i++;
  330:     }
  331: 
  332:   *sindex = i;
  333: }
  334: 
  335: static char *
  336: quote_breaks (char *s)
  337: {
  338:   register char *p, *r;
  339:   char *ret;
  340:   int len = 3;
  341: 
  342:   for (p = s; p && *p; p++, len++)
  343:     {
  344:       if (*p == '\'')
  345: 	len += 3;
  346:       else if (whitespace (*p) || *p == '\n')
  347: 	len += 2;
  348:     }
  349: 
  350:   r = ret = (char *)xmalloc (len);
  351:   *r++ = '\'';
  352:   for (p = s; p && *p; )
  353:     {
  354:       if (*p == '\'')
  355: 	{
  356: 	  *r++ = '\'';
  357: 	  *r++ = '\\';
  358: 	  *r++ = '\'';
  359: 	  *r++ = '\'';
  360: 	  p++;
  361: 	}
  362:       else if (whitespace (*p) || *p == '\n')
  363: 	{
  364: 	  *r++ = '\'';
  365: 	  *r++ = *p++;
  366: 	  *r++ = '\'';
  367: 	}
  368:       else
  369: 	*r++ = *p++;
  370:     }
  371:   *r++ = '\'';
  372:   *r = '\0';
  373:   return ret;
  374: }
  375: 
  376: static char *
  377: hist_error(char *s, int start, int current, int errtype)
  378: {
  379:   char *temp;
  380:   const char *emsg;
  381:   int ll, elen;
  382: 
  383:   ll = current - start;
  384: 
  385:   switch (errtype)
  386:     {
  387:     case EVENT_NOT_FOUND:
  388:       emsg = "event not found";
  389:       elen = 15;
  390:       break;
  391:     case BAD_WORD_SPEC:
  392:       emsg = "bad word specifier";
  393:       elen = 18;
  394:       break;
  395:     case SUBST_FAILED:
  396:       emsg = "substitution failed";
  397:       elen = 19;
  398:       break;
  399:     case BAD_MODIFIER:
  400:       emsg = "unrecognized history modifier";
  401:       elen = 29;
  402:       break;
  403:     case NO_PREV_SUBST:
  404:       emsg = "no previous substitution";
  405:       elen = 24;
  406:       break;
  407:     default:
  408:       emsg = "unknown expansion error";
  409:       elen = 23;
  410:       break;
  411:     }
  412: 
  413:   temp = (char *)xmalloc (ll + elen + 3);
  414:   if (s[start])
  415:     strncpy (temp, s + start, ll);
  416:   else
  417:     ll = 0;
  418:   temp[ll] = ':';
  419:   temp[ll + 1] = ' ';
  420:   strcpy (temp + ll + 2, emsg);
  421:   return (temp);
  422: }
  423: 
  424: /* Get a history substitution string from STR starting at *IPTR
  425:    and return it.  The length is returned in LENPTR.
  426: 
  427:    A backslash can quote the delimiter.  If the string is the
  428:    empty string, the previous pattern is used.  If there is
  429:    no previous pattern for the lhs, the last history search
  430:    string is used.
  431: 
  432:    If IS_RHS is 1, we ignore empty strings and set the pattern
  433:    to "" anyway.  subst_lhs is not changed if the lhs is empty;
  434:    subst_rhs is allowed to be set to the empty string. */
  435: 
  436: static char *
  437: get_subst_pattern (char *str, int *iptr, int delimiter, int is_rhs, int *lenptr)
  438: {
  439:   register int si, i, j, k;
  440:   char *s;
  441: #if defined (HANDLE_MULTIBYTE)
  442:   mbstate_t ps;
  443: #endif
  444: 
  445:   s = (char *)NULL;
  446:   i = *iptr;
  447: 
  448: #if defined (HANDLE_MULTIBYTE)
  449:   memset (&ps, 0, sizeof (mbstate_t));
  450:   _rl_adjust_point (str, i, &ps);
  451: #endif
  452: 
  453:   for (si = i; str[si] && str[si] != delimiter; si++)
  454: #if defined (HANDLE_MULTIBYTE)
  455:     if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
  456:       {
  457: 	int v;
  458: 	if ((v = _rl_get_char_len (str + si, &ps)) > 1)
  459: 	  si += v - 1;
  460: 	else if (str[si] == '\\' && str[si + 1] == delimiter)
  461: 	  si++;
  462:       }
  463:     else
  464: #endif /* HANDLE_MULTIBYTE */
  465:       if (str[si] == '\\' && str[si + 1] == delimiter)
  466: 	si++;
  467: 
  468:   if (si > i || is_rhs)
  469:     {
  470:       s = (char *)xmalloc (si - i + 1);
  471:       for (j = 0, k = i; k < si; j++, k++)
  472: 	{
  473: 	  /* Remove a backslash quoting the search string delimiter. */
  474: 	  if (str[k] == '\\' && str[k + 1] == delimiter)
  475: 	    k++;
  476: 	  s[j] = str[k];
  477: 	}
  478:       s[j] = '\0';
  479:       if (lenptr)
  480: 	*lenptr = j;
  481:     }
  482: 
  483:   i = si;
  484:   if (str[i])
  485:     i++;
  486:   *iptr = i;
  487: 
  488:   return s;
  489: }
  490: 
  491: static void
  492: postproc_subst_rhs (void)
  493: {
  494:   char *new;
  495:   int i, j, new_size;
  496: 
  497:   new = (char *)xmalloc (new_size = subst_rhs_len + subst_lhs_len);
  498:   for (i = j = 0; i < subst_rhs_len; i++)
  499:     {
  500:       if (subst_rhs[i] == '&')
  501: 	{
  502: 	  if (j + subst_lhs_len >= new_size)
  503: 	    new = (char *)xrealloc (new, (new_size = new_size * 2 + subst_lhs_len));
  504: 	  strcpy (new + j, subst_lhs);
  505: 	  j += subst_lhs_len;
  506: 	}
  507:       else
  508: 	{
  509: 	  /* a single backslash protects the `&' from lhs interpolation */
  510: 	  if (subst_rhs[i] == '\\' && subst_rhs[i + 1] == '&')
  511: 	    i++;
  512: 	  if (j >= new_size)
  513: 	    new = (char *)xrealloc (new, new_size *= 2);
  514: 	  new[j++] = subst_rhs[i];
  515: 	}
  516:     }
  517:   new[j] = '\0';
  518:   xfree (subst_rhs);
  519:   subst_rhs = new;
  520:   subst_rhs_len = j;
  521: }
  522: 
  523: /* Expand the bulk of a history specifier starting at STRING[START].
  524:    Returns 0 if everything is OK, -1 if an error occurred, and 1
  525:    if the `p' modifier was supplied and the caller should just print
  526:    the returned string.  Returns the new index into string in
  527:    *END_INDEX_PTR, and the expanded specifier in *RET_STRING. */
  528: /* need current line for !# */
  529: static int
  530: history_expand_internal (char *string, int start, int qc, int *end_index_ptr, char **ret_string, char *current_line)
  531: {
  532:   int i, n, starting_index;
  533:   int substitute_globally, subst_bywords, want_quotes, print_only;
  534:   char *event, *temp, *result, *tstr, *t, c, *word_spec;
  535:   int result_len;
  536: #if defined (HANDLE_MULTIBYTE)
  537:   mbstate_t ps;
  538: 
  539:   memset (&ps, 0, sizeof (mbstate_t));
  540: #endif
  541: 
  542:   result = (char *)xmalloc (result_len = 128);
  543: 
  544:   i = start;
  545: 
  546:   /* If it is followed by something that starts a word specifier,
  547:      then !! is implied as the event specifier. */
  548: 
  549:   if (member (string[i + 1], ":$*%^"))
  550:     {
  551:       char fake_s[3];
  552:       int fake_i = 0;
  553:       i++;
  554:       fake_s[0] = fake_s[1] = history_expansion_char;
  555:       fake_s[2] = '\0';
  556:       event = get_history_event (fake_s, &fake_i, 0);
  557:     }
  558:   else if (string[i + 1] == '#')
  559:     {
  560:       i += 2;
  561:       event = current_line;
  562:     }
  563:   else
  564:     event = get_history_event (string, &i, qc);
  565: 	  
  566:   if (event == 0)
  567:     {
  568:       *ret_string = hist_error (string, start, i, EVENT_NOT_FOUND);
  569:       xfree (result);
  570:       return (-1);
  571:     }
  572: 
  573:   /* If a word specifier is found, then do what that requires. */
  574:   starting_index = i;
  575:   word_spec = get_history_word_specifier (string, event, &i);
  576: 
  577:   /* There is no such thing as a `malformed word specifier'.  However,
  578:      it is possible for a specifier that has no match.  In that case,
  579:      we complain. */
  580:   if (word_spec == (char *)&error_pointer)
  581:     {
  582:       *ret_string = hist_error (string, starting_index, i, BAD_WORD_SPEC);
  583:       xfree (result);
  584:       return (-1);
  585:     }
  586: 
  587:   /* If no word specifier, than the thing of interest was the event. */
  588:   temp = word_spec ? savestring (word_spec) : savestring (event);
  589:   FREE (word_spec);
  590: 
  591:   /* Perhaps there are other modifiers involved.  Do what they say. */
  592:   want_quotes = substitute_globally = subst_bywords = print_only = 0;
  593:   starting_index = i;
  594: 
  595:   while (string[i] == ':')
  596:     {
  597:       c = string[i + 1];
  598: 
  599:       if (c == 'g' || c == 'a')
  600: 	{
  601: 	  substitute_globally = 1;
  602: 	  i++;
  603: 	  c = string[i + 1];
  604: 	}
  605:       else if (c == 'G')
  606: 	{
  607: 	  subst_bywords = 1;
  608: 	  i++;
  609: 	  c = string[i + 1];
  610: 	}
  611: 
  612:       switch (c)
  613: 	{
  614: 	default:
  615: 	  *ret_string = hist_error (string, i+1, i+2, BAD_MODIFIER);
  616: 	  xfree (result);
  617: 	  xfree (temp);
  618: 	  return -1;
  619: 
  620: 	case 'q':
  621: 	  want_quotes = 'q';
  622: 	  break;
  623: 
  624: 	case 'x':
  625: 	  want_quotes = 'x';
  626: 	  break;
  627: 
  628: 	  /* :p means make this the last executed line.  So we
  629: 	     return an error state after adding this line to the
  630: 	     history. */
  631: 	case 'p':
  632: 	  print_only = 1;
  633: 	  break;
  634: 
  635: 	  /* :t discards all but the last part of the pathname. */
  636: 	case 't':
  637: 	  tstr = strrchr (temp, '/');
  638: 	  if (tstr)
  639: 	    {
  640: 	      tstr++;
  641: 	      t = savestring (tstr);
  642: 	      xfree (temp);
  643: 	      temp = t;
  644: 	    }
  645: 	  break;
  646: 
  647: 	  /* :h discards the last part of a pathname. */
  648: 	case 'h':
  649: 	  tstr = strrchr (temp, '/');
  650: 	  if (tstr)
  651: 	    *tstr = '\0';
  652: 	  break;
  653: 
  654: 	  /* :r discards the suffix. */
  655: 	case 'r':
  656: 	  tstr = strrchr (temp, '.');
  657: 	  if (tstr)
  658: 	    *tstr = '\0';
  659: 	  break;
  660: 
  661: 	  /* :e discards everything but the suffix. */
  662: 	case 'e':
  663: 	  tstr = strrchr (temp, '.');
  664: 	  if (tstr)
  665: 	    {
  666: 	      t = savestring (tstr);
  667: 	      xfree (temp);
  668: 	      temp = t;
  669: 	    }
  670: 	  break;
  671: 
  672: 	/* :s/this/that substitutes `that' for the first
  673: 	   occurrence of `this'.  :gs/this/that substitutes `that'
  674: 	   for each occurrence of `this'.  :& repeats the last
  675: 	   substitution.  :g& repeats the last substitution
  676: 	   globally. */
  677: 
  678: 	case '&':
  679: 	case 's':
  680: 	  {
  681: 	    char *new_event;
  682: 	    int delimiter, failed, si, l_temp, ws, we;
  683: 
  684: 	    if (c == 's')
  685: 	      {
  686: 		if (i + 2 < (int)strlen (string))
  687: 		  {
  688: #if defined (HANDLE_MULTIBYTE)
  689: 		    if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
  690: 		      {
  691: 			_rl_adjust_point (string, i + 2, &ps);
  692: 			if (_rl_get_char_len (string + i + 2, &ps) > 1)
  693: 			  delimiter = 0;
  694: 			else
  695: 			  delimiter = string[i + 2];
  696: 		      }
  697: 		    else
  698: #endif /* HANDLE_MULTIBYTE */
  699: 		      delimiter = string[i + 2];
  700: 		  }
  701: 		else
  702: 		  break;	/* no search delimiter */
  703: 
  704: 		i += 3;
  705: 
  706: 		t = get_subst_pattern (string, &i, delimiter, 0, &subst_lhs_len);
  707: 		/* An empty substitution lhs with no previous substitution
  708: 		   uses the last search string as the lhs. */
  709: 		if (t)
  710: 		  {
  711: 		    FREE (subst_lhs);
  712: 		    subst_lhs = t;
  713: 		  }
  714: 		else if (!subst_lhs)
  715: 		  {
  716: 		    if (search_string && *search_string)
  717: 		      {
  718: 			subst_lhs = savestring (search_string);
  719: 			subst_lhs_len = strlen (subst_lhs);
  720: 		      }
  721: 		    else
  722: 		      {
  723: 			subst_lhs = (char *) NULL;
  724: 			subst_lhs_len = 0;
  725: 		      }
  726: 		  }
  727: 
  728: 		FREE (subst_rhs);
  729: 		subst_rhs = get_subst_pattern (string, &i, delimiter, 1, &subst_rhs_len);
  730: 
  731: 		/* If `&' appears in the rhs, it's supposed to be replaced
  732: 		   with the lhs. */
  733: 		if (member ('&', subst_rhs))
  734: 		  postproc_subst_rhs ();
  735: 	      }
  736: 	    else
  737: 	      i += 2;
  738: 
  739: 	    /* If there is no lhs, the substitution can't succeed. */
  740: 	    if (subst_lhs_len == 0)
  741: 	      {
  742: 		*ret_string = hist_error (string, starting_index, i, NO_PREV_SUBST);
  743: 		xfree (result);
  744: 		xfree (temp);
  745: 		return -1;
  746: 	      }
  747: 
  748: 	    l_temp = strlen (temp);
  749: 	    /* Ignore impossible cases. */
  750: 	    if (subst_lhs_len > l_temp)
  751: 	      {
  752: 		*ret_string = hist_error (string, starting_index, i, SUBST_FAILED);
  753: 		xfree (result);
  754: 		xfree (temp);
  755: 		return (-1);
  756: 	      }
  757: 
  758: 	    /* Find the first occurrence of THIS in TEMP. */
  759: 	    /* Substitute SUBST_RHS for SUBST_LHS in TEMP.  There are three
  760: 	       cases to consider:
  761: 
  762: 		 1.  substitute_globally == subst_bywords == 0
  763: 		 2.  substitute_globally == 1 && subst_bywords == 0
  764: 		 3.  substitute_globally == 0 && subst_bywords == 1
  765: 
  766: 	       In the first case, we substitute for the first occurrence only.
  767: 	       In the second case, we substitute for every occurrence.
  768: 	       In the third case, we tokenize into words and substitute the
  769: 	       first occurrence of each word. */
  770: 
  771: 	    si = we = 0;
  772: 	    for (failed = 1; (si + subst_lhs_len) <= l_temp; si++)
  773: 	      {
  774: 		/* First skip whitespace and find word boundaries if
  775: 		   we're past the end of the word boundary we found
  776: 		   the last time. */
  777: 		if (subst_bywords && si > we)
  778: 		  {
  779: 		    for (; temp[si] && fielddelim (temp[si]); si++)
  780: 		      ;
  781: 		    ws = si;
  782: 		    we = history_tokenize_word (temp, si);
  783: 		  }
  784: 
  785: 		if (STREQN (temp+si, subst_lhs, subst_lhs_len))
  786: 		  {
  787: 		    int len = subst_rhs_len - subst_lhs_len + l_temp;
  788: 		    new_event = (char *)xmalloc (1 + len);
  789: 		    strncpy (new_event, temp, si);
  790: 		    strncpy (new_event + si, subst_rhs, subst_rhs_len);
  791: 		    strncpy (new_event + si + subst_rhs_len,
  792: 			     temp + si + subst_lhs_len,
  793: 			     l_temp - (si + subst_lhs_len));
  794: 		    new_event[len] = '\0';
  795: 		    xfree (temp);
  796: 		    temp = new_event;
  797: 
  798: 		    failed = 0;
  799: 
  800: 		    if (substitute_globally)
  801: 		      {
  802: 			/* Reported to fix a bug that causes it to skip every
  803: 			   other match when matching a single character.  Was
  804: 			   si += subst_rhs_len previously. */
  805: 			si += subst_rhs_len - 1;
  806: 			l_temp = strlen (temp);
  807: 			substitute_globally++;
  808: 			continue;
  809: 		      }
  810: 		    else if (subst_bywords)
  811: 		      {
  812: 			si = we;
  813: 			l_temp = strlen (temp);
  814: 			continue;
  815: 		      }
  816: 		    else
  817: 		      break;
  818: 		  }
  819: 	      }
  820: 
  821: 	    if (substitute_globally > 1)
  822: 	      {
  823: 		substitute_globally = 0;
  824: 		continue;	/* don't want to increment i */
  825: 	      }
  826: 
  827: 	    if (failed == 0)
  828: 	      continue;		/* don't want to increment i */
  829: 
  830: 	    *ret_string = hist_error (string, starting_index, i, SUBST_FAILED);
  831: 	    xfree (result);
  832: 	    xfree (temp);
  833: 	    return (-1);
  834: 	  }
  835: 	}
  836:       i += 2;
  837:     }
  838:   /* Done with modifiers. */
  839:   /* Believe it or not, we have to back the pointer up by one. */
  840:   --i;
  841: 
  842:   if (want_quotes)
  843:     {
  844:       char *x;
  845: 
  846:       if (want_quotes == 'q')
  847: 	x = sh_single_quote (temp);
  848:       else if (want_quotes == 'x')
  849: 	x = quote_breaks (temp);
  850:       else
  851: 	x = savestring (temp);
  852: 
  853:       xfree (temp);
  854:       temp = x;
  855:     }
  856: 
  857:   n = strlen (temp);
  858:   if (n >= result_len)
  859:     result = (char *)xrealloc (result, n + 2);
  860:   strcpy (result, temp);
  861:   xfree (temp);
  862: 
  863:   *end_index_ptr = i;
  864:   *ret_string = result;
  865:   return (print_only);
  866: }
  867: 
  868: /* Expand the string STRING, placing the result into OUTPUT, a pointer
  869:    to a string.  Returns:
  870: 
  871:   -1) If there was an error in expansion.
  872:    0) If no expansions took place (or, if the only change in
  873:       the text was the de-slashifying of the history expansion
  874:       character)
  875:    1) If expansions did take place
  876:    2) If the `p' modifier was given and the caller should print the result
  877: 
  878:   If an error occurred in expansion, then OUTPUT contains a descriptive
  879:   error message. */
  880: 
  881: #define ADD_STRING(s) \
  882: 	do \
  883: 	  { \
  884: 	    int sl = strlen (s); \
  885: 	    j += sl; \
  886: 	    if (j >= result_len) \
  887: 	      { \
  888: 		while (j >= result_len) \
  889: 		  result_len += 128; \
  890: 		result = (char *)xrealloc (result, result_len); \
  891: 	      } \
  892: 	    strcpy (result + j - sl, s); \
  893: 	  } \
  894: 	while (0)
  895: 
  896: #define ADD_CHAR(c) \
  897: 	do \
  898: 	  { \
  899: 	    if (j >= result_len - 1) \
  900: 	      result = (char *)xrealloc (result, result_len += 64); \
  901: 	    result[j++] = c; \
  902: 	    result[j] = '\0'; \
  903: 	  } \
  904: 	while (0)
  905: 
  906: int
  907: history_expand (char *hstring, char **output)
  908: {
  909:   register int j;
  910:   int i, r, l, passc, cc, modified, eindex, only_printing, dquote, squote, flag;
  911:   char *string;
  912: 
  913:   /* The output string, and its length. */
  914:   int result_len;
  915:   char *result;
  916: 
  917: #if defined (HANDLE_MULTIBYTE)
  918:   char mb[MB_LEN_MAX];
  919:   mbstate_t ps;
  920: #endif
  921: 
  922:   /* Used when adding the string. */
  923:   char *temp;
  924: 
  925:   if (output == 0)
  926:     return 0;
  927: 
  928:   /* Setting the history expansion character to 0 inhibits all
  929:      history expansion. */
  930:   if (history_expansion_char == 0)
  931:     {
  932:       *output = savestring (hstring);
  933:       return (0);
  934:     }
  935:     
  936:   /* Prepare the buffer for printing error messages. */
  937:   result = (char *)xmalloc (result_len = 256);
  938:   result[0] = '\0';
  939: 
  940:   only_printing = modified = 0;
  941:   l = strlen (hstring);
  942: 
  943:   /* Grovel the string.  Only backslash and single quotes can quote the
  944:      history escape character.  We also handle arg specifiers. */
  945: 
  946:   /* Before we grovel forever, see if the history_expansion_char appears
  947:      anywhere within the text. */
  948: 
  949:   /* The quick substitution character is a history expansion all right.  That
  950:      is to say, "^this^that^" is equivalent to "!!:s^this^that^", and in fact,
  951:      that is the substitution that we do. */
  952:   if (hstring[0] == history_subst_char)
  953:     {
  954:       string = (char *)xmalloc (l + 5);
  955: 
  956:       string[0] = string[1] = history_expansion_char;
  957:       string[2] = ':';
  958:       string[3] = 's';
  959:       strcpy (string + 4, hstring);
  960:       l += 4;
  961:     }
  962:   else
  963:     {
  964: #if defined (HANDLE_MULTIBYTE)
  965:       memset (&ps, 0, sizeof (mbstate_t));
  966: #endif
  967: 
  968:       string = hstring;
  969:       /* If not quick substitution, still maybe have to do expansion. */
  970: 
  971:       /* `!' followed by one of the characters in history_no_expand_chars
  972: 	 is NOT an expansion. */
  973:       dquote = history_quoting_state == '"';
  974:       squote = history_quoting_state == '\'';
  975: 
  976:       /* If the calling application tells us we are already reading a
  977: 	 single-quoted string, consume the rest of the string right now
  978: 	 and then go on. */
  979:       i = 0;
  980:       if (squote && history_quotes_inhibit_expansion)
  981: 	{
  982: 	  hist_string_extract_single_quoted (string, &i, 0);
  983: 	  squote = 0;
  984: 	  if (string[i])
  985: 	    i++;
  986: 	}
  987: 
  988:       for ( ; string[i]; i++)
  989: 	{
  990: #if defined (HANDLE_MULTIBYTE)
  991: 	  if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
  992: 	    {
  993: 	      int v;
  994: 	      v = _rl_get_char_len (string + i, &ps);
  995: 	      if (v > 1)
  996: 		{
  997: 		  i += v - 1;
  998: 		  continue;
  999: 		}
 1000: 	    }
 1001: #endif /* HANDLE_MULTIBYTE */
 1002: 
 1003: 	  cc = string[i + 1];
 1004: 	  /* The history_comment_char, if set, appearing at the beginning
 1005: 	     of a word signifies that the rest of the line should not have
 1006: 	     history expansion performed on it.
 1007: 	     Skip the rest of the line and break out of the loop. */
 1008: 	  if (history_comment_char && string[i] == history_comment_char &&
 1009: 	      dquote == 0 &&
 1010: 	      (i == 0 || member (string[i - 1], history_word_delimiters)))
 1011: 	    {
 1012: 	      while (string[i])
 1013: 		i++;
 1014: 	      break;
 1015: 	    }
 1016: 	  else if (string[i] == history_expansion_char)
 1017: 	    {
 1018: 	      if (cc == 0 || member (cc, history_no_expand_chars))
 1019: 		continue;
 1020: 	      /* DQUOTE won't be set unless history_quotes_inhibit_expansion
 1021: 		 is set.  The idea here is to treat double-quoted strings the
 1022: 		 same as the word outside double quotes; in effect making the
 1023: 		 double quote part of history_no_expand_chars when DQUOTE is
 1024: 		 set. */
 1025: 	      else if (dquote && cc == '"')
 1026: 		continue;
 1027: 	      /* If the calling application has set
 1028: 		 history_inhibit_expansion_function to a function that checks
 1029: 		 for special cases that should not be history expanded,
 1030: 		 call the function and skip the expansion if it returns a
 1031: 		 non-zero value. */
 1032: 	      else if (history_inhibit_expansion_function &&
 1033: 			(*history_inhibit_expansion_function) (string, i))
 1034: 		continue;
 1035: 	      else
 1036: 		break;
 1037: 	    }
 1038: 	  /* Shell-like quoting: allow backslashes to quote double quotes
 1039: 	     inside a double-quoted string. */
 1040: 	  else if (dquote && string[i] == '\\' && cc == '"')
 1041: 	    i++;
 1042: 	  /* More shell-like quoting:  if we're paying attention to single
 1043: 	     quotes and letting them quote the history expansion character,
 1044: 	     then we need to pay attention to double quotes, because single
 1045: 	     quotes are not special inside double-quoted strings. */
 1046: 	  else if (history_quotes_inhibit_expansion && string[i] == '"')
 1047: 	    {
 1048: 	      dquote = 1 - dquote;
 1049: 	    }
 1050: 	  else if (dquote == 0 && history_quotes_inhibit_expansion && string[i] == '\'')
 1051: 	    {
 1052: 	      /* If this is bash, single quotes inhibit history expansion. */
 1053: 	      flag = (i > 0 && string[i - 1] == '$');
 1054: 	      i++;
 1055: 	      hist_string_extract_single_quoted (string, &i, flag);
 1056: 	    }
 1057: 	  else if (history_quotes_inhibit_expansion && string[i] == '\\')
 1058: 	    {
 1059: 	      /* If this is bash, allow backslashes to quote single
 1060: 		 quotes and the history expansion character. */
 1061: 	      if (cc == '\'' || cc == history_expansion_char)
 1062: 		i++;
 1063: 	    }
 1064: 	  
 1065: 	}
 1066: 	  
 1067:       if (string[i] != history_expansion_char)
 1068: 	{
 1069: 	  xfree (result);
 1070: 	  *output = savestring (string);
 1071: 	  return (0);
 1072: 	}
 1073:     }
 1074: 
 1075:   /* Extract and perform the substitution. */
 1076:   dquote = history_quoting_state == '"';
 1077:   squote = history_quoting_state == '\'';
 1078: 
 1079:   /* If the calling application tells us we are already reading a
 1080:      single-quoted string, consume the rest of the string right now
 1081:      and then go on. */
 1082:   i = j = 0;
 1083:   if (squote && history_quotes_inhibit_expansion)
 1084:     {
 1085:       int c;
 1086: 
 1087:       hist_string_extract_single_quoted (string, &i, 0);
 1088:       squote = 0;
 1089:       for (c = 0; c < i; c++)
 1090: 	ADD_CHAR (string[c]);      
 1091:       if (string[i])
 1092: 	{
 1093: 	  ADD_CHAR (string[i]);
 1094: 	  i++;
 1095: 	}
 1096:     }
 1097: 
 1098:   for (passc = 0; i < l; i++)
 1099:     {
 1100:       int qc, tchar = string[i];
 1101: 
 1102:       if (passc)
 1103: 	{
 1104: 	  passc = 0;
 1105: 	  ADD_CHAR (tchar);
 1106: 	  continue;
 1107: 	}
 1108: 
 1109: #if defined (HANDLE_MULTIBYTE)
 1110:       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
 1111: 	{
 1112: 	  int k, c;
 1113: 
 1114: 	  c = tchar;
 1115: 	  memset (mb, 0, sizeof (mb));
 1116: 	  for (k = 0; k < MB_LEN_MAX; k++)
 1117: 	    {
 1118: 	      mb[k] = (char)c;
 1119: 	      memset (&ps, 0, sizeof (mbstate_t));
 1120: 	      if (_rl_get_char_len (mb, &ps) == -2)
 1121: 		c = string[++i];
 1122: 	      else
 1123: 		break;
 1124: 	    }
 1125: 	  if (strlen (mb) > 1)
 1126: 	    {
 1127: 	      ADD_STRING (mb);
 1128: 	      continue;
 1129: 	    }
 1130: 	}
 1131: #endif /* HANDLE_MULTIBYTE */
 1132: 
 1133:       if (tchar == history_expansion_char)
 1134: 	tchar = -3;
 1135:       else if (tchar == history_comment_char)
 1136: 	tchar = -2;
 1137: 
 1138:       switch (tchar)
 1139: 	{
 1140: 	default:
 1141: 	  ADD_CHAR (string[i]);
 1142: 	  break;
 1143: 
 1144: 	case '\\':
 1145: 	  passc++;
 1146: 	  ADD_CHAR (tchar);
 1147: 	  break;
 1148: 
 1149: 	case '"':
 1150: 	  dquote = 1 - dquote;
 1151: 	  ADD_CHAR (tchar);
 1152: 	  break;
 1153: 	  
 1154: 	case '\'':
 1155: 	  {
 1156: 	    /* If history_quotes_inhibit_expansion is set, single quotes
 1157: 	       inhibit history expansion, otherwise they are treated like
 1158: 	       double quotes. */
 1159: 	    if (squote)
 1160: 	      {
 1161: 	        squote = 0;
 1162: 	        ADD_CHAR (tchar);
 1163: 	      }
 1164: 	    else if (dquote == 0 && history_quotes_inhibit_expansion)
 1165: 	      {
 1166: 		int quote, slen;
 1167: 
 1168: 		flag = (i > 0 && string[i - 1] == '$');
 1169: 		quote = i++;
 1170: 		hist_string_extract_single_quoted (string, &i, flag);
 1171: 
 1172: 		slen = i - quote + 2;
 1173: 		temp = (char *)xmalloc (slen);
 1174: 		strncpy (temp, string + quote, slen);
 1175: 		temp[slen - 1] = '\0';
 1176: 		ADD_STRING (temp);
 1177: 		xfree (temp);
 1178: 	      }
 1179: 	    else if (dquote == 0 && squote == 0 && history_quotes_inhibit_expansion == 0)
 1180: 	      {
 1181: 	        squote = 1;
 1182: 	        ADD_CHAR (string[i]);
 1183: 	      }
 1184: 	    else
 1185: 	      ADD_CHAR (string[i]);
 1186: 	    break;
 1187: 	  }
 1188: 
 1189: 	case -2:		/* history_comment_char */
 1190: 	  if ((dquote == 0 || history_quotes_inhibit_expansion == 0) &&
 1191: 	      (i == 0 || member (string[i - 1], history_word_delimiters)))
 1192: 	    {
 1193: 	      temp = (char *)xmalloc (l - i + 1);
 1194: 	      strcpy (temp, string + i);
 1195: 	      ADD_STRING (temp);
 1196: 	      xfree (temp);
 1197: 	      i = l;
 1198: 	    }
 1199: 	  else
 1200: 	    ADD_CHAR (string[i]);
 1201: 	  break;
 1202: 
 1203: 	case -3:		/* history_expansion_char */
 1204: 	  cc = string[i + 1];
 1205: 
 1206: 	  /* If the history_expansion_char is followed by one of the
 1207: 	     characters in history_no_expand_chars, then it is not a
 1208: 	     candidate for expansion of any kind. */
 1209: 	  if (cc == 0 || member (cc, history_no_expand_chars) ||
 1210: 			 (dquote && cc == '"') ||
 1211: 	  		 (history_inhibit_expansion_function && (*history_inhibit_expansion_function) (string, i)))
 1212: 	    {
 1213: 	      ADD_CHAR (string[i]);
 1214: 	      break;
 1215: 	    }
 1216: 
 1217: #if defined (NO_BANG_HASH_MODIFIERS)
 1218: 	  /* There is something that is listed as a `word specifier' in csh
 1219: 	     documentation which means `the expanded text to this point'.
 1220: 	     That is not a word specifier, it is an event specifier.  If we
 1221: 	     don't want to allow modifiers with `!#', just stick the current
 1222: 	     output line in again. */
 1223: 	  if (cc == '#')
 1224: 	    {
 1225: 	      if (result)
 1226: 		{
 1227: 		  temp = (char *)xmalloc (1 + strlen (result));
 1228: 		  strcpy (temp, result);
 1229: 		  ADD_STRING (temp);
 1230: 		  xfree (temp);
 1231: 		}
 1232: 	      i++;
 1233: 	      break;
 1234: 	    }
 1235: #endif
 1236: 	  qc = squote ? '\'' : (dquote ? '"' : 0);
 1237: 	  r = history_expand_internal (string, i, qc, &eindex, &temp, result);
 1238: 	  if (r < 0)
 1239: 	    {
 1240: 	      *output = temp;
 1241: 	      xfree (result);
 1242: 	      if (string != hstring)
 1243: 		xfree (string);
 1244: 	      return -1;
 1245: 	    }
 1246: 	  else
 1247: 	    {
 1248: 	      if (temp)
 1249: 		{
 1250: 		  modified++;
 1251: 		  if (*temp)
 1252: 		    ADD_STRING (temp);
 1253: 		  xfree (temp);
 1254: 		}
 1255: 	      only_printing += r == 1;
 1256: 	      i = eindex;
 1257: 	    }
 1258: 	  break;
 1259: 	}
 1260:     }
 1261: 
 1262:   *output = result;
 1263:   if (string != hstring)
 1264:     xfree (string);
 1265: 
 1266:   if (only_printing)
 1267:     {
 1268: #if 0
 1269:       add_history (result);
 1270: #endif
 1271:       return (2);
 1272:     }
 1273: 
 1274:   return (modified != 0);
 1275: }
 1276: 
 1277: /* Return a consed string which is the word specified in SPEC, and found
 1278:    in FROM.  NULL is returned if there is no spec.  The address of
 1279:    ERROR_POINTER is returned if the word specified cannot be found.
 1280:    CALLER_INDEX is the offset in SPEC to start looking; it is updated
 1281:    to point to just after the last character parsed. */
 1282: static char *
 1283: get_history_word_specifier (char *spec, char *from, int *caller_index)
 1284: {
 1285:   register int i = *caller_index;
 1286:   int first, last;
 1287:   int expecting_word_spec = 0;
 1288:   char *result;
 1289: 
 1290:   /* The range of words to return doesn't exist yet. */
 1291:   first = last = 0;
 1292:   result = (char *)NULL;
 1293: 
 1294:   /* If we found a colon, then this *must* be a word specification.  If
 1295:      it isn't, then it is an error. */
 1296:   if (spec[i] == ':')
 1297:     {
 1298:       i++;
 1299:       expecting_word_spec++;
 1300:     }
 1301: 
 1302:   /* Handle special cases first. */
 1303: 
 1304:   /* `%' is the word last searched for. */
 1305:   if (spec[i] == '%')
 1306:     {
 1307:       *caller_index = i + 1;
 1308:       return (search_match ? savestring (search_match) : savestring (""));
 1309:     }
 1310: 
 1311:   /* `*' matches all of the arguments, but not the command. */
 1312:   if (spec[i] == '*')
 1313:     {
 1314:       *caller_index = i + 1;
 1315:       result = history_arg_extract (1, '$', from);
 1316:       return (result ? result : savestring (""));
 1317:     }
 1318: 
 1319:   /* `$' is last arg. */
 1320:   if (spec[i] == '$')
 1321:     {
 1322:       *caller_index = i + 1;
 1323:       return (history_arg_extract ('$', '$', from));
 1324:     }
 1325: 
 1326:   /* Try to get FIRST and LAST figured out. */
 1327: 
 1328:   if (spec[i] == '-')
 1329:     first = 0;
 1330:   else if (spec[i] == '^')
 1331:     {
 1332:       first = 1;
 1333:       i++;
 1334:     }
 1335:   else if (_rl_digit_p (spec[i]) && expecting_word_spec)
 1336:     {
 1337:       for (first = 0; _rl_digit_p (spec[i]); i++)
 1338: 	first = (first * 10) + _rl_digit_value (spec[i]);
 1339:     }
 1340:   else
 1341:     return ((char *)NULL);	/* no valid `first' for word specifier */
 1342: 
 1343:   if (spec[i] == '^' || spec[i] == '*')
 1344:     {
 1345:       last = (spec[i] == '^') ? 1 : '$';	/* x* abbreviates x-$ */
 1346:       i++;
 1347:     }
 1348:   else if (spec[i] != '-')
 1349:     last = first;
 1350:   else
 1351:     {
 1352:       i++;
 1353: 
 1354:       if (_rl_digit_p (spec[i]))
 1355: 	{
 1356: 	  for (last = 0; _rl_digit_p (spec[i]); i++)
 1357: 	    last = (last * 10) + _rl_digit_value (spec[i]);
 1358: 	}
 1359:       else if (spec[i] == '$')
 1360: 	{
 1361: 	  i++;
 1362: 	  last = '$';
 1363: 	}
 1364:       else if (spec[i] == '^')
 1365: 	{
 1366: 	  i++;
 1367: 	  last = 1;
 1368: 	}
 1369: #if 0
 1370:       else if (!spec[i] || spec[i] == ':')
 1371: 	/* check against `:' because there could be a modifier separator */
 1372: #else
 1373:       else
 1374: 	/* csh seems to allow anything to terminate the word spec here,
 1375: 	   leaving it as an abbreviation. */
 1376: #endif
 1377: 	last = -1;		/* x- abbreviates x-$ omitting word `$' */
 1378:     }
 1379: 
 1380:   *caller_index = i;
 1381: 
 1382:   if (last >= first || last == '$' || last < 0)
 1383:     result = history_arg_extract (first, last, from);
 1384: 
 1385:   return (result ? result : (char *)&error_pointer);
 1386: }
 1387: 
 1388: /* Extract the args specified, starting at FIRST, and ending at LAST.
 1389:    The args are taken from STRING.  If either FIRST or LAST is < 0,
 1390:    then make that arg count from the right (subtract from the number of
 1391:    tokens, so that FIRST = -1 means the next to last token on the line).
 1392:    If LAST is `$' the last arg from STRING is used. */
 1393: char *
 1394: history_arg_extract (int first, int last, const char *string)
 1395: {
 1396:   register int i, len;
 1397:   char *result;
 1398:   int size, offset;
 1399:   char **list;
 1400: 
 1401:   /* XXX - think about making history_tokenize return a struct array,
 1402:      each struct in array being a string and a length to avoid the
 1403:      calls to strlen below. */
 1404:   if ((list = history_tokenize (string)) == NULL)
 1405:     return ((char *)NULL);
 1406: 
 1407:   for (len = 0; list[len]; len++)
 1408:     ;
 1409: 
 1410:   if (last < 0)
 1411:     last = len + last - 1;
 1412: 
 1413:   if (first < 0)
 1414:     first = len + first - 1;
 1415: 
 1416:   if (last == '$')
 1417:     last = len - 1;
 1418: 
 1419:   if (first == '$')
 1420:     first = len - 1;
 1421: 
 1422:   last++;
 1423: 
 1424:   if (first >= len || last > len || first < 0 || last < 0 || first > last)
 1425:     result = ((char *)NULL);
 1426:   else
 1427:     {
 1428:       for (size = 0, i = first; i < last; i++)
 1429: 	size += strlen (list[i]) + 1;
 1430:       result = (char *)xmalloc (size + 1);
 1431:       result[0] = '\0';
 1432: 
 1433:       for (i = first, offset = 0; i < last; i++)
 1434: 	{
 1435: 	  strcpy (result + offset, list[i]);
 1436: 	  offset += strlen (list[i]);
 1437: 	  if (i + 1 < last)
 1438: 	    {
 1439:       	      result[offset++] = ' ';
 1440: 	      result[offset] = 0;
 1441: 	    }
 1442: 	}
 1443:     }
 1444: 
 1445:   for (i = 0; i < len; i++)
 1446:     xfree (list[i]);
 1447:   xfree (list);
 1448: 
 1449:   return (result);
 1450: }
 1451: 
 1452: static int
 1453: history_tokenize_word (const char *string, int ind)
 1454: {
 1455:   register int i, j;
 1456:   int delimiter, nestdelim, delimopen;
 1457: 
 1458:   i = ind;
 1459:   delimiter = nestdelim = 0;
 1460: 
 1461:   if (member (string[i], "()\n"))	/* XXX - included \n, but why? been here forever */
 1462:     {
 1463:       i++;
 1464:       return i;
 1465:     }
 1466: 
 1467:   if (ISDIGIT (string[i]))
 1468:     {
 1469:       j = i;
 1470:       while (string[j] && ISDIGIT (string[j]))
 1471: 	j++;
 1472:       if (string[j] == 0)
 1473: 	return (j);
 1474:       if (string[j] == '<' || string[j] == '>')
 1475: 	i = j;			/* digit sequence is a file descriptor */
 1476:       else
 1477: 	{
 1478: 	  i = j;
 1479: 	  goto get_word;	/* digit sequence is part of a word */
 1480: 	}
 1481:     }
 1482: 
 1483:   if (member (string[i], "<>;&|"))
 1484:     {
 1485:       int peek = string[i + 1];
 1486: 
 1487:       if (peek == string[i])
 1488: 	{
 1489: 	  if (peek == '<' && string[i + 2] == '-')
 1490: 	    i++;
 1491: 	  else if (peek == '<' && string[i + 2] == '<')
 1492: 	    i++;
 1493: 	  i += 2;
 1494: 	  return i;
 1495: 	}
 1496:       else if (peek == '&' && (string[i] == '>' || string[i] == '<'))
 1497: 	{
 1498: 	  j = i + 2;
 1499: 	  while (string[j] && ISDIGIT (string[j]))	/* file descriptor */
 1500: 	    j++;
 1501: 	  if (string[j] =='-')		/* <&[digits]-, >&[digits]- */
 1502: 	    j++;
 1503: 	  return j;
 1504: 	}
 1505:       else if ((peek == '>' && string[i] == '&') || (peek == '|' && string[i] == '>'))
 1506: 	{
 1507: 	  i += 2;
 1508: 	  return i;
 1509: 	}
 1510:       /* XXX - process substitution -- separated out for later -- bash-4.2 */
 1511:       else if (peek == '(' && (string[i] == '>' || string[i] == '<')) /*)*/
 1512: 	{
 1513: 	  i += 2;
 1514: 	  delimopen = '(';
 1515: 	  delimiter = ')';
 1516: 	  nestdelim = 1;
 1517: 	  goto get_word;
 1518: 	}
 1519: 
 1520:       i++;
 1521:       return i;
 1522:     }
 1523: 
 1524: get_word:
 1525:   /* Get word from string + i; */
 1526: 
 1527:   if (delimiter == 0 && member (string[i], HISTORY_QUOTE_CHARACTERS))
 1528:     delimiter = string[i++];
 1529: 
 1530:   for (; string[i]; i++)
 1531:     {
 1532:       if (string[i] == '\\' && string[i + 1] == '\n')
 1533: 	{
 1534: 	  i++;
 1535: 	  continue;
 1536: 	}
 1537: 
 1538:       if (string[i] == '\\' && delimiter != '\'' &&
 1539: 	  (delimiter != '"' || member (string[i], slashify_in_quotes)))
 1540: 	{
 1541: 	  i++;
 1542: 	  continue;
 1543: 	}
 1544: 
 1545:       /* delimiter must be set and set to something other than a quote if
 1546: 	 nestdelim is set, so these tests are safe. */
 1547:       if (nestdelim && string[i] == delimopen)
 1548: 	{
 1549: 	  nestdelim++;
 1550: 	  continue;
 1551: 	}
 1552:       if (nestdelim && string[i] == delimiter)
 1553: 	{
 1554: 	  nestdelim--;
 1555: 	  if (nestdelim == 0)
 1556: 	    delimiter = 0;
 1557: 	  continue;
 1558: 	}
 1559:       
 1560:       if (delimiter && string[i] == delimiter)
 1561: 	{
 1562: 	  delimiter = 0;
 1563: 	  continue;
 1564: 	}
 1565: 
 1566:       /* Command and process substitution; shell extended globbing patterns */
 1567:       if (nestdelim == 0 && delimiter == 0 && member (string[i], "<>$!@?+*") && string[i+1] == '(') /*)*/
 1568: 	{
 1569: 	  i += 2;
 1570: 	  delimopen = '(';
 1571: 	  delimiter = ')';
 1572: 	  nestdelim = 1;
 1573: 	  continue;
 1574: 	}
 1575:       
 1576:       if (delimiter == 0 && (member (string[i], history_word_delimiters)))
 1577: 	break;
 1578: 
 1579:       if (delimiter == 0 && member (string[i], HISTORY_QUOTE_CHARACTERS))
 1580: 	delimiter = string[i];
 1581:     }
 1582: 
 1583:   return i;
 1584: }
 1585: 
 1586: static char *
 1587: history_substring (const char *string, int start, int end)
 1588: {
 1589:   register int len;
 1590:   register char *result;
 1591: 
 1592:   len = end - start;
 1593:   result = (char *)xmalloc (len + 1);
 1594:   strncpy (result, string + start, len);
 1595:   result[len] = '\0';
 1596:   return result;
 1597: }
 1598: 
 1599: /* Parse STRING into tokens and return an array of strings.  If WIND is
 1600:    not -1 and INDP is not null, we also want the word surrounding index
 1601:    WIND.  The position in the returned array of strings is returned in
 1602:    *INDP. */
 1603: static char **
 1604: history_tokenize_internal (const char *string, int wind, int *indp)
 1605: {
 1606:   char **result;
 1607:   register int i, start, result_index, size;
 1608: 
 1609:   /* If we're searching for a string that's not part of a word (e.g., " "),
 1610:      make sure we set *INDP to a reasonable value. */
 1611:   if (indp && wind != -1)
 1612:     *indp = -1;
 1613: 
 1614:   /* Get a token, and stuff it into RESULT.  The tokens are split
 1615:      exactly where the shell would split them. */
 1616:   for (i = result_index = size = 0, result = (char **)NULL; string[i]; )
 1617:     {
 1618:       /* Skip leading whitespace. */
 1619:       for (; string[i] && fielddelim (string[i]); i++)
 1620: 	;
 1621:       if (string[i] == 0 || string[i] == history_comment_char)
 1622: 	return (result);
 1623: 
 1624:       start = i;
 1625: 
 1626:       i = history_tokenize_word (string, start);
 1627: 
 1628:       /* If we have a non-whitespace delimiter character (which would not be
 1629: 	 skipped by the loop above), use it and any adjacent delimiters to
 1630: 	 make a separate field.  Any adjacent white space will be skipped the
 1631: 	 next time through the loop. */
 1632:       if (i == start && history_word_delimiters)
 1633: 	{
 1634: 	  i++;
 1635: 	  while (string[i] && member (string[i], history_word_delimiters))
 1636: 	    i++;
 1637: 	}
 1638: 
 1639:       /* If we are looking for the word in which the character at a
 1640: 	 particular index falls, remember it. */
 1641:       if (indp && wind != -1 && wind >= start && wind < i)
 1642:         *indp = result_index;
 1643: 
 1644:       if (result_index + 2 >= size)
 1645: 	result = (char **)xrealloc (result, ((size += 10) * sizeof (char *)));
 1646: 
 1647:       result[result_index++] = history_substring (string, start, i);
 1648:       result[result_index] = (char *)NULL;
 1649:     }
 1650: 
 1651:   return (result);
 1652: }
 1653: 
 1654: /* Return an array of tokens, much as the shell might.  The tokens are
 1655:    parsed out of STRING. */
 1656: char **
 1657: history_tokenize (const char *string)
 1658: {
 1659:   return (history_tokenize_internal (string, -1, (int *)NULL));
 1660: }
 1661: 
 1662: /* Free members of WORDS from START to an empty string */
 1663: static void
 1664: freewords (char **words, int start)
 1665: {
 1666:   register int i;
 1667: 
 1668:   for (i = start; words[i]; i++)
 1669:     xfree (words[i]);
 1670: }
 1671: 
 1672: /* Find and return the word which contains the character at index IND
 1673:    in the history line LINE.  Used to save the word matched by the
 1674:    last history !?string? search. */
 1675: static char *
 1676: history_find_word (char *line, int ind)
 1677: {
 1678:   char **words, *s;
 1679:   int i, wind;
 1680: 
 1681:   words = history_tokenize_internal (line, ind, &wind);
 1682:   if (wind == -1 || words == 0)
 1683:     {
 1684:       if (words)
 1685: 	freewords (words, 0);
 1686:       FREE (words);
 1687:       return ((char *)NULL);
 1688:     }
 1689:   s = words[wind];
 1690:   for (i = 0; i < wind; i++)
 1691:     xfree (words[i]);
 1692:   freewords (words, wind + 1);
 1693:   xfree (words);
 1694:   return s;
 1695: }

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