1 /* History.c -- standalone history library */
3 /* Copyright (C) 1989, 1991 Free Software Foundation, Inc.
5 This file contains the GNU History Library (the Library), a set of
6 routines for managing the text of previously typed lines.
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 of the License, or
11 (at your option) any later version.
13 The Library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
22 /* The goal is to make the implementation transparent, so that you
23 don't have to know what data types are used, just what functions
24 you can call. I think I have done that. */
26 /* Remove these declarations when we have a complete libgnu.a. */
27 #if !defined (STATIC_MALLOC)
28 extern char *xmalloc (), *xrealloc ();
30 static char *xmalloc (), *xrealloc ();
36 #include <sys/types.h>
46 #define savestring(x) (char *)strcpy (xmalloc (1 + strlen (x)), (x))
50 #define whitespace(c) (((c) == ' ') || ((c) == '\t'))
54 #define digit(c) ((c) >= '0' && (c) <= '9')
58 #define member(c, s) ((c) ? index ((s), (c)) : 0)
61 /* **************************************************************** */
63 /* History Functions */
65 /* **************************************************************** */
67 /* An array of HIST_ENTRY. This is where we store the history. */
68 static HIST_ENTRY **the_history = (HIST_ENTRY **)NULL;
70 /* Non-zero means that we have enforced a limit on the amount of
71 history that we save. */
72 int history_stifled = 0;
74 /* If HISTORY_STIFLED is non-zero, then this is the maximum number of
75 entries to remember. */
76 int max_input_history;
78 /* The current location of the interactive history pointer. Just makes
79 life easier for outside callers. */
80 static int history_offset = 0;
82 /* The number of strings currently stored in the input_history list. */
83 int history_length = 0;
85 /* The current number of slots allocated to the input_history. */
86 static int history_size = 0;
88 /* The number of slots to increase the_history by. */
89 #define DEFAULT_HISTORY_GROW_SIZE 50
91 /* The character that represents the start of a history expansion
92 request. This is usually `!'. */
93 char history_expansion_char = '!';
95 /* The character that invokes word substitution if found at the start of
96 a line. This is usually `^'. */
97 char history_subst_char = '^';
99 /* During tokenization, if this character is seen as the first character
100 of a word, then it, and all subsequent characters upto a newline are
101 ignored. For a Bourne shell, this should be '#'. Bash special cases
102 the interactive comment character to not be a comment delimiter. */
103 char history_comment_char = '\0';
105 /* The list of characters which inhibit the expansion of text if found
106 immediately following history_expansion_char. */
107 char *history_no_expand_chars = " \t\n\r=";
109 /* The logical `base' of the history array. It defaults to 1. */
110 int history_base = 1;
112 /* Begin a session in which the history functions might be used. This
113 initializes interactive variables. */
117 history_offset = history_length;
120 /* Return the number of bytes that the primary history entries are using.
121 This just adds up the lengths of the_history->lines. */
123 history_total_bytes ()
125 register int i, result;
129 for (i = 0; the_history && the_history[i]; i++)
130 result += strlen (the_history[i]->line);
135 /* Place STRING at the end of the history list. The data field
143 if (history_stifled && (history_length == max_input_history))
147 /* If the history is stifled, and history_length is zero,
148 and it equals max_input_history, we don't save items. */
152 /* If there is something in the slot, then remove it. */
155 free (the_history[0]->line);
156 free (the_history[0]);
159 for (i = 0; i < history_length; i++)
160 the_history[i] = the_history[i + 1];
169 the_history = (HIST_ENTRY **)
170 xmalloc ((history_size = DEFAULT_HISTORY_GROW_SIZE)
171 * sizeof (HIST_ENTRY *));
177 if (history_length == (history_size - 1))
179 the_history = (HIST_ENTRY **)
180 xrealloc (the_history,
181 ((history_size += DEFAULT_HISTORY_GROW_SIZE)
182 * sizeof (HIST_ENTRY *)));
188 temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
189 temp->line = savestring (string);
190 temp->data = (char *)NULL;
192 the_history[history_length] = (HIST_ENTRY *)NULL;
193 the_history[history_length - 1] = temp;
196 /* Make the history entry at WHICH have LINE and DATA. This returns
197 the old entry so you can dispose of the data. In the case of an
198 invalid WHICH, a NULL pointer is returned. */
200 replace_history_entry (which, line, data)
205 HIST_ENTRY *temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
206 HIST_ENTRY *old_value;
208 if (which >= history_length)
209 return ((HIST_ENTRY *)NULL);
211 old_value = the_history[which];
213 temp->line = savestring (line);
215 the_history[which] = temp;
220 /* Returns the magic number which says what history element we are
221 looking at now. In this implementation, it returns history_offset. */
225 return (history_offset);
228 /* Search the history for STRING, starting at history_offset.
229 If DIRECTION < 0, then the search is through previous entries, else
230 through subsequent. If ANCHORED is non-zero, the string must
231 appear at the beginning of a history line, otherwise, the string
232 may appear anywhere in the line. If the string is found, then
233 current_history () is the history entry, and the value of this
234 function is the offset in the line of that history entry that the
235 string was found in. Otherwise, nothing is changed, and a -1 is
238 #define ANCHORED_SEARCH 1
239 #define NON_ANCHORED_SEARCH 0
242 history_search_internal (string, direction, anchored)
244 int direction, anchored;
246 register int i = history_offset;
247 register int reverse = (direction < 0);
250 int string_len = strlen (string);
252 /* Take care of trivial cases first. */
254 if (!history_length || ((i == history_length) && !reverse))
257 if (reverse && (i == history_length))
262 /* Search each line in the history list for STRING. */
264 /* At limit for direction? */
265 if ((reverse && i < 0) ||
266 (!reverse && i == history_length))
269 line = the_history[i]->line;
270 index = strlen (line);
272 /* If STRING is longer than line, no match. */
273 if (string_len > index)
276 /* Handle anchored searches first. */
277 if (anchored == ANCHORED_SEARCH)
279 if (strncmp (string, line, string_len) == 0)
288 /* Do substring search. */
295 if (strncmp (string, line + index, string_len) == 0)
305 register int limit = index - string_len + 1;
308 while (index < limit)
310 if (strncmp (string, line + index, string_len) == 0)
326 /* Do a non-anchored search for STRING through the history in DIRECTION. */
328 history_search (string, direction)
332 return (history_search_internal (string, direction, NON_ANCHORED_SEARCH));
335 /* Do an anchored search for string through the history in DIRECTION. */
337 history_search_prefix (string, direction)
341 return (history_search_internal (string, direction, ANCHORED_SEARCH));
344 /* Remove history element WHICH from the history. The removed
345 element is returned to you so you can free the line, data,
346 and containing structure. */
348 remove_history (which)
351 HIST_ENTRY *return_value;
353 if (which >= history_length || !history_length)
354 return_value = (HIST_ENTRY *)NULL;
358 return_value = the_history[which];
360 for (i = which; i < history_length; i++)
361 the_history[i] = the_history[i + 1];
366 return (return_value);
369 /* Stifle the history list, remembering only MAX number of lines. */
374 if (history_length > max)
378 /* This loses because we cannot free the data. */
379 for (i = 0; i < (history_length - max); i++)
381 free (the_history[i]->line);
382 free (the_history[i]);
385 for (j = 0, i = history_length - max; j < max; i++, j++)
386 the_history[j] = the_history[i];
387 the_history[j] = (HIST_ENTRY *)NULL;
391 max_input_history = max;
394 /* Stop stifling the history. This returns the previous amount the history
395 was stifled by. The value is positive if the history was stifled, negative
400 int result = max_input_history;
409 /* Return the string that should be used in the place of this
410 filename. This only matters when you don't specify the
411 filename to read_history (), or write_history (). */
413 history_filename (filename)
416 char *return_val = filename ? savestring (filename) : (char *)NULL;
420 char *home = (char *)getenv ("HOME");
421 if (!home) home = ".";
422 return_val = (char *)xmalloc (2 + strlen (home) + strlen (".history"));
423 sprintf (return_val, "%s/.history", home);
428 /* Add the contents of FILENAME to the history list, a line at a time.
429 If FILENAME is NULL, then read from ~/.history. Returns 0 if
430 successful, or errno if not. */
432 read_history (filename)
435 return (read_history_range (filename, 0, -1));
438 /* Read a range of lines from FILENAME, adding them to the history list.
439 Start reading at the FROM'th line and end at the TO'th. If FROM
440 is zero, start at the beginning. If TO is less than FROM, read
441 until the end of the file. If FILENAME is NULL, then read from
442 ~/.history. Returns 0 if successful, or errno if not. */
444 read_history_range (filename, from, to)
448 register int line_start, line_end;
449 char *input, *buffer = (char *)NULL;
450 int file, current_line;
454 input = history_filename (filename);
455 file = open (input, O_RDONLY, 0666);
458 (stat (input, &finfo) == -1))
461 buffer = (char *)xmalloc (finfo.st_size + 1);
463 if (read (file, buffer, finfo.st_size) != finfo.st_size)
477 /* Set TO to larger than end of file if negative. */
481 /* Start at beginning of file, work to end. */
482 line_start = line_end = current_line = 0;
484 /* Skip lines until we are at FROM. */
485 while (line_start < finfo.st_size && current_line < from)
487 for (line_end = line_start; line_end < finfo.st_size; line_end++)
488 if (buffer[line_end] == '\n')
491 line_start = line_end + 1;
492 if (current_line == from)
497 /* If there are lines left to gobble, then gobble them now. */
498 for (line_end = line_start; line_end < finfo.st_size; line_end++)
499 if (buffer[line_end] == '\n')
501 buffer[line_end] = '\0';
503 if (buffer[line_start])
504 add_history (buffer + line_start);
508 if (current_line >= to)
511 line_start = line_end + 1;
516 /* Truncate the history file FNAME, leaving only LINES trailing lines.
517 If FNAME is NULL, then use ~/.history. */
518 history_truncate_file (fname, lines)
524 char *buffer = (char *)NULL, *filename;
527 filename = history_filename (fname);
528 if (stat (filename, &finfo) == -1)
531 file = open (filename, O_RDONLY, 0666);
536 buffer = (char *)xmalloc (finfo.st_size + 1);
537 read (file, buffer, finfo.st_size);
540 /* Count backwards from the end of buffer until we have passed
542 for (i = finfo.st_size; lines && i; i--)
544 if (buffer[i] == '\n')
548 /* If there are fewer lines in the file than we want to truncate to,
549 then we are all done. */
553 /* Otherwise, write from the start of this line until the end of the
556 if (buffer[i] == '\n')
562 file = open (filename, O_WRONLY | O_TRUNC | O_CREAT, 0666);
566 write (file, buffer + i, finfo.st_size - i);
576 #define HISTORY_APPEND 0
577 #define HISTORY_OVERWRITE 1
579 /* Workhorse function for writing history. Writes NELEMENT entries
580 from the history list to FILENAME. OVERWRITE is non-zero if you
581 wish to replace FILENAME with the entries. */
583 history_do_write (filename, nelements, overwrite)
585 int nelements, overwrite;
589 char *output = history_filename (filename);
593 mode = O_WRONLY | O_CREAT | O_TRUNC;
595 mode = O_WRONLY | O_APPEND;
597 if ((file = open (output, mode, 0666)) == -1)
600 if (nelements > history_length)
601 nelements = history_length;
603 /* Build a buffer of all the lines to write, and write them in one syscall.
610 /* Calculate the total number of bytes to write. */
611 for (i = history_length - nelements; i < history_length; i++)
612 buffer_size += 1 + strlen (the_history[i]->line);
614 /* Allocate the buffer, and fill it. */
615 buffer = (char *)xmalloc (buffer_size);
617 for (i = history_length - nelements; i < history_length; i++)
619 strcpy (buffer + j, the_history[i]->line);
620 j += strlen (the_history[i]->line);
624 write (file, buffer, buffer_size);
632 /* Append NELEMENT entries to FILENAME. The entries appended are from
633 the end of the list minus NELEMENTs up to the end of the list. */
635 append_history (nelements, filename)
639 return (history_do_write (filename, nelements, HISTORY_APPEND));
642 /* Overwrite FILENAME with the current history. If FILENAME is NULL,
643 then write the history list to ~/.history. Values returned
644 are as in read_history ().*/
646 write_history (filename)
649 return (history_do_write (filename, history_length, HISTORY_OVERWRITE));
652 /* Return the history entry at the current position, as determined by
653 history_offset. If there is no entry there, return a NULL pointer. */
657 if ((history_offset == history_length) || !the_history)
658 return ((HIST_ENTRY *)NULL);
660 return (the_history[history_offset]);
663 /* Back up history_offset to the previous history entry, and return
664 a pointer to that entry. If there is no previous entry then return
670 return ((HIST_ENTRY *)NULL);
672 return (the_history[--history_offset]);
675 /* Move history_offset forward to the next history entry, and return
676 a pointer to that entry. If there is no next entry then return a
681 if (history_offset == history_length)
682 return ((HIST_ENTRY *)NULL);
684 return (the_history[++history_offset]);
687 /* Return the current history array. The caller has to be carefull, since this
688 is the actual array of data, and could be bashed or made corrupt easily.
689 The array is terminated with a NULL pointer. */
693 return (the_history);
696 /* Return the history entry which is logically at OFFSET in the history array.
697 OFFSET is relative to history_base. */
702 int index = offset - history_base;
704 if (index >= history_length ||
707 return ((HIST_ENTRY *)NULL);
708 return (the_history[index]);
711 /* Search for STRING in the history list. DIR is < 0 for searching
712 backwards. POS is an absolute index into the history list at
713 which point to begin searching. */
715 history_search_pos (string, dir, pos)
719 int ret, old = where_history ();
720 history_set_pos (pos);
721 if (history_search (string, dir) == -1)
723 history_set_pos (old);
726 ret = where_history ();
727 history_set_pos (old);
731 /* Make the current history item be the one at POS, an absolute index.
732 Returns zero if POS is out of range, else non-zero. */
734 history_set_pos (pos)
737 if (pos > history_length || pos < 0 || !the_history)
739 history_offset = pos;
744 /* **************************************************************** */
746 /* History Expansion */
748 /* **************************************************************** */
750 /* Hairy history expansion on text, not tokens. This is of general
751 use, and thus belongs in this library. */
753 /* The last string searched for in a !?string? search. */
754 static char *search_string = (char *)NULL;
756 /* Return the event specified at TEXT + OFFSET modifying OFFSET to
757 point to after the event specifier. Just a pointer to the history
758 line is returned; NULL is returned in the event of a bad specifier.
759 You pass STRING with *INDEX equal to the history_expansion_char that
760 begins this specification.
761 DELIMITING_QUOTE is a character that is allowed to end the string
762 specification for what to search for in addition to the normal
763 characters `:', ` ', `\t', `\n', and sometimes `?'.
764 So you might call this function like:
765 line = get_history_event ("!echo:p", &index, 0); */
767 get_history_event (string, caller_index, delimiting_quote)
770 int delimiting_quote;
772 register int i = *caller_index;
776 /* The event can be specified in a number of ways.
778 !! the previous command
780 !-n current command-line minus N
781 !str the most recent command starting with STR
783 the most recent command containing STR
785 All values N are determined via HISTORY_BASE. */
787 if (string[i] != history_expansion_char)
788 return ((char *)NULL);
790 /* Move on to the specification. */
793 /* Handle !! case. */
794 if (string[i] == history_expansion_char)
797 which = history_base + (history_length - 1);
802 /* Hack case of numeric line specification. */
804 if (string[i] == '-')
810 if (digit (string[i]))
814 /* Get the extent of the digits. */
815 for (; digit (string[i]); i++);
817 /* Get the digit value. */
818 sscanf (string + start, "%d", &which);
823 which = (history_length + history_base) - which;
826 if (entry = history_get (which))
827 return (entry->line);
829 return ((char *)NULL);
832 /* This must be something to search for. If the spec begins with
833 a '?', then the string may be anywhere on the line. Otherwise,
834 the string must be found at the start of a line. */
838 int substring_okay = 0;
840 if (string[i] == '?')
846 for (index = i; string[i]; i++)
847 if (whitespace (string[i]) ||
850 (substring_okay && string[i] == '?') ||
851 string[i] == delimiting_quote)
854 temp = (char *)alloca (1 + (i - index));
855 strncpy (temp, &string[index], (i - index));
856 temp[i - index] = '\0';
858 if (string[i] == '?')
865 index = history_search_internal
866 (temp, -1, substring_okay ? NON_ANCHORED_SEARCH : ANCHORED_SEARCH);
871 history_offset = history_length;
872 return ((char *)NULL);
878 entry = current_history ();
879 history_offset = history_length;
881 /* If this was a substring search, then remember the string that
882 we matched for word substitution. */
886 free (search_string);
887 search_string = savestring (temp);
890 return (entry->line);
902 /* Expand the string STRING, placing the result into OUTPUT, a pointer
903 to a string. Returns:
905 0) If no expansions took place (or, if the only change in
906 the text was the de-slashifying of the history expansion
908 1) If expansions did take place
909 -1) If there was an error in expansion.
911 If an error ocurred in expansion, then OUTPUT contains a descriptive
914 history_expand (string, output)
918 register int j, l = strlen (string);
919 int i, word_spec_error = 0;
920 int cc, modified = 0;
921 char *word_spec, *event;
922 int starting_index, only_printing = 0, substitute_globally = 0;
924 char *get_history_word_specifier (), *rindex ();
926 /* The output string, and its length. */
928 char *result = (char *)NULL;
930 /* Used in add_string; */
931 char *temp, tt[2], tbl[3];
933 /* Prepare the buffer for printing error messages. */
934 result = (char *)xmalloc (len = 255);
936 result[0] = tt[1] = tbl[2] = '\0';
938 tbl[1] = history_expansion_char;
940 /* Grovel the string. Only backslash can quote the history escape
941 character. We also handle arg specifiers. */
943 /* Before we grovel forever, see if the history_expansion_char appears
944 anywhere within the text. */
946 /* The quick substitution character is a history expansion all right. That
947 is to say, "^this^that^" is equivalent to "!!:s^this^that^", and in fact,
948 that is the substitution that we do. */
949 if (string[0] == history_subst_char)
951 char *format_string = (char *)alloca (10 + strlen (string));
953 sprintf (format_string, "%c%c:s%s",
954 history_expansion_char, history_expansion_char,
956 string = format_string;
961 /* If not quick substitution, still maybe have to do expansion. */
963 /* `!' followed by one of the characters in history_no_expand_chars
964 is NOT an expansion. */
965 for (i = 0; string[i]; i++)
966 if (string[i] == history_expansion_char)
967 if (!string[i + 1] || member (string[i + 1], history_no_expand_chars))
973 *output = savestring (string);
978 for (i = j = 0; i < l; i++)
980 int tchar = string[i];
981 if (tchar == history_expansion_char)
987 if (string[i + 1] == history_expansion_char)
996 /* case history_expansion_char: */
998 starting_index = i + 1;
1001 /* If the history_expansion_char is followed by one of the
1002 characters in history_no_expand_chars, then it is not a
1003 candidate for expansion of any kind. */
1004 if (member (cc, history_no_expand_chars))
1007 /* There is something that is listed as a `word specifier' in csh
1008 documentation which means `the expanded text to this point'.
1009 That is not a word specifier, it is an event specifier. */
1012 goto hack_pound_sign;
1014 /* If it is followed by something that starts a word specifier,
1015 then !! is implied as the event specifier. */
1017 if (member (cc, ":$*%^"))
1022 fake_s[0] = fake_s[1] = history_expansion_char;
1024 event = get_history_event (fake_s, &fake_i, 0);
1028 int quoted_search_delimiter = 0;
1030 /* If the character before this `!' is a double or single
1031 quote, then this expansion takes place inside of the
1032 quoted string. If we have to search for some text ("!foo"),
1033 allow the delimiter to end the search string. */
1034 if (i && (string[i - 1] == '\'' || string[i - 1] == '"'))
1035 quoted_search_delimiter = string[i - 1];
1037 event = get_history_event (string, &i, quoted_search_delimiter);
1043 int l = 1 + (i - starting_index);
1045 temp = (char *)alloca (1 + l);
1046 strncpy (temp, string + starting_index, l);
1048 sprintf (result, "%s: %s.", temp,
1049 word_spec_error ? "Bad word specifier" : "Event not found");
1055 /* If a word specifier is found, then do what that requires. */
1058 word_spec = get_history_word_specifier (string, event, &i);
1060 /* There is no such thing as a `malformed word specifier'. However,
1061 it is possible for a specifier that has no match. In that case,
1063 if (word_spec == (char *)-1)
1067 goto event_not_found;
1070 /* If no word specifier, than the thing of interest was the event. */
1075 temp = (char *)alloca (1 + strlen (word_spec));
1076 strcpy (temp, word_spec);
1080 /* Perhaps there are other modifiers involved. Do what they say. */
1084 if (string[i] == ':')
1088 switch (string[i + 1])
1090 /* :p means make this the last executed line. So we
1091 return an error state after adding this line to the
1097 /* :t discards all but the last part of the pathname. */
1099 tstr = rindex (temp, '/');
1104 /* :h discards the last part of a pathname. */
1106 tstr = rindex (temp, '/');
1111 /* :r discards the suffix. */
1113 tstr = rindex (temp, '.');
1118 /* :e discards everything but the suffix. */
1120 tstr = rindex (temp, '.');
1125 /* :s/this/that substitutes `this' for `that'. */
1126 /* :gs/this/that substitutes `this' for `that' globally. */
1128 if (string[i + 2] == 's')
1131 substitute_globally = 1;
1139 char *this, *that, *new_event;
1141 int si, l_this, l_that, l_temp = strlen (temp);
1143 if (i + 2 < strlen (string))
1144 delimiter = string[i + 2];
1152 for (si = i; string[si] && string[si] != delimiter; si++);
1154 this = (char *)alloca (1 + l_this);
1155 strncpy (this, string + i, l_this);
1156 this[l_this] = '\0';
1163 for (si = i; string[si] && string[si] != delimiter; si++);
1165 that = (char *)alloca (1 + l_that);
1166 strncpy (that, string + i, l_that);
1167 that[l_that] = '\0';
1170 if (string[si]) i++;
1172 /* Ignore impossible cases. */
1173 if (l_this > l_temp)
1174 goto cant_substitute;
1176 /* Find the first occurrence of THIS in TEMP. */
1178 for (; (si + l_this) <= l_temp; si++)
1179 if (strncmp (temp + si, this, l_this) == 0)
1182 (char *)alloca (1 + (l_that - l_this) + l_temp);
1183 strncpy (new_event, temp, si);
1184 strncpy (new_event + si, that, l_that);
1185 strncpy (new_event + si + l_that,
1187 l_temp - (si + l_this));
1188 new_event[(l_that - l_this) + l_temp] = '\0';
1191 if (substitute_globally)
1194 l_temp = strlen (temp);
1195 substitute_globally++;
1204 if (substitute_globally > 1)
1206 substitute_globally = 0;
1210 goto event_not_found;
1213 /* :# is the line so far. Note that we have to
1214 alloca () it since RESULT could be realloc ()'ed
1215 below in add_string. */
1220 temp = (char *)alloca (1 + strlen (result));
1221 strcpy (temp, result);
1232 /* Believe it or not, we have to back the pointer up by one. */
1236 /* A regular character. Just add it to the output string. */
1249 result = (char *)xrealloc (result, (len += 255));
1251 strcpy (result + (j - strlen (temp)), temp);
1259 add_history (result);
1263 return (modified != 0);
1266 /* Return a consed string which is the word specified in SPEC, and found
1267 in FROM. NULL is returned if there is no spec. -1 is returned if
1268 the word specified cannot be found. CALLER_INDEX is the offset in
1269 SPEC to start looking; it is updated to point to just after the last
1270 character parsed. */
1272 get_history_word_specifier (spec, from, caller_index)
1276 register int i = *caller_index;
1278 int expecting_word_spec = 0;
1279 char *history_arg_extract ();
1281 /* The range of words to return doesn't exist yet. */
1284 /* If we found a colon, then this *must* be a word specification. If
1285 it isn't, then it is an error. */
1287 i++, expecting_word_spec++;
1289 /* Handle special cases first. */
1291 /* `%' is the word last searched for. */
1294 *caller_index = i + 1;
1296 return (savestring (search_string));
1298 return (savestring (""));
1301 /* `*' matches all of the arguments, but not the command. */
1306 *caller_index = i + 1;
1307 star_result = history_arg_extract (1, '$', from);
1310 star_result = savestring ("");
1312 return (star_result);
1315 /* `$' is last arg. */
1318 *caller_index = i + 1;
1319 return (history_arg_extract ('$', '$', from));
1322 /* Try to get FIRST and LAST figured out. */
1323 if (spec[i] == '-' || spec[i] == '^')
1330 if (digit (spec[i]) && expecting_word_spec)
1332 sscanf (spec + i, "%d", &first);
1333 for (; digit (spec[i]); i++);
1336 return ((char *)NULL);
1354 if (digit (spec[i]))
1356 sscanf (spec + i, "%d", &last);
1357 for (; digit (spec[i]); i++);
1368 char *result = (char *)NULL;
1373 result = history_arg_extract (first, last, from);
1378 return ((char *)-1);
1382 /* Extract the args specified, starting at FIRST, and ending at LAST.
1383 The args are taken from STRING. If either FIRST or LAST is < 0,
1384 then make that arg count from the right (subtract from the number of
1385 tokens, so that FIRST = -1 means the next to last token on the line). */
1387 history_arg_extract (first, last, string)
1391 register int i, len;
1392 char *result = (char *)NULL;
1393 int size = 0, offset = 0;
1395 char **history_tokenize (), **list;
1397 if (!(list = history_tokenize (string)))
1398 return ((char *)NULL);
1400 for (len = 0; list[len]; len++);
1403 last = len + last - 1;
1406 first = len + first - 1;
1416 if (first > len || last > len || first < 0 || last < 0)
1417 result = ((char *)NULL);
1420 for (i = first; i < last; i++)
1422 int l = strlen (list[i]);
1425 result = (char *)xmalloc ((size = (2 + l)));
1427 result = (char *)xrealloc (result, (size += (2 + l)));
1428 strcpy (result + offset, list[i]);
1432 strcpy (result + offset, " ");
1438 for (i = 0; i < len; i++)
1446 #define slashify_in_quotes "\\`\"$"
1448 /* Return an array of tokens, much as the shell might. The tokens are
1449 parsed out of STRING. */
1451 history_tokenize (string)
1454 char **result = (char **)NULL;
1455 register int i, start, result_index, size;
1458 i = result_index = size = 0;
1460 /* Get a token, and stuff it into RESULT. The tokens are split
1461 exactly where the shell would split them. */
1464 /* Skip leading whitespace. */
1465 for (; string[i] && whitespace(string[i]); i++);
1469 if (!string[i] || string[i] == history_comment_char)
1472 if (member (string[i], "()\n")) {
1477 if (member (string[i], "<>;&|")) {
1478 int peek = string[i + 1];
1480 if (peek == string[i]) {
1482 if (string[1 + 2] == '-')
1488 if (member (peek, ">:&|")) {
1494 (string[i] == '>' || string[i] == '<')) ||
1496 (string[i] == '&'))) {
1505 /* Get word from string + i; */
1509 if (member (string[i], "\"'`"))
1510 delimiter = string[i++];
1512 for (;string[i]; i++) {
1514 if (string[i] == '\\') {
1516 if (string[i + 1] == '\n') {
1520 if (delimiter != '\'')
1521 if ((delimiter != '"') ||
1522 (member (string[i], slashify_in_quotes))) {
1529 if (delimiter && string[i] == delimiter) {
1534 if (!delimiter && (member (string[i], " \t\n;&()|<>")))
1537 if (!delimiter && member (string[i], "\"'`")) {
1538 delimiter = string[i];
1545 if (result_index + 2 >= size) {
1547 result = (char **)xmalloc ((size = 10) * (sizeof (char *)));
1550 (char **)xrealloc (result, ((size += 10) * (sizeof (char *))));
1552 result[result_index] = (char *)xmalloc (1 + len);
1553 strncpy (result[result_index], string + start, len);
1554 result[result_index][len] = '\0';
1556 result[result_index] = (char *)NULL;
1564 #if defined (STATIC_MALLOC)
1566 /* **************************************************************** */
1568 /* xmalloc and xrealloc () */
1570 /* **************************************************************** */
1572 static void memory_error_and_abort ();
1578 char *temp = (char *)malloc (bytes);
1581 memory_error_and_abort ();
1586 xrealloc (pointer, bytes)
1593 temp = (char *)xmalloc (bytes);
1595 temp = (char *)realloc (pointer, bytes);
1598 memory_error_and_abort ();
1604 memory_error_and_abort ()
1606 fprintf (stderr, "history: Out of virtual memory!\n");
1609 #endif /* STATIC_MALLOC */
1612 /* **************************************************************** */
1616 /* **************************************************************** */
1620 char line[1024], *t;
1627 fprintf (stdout, "history%% ");
1631 strcpy (line, "quit");
1640 result = history_expand (line, &expansion);
1641 strcpy (line, expansion);
1644 fprintf (stderr, "%s\n", line);
1652 if (strcmp (line, "quit") == 0) done = 1;
1653 if (strcmp (line, "save") == 0) write_history (0);
1654 if (strcmp (line, "read") == 0) read_history (0);
1655 if (strcmp (line, "list") == 0)
1657 register HIST_ENTRY **the_list = history_list ();
1661 for (i = 0; the_list[i]; i++)
1662 fprintf (stdout, "%d: %s\n", i + history_base, the_list[i]->line);
1664 if (strncmp (line, "delete", strlen ("delete")) == 0)
1667 if ((sscanf (line + strlen ("delete"), "%d", &which)) == 1)
1669 HIST_ENTRY *entry = remove_history (which);
1671 fprintf (stderr, "No such entry %d\n", which);
1680 fprintf (stderr, "non-numeric arg given to `delete'\n");
1690 * compile-command: "gcc -g -DTEST -o history history.c"