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