9172755d003b8f02d4ffbb29bb91c37be6c2c015
[platform/upstream/bash.git] / lib / readline / history.c
1 /* History.c -- standalone history library */
2
3 /* Copyright (C) 1989, 1992 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 1, 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    675 Mass Ave, Cambridge, MA 02139, USA. */
22
23 /* The goal is to make the implementation transparent, so that you
24    don't have to know what data types are used, just what functions
25    you can call.  I think I have done that. */
26 #define READLINE_LIBRARY
27
28 #include <stdio.h>
29 #include <sys/types.h>
30 #include <sys/file.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #if defined (HAVE_STDLIB_H)
34 #  include <stdlib.h>
35 #else
36 #  include "ansi_stdlib.h"
37 #endif /* HAVE_STDLIB_H */
38 #if defined (HAVE_UNISTD_H)
39 #  include <unistd.h>
40 #endif
41 #if defined (HAVE_STRING_H)
42 #  include <string.h>
43 #else
44 #  include <strings.h>
45 #endif /* !HAVE_STRING_H */
46 #include <errno.h>
47
48 /* Not all systems declare ERRNO in errno.h... and some systems #define it! */
49 #if !defined (errno)
50 extern int errno;
51 #endif /* !errno */
52
53 #include "memalloc.h"
54 #include "history.h"
55
56 #if defined (STATIC_MALLOC)
57 static char *xmalloc (), *xrealloc ();
58 #else
59 extern char *xmalloc (), *xrealloc ();
60 #endif /* STATIC_MALLOC */
61
62 #define STREQ(a, b)     (((a)[0] == (b)[0]) && (strcmp ((a), (b)) == 0))
63 #define STREQN(a, b, n) (((a)[0] == (b)[0]) && (strncmp ((a), (b), (n)) == 0))
64
65 #ifndef savestring
66 #  ifndef strcpy
67 extern char *strcpy ();
68 #  endif
69 #define savestring(x) strcpy (xmalloc (1 + strlen (x)), (x))
70 #endif
71
72 #ifndef whitespace
73 #define whitespace(c) (((c) == ' ') || ((c) == '\t'))
74 #endif
75
76 #ifndef digit_p
77 #define digit_p(c)  ((c) >= '0' && (c) <= '9')
78 #endif
79
80 #ifndef digit_value
81 #define digit_value(c) ((c) - '0')
82 #endif
83
84 #ifndef member
85 #  ifndef strchr
86 extern char *strchr ();
87 #  endif
88 #define member(c, s) ((c) ? ((char *)strchr ((s), (c)) != (char *)NULL) : 0)
89 #endif
90
91 /* Possible history errors passed to hist_error. */
92 #define EVENT_NOT_FOUND 0
93 #define BAD_WORD_SPEC   1
94 #define SUBST_FAILED    2
95 #define BAD_MODIFIER    3
96
97 static char error_pointer;
98
99 static char *subst_lhs;
100 static char *subst_rhs;
101 static int subst_lhs_len = 0;
102 static int subst_rhs_len = 0;
103
104 static char *get_history_word_specifier ();
105 static char *history_find_word ();
106
107 #if defined (SHELL)
108 extern char *single_quote ();
109 #endif
110
111 /* **************************************************************** */
112 /*                                                                  */
113 /*                      History Functions                           */
114 /*                                                                  */
115 /* **************************************************************** */
116
117 /* An array of HIST_ENTRY.  This is where we store the history. */
118 static HIST_ENTRY **the_history = (HIST_ENTRY **)NULL;
119
120 /* Non-zero means that we have enforced a limit on the amount of
121    history that we save. */
122 static int history_stifled = 0;
123
124 /* If HISTORY_STIFLED is non-zero, then this is the maximum number of
125    entries to remember. */
126 int max_input_history;
127
128 /* The current location of the interactive history pointer.  Just makes
129    life easier for outside callers. */
130 static int history_offset = 0;
131
132 /* The number of strings currently stored in the input_history list. */
133 int history_length = 0;
134
135 /* The current number of slots allocated to the input_history. */
136 static int history_size = 0;
137
138 /* The number of slots to increase the_history by. */
139 #define DEFAULT_HISTORY_GROW_SIZE 50
140
141 /* The character that represents the start of a history expansion
142    request.  This is usually `!'. */
143 char history_expansion_char = '!';
144
145 /* The character that invokes word substitution if found at the start of
146    a line.  This is usually `^'. */
147 char history_subst_char = '^';
148
149 /* During tokenization, if this character is seen as the first character
150    of a word, then it, and all subsequent characters upto a newline are
151    ignored.  For a Bourne shell, this should be '#'.  Bash special cases
152    the interactive comment character to not be a comment delimiter. */
153 char history_comment_char = '\0';
154
155 /* The list of characters which inhibit the expansion of text if found
156    immediately following history_expansion_char. */
157 char *history_no_expand_chars = " \t\n\r=";
158
159 /* The logical `base' of the history array.  It defaults to 1. */
160 int history_base = 1;
161
162 /* Return the current HISTORY_STATE of the history. */
163 HISTORY_STATE *
164 history_get_history_state ()
165 {
166   HISTORY_STATE *state;
167
168   state = (HISTORY_STATE *)xmalloc (sizeof (HISTORY_STATE));
169   state->entries = the_history;
170   state->offset = history_offset;
171   state->length = history_length;
172   state->size = history_size;
173   state->flags = 0;
174   if (history_stifled)
175     state->flags |= HS_STIFLED;
176
177   return (state);
178 }
179
180 /* Set the state of the current history array to STATE. */
181 void
182 history_set_history_state (state)
183      HISTORY_STATE *state;
184 {
185   the_history = state->entries;
186   history_offset = state->offset;
187   history_length = state->length;
188   history_size = state->size;
189   if (state->flags & HS_STIFLED)
190     history_stifled = 1;
191 }
192
193 /* Begin a session in which the history functions might be used.  This
194    initializes interactive variables. */
195 void
196 using_history ()
197 {
198   history_offset = history_length;
199 }
200
201 /* Return the number of bytes that the primary history entries are using.
202    This just adds up the lengths of the_history->lines. */
203 int
204 history_total_bytes ()
205 {
206   register int i, result;
207
208   result = 0;
209
210   for (i = 0; the_history && the_history[i]; i++)
211     result += strlen (the_history[i]->line);
212
213   return (result);
214 }
215
216 /* Place STRING at the end of the history list.  The data field
217    is  set to NULL. */
218 void
219 add_history (string)
220      char *string;
221 {
222   HIST_ENTRY *temp;
223
224   if (history_stifled && (history_length == max_input_history))
225     {
226       register int i;
227
228       /* If the history is stifled, and history_length is zero,
229          and it equals max_input_history, we don't save items. */
230       if (history_length == 0)
231         return;
232
233       /* If there is something in the slot, then remove it. */
234       if (the_history[0])
235         {
236           free (the_history[0]->line);
237           free (the_history[0]);
238         }
239
240       /* Copy the rest of the entries, moving down one slot. */
241       for (i = 0; i < history_length; i++)
242         the_history[i] = the_history[i + 1];
243
244       history_base++;
245
246     }
247   else
248     {
249       if (!history_size)
250         {
251           history_size = DEFAULT_HISTORY_GROW_SIZE;
252           the_history = (HIST_ENTRY **)xmalloc (history_size * sizeof (HIST_ENTRY *));
253           history_length = 1;
254
255         }
256       else
257         {
258           if (history_length == (history_size - 1))
259             {
260               history_size += DEFAULT_HISTORY_GROW_SIZE;
261               the_history = (HIST_ENTRY **)
262                 xrealloc (the_history, history_size * sizeof (HIST_ENTRY *));
263             }
264           history_length++;
265         }
266     }
267
268   temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
269   temp->line = savestring (string);
270   temp->data = (char *)NULL;
271
272   the_history[history_length] = (HIST_ENTRY *)NULL;
273   the_history[history_length - 1] = temp;
274 }
275
276 /* Make the history entry at WHICH have LINE and DATA.  This returns
277    the old entry so you can dispose of the data.  In the case of an
278    invalid WHICH, a NULL pointer is returned. */
279 HIST_ENTRY *
280 replace_history_entry (which, line, data)
281      int which;
282      char *line;
283      char *data;
284 {
285   HIST_ENTRY *temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
286   HIST_ENTRY *old_value;
287
288   if (which >= history_length)
289     return ((HIST_ENTRY *)NULL);
290
291   old_value = the_history[which];
292
293   temp->line = savestring (line);
294   temp->data = data;
295   the_history[which] = temp;
296
297   return (old_value);
298 }
299
300 /* Returns the magic number which says what history element we are
301    looking at now.  In this implementation, it returns history_offset. */
302 int
303 where_history ()
304 {
305   return (history_offset);
306 }
307
308 /* Search the history for STRING, starting at history_offset.
309    If DIRECTION < 0, then the search is through previous entries, else
310    through subsequent.  If ANCHORED is non-zero, the string must
311    appear at the beginning of a history line, otherwise, the string
312    may appear anywhere in the line.  If the string is found, then
313    current_history () is the history entry, and the value of this
314    function is the offset in the line of that history entry that the
315    string was found in.  Otherwise, nothing is changed, and a -1 is
316    returned. */
317
318 #define ANCHORED_SEARCH 1
319 #define NON_ANCHORED_SEARCH 0
320
321 static int
322 history_search_internal (string, direction, anchored)
323      char *string;
324      int direction, anchored;
325 {
326   register int i, reverse;
327   register char *line;
328   register int line_index;
329   int string_len;
330
331   i = history_offset;
332   reverse = (direction < 0);
333
334   /* Take care of trivial cases first. */
335   if (string == 0 || *string == '\0')
336     return (-1);
337
338   if (!history_length || ((i == history_length) && !reverse))
339     return (-1);
340
341   if (reverse && (i == history_length))
342     i--;
343
344 #define NEXT_LINE() do { if (reverse) i--; else i++; } while (0)
345
346   string_len = strlen (string);
347   while (1)
348     {
349       /* Search each line in the history list for STRING. */
350
351       /* At limit for direction? */
352       if ((reverse && i < 0) || (!reverse && i == history_length))
353         return (-1);
354
355       line = the_history[i]->line;
356       line_index = strlen (line);
357
358       /* If STRING is longer than line, no match. */
359       if (string_len > line_index)
360         {
361           NEXT_LINE ();
362           continue;
363         }
364
365       /* Handle anchored searches first. */
366       if (anchored == ANCHORED_SEARCH)
367         {
368           if (STREQN (string, line, string_len))
369             {
370               history_offset = i;
371               return (0);
372             }
373
374           NEXT_LINE ();
375           continue;
376         }
377
378       /* Do substring search. */
379       if (reverse)
380         {
381           line_index -= string_len;
382
383           while (line_index >= 0)
384             {
385               if (STREQN (string, line + line_index, string_len))
386                 {
387                   history_offset = i;
388                   return (line_index);
389                 }
390               line_index--;
391             }
392         }
393       else
394         {
395           register int limit = line_index - string_len + 1;
396           line_index = 0;
397
398           while (line_index < limit)
399             {
400               if (STREQN (string, line + line_index, string_len))
401                 {
402                   history_offset = i;
403                   return (line_index);
404                 }
405               line_index++;
406             }
407         }
408       NEXT_LINE ();
409     }
410 }
411
412 /* Do a non-anchored search for STRING through the history in DIRECTION. */
413 int
414 history_search (string, direction)
415      char *string;
416      int direction;
417 {
418   return (history_search_internal (string, direction, NON_ANCHORED_SEARCH));
419 }
420
421 /* Do an anchored search for string through the history in DIRECTION. */
422 int
423 history_search_prefix (string, direction)
424      char *string;
425      int direction;
426 {
427   return (history_search_internal (string, direction, ANCHORED_SEARCH));
428 }
429
430 /* Remove history element WHICH from the history.  The removed
431    element is returned to you so you can free the line, data,
432    and containing structure. */
433 HIST_ENTRY *
434 remove_history (which)
435      int which;
436 {
437   HIST_ENTRY *return_value;
438
439   if (which >= history_length || !history_length)
440     return_value = (HIST_ENTRY *)NULL;
441   else
442     {
443       register int i;
444       return_value = the_history[which];
445
446       for (i = which; i < history_length; i++)
447         the_history[i] = the_history[i + 1];
448
449       history_length--;
450     }
451
452   return (return_value);
453 }
454
455 /* Stifle the history list, remembering only MAX number of lines. */
456 void
457 stifle_history (max)
458      int max;
459 {
460   if (max < 0)
461     max = 0;
462
463   if (history_length > max)
464     {
465       register int i, j;
466
467       /* This loses because we cannot free the data. */
468       for (i = 0; i < (history_length - max); i++)
469         {
470           free (the_history[i]->line);
471           free (the_history[i]);
472         }
473
474       history_base = i;
475       for (j = 0, i = history_length - max; j < max; i++, j++)
476         the_history[j] = the_history[i];
477       the_history[j] = (HIST_ENTRY *)NULL;
478       history_length = j;
479     }
480
481   history_stifled = 1;
482   max_input_history = max;
483 }
484
485 /* Stop stifling the history.  This returns the previous amount the history
486  was stifled by.  The value is positive if the history was stifled, negative
487  if it wasn't. */
488 int
489 unstifle_history ()
490 {
491   int result = max_input_history;
492
493   if (history_stifled)
494     {
495       result = -result;
496       history_stifled = 0;
497     }
498
499   return (result);
500 }
501
502 int
503 history_is_stifled ()
504 {
505   return (history_stifled);
506 }
507
508 /* Return the string that should be used in the place of this
509    filename.  This only matters when you don't specify the
510    filename to read_history (), or write_history (). */
511 static char *
512 history_filename (filename)
513      char *filename;
514 {
515   char *return_val = filename ? savestring (filename) : (char *)NULL;
516
517   if (!return_val)
518     {
519       char *home;
520       int home_len;
521
522       home = getenv ("HOME");
523
524       if (!home)
525         home = ".";
526
527       home_len = strlen (home);
528       /* strlen(".history") == 8 */
529       return_val = xmalloc (2 + home_len + 8);
530
531       strcpy (return_val, home);
532       return_val[home_len] = '/';
533       strcpy (return_val + home_len + 1, ".history");
534     }
535
536   return (return_val);
537 }
538
539 /* Add the contents of FILENAME to the history list, a line at a time.
540    If FILENAME is NULL, then read from ~/.history.  Returns 0 if
541    successful, or errno if not. */
542 int
543 read_history (filename)
544      char *filename;
545 {
546   return (read_history_range (filename, 0, -1));
547 }
548
549 /* Read a range of lines from FILENAME, adding them to the history list.
550    Start reading at the FROM'th line and end at the TO'th.  If FROM
551    is zero, start at the beginning.  If TO is less than FROM, read
552    until the end of the file.  If FILENAME is NULL, then read from
553    ~/.history.  Returns 0 if successful, or errno if not. */
554 int
555 read_history_range (filename, from, to)
556      char *filename;
557      int from, to;
558 {
559   register int line_start, line_end;
560   char *input, *buffer = (char *)NULL;
561   int file, current_line;
562   struct stat finfo;
563
564   input = history_filename (filename);
565   file = open (input, O_RDONLY, 0666);
566
567   if ((file < 0) || (fstat (file, &finfo) == -1))
568     goto error_and_exit;
569
570   buffer = xmalloc ((int)finfo.st_size + 1);
571
572   if (read (file, buffer, finfo.st_size) != finfo.st_size)
573     {
574   error_and_exit:
575       if (file >= 0)
576         close (file);
577
578       if (input)
579         free (input);
580
581       if (buffer)
582         free (buffer);
583
584       return (errno);
585     }
586
587   close (file);
588
589   /* Set TO to larger than end of file if negative. */
590   if (to < 0)
591     to = finfo.st_size;
592
593   /* Start at beginning of file, work to end. */
594   line_start = line_end = current_line = 0;
595
596   /* Skip lines until we are at FROM. */
597   while (line_start < finfo.st_size && current_line < from)
598     {
599       for (line_end = line_start; line_end < finfo.st_size; line_end++)
600         if (buffer[line_end] == '\n')
601           {
602             current_line++;
603             line_start = line_end + 1;
604             if (current_line == from)
605               break;
606           }
607     }
608
609   /* If there are lines left to gobble, then gobble them now. */
610   for (line_end = line_start; line_end < finfo.st_size; line_end++)
611     if (buffer[line_end] == '\n')
612       {
613         buffer[line_end] = '\0';
614
615         if (buffer[line_start])
616           add_history (buffer + line_start);
617
618         current_line++;
619
620         if (current_line >= to)
621           break;
622
623         line_start = line_end + 1;
624       }
625
626   if (input)
627     free (input);
628
629   if (buffer)
630     free (buffer);
631
632   return (0);
633 }
634
635 /* Truncate the history file FNAME, leaving only LINES trailing lines.
636    If FNAME is NULL, then use ~/.history. */
637 int
638 history_truncate_file (fname, lines)
639      char *fname;
640      register int lines;
641 {
642   register int i;
643   int file, chars_read;
644   char *buffer = (char *)NULL, *filename;
645   struct stat finfo;
646
647   filename = history_filename (fname);
648   file = open (filename, O_RDONLY, 0666);
649
650   if (file == -1 || fstat (file, &finfo) == -1)
651     goto truncate_exit;
652
653   buffer = xmalloc ((int)finfo.st_size + 1);
654   chars_read = read (file, buffer, finfo.st_size);
655   close (file);
656
657   if (chars_read <= 0)
658     goto truncate_exit;
659
660   /* Count backwards from the end of buffer until we have passed
661      LINES lines. */
662   for (i = chars_read - 1; lines && i; i--)
663     {
664       if (buffer[i] == '\n')
665         lines--;
666     }
667
668   /* If this is the first line, then the file contains exactly the
669      number of lines we want to truncate to, so we don't need to do
670      anything.  It's the first line if we don't find a newline between
671      the current value of i and 0.  Otherwise, write from the start of
672      this line until the end of the buffer. */
673   for ( ; i; i--)
674     if (buffer[i] == '\n')
675       {
676         i++;
677         break;
678       }
679
680   /* Write only if there are more lines in the file than we want to
681      truncate to. */
682   if (i && ((file = open (filename, O_WRONLY|O_TRUNC, 0666)) != -1))
683     {
684       write (file, buffer + i, finfo.st_size - i);
685       close (file);
686     }
687
688  truncate_exit:
689   if (buffer)
690     free (buffer);
691
692   free (filename);
693   return 0;
694 }
695
696 #define HISTORY_APPEND 0
697 #define HISTORY_OVERWRITE 1
698
699 /* Workhorse function for writing history.  Writes NELEMENT entries
700    from the history list to FILENAME.  OVERWRITE is non-zero if you
701    wish to replace FILENAME with the entries. */
702 static int
703 history_do_write (filename, nelements, overwrite)
704      char *filename;
705      int nelements, overwrite;
706 {
707   register int i;
708   char *output = history_filename (filename);
709   int file, mode;
710
711   mode = overwrite ? O_WRONLY | O_CREAT | O_TRUNC : O_WRONLY | O_APPEND;
712
713   if ((file = open (output, mode, 0666)) == -1)
714     {
715       if (output)
716         free (output);
717
718       return (errno);
719     }
720
721   if (nelements > history_length)
722     nelements = history_length;
723
724   /* Build a buffer of all the lines to write, and write them in one syscall.
725      Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */
726   {
727     register int j = 0;
728     int buffer_size = 0;
729     char *buffer;
730
731     /* Calculate the total number of bytes to write. */
732     for (i = history_length - nelements; i < history_length; i++)
733       buffer_size += 1 + strlen (the_history[i]->line);
734
735     /* Allocate the buffer, and fill it. */
736     buffer = xmalloc (buffer_size);
737
738     for (i = history_length - nelements; i < history_length; i++)
739       {
740         strcpy (buffer + j, the_history[i]->line);
741         j += strlen (the_history[i]->line);
742         buffer[j++] = '\n';
743       }
744
745     write (file, buffer, buffer_size);
746     free (buffer);
747   }
748
749   close (file);
750
751   if (output)
752     free (output);
753
754   return (0);
755 }
756
757 /* Append NELEMENT entries to FILENAME.  The entries appended are from
758    the end of the list minus NELEMENTs up to the end of the list. */
759 int
760 append_history (nelements, filename)
761      int nelements;
762      char *filename;
763 {
764   return (history_do_write (filename, nelements, HISTORY_APPEND));
765 }
766
767 /* Overwrite FILENAME with the current history.  If FILENAME is NULL,
768    then write the history list to ~/.history.  Values returned
769    are as in read_history ().*/
770 int
771 write_history (filename)
772      char *filename;
773 {
774   return (history_do_write (filename, history_length, HISTORY_OVERWRITE));
775 }
776
777 /* Return the history entry at the current position, as determined by
778    history_offset.  If there is no entry there, return a NULL pointer. */
779 HIST_ENTRY *
780 current_history ()
781 {
782   if ((history_offset == history_length) || !the_history)
783     return ((HIST_ENTRY *)NULL);
784   else
785     return (the_history[history_offset]);
786 }
787
788 /* Back up history_offset to the previous history entry, and return
789    a pointer to that entry.  If there is no previous entry then return
790    a NULL pointer. */
791 HIST_ENTRY *
792 previous_history ()
793 {
794   if (!history_offset)
795     return ((HIST_ENTRY *)NULL);
796   else
797     return (the_history[--history_offset]);
798 }
799
800 /* Move history_offset forward to the next history entry, and return
801    a pointer to that entry.  If there is no next entry then return a
802    NULL pointer. */
803 HIST_ENTRY *
804 next_history ()
805 {
806   if (history_offset == history_length)
807     return ((HIST_ENTRY *)NULL);
808   else
809     return (the_history[++history_offset]);
810 }
811
812 /* Return the current history array.  The caller has to be carefull, since this
813    is the actual array of data, and could be bashed or made corrupt easily.
814    The array is terminated with a NULL pointer. */
815 HIST_ENTRY **
816 history_list ()
817 {
818   return (the_history);
819 }
820
821 /* Return the history entry which is logically at OFFSET in the history array.
822    OFFSET is relative to history_base. */
823 HIST_ENTRY *
824 history_get (offset)
825      int offset;
826 {
827   int local_index = offset - history_base;
828
829   if (local_index >= history_length ||
830       local_index < 0 ||
831       !the_history)
832     return ((HIST_ENTRY *)NULL);
833   return (the_history[local_index]);
834 }
835
836 /* Search for STRING in the history list.  DIR is < 0 for searching
837    backwards.  POS is an absolute index into the history list at
838    which point to begin searching. */
839 int
840 history_search_pos (string, dir, pos)
841      char *string;
842      int dir, pos;
843 {
844   int ret, old = where_history ();
845   history_set_pos (pos);
846   if (history_search (string, dir) == -1)
847     {
848       history_set_pos (old);
849       return (-1);
850     }
851   ret = where_history ();
852   history_set_pos (old);
853   return ret;
854 }
855
856 /* Make the current history item be the one at POS, an absolute index.
857    Returns zero if POS is out of range, else non-zero. */
858 int
859 history_set_pos (pos)
860      int pos;
861 {
862   if (pos > history_length || pos < 0 || !the_history)
863     return (0);
864   history_offset = pos;
865   return (1);
866 }
867  
868 \f
869 /* **************************************************************** */
870 /*                                                                  */
871 /*                      History Expansion                           */
872 /*                                                                  */
873 /* **************************************************************** */
874
875 /* Hairy history expansion on text, not tokens.  This is of general
876    use, and thus belongs in this library. */
877
878 /* The last string searched for in a !?string? search. */
879 static char *search_string = (char *)NULL;
880
881 /* The last string matched by a !?string? search. */
882 static char *search_match = (char *)NULL;
883
884 /* Return the event specified at TEXT + OFFSET modifying OFFSET to
885    point to after the event specifier.  Just a pointer to the history
886    line is returned; NULL is returned in the event of a bad specifier.
887    You pass STRING with *INDEX equal to the history_expansion_char that
888    begins this specification.
889    DELIMITING_QUOTE is a character that is allowed to end the string
890    specification for what to search for in addition to the normal
891    characters `:', ` ', `\t', `\n', and sometimes `?'.
892    So you might call this function like:
893    line = get_history_event ("!echo:p", &index, 0);  */
894 char *
895 get_history_event (string, caller_index, delimiting_quote)
896      char *string;
897      int *caller_index;
898      int delimiting_quote;
899 {
900   register int i = *caller_index;
901   register char c;
902   HIST_ENTRY *entry;
903   int which, sign = 1;
904   int local_index, search_mode, substring_okay = 0;
905   char *temp;
906
907   /* The event can be specified in a number of ways.
908
909      !!   the previous command
910      !n   command line N
911      !-n  current command-line minus N
912      !str the most recent command starting with STR
913      !?str[?]
914           the most recent command containing STR
915
916      All values N are determined via HISTORY_BASE. */
917
918   if (string[i] != history_expansion_char)
919     return ((char *)NULL);
920
921   /* Move on to the specification. */
922   i++;
923
924 #define RETURN_ENTRY(e, w) \
925         return ((e = history_get (w)) ? e->line : (char *)NULL)
926
927   /* Handle !! case. */
928   if (string[i] == history_expansion_char)
929     {
930       i++;
931       which = history_base + (history_length - 1);
932       *caller_index = i;
933       RETURN_ENTRY (entry, which);
934     }
935
936   /* Hack case of numeric line specification. */
937   if (string[i] == '-')
938     {
939       sign = -1;
940       i++;
941     }
942
943   if (digit_p (string[i]))
944     {
945       /* Get the extent of the digits and compute the value. */
946       for (which = 0; digit_p (string[i]); i++)
947         which = (which * 10) + digit_value (string[i]);
948
949       *caller_index = i;
950
951       if (sign < 0)
952         which = (history_length + history_base) - which;
953
954       RETURN_ENTRY (entry, which);
955     }
956
957   /* This must be something to search for.  If the spec begins with
958      a '?', then the string may be anywhere on the line.  Otherwise,
959      the string must be found at the start of a line. */
960   if (string[i] == '?')
961     {
962       substring_okay++;
963       i++;
964     }
965
966   /* Only a closing `?' or a newline delimit a substring search string. */
967   for (local_index = i; c = string[i]; i++)
968     if ((!substring_okay && (whitespace (c) || c == ':' ||
969 #if defined (SHELL)
970           member (c, ";&()|<>") ||
971 #endif /* SHELL */
972           string[i] == delimiting_quote)) ||
973         string[i] == '\n' ||
974         (substring_okay && string[i] == '?'))
975       break;
976
977   temp = xmalloc (1 + (i - local_index));
978   strncpy (temp, &string[local_index], (i - local_index));
979   temp[i - local_index] = '\0';
980
981   if (substring_okay && string[i] == '?')
982     i++;
983
984   *caller_index = i;
985
986 #define FAIL_SEARCH() \
987   do { history_offset = history_length; free (temp) ; return (char *)NULL; } while (0)
988
989   search_mode = substring_okay ? NON_ANCHORED_SEARCH : ANCHORED_SEARCH;
990   while (1)
991     {
992       local_index = history_search_internal (temp, -1, search_mode);
993
994       if (local_index < 0)
995         FAIL_SEARCH ();
996
997       if (local_index == 0 || substring_okay)
998         {
999           entry = current_history ();
1000           history_offset = history_length;
1001         
1002           /* If this was a substring search, then remember the
1003              string that we matched for word substitution. */
1004           if (substring_okay)
1005             {
1006               if (search_string)
1007                 free (search_string);
1008               search_string = temp;
1009
1010               if (search_match)
1011                 free (search_match);
1012               search_match = history_find_word (entry->line, local_index);
1013             }
1014           else
1015             free (temp);
1016           return (entry->line);
1017         }
1018
1019       if (history_offset)
1020         history_offset--;
1021       else
1022         FAIL_SEARCH ();
1023     }
1024 #undef FAIL_SEARCH
1025 #undef RETURN_ENTRY
1026 }
1027 #if defined (SHELL)
1028 /* Function for extracting single-quoted strings.  Used for inhibiting
1029    history expansion within single quotes. */
1030
1031 /* Extract the contents of STRING as if it is enclosed in single quotes.
1032    SINDEX, when passed in, is the offset of the character immediately
1033    following the opening single quote; on exit, SINDEX is left pointing
1034    to the closing single quote. */
1035 static void
1036 rl_string_extract_single_quoted (string, sindex)
1037      char *string;
1038      int *sindex;
1039 {
1040   register int i = *sindex;
1041
1042   while (string[i] && string[i] != '\'')
1043     i++;
1044
1045   *sindex = i;
1046 }
1047
1048 static char *
1049 quote_breaks (s)
1050      char *s;
1051 {
1052   register char *p, *r;
1053   char *ret;
1054   int len = 3;
1055
1056   for (p = s; p && *p; p++, len++)
1057     {
1058       if (*p == '\'')
1059         len += 3;
1060       else if (whitespace (*p) || *p == '\n')
1061         len += 2;
1062     }
1063
1064   r = ret = xmalloc (len);
1065   *r++ = '\'';
1066   for (p = s; p && *p; )
1067     {
1068       if (*p == '\'')
1069         {
1070           *r++ = '\'';
1071           *r++ = '\\';
1072           *r++ = '\'';
1073           *r++ = '\'';
1074           p++;
1075         }
1076       else if (whitespace (*p) || *p == '\n')
1077         {
1078           *r++ = '\'';
1079           *r++ = *p++;
1080           *r++ = '\'';
1081         }
1082       else
1083         *r++ = *p++;
1084     }
1085   *r++ = '\'';
1086   *r = '\0';
1087   return ret;
1088 }
1089 #endif /* SHELL */
1090
1091 static char *
1092 hist_error(s, start, current, errtype)
1093       char *s;
1094       int start, current, errtype;
1095 {
1096   char *temp, *emsg;
1097   int ll, elen;
1098
1099   ll = current - start;
1100
1101   switch (errtype)
1102     {
1103     case EVENT_NOT_FOUND:
1104       emsg = "event not found";
1105       elen = 15;
1106       break;
1107     case BAD_WORD_SPEC:
1108       emsg = "bad word specifier";
1109       elen = 18;
1110       break;
1111     case SUBST_FAILED:
1112       emsg = "substitution failed";
1113       elen = 19;
1114       break;
1115     case BAD_MODIFIER:
1116       emsg = "unrecognized history modifier";
1117       elen = 29;
1118       break;
1119     default:
1120       emsg = "unknown expansion error";
1121       elen = 23;
1122       break;
1123     }
1124
1125   temp = xmalloc (ll + elen + 3);
1126   strncpy (temp, s + start, ll);
1127   temp[ll] = ':';
1128   temp[ll + 1] = ' ';
1129   strcpy (temp + ll + 2, emsg);
1130   return (temp);
1131 }
1132
1133 /* Get a history substitution string from STR starting at *IPTR
1134    and return it.  The length is returned in LENPTR.
1135
1136    A backslash can quote the delimiter.  If the string is the
1137    empty string, the previous pattern is used.  If there is
1138    no previous pattern for the lhs, the last history search
1139    string is used.
1140
1141    If IS_RHS is 1, we ignore empty strings and set the pattern
1142    to "" anyway.  subst_lhs is not changed if the lhs is empty;
1143    subst_rhs is allowed to be set to the empty string. */
1144
1145 static char *
1146 get_subst_pattern (str, iptr, delimiter, is_rhs, lenptr)
1147      char *str;
1148      int *iptr, delimiter, is_rhs, *lenptr;
1149 {
1150   register int si, i, j, k;
1151   char *s = (char *) NULL;
1152
1153   i = *iptr;
1154
1155   for (si = i; str[si] && str[si] != delimiter; si++)
1156     if (str[si] == '\\' && str[si + 1] == delimiter)
1157       si++;
1158
1159   if (si > i || is_rhs)
1160     {
1161       s = xmalloc (si - i + 1);
1162       for (j = 0, k = i; k < si; j++, k++)
1163         {
1164           /* Remove a backslash quoting the search string delimiter. */
1165           if (str[k] == '\\' && str[k + 1] == delimiter)
1166             k++;
1167           s[j] = str[k];
1168         }
1169       s[j] = '\0';
1170       if (lenptr)
1171         *lenptr = j;
1172     }
1173
1174   i = si;
1175   if (str[i])
1176     i++;
1177   *iptr = i;
1178
1179   return s;
1180 }
1181
1182 static void
1183 postproc_subst_rhs ()
1184 {
1185   char *new;
1186   int i, j, new_size;
1187
1188   new = xmalloc (new_size = subst_rhs_len + subst_lhs_len);
1189   for (i = j = 0; i < subst_rhs_len; i++)
1190     {
1191       if (subst_rhs[i] == '&')
1192         {
1193           if (j + subst_lhs_len >= new_size)
1194             new = xrealloc (new, (new_size = new_size * 2 + subst_lhs_len));
1195           strcpy (new + j, subst_lhs);
1196           j += subst_lhs_len;
1197         }
1198       else
1199         {
1200           /* a single backslash protects the `&' from lhs interpolation */
1201           if (subst_rhs[i] == '\\' && subst_rhs[i + 1] == '&')
1202             i++;
1203           if (j >= new_size)
1204             new = xrealloc (new, new_size *= 2);
1205           new[j++] = subst_rhs[i];
1206         }
1207     }
1208   new[j] = '\0';
1209   free (subst_rhs);
1210   subst_rhs = new;
1211   subst_rhs_len = j;
1212 }
1213
1214 /* Expand the bulk of a history specifier starting at STRING[START].
1215    Returns 0 if everything is OK, -1 if an error occurred, and 1
1216    if the `p' modifier was supplied and the caller should just print
1217    the returned string.  Returns the new index into string in
1218    *END_INDEX_PTR, and the expanded specifier in *RET_STRING. */
1219 static int
1220 history_expand_internal (string, start, end_index_ptr, ret_string, current_line)
1221      char *string;
1222      int start, *end_index_ptr;
1223      char **ret_string;
1224      char *current_line;        /* for !# */
1225 {
1226   int i, n, starting_index;
1227   int substitute_globally, want_quotes, print_only;
1228   char *event, *temp, *result, *tstr, *t, c, *word_spec;
1229   int result_len;
1230
1231   result = xmalloc (result_len = 128);
1232
1233   i = start;
1234
1235   /* If it is followed by something that starts a word specifier,
1236      then !! is implied as the event specifier. */
1237
1238   if (member (string[i + 1], ":$*%^"))
1239     {
1240       char fake_s[3];
1241       int fake_i = 0;
1242       i++;
1243       fake_s[0] = fake_s[1] = history_expansion_char;
1244       fake_s[2] = '\0';
1245       event = get_history_event (fake_s, &fake_i, 0);
1246     }
1247   else if (string[i + 1] == '#')
1248     {
1249       i += 2;
1250       event = current_line;
1251     }
1252   else
1253     {
1254       int quoted_search_delimiter = 0;
1255
1256       /* If the character before this `!' is a double or single
1257          quote, then this expansion takes place inside of the
1258          quoted string.  If we have to search for some text ("!foo"),
1259          allow the delimiter to end the search string. */
1260       if (i && (string[i - 1] == '\'' || string[i - 1] == '"'))
1261         quoted_search_delimiter = string[i - 1];
1262       event = get_history_event (string, &i, quoted_search_delimiter);
1263     }
1264           
1265   if (!event)
1266     {
1267       *ret_string = hist_error (string, start, i, EVENT_NOT_FOUND);
1268       free (result);
1269       return (-1);
1270     }
1271
1272   /* If a word specifier is found, then do what that requires. */
1273   starting_index = i;
1274   word_spec = get_history_word_specifier (string, event, &i);
1275
1276   /* There is no such thing as a `malformed word specifier'.  However,
1277      it is possible for a specifier that has no match.  In that case,
1278      we complain. */
1279   if (word_spec == (char *)&error_pointer)
1280     {
1281       *ret_string = hist_error (string, starting_index, i, BAD_WORD_SPEC);
1282       free (result);
1283       return (-1);
1284     }
1285
1286   /* If no word specifier, than the thing of interest was the event. */
1287   if (!word_spec)
1288     temp = savestring (event);
1289   else
1290     {
1291       temp = savestring (word_spec);
1292       free (word_spec);
1293     }
1294
1295   /* Perhaps there are other modifiers involved.  Do what they say. */
1296   want_quotes = substitute_globally = print_only = 0;
1297   starting_index = i;
1298
1299   while (string[i] == ':')
1300     {
1301       c = string[i + 1];
1302
1303       if (c == 'g')
1304         {
1305           substitute_globally = 1;
1306           i++;
1307           c = string[i + 1];
1308         }
1309
1310       switch (c)
1311         {
1312         default:
1313           *ret_string = hist_error (string, i+1, i+2, BAD_MODIFIER);
1314           free (result);
1315           free (temp);
1316           return -1;
1317
1318 #if defined (SHELL)
1319         case 'q':
1320           want_quotes = 'q';
1321           break;
1322
1323         case 'x':
1324           want_quotes = 'x';
1325           break;
1326 #endif /* SHELL */
1327
1328           /* :p means make this the last executed line.  So we
1329              return an error state after adding this line to the
1330              history. */
1331         case 'p':
1332           print_only++;
1333           break;
1334
1335           /* :t discards all but the last part of the pathname. */
1336         case 't':
1337           tstr = strrchr (temp, '/');
1338           if (tstr)
1339             {
1340               tstr++;
1341               t = savestring (tstr);
1342               free (temp);
1343               temp = t;
1344             }
1345           break;
1346
1347           /* :h discards the last part of a pathname. */
1348         case 'h':
1349           tstr = strrchr (temp, '/');
1350           if (tstr)
1351             *tstr = '\0';
1352           break;
1353
1354           /* :r discards the suffix. */
1355         case 'r':
1356           tstr = strrchr (temp, '.');
1357           if (tstr)
1358             *tstr = '\0';
1359           break;
1360
1361           /* :e discards everything but the suffix. */
1362         case 'e':
1363           tstr = strrchr (temp, '.');
1364           if (tstr)
1365             {
1366               t = savestring (tstr);
1367               free (temp);
1368               temp = t;
1369             }
1370           break;
1371
1372         /* :s/this/that substitutes `that' for the first
1373            occurrence of `this'.  :gs/this/that substitutes `that'
1374            for each occurrence of `this'.  :& repeats the last
1375            substitution.  :g& repeats the last substitution
1376            globally. */
1377
1378         case '&':
1379         case 's':
1380           {
1381             char *new_event, *t;
1382             int delimiter, failed, si, l_temp;
1383
1384             if (c == 's')
1385               {
1386                 if (i + 2 < (int)strlen (string))
1387                   delimiter = string[i + 2];
1388                 else
1389                   break;        /* no search delimiter */
1390
1391                 i += 3;
1392
1393                 t = get_subst_pattern (string, &i, delimiter, 0, &subst_lhs_len);
1394                 /* An empty substitution lhs with no previous substitution
1395                    uses the last search string as the lhs. */
1396                 if (t)
1397                   {
1398                     if (subst_lhs)
1399                       free (subst_lhs);
1400                     subst_lhs = t;
1401                   }
1402                 else if (!subst_lhs)
1403                   {
1404                     if (search_string && *search_string)
1405                       {
1406                         subst_lhs = savestring (search_string);
1407                         subst_lhs_len = strlen (subst_lhs);
1408                       }
1409                     else
1410                       {
1411                         subst_lhs = (char *) NULL;
1412                         subst_lhs_len = 0;
1413                       }
1414                   }
1415
1416                 /* If there is no lhs, the substitution can't succeed. */
1417                 if (subst_lhs_len == 0)
1418                   {
1419                     *ret_string = hist_error (string, starting_index, i, SUBST_FAILED);
1420                     free (result);
1421                     free (temp);
1422                     return -1;
1423                   }
1424
1425                 if (subst_rhs)
1426                   free (subst_rhs);
1427                 subst_rhs = get_subst_pattern (string, &i, delimiter, 1, &subst_rhs_len);
1428
1429                 /* If `&' appears in the rhs, it's supposed to be replaced
1430                    with the lhs. */
1431                 if (member ('&', subst_rhs))
1432                   postproc_subst_rhs ();
1433               }
1434             else
1435               i += 2;
1436
1437             l_temp = strlen (temp);
1438             /* Ignore impossible cases. */
1439             if (subst_lhs_len > l_temp)
1440               {
1441                 *ret_string = hist_error (string, starting_index, i, SUBST_FAILED);
1442                 free (result);
1443                 free (temp);
1444                 return (-1);
1445               }
1446
1447             /* Find the first occurrence of THIS in TEMP. */
1448             si = 0;
1449             for (failed = 1; (si + subst_lhs_len) <= l_temp; si++)
1450               if (STREQN (temp+si, subst_lhs, subst_lhs_len))
1451                 {
1452                   int len = subst_rhs_len - subst_lhs_len + l_temp;
1453                   new_event = xmalloc (1 + len);
1454                   strncpy (new_event, temp, si);
1455                   strncpy (new_event + si, subst_rhs, subst_rhs_len);
1456                   strncpy (new_event + si + subst_rhs_len,
1457                            temp + si + subst_lhs_len,
1458                            l_temp - (si + subst_lhs_len));
1459                   new_event[len] = '\0';
1460                   free (temp);
1461                   temp = new_event;
1462
1463                   failed = 0;
1464
1465                   if (substitute_globally)
1466                     {
1467                       si += subst_rhs_len;
1468                       l_temp = strlen (temp);
1469                       substitute_globally++;
1470                       continue;
1471                     }
1472                   else
1473                     break;
1474                 }
1475
1476             if (substitute_globally > 1)
1477               {
1478                 substitute_globally = 0;
1479                 continue;       /* don't want to increment i */
1480               }
1481
1482             if (failed == 0)
1483               continue;         /* don't want to increment i */
1484
1485             *ret_string = hist_error (string, starting_index, i, SUBST_FAILED);
1486             free (result);
1487             free (temp);
1488             return (-1);
1489           }
1490         }
1491       i += 2;
1492     }
1493   /* Done with modfiers. */
1494   /* Believe it or not, we have to back the pointer up by one. */
1495   --i;
1496
1497 #if defined (SHELL)
1498   if (want_quotes)
1499     {
1500       char *x;
1501
1502       if (want_quotes == 'q')
1503         x = single_quote (temp);
1504       else if (want_quotes == 'x')
1505         x = quote_breaks (temp);
1506       else
1507         x = savestring (temp);
1508
1509       free (temp);
1510       temp = x;
1511     }
1512 #endif /* SHELL */
1513
1514   n = strlen (temp);
1515   if (n > result_len)
1516     result = xrealloc (result, n + 2);
1517   strcpy (result, temp);
1518   free (temp);
1519
1520   *end_index_ptr = i;
1521   *ret_string = result;
1522   return (print_only);
1523 }
1524
1525 /* Expand the string STRING, placing the result into OUTPUT, a pointer
1526    to a string.  Returns:
1527
1528   -1) If there was an error in expansion.
1529    0) If no expansions took place (or, if the only change in
1530       the text was the de-slashifying of the history expansion
1531       character)
1532    1) If expansions did take place
1533    2) If the `p' modifier was given and the caller should print the result
1534
1535   If an error ocurred in expansion, then OUTPUT contains a descriptive
1536   error message. */
1537
1538 #define ADD_STRING(s) \
1539         do \
1540           { \
1541             int sl = strlen (s); \
1542             j += sl; \
1543             if (j >= result_len) \
1544               { \
1545                 while (j >= result_len) \
1546                   result_len += 128; \
1547                 result = xrealloc (result, result_len); \
1548               } \
1549             strcpy (result + j - sl, s); \
1550           } \
1551         while (0)
1552
1553 #define ADD_CHAR(c) \
1554         do \
1555           { \
1556             if (j >= result_len - 1) \
1557               result = xrealloc (result, result_len += 64); \
1558             result[j++] = c; \
1559             result[j] = '\0'; \
1560           } \
1561         while (0)
1562
1563 int
1564 history_expand (hstring, output)
1565      char *hstring;
1566      char **output;
1567 {
1568   register int j;
1569   int i, r, l, passc, cc, modified, eindex, only_printing;
1570   char *string;
1571
1572   /* The output string, and its length. */
1573   int result_len;
1574   char *result;
1575
1576   /* Used when adding the string. */
1577   char *temp;
1578
1579   /* Setting the history expansion character to 0 inhibits all
1580      history expansion. */
1581   if (history_expansion_char == 0)
1582     {
1583       *output = savestring (hstring);
1584       return (0);
1585     }
1586     
1587   /* Prepare the buffer for printing error messages. */
1588   result = xmalloc (result_len = 256);
1589   result[0] = '\0';
1590
1591   only_printing = modified = 0;
1592   l = strlen (hstring);
1593
1594   /* Grovel the string.  Only backslash can quote the history escape
1595      character.  We also handle arg specifiers. */
1596
1597   /* Before we grovel forever, see if the history_expansion_char appears
1598      anywhere within the text. */
1599
1600   /* The quick substitution character is a history expansion all right.  That
1601      is to say, "^this^that^" is equivalent to "!!:s^this^that^", and in fact,
1602      that is the substitution that we do. */
1603   if (hstring[0] == history_subst_char)
1604     {
1605       string = xmalloc (l + 5);
1606
1607       string[0] = string[1] = history_expansion_char;
1608       string[2] = ':';
1609       string[3] = 's';
1610       strcpy (string + 4, hstring);
1611       l += 4;
1612     }
1613   else
1614     {
1615       string = hstring;
1616       /* If not quick substitution, still maybe have to do expansion. */
1617
1618       /* `!' followed by one of the characters in history_no_expand_chars
1619          is NOT an expansion. */
1620       for (i = 0; string[i]; i++)
1621         {
1622           cc = string[i + 1];
1623           if (string[i] == history_expansion_char)
1624             {
1625               if (!cc || member (cc, history_no_expand_chars))
1626                 continue;
1627 #if defined (SHELL)
1628               /* The shell uses ! as a pattern negation character
1629                  in globbing [...] expressions, so let those pass
1630                  without expansion. */
1631               else if (i > 0 && (string[i - 1] == '[') &&
1632                        member (']', string + i + 1))
1633                 continue;
1634 #endif /* SHELL */
1635               else
1636                 break;
1637             }
1638 #if defined (SHELL)
1639           else if (string[i] == '\'')
1640             {
1641               /* If this is bash, single quotes inhibit history expansion. */
1642               i++;
1643               rl_string_extract_single_quoted (string, &i);
1644             }
1645           else if (string[i] == '\\')
1646             {
1647               /* If this is bash, allow backslashes to quote single
1648                  quotes and
1649                  the history expansion character. */
1650               if (cc == '\'' || cc == history_expansion_char)
1651                 i++;
1652             }
1653 #endif /* SHELL */
1654         }
1655           
1656       if (string[i] != history_expansion_char)
1657         {
1658           free (result);
1659           *output = savestring (string);
1660           return (0);
1661         }
1662     }
1663
1664   /* Extract and perform the substitution. */
1665   for (passc = i = j = 0; i < l; i++)
1666     {
1667       int tchar = string[i];
1668
1669       if (passc)
1670         {
1671           passc = 0;
1672           ADD_CHAR (tchar);
1673           continue;
1674         }
1675
1676       if (tchar == history_expansion_char)
1677         tchar = -3;
1678
1679       switch (tchar)
1680         {
1681         default:
1682           ADD_CHAR (string[i]);
1683           break;
1684
1685         case '\\':
1686           passc++;
1687           ADD_CHAR (tchar);
1688           break;
1689
1690 #if defined (SHELL)
1691         case '\'':
1692           {
1693             /* If this is bash, single quotes inhibit history expansion. */
1694             int quote, slen;
1695
1696             quote = i++;
1697             rl_string_extract_single_quoted (string, &i);
1698
1699             slen = i - quote + 2;
1700             temp = xmalloc (slen);
1701             strncpy (temp, string + quote, slen);
1702             temp[slen - 1] = '\0';
1703             ADD_STRING (temp);
1704             free (temp);
1705             break;
1706           }
1707 #endif /* SHELL */
1708
1709         case -3:                /* history_expansion_char */
1710           cc = string[i + 1];
1711
1712           /* If the history_expansion_char is followed by one of the
1713              characters in history_no_expand_chars, then it is not a
1714              candidate for expansion of any kind. */
1715           if (member (cc, history_no_expand_chars))
1716             {
1717               ADD_CHAR (string[i]);
1718               break;
1719             }
1720
1721 #if defined (NO_BANG_HASH_MODIFIERS)
1722           /* There is something that is listed as a `word specifier' in csh
1723              documentation which means `the expanded text to this point'.
1724              That is not a word specifier, it is an event specifier.  If we
1725              don't want to allow modifiers with `!#', just stick the current
1726              output line in again. */
1727           if (cc == '#')
1728             {
1729               if (result)
1730                 {
1731                   temp = xmalloc (1 + strlen (result));
1732                   strcpy (temp, result);
1733                   ADD_STRING (temp);
1734                   free (temp);
1735                 }
1736               i++;
1737               break;
1738             }
1739 #endif
1740
1741           r = history_expand_internal (string, i, &eindex, &temp, result);
1742           if (r < 0)
1743             {
1744               *output = temp;
1745               free (result);
1746               if (string != hstring)
1747                 free (string);
1748               return -1;
1749             }
1750           else
1751             {
1752               if (temp)
1753                 {
1754                   modified++;
1755                   if (*temp)
1756                     ADD_STRING (temp);
1757                   free (temp);
1758                 }
1759               only_printing = r == 1;
1760               i = eindex;
1761             }
1762           break;
1763         }
1764     }
1765
1766   *output = result;
1767   if (string != hstring)
1768     free (string);
1769
1770   if (only_printing)
1771     {
1772       add_history (result);
1773       return (2);
1774     }
1775
1776   return (modified != 0);
1777 }
1778
1779 /* Return a consed string which is the word specified in SPEC, and found
1780    in FROM.  NULL is returned if there is no spec.  The address of
1781    ERROR_POINTER is returned if the word specified cannot be found.
1782    CALLER_INDEX is the offset in SPEC to start looking; it is updated
1783    to point to just after the last character parsed. */
1784 static char *
1785 get_history_word_specifier (spec, from, caller_index)
1786      char *spec, *from;
1787      int *caller_index;
1788 {
1789   register int i = *caller_index;
1790   int first, last;
1791   int expecting_word_spec = 0;
1792   char *result;
1793
1794   /* The range of words to return doesn't exist yet. */
1795   first = last = 0;
1796   result = (char *)NULL;
1797
1798   /* If we found a colon, then this *must* be a word specification.  If
1799      it isn't, then it is an error. */
1800   if (spec[i] == ':')
1801     {
1802       i++;
1803       expecting_word_spec++;
1804     }
1805
1806   /* Handle special cases first. */
1807
1808   /* `%' is the word last searched for. */
1809   if (spec[i] == '%')
1810     {
1811       *caller_index = i + 1;
1812       return (search_match ? savestring (search_match) : savestring (""));
1813     }
1814
1815   /* `*' matches all of the arguments, but not the command. */
1816   if (spec[i] == '*')
1817     {
1818       *caller_index = i + 1;
1819       result = history_arg_extract (1, '$', from);
1820       return (result ? result : savestring (""));
1821     }
1822
1823   /* `$' is last arg. */
1824   if (spec[i] == '$')
1825     {
1826       *caller_index = i + 1;
1827       return (history_arg_extract ('$', '$', from));
1828     }
1829
1830   /* Try to get FIRST and LAST figured out. */
1831
1832   if (spec[i] == '-')
1833     first = 0;
1834   else if (spec[i] == '^')
1835     first = 1;
1836   else if (digit_p (spec[i]) && expecting_word_spec)
1837     {
1838       for (first = 0; digit_p (spec[i]); i++)
1839         first = (first * 10) + digit_value (spec[i]);
1840     }
1841   else
1842     return ((char *)NULL);      /* no valid `first' for word specifier */
1843
1844   if (spec[i] == '^' || spec[i] == '*')
1845     {
1846       last = (spec[i] == '^') ? 1 : '$';        /* x* abbreviates x-$ */
1847       i++;
1848     }
1849   else if (spec[i] != '-')
1850     last = first;
1851   else
1852     {
1853       i++;
1854
1855       if (digit_p (spec[i]))
1856         {
1857           for (last = 0; digit_p (spec[i]); i++)
1858             last = (last * 10) + digit_value (spec[i]);
1859         }
1860       else if (spec[i] == '$')
1861         {
1862           i++;
1863           last = '$';
1864         }
1865       else if (!spec[i] || spec[i] == ':')  /* could be modifier separator */
1866         last = -1;              /* x- abbreviates x-$ omitting word `$' */
1867     }
1868
1869   *caller_index = i;
1870
1871   if (last >= first || last == '$' || last < 0)
1872     result = history_arg_extract (first, last, from);
1873
1874   return (result ? result : (char *)&error_pointer);
1875 }
1876
1877 /* Extract the args specified, starting at FIRST, and ending at LAST.
1878    The args are taken from STRING.  If either FIRST or LAST is < 0,
1879    then make that arg count from the right (subtract from the number of
1880    tokens, so that FIRST = -1 means the next to last token on the line).
1881    If LAST is `$' the last arg from STRING is used. */
1882 char *
1883 history_arg_extract (first, last, string)
1884      int first, last;
1885      char *string;
1886 {
1887   register int i, len;
1888   char *result = (char *)NULL;
1889   int size = 0, offset = 0;
1890   char **list;
1891
1892   /* XXX - think about making history_tokenize return a struct array,
1893      each struct in array being a string and a length to avoid the
1894      calls to strlen below. */
1895   if ((list = history_tokenize (string)) == NULL)
1896     return ((char *)NULL);
1897
1898   for (len = 0; list[len]; len++)
1899     ;
1900
1901   if (last < 0)
1902     last = len + last - 1;
1903
1904   if (first < 0)
1905     first = len + first - 1;
1906
1907   if (last == '$')
1908     last = len - 1;
1909
1910   if (first == '$')
1911     first = len - 1;
1912
1913   last++;
1914
1915   if (first >= len || last > len || first < 0 || last < 0 || first > last)
1916     result = ((char *)NULL);
1917   else
1918     {
1919       for (size = 0, i = first; i < last; i++)
1920         size += strlen (list[i]) + 1;
1921       result = xmalloc (size + 1);
1922       result[0] = '\0';
1923
1924       for (i = first; i < last; i++)
1925         {
1926           strcpy (result + offset, list[i]);
1927           offset += strlen (list[i]);
1928           if (i + 1 < last)
1929             {
1930               result[offset++] = ' ';
1931               result[offset] = 0;
1932             }
1933         }
1934     }
1935
1936   for (i = 0; i < len; i++)
1937     free (list[i]);
1938   free (list);
1939
1940   return (result);
1941 }
1942
1943 #define slashify_in_quotes "\\`\"$"
1944
1945 /* Parse STRING into tokens and return an array of strings.  If WIND is
1946    not -1 and INDP is not null, we also want the word surrounding index
1947    WIND.  The position in the returned array of strings is returned in
1948    *INDP. */
1949 static char **
1950 history_tokenize_internal (string, wind, indp)
1951      char *string;
1952      int wind, *indp;
1953 {
1954   char **result = (char **)NULL;
1955   register int i, start, result_index, size;
1956   int len;
1957
1958   i = result_index = size = 0;
1959
1960   /* Get a token, and stuff it into RESULT.  The tokens are split
1961      exactly where the shell would split them. */
1962   while (string[i])
1963     {
1964       int delimiter = 0;
1965
1966       /* Skip leading whitespace. */
1967       for (; string[i] && whitespace (string[i]); i++)
1968         ;
1969       if (!string[i] || string[i] == history_comment_char)
1970         return (result);
1971
1972       start = i;
1973       
1974       if (member (string[i], "()\n"))
1975         {
1976           i++;
1977           goto got_token;
1978         }
1979
1980       if (member (string[i], "<>;&|$"))
1981         {
1982           int peek = string[i + 1];
1983
1984           if (peek == string[i] && peek != '$')
1985             {
1986               if (peek == '<' && string[i + 2] == '-')
1987                 i++;
1988               i += 2;
1989               goto got_token;
1990             }
1991           else
1992             {
1993               if ((peek == '&' && (string[i] == '>' || string[i] == '<')) ||
1994                   ((peek == '>') && (string[i] == '&')) ||
1995                   ((peek == '(') && (string[i] == '$')))
1996                 {
1997                   i += 2;
1998                   goto got_token;
1999                 }
2000             }
2001           if (string[i] != '$')
2002             {
2003               i++;
2004               goto got_token;
2005             }
2006         }
2007
2008       /* Get word from string + i; */
2009
2010       if (member (string[i], "\"'`"))
2011         delimiter = string[i++];
2012
2013       for (; string[i]; i++)
2014         {
2015           if (string[i] == '\\' && string[i + 1] == '\n')
2016             {
2017               i++;
2018               continue;
2019             }
2020
2021           if (string[i] == '\\' && delimiter != '\'' &&
2022               (delimiter != '"' || member (string[i], slashify_in_quotes)))
2023             {
2024               i++;
2025               continue;
2026             }
2027
2028           if (delimiter && string[i] == delimiter)
2029             {
2030               delimiter = 0;
2031               continue;
2032             }
2033
2034           if (!delimiter && (member (string[i], " \t\n;&()|<>")))
2035             break;
2036
2037           if (!delimiter && member (string[i], "\"'`"))
2038             delimiter = string[i];
2039         }
2040     got_token:
2041
2042       /* If we are looking for the word in which the character at a
2043          particular index falls, remember it. */
2044       if (indp && wind >= 0 && wind >= start && wind < i)
2045         *indp = result_index;
2046
2047       len = i - start;
2048       if (result_index + 2 >= size)
2049         result = (char **)xrealloc (result, ((size += 10) * sizeof (char *)));
2050       result[result_index] = xmalloc (1 + len);
2051       strncpy (result[result_index], string + start, len);
2052       result[result_index][len] = '\0';
2053       result[++result_index] = (char *)NULL;
2054     }
2055
2056   return (result);
2057 }
2058
2059 /* Return an array of tokens, much as the shell might.  The tokens are
2060    parsed out of STRING. */
2061 char **
2062 history_tokenize (string)
2063      char *string;
2064 {
2065   return (history_tokenize_internal (string, -1, (int *)NULL));
2066 }
2067
2068 /* Find and return the word which contains the character at index IND
2069    in the history line LINE.  Used to save the word matched by the
2070    last history !?string? search. */
2071 static char *
2072 history_find_word (line, ind)
2073      char *line;
2074      int ind;
2075 {
2076   char **words, *s;
2077   int i, wind;
2078
2079   words = history_tokenize_internal (line, ind, &wind);
2080   if (wind == -1)
2081     return ((char *)NULL);
2082   s = words[wind];
2083   for (i = 0; i < wind; i++)
2084     free (words[i]);
2085   for (i = wind + 1; words[i]; i++)
2086     free (words[i]);
2087   free (words);
2088   return s;
2089 }
2090
2091 #if defined (STATIC_MALLOC)
2092 \f
2093 /* **************************************************************** */
2094 /*                                                                  */
2095 /*                      xmalloc and xrealloc ()                     */
2096 /*                                                                  */
2097 /* **************************************************************** */
2098
2099 static void memory_error_and_abort ();
2100
2101 static char *
2102 xmalloc (bytes)
2103      int bytes;
2104 {
2105   char *temp = (char *)malloc (bytes);
2106
2107   if (!temp)
2108     memory_error_and_abort ();
2109   return (temp);
2110 }
2111
2112 static char *
2113 xrealloc (pointer, bytes)
2114      char *pointer;
2115      int bytes;
2116 {
2117   char *temp;
2118
2119   if (!pointer)
2120     temp = (char *)xmalloc (bytes);
2121   else
2122     temp = (char *)realloc (pointer, bytes);
2123
2124   if (!temp)
2125     memory_error_and_abort ();
2126
2127   return (temp);
2128 }
2129
2130 static void
2131 memory_error_and_abort ()
2132 {
2133   fprintf (stderr, "history: Out of virtual memory!\n");
2134   abort ();
2135 }
2136 #endif /* STATIC_MALLOC */
2137 \f
2138 /* **************************************************************** */
2139 /*                                                                  */
2140 /*                              Test Code                           */
2141 /*                                                                  */
2142 /* **************************************************************** */
2143 #ifdef TEST
2144 main ()
2145 {
2146   char line[1024], *t;
2147   int done = 0;
2148
2149   line[0] = 0;
2150
2151   while (!done)
2152     {
2153       fprintf (stdout, "history%% ");
2154       t = gets (line);
2155
2156       if (!t)
2157         strcpy (line, "quit");
2158
2159       if (line[0])
2160         {
2161           char *expansion;
2162           int result;
2163
2164           using_history ();
2165
2166           result = history_expand (line, &expansion);
2167           strcpy (line, expansion);
2168           free (expansion);
2169           if (result)
2170             fprintf (stderr, "%s\n", line);
2171
2172           if (result < 0)
2173             continue;
2174
2175           add_history (line);
2176         }
2177
2178       if (strcmp (line, "quit") == 0) done = 1;
2179       if (strcmp (line, "save") == 0) write_history (0);
2180       if (strcmp (line, "read") == 0) read_history (0);
2181       if (strcmp (line, "list") == 0)
2182         {
2183           register HIST_ENTRY **the_list = history_list ();
2184           register int i;
2185
2186           if (the_list)
2187             for (i = 0; the_list[i]; i++)
2188               fprintf (stdout, "%d: %s\n", i + history_base, the_list[i]->line);
2189         }
2190       if (strncmp (line, "delete", strlen ("delete")) == 0)
2191         {
2192           int which;
2193           if ((sscanf (line + strlen ("delete"), "%d", &which)) == 1)
2194             {
2195               HIST_ENTRY *entry = remove_history (which);
2196               if (!entry)
2197                 fprintf (stderr, "No such entry %d\n", which);
2198               else
2199                 {
2200                   free (entry->line);
2201                   free (entry);
2202                 }
2203             }
2204           else
2205             {
2206               fprintf (stderr, "non-numeric arg given to `delete'\n");
2207             }
2208         }
2209     }
2210 }
2211
2212 #endif /* TEST */
2213 \f
2214 /*
2215 * Local variables:
2216 * compile-command: "gcc -g -DTEST -o history history.c"
2217 * end:
2218 */