1 /* History.c -- standalone history library */
3 /* Copyright (C) 1989 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 1, or (at your option)
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.
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. */
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. */
27 /* Remove these declarations when we have a complete libgnu.a. */
28 #if !defined (STATIC_MALLOC)
29 extern char *xmalloc (), *xrealloc ();
31 static char *xmalloc (), *xrealloc ();
36 #include <sys/types.h>
41 #if defined (__GNUC__)
42 # define alloca __builtin_alloca
44 # if defined (sparc) || defined (HAVE_ALLOCA_H)
46 # endif /* sparc || HAVE_ALLOCA_H */
47 #endif /* !__GNU_C__ */
52 #define savestring(x) (char *)strcpy (xmalloc (1 + strlen (x)), (x))
56 #define whitespace(c) (((c) == ' ') || ((c) == '\t'))
60 #define digit(c) ((c) >= '0' && (c) <= '9')
64 #define member(c, s) ((c) ? index ((s), (c)) : 0)
67 /* **************************************************************** */
69 /* History Functions */
71 /* **************************************************************** */
73 /* An array of HIST_ENTRY. This is where we store the history. */
74 static HIST_ENTRY
**the_history
= (HIST_ENTRY
**)NULL
;
76 /* Non-zero means that we have enforced a limit on the amount of
77 history that we save. */
78 int history_stifled
= 0;
80 /* If HISTORY_STIFLED is non-zero, then this is the maximum number of
81 entries to remember. */
82 int max_input_history
;
84 /* The current location of the interactive history pointer. Just makes
85 life easier for outside callers. */
86 static int history_offset
= 0;
88 /* The number of strings currently stored in the input_history list. */
89 int history_length
= 0;
91 /* The current number of slots allocated to the input_history. */
92 static int history_size
= 0;
94 /* The number of slots to increase the_history by. */
95 #define DEFAULT_HISTORY_GROW_SIZE 50
97 /* The character that represents the start of a history expansion
98 request. This is usually `!'. */
99 char history_expansion_char
= '!';
101 /* The character that invokes word substitution if found at the start of
102 a line. This is usually `^'. */
103 char history_subst_char
= '^';
105 /* During tokenization, if this character is seen as the first character
106 of a word, then it, and all subsequent characters upto a newline are
107 ignored. For a Bourne shell, this should be '#'. Bash special cases
108 the interactive comment character to not be a comment delimiter. */
109 char history_comment_char
= '\0';
111 /* The list of characters which inhibit the expansion of text if found
112 immediately following history_expansion_char. */
113 char *history_no_expand_chars
= " \t\n\r=";
115 /* The logical `base' of the history array. It defaults to 1. */
116 int history_base
= 1;
118 /* Begin a session in which the history functions might be used. This
119 initializes interactive variables. */
123 history_offset
= history_length
;
126 /* Return the number of bytes that the primary history entries are using.
127 This just adds up the lengths of the_history->lines. */
129 history_total_bytes ()
131 register int i
, result
;
135 for (i
= 0; the_history
&& the_history
[i
]; i
++)
136 result
+= strlen (the_history
[i
]->line
);
141 /* Place STRING at the end of the history list. The data field
149 if (history_stifled
&& (history_length
== max_input_history
))
153 /* If the history is stifled, and history_length is zero,
154 and it equals max_input_history, we don't save items. */
158 /* If there is something in the slot, then remove it. */
161 free (the_history
[0]->line
);
162 free (the_history
[0]);
165 for (i
= 0; i
< history_length
; i
++)
166 the_history
[i
] = the_history
[i
+ 1];
175 the_history
= (HIST_ENTRY
**)
176 xmalloc ((history_size
= DEFAULT_HISTORY_GROW_SIZE
)
177 * sizeof (HIST_ENTRY
*));
183 if (history_length
== (history_size
- 1))
185 the_history
= (HIST_ENTRY
**)
186 xrealloc (the_history
,
187 ((history_size
+= DEFAULT_HISTORY_GROW_SIZE
)
188 * sizeof (HIST_ENTRY
*)));
194 temp
= (HIST_ENTRY
*)xmalloc (sizeof (HIST_ENTRY
));
195 temp
->line
= savestring (string
);
196 temp
->data
= (char *)NULL
;
198 the_history
[history_length
] = (HIST_ENTRY
*)NULL
;
199 the_history
[history_length
- 1] = temp
;
202 /* Make the history entry at WHICH have LINE and DATA. This returns
203 the old entry so you can dispose of the data. In the case of an
204 invalid WHICH, a NULL pointer is returned. */
206 replace_history_entry (which
, line
, data
)
211 HIST_ENTRY
*temp
= (HIST_ENTRY
*)xmalloc (sizeof (HIST_ENTRY
));
212 HIST_ENTRY
*old_value
;
214 if (which
>= history_length
)
215 return ((HIST_ENTRY
*)NULL
);
217 old_value
= the_history
[which
];
219 temp
->line
= savestring (line
);
221 the_history
[which
] = temp
;
226 /* Returns the magic number which says what history element we are
227 looking at now. In this implementation, it returns history_offset. */
231 return (history_offset
);
234 /* Search the history for STRING, starting at history_offset.
235 If DIRECTION < 0, then the search is through previous entries, else
236 through subsequent. If ANCHORED is non-zero, the string must
237 appear at the beginning of a history line, otherwise, the string
238 may appear anywhere in the line. If the string is found, then
239 current_history () is the history entry, and the value of this
240 function is the offset in the line of that history entry that the
241 string was found in. Otherwise, nothing is changed, and a -1 is
244 #define ANCHORED_SEARCH 1
245 #define NON_ANCHORED_SEARCH 0
248 history_search_internal (string
, direction
, anchored
)
250 int direction
, anchored
;
252 register int i
= history_offset
;
253 register int reverse
= (direction
< 0);
256 int string_len
= strlen (string
);
258 /* Take care of trivial cases first. */
260 if (!history_length
|| ((i
== history_length
) && !reverse
))
263 if (reverse
&& (i
== history_length
))
268 /* Search each line in the history list for STRING. */
270 /* At limit for direction? */
271 if ((reverse
&& i
< 0) ||
272 (!reverse
&& i
== history_length
))
275 line
= the_history
[i
]->line
;
276 index
= strlen (line
);
278 /* If STRING is longer than line, no match. */
279 if (string_len
> index
)
282 /* Handle anchored searches first. */
283 if (anchored
== ANCHORED_SEARCH
)
285 if (strncmp (string
, line
, string_len
) == 0)
294 /* Do substring search. */
301 if (strncmp (string
, line
+ index
, string_len
) == 0)
311 register int limit
= index
- string_len
+ 1;
314 while (index
< limit
)
316 if (strncmp (string
, line
+ index
, string_len
) == 0)
332 /* Do a non-anchored search for STRING through the history in DIRECTION. */
334 history_search (string
, direction
)
338 return (history_search_internal (string
, direction
, NON_ANCHORED_SEARCH
));
341 /* Do an anchored search for string through the history in DIRECTION. */
343 history_search_prefix (string
, direction
)
347 return (history_search_internal (string
, direction
, ANCHORED_SEARCH
));
350 /* Remove history element WHICH from the history. The removed
351 element is returned to you so you can free the line, data,
352 and containing structure. */
354 remove_history (which
)
357 HIST_ENTRY
*return_value
;
359 if (which
>= history_length
|| !history_length
)
360 return_value
= (HIST_ENTRY
*)NULL
;
364 return_value
= the_history
[which
];
366 for (i
= which
; i
< history_length
; i
++)
367 the_history
[i
] = the_history
[i
+ 1];
372 return (return_value
);
375 /* Stifle the history list, remembering only MAX number of lines. */
380 if (history_length
> max
)
384 /* This loses because we cannot free the data. */
385 for (i
= 0; i
< (history_length
- max
); i
++)
387 free (the_history
[i
]->line
);
388 free (the_history
[i
]);
391 for (j
= 0, i
= history_length
- max
; j
< max
; i
++, j
++)
392 the_history
[j
] = the_history
[i
];
393 the_history
[j
] = (HIST_ENTRY
*)NULL
;
397 max_input_history
= max
;
400 /* Stop stifling the history. This returns the previous amount the history
401 was stifled by. The value is positive if the history was stifled, negative
406 int result
= max_input_history
;
415 /* Return the string that should be used in the place of this
416 filename. This only matters when you don't specify the
417 filename to read_history (), or write_history (). */
419 history_filename (filename
)
422 char *return_val
= filename
? savestring (filename
) : (char *)NULL
;
426 char *home
= (char *)getenv ("HOME");
427 if (!home
) home
= ".";
428 return_val
= (char *)xmalloc (2 + strlen (home
) + strlen (".history"));
429 sprintf (return_val
, "%s/.history", home
);
434 /* Add the contents of FILENAME to the history list, a line at a time.
435 If FILENAME is NULL, then read from ~/.history. Returns 0 if
436 successful, or errno if not. */
438 read_history (filename
)
441 return (read_history_range (filename
, 0, -1));
444 /* Read a range of lines from FILENAME, adding them to the history list.
445 Start reading at the FROM'th line and end at the TO'th. If FROM
446 is zero, start at the beginning. If TO is less than FROM, read
447 until the end of the file. If FILENAME is NULL, then read from
448 ~/.history. Returns 0 if successful, or errno if not. */
450 read_history_range (filename
, from
, to
)
454 register int line_start
, line_end
;
455 char *input
, *buffer
= (char *)NULL
;
456 int file
, current_line
;
460 input
= history_filename (filename
);
461 file
= open (input
, O_RDONLY
, 0666);
464 (stat (input
, &finfo
) == -1))
467 buffer
= (char *)xmalloc (finfo
.st_size
+ 1);
469 if (read (file
, buffer
, finfo
.st_size
) != finfo
.st_size
)
483 /* Set TO to larger than end of file if negative. */
487 /* Start at beginning of file, work to end. */
488 line_start
= line_end
= current_line
= 0;
490 /* Skip lines until we are at FROM. */
491 while (line_start
< finfo
.st_size
&& current_line
< from
)
493 for (line_end
= line_start
; line_end
< finfo
.st_size
; line_end
++)
494 if (buffer
[line_end
] == '\n')
497 line_start
= line_end
+ 1;
498 if (current_line
== from
)
503 /* If there are lines left to gobble, then gobble them now. */
504 for (line_end
= line_start
; line_end
< finfo
.st_size
; line_end
++)
505 if (buffer
[line_end
] == '\n')
507 buffer
[line_end
] = '\0';
509 if (buffer
[line_start
])
510 add_history (buffer
+ line_start
);
514 if (current_line
>= to
)
517 line_start
= line_end
+ 1;
522 /* Truncate the history file FNAME, leaving only LINES trailing lines.
523 If FNAME is NULL, then use ~/.history. */
524 history_truncate_file (fname
, lines
)
530 char *buffer
= (char *)NULL
, *filename
;
533 filename
= history_filename (fname
);
534 if (stat (filename
, &finfo
) == -1)
537 file
= open (filename
, O_RDONLY
, 0666);
542 buffer
= (char *)xmalloc (finfo
.st_size
+ 1);
543 read (file
, buffer
, finfo
.st_size
);
546 /* Count backwards from the end of buffer until we have passed
548 for (i
= finfo
.st_size
; lines
&& i
; i
--)
550 if (buffer
[i
] == '\n')
554 /* If there are fewer lines in the file than we want to truncate to,
555 then we are all done. */
559 /* Otherwise, write from the start of this line until the end of the
562 if (buffer
[i
] == '\n')
568 file
= open (filename
, O_WRONLY
| O_TRUNC
| O_CREAT
, 0666);
572 write (file
, buffer
+ i
, finfo
.st_size
- i
);
582 #define HISTORY_APPEND 0
583 #define HISTORY_OVERWRITE 1
585 /* Workhorse function for writing history. Writes NELEMENT entries
586 from the history list to FILENAME. OVERWRITE is non-zero if you
587 wish to replace FILENAME with the entries. */
589 history_do_write (filename
, nelements
, overwrite
)
591 int nelements
, overwrite
;
595 char *output
= history_filename (filename
);
600 mode
= O_WRONLY
| O_CREAT
| O_TRUNC
;
602 mode
= O_WRONLY
| O_APPEND
;
604 if ((file
= open (output
, mode
, 0666)) == -1)
607 if (nelements
> history_length
)
608 nelements
= history_length
;
610 for (i
= history_length
- nelements
; i
< history_length
; i
++)
612 if (write (file
, the_history
[i
]->line
, strlen (the_history
[i
]->line
)) < 0)
614 if (write (file
, &cr
, 1) < 0)
622 /* Append NELEMENT entries to FILENAME. The entries appended are from
623 the end of the list minus NELEMENTs up to the end of the list. */
625 append_history (nelements
, filename
)
629 return (history_do_write (filename
, nelements
, HISTORY_APPEND
));
632 /* Overwrite FILENAME with the current history. If FILENAME is NULL,
633 then write the history list to ~/.history. Values returned
634 are as in read_history ().*/
636 write_history (filename
)
639 return (history_do_write (filename
, history_length
, HISTORY_OVERWRITE
));
642 /* Return the history entry at the current position, as determined by
643 history_offset. If there is no entry there, return a NULL pointer. */
647 if ((history_offset
== history_length
) || !the_history
)
648 return ((HIST_ENTRY
*)NULL
);
650 return (the_history
[history_offset
]);
653 /* Back up history_offset to the previous history entry, and return
654 a pointer to that entry. If there is no previous entry then return
660 return ((HIST_ENTRY
*)NULL
);
662 return (the_history
[--history_offset
]);
665 /* Move history_offset forward to the next history entry, and return
666 a pointer to that entry. If there is no next entry then return a
671 if (history_offset
== history_length
)
672 return ((HIST_ENTRY
*)NULL
);
674 return (the_history
[++history_offset
]);
677 /* Return the current history array. The caller has to be carefull, since this
678 is the actual array of data, and could be bashed or made corrupt easily.
679 The array is terminated with a NULL pointer. */
683 return (the_history
);
686 /* Return the history entry which is logically at OFFSET in the history array.
687 OFFSET is relative to history_base. */
692 int index
= offset
- history_base
;
694 if (index
>= history_length
||
697 return ((HIST_ENTRY
*)NULL
);
698 return (the_history
[index
]);
701 /* Search for STRING in the history list. DIR is < 0 for searching
702 backwards. POS is an absolute index into the history list at
703 which point to begin searching. */
705 history_search_pos (string
, dir
, pos
)
709 int ret
, old
= where_history ();
710 history_set_pos (pos
);
711 if (history_search (string
, dir
) == -1)
713 history_set_pos (old
);
716 ret
= where_history ();
717 history_set_pos (old
);
721 /* Make the current history item be the one at POS, an absolute index.
722 Returns zero if POS is out of range, else non-zero. */
724 history_set_pos (pos
)
727 if (pos
> history_length
|| pos
< 0 || !the_history
)
729 history_offset
= pos
;
734 /* **************************************************************** */
736 /* History Expansion */
738 /* **************************************************************** */
740 /* Hairy history expansion on text, not tokens. This is of general
741 use, and thus belongs in this library. */
743 /* The last string searched for in a !?string? search. */
744 static char *search_string
= (char *)NULL
;
746 /* Return the event specified at TEXT + OFFSET modifying OFFSET to
747 point to after the event specifier. Just a pointer to the history
748 line is returned; NULL is returned in the event of a bad specifier.
749 You pass STRING with *INDEX equal to the history_expansion_char that
750 begins this specification.
751 DELIMITING_QUOTE is a character that is allowed to end the string
752 specification for what to search for in addition to the normal
753 characters `:', ` ', `\t', `\n', and sometimes `?'.
754 So you might call this function like:
755 line = get_history_event ("!echo:p", &index, 0); */
757 get_history_event (string
, caller_index
, delimiting_quote
)
760 int delimiting_quote
;
762 register int i
= *caller_index
;
766 /* The event can be specified in a number of ways.
768 !! the previous command
770 !-n current command-line minus N
771 !str the most recent command starting with STR
773 the most recent command containing STR
775 All values N are determined via HISTORY_BASE. */
777 if (string
[i
] != history_expansion_char
)
778 return ((char *)NULL
);
780 /* Move on to the specification. */
783 /* Handle !! case. */
784 if (string
[i
] == history_expansion_char
)
787 which
= history_base
+ (history_length
- 1);
792 /* Hack case of numeric line specification. */
794 if (string
[i
] == '-')
800 if (digit (string
[i
]))
804 /* Get the extent of the digits. */
805 for (; digit (string
[i
]); i
++);
807 /* Get the digit value. */
808 sscanf (string
+ start
, "%d", &which
);
813 which
= (history_length
+ history_base
) - which
;
816 if (entry
= history_get (which
))
817 return (entry
->line
);
819 return ((char *)NULL
);
822 /* This must be something to search for. If the spec begins with
823 a '?', then the string may be anywhere on the line. Otherwise,
824 the string must be found at the start of a line. */
828 int substring_okay
= 0;
830 if (string
[i
] == '?')
836 for (index
= i
; string
[i
]; i
++)
837 if (whitespace (string
[i
]) ||
840 (substring_okay
&& string
[i
] == '?') ||
841 string
[i
] == delimiting_quote
)
844 temp
= (char *)alloca (1 + (i
- index
));
845 strncpy (temp
, &string
[index
], (i
- index
));
846 temp
[i
- index
] = '\0';
848 if (string
[i
] == '?')
855 index
= history_search_internal
856 (temp
, -1, substring_okay
? NON_ANCHORED_SEARCH
: ANCHORED_SEARCH
);
861 history_offset
= history_length
;
862 return ((char *)NULL
);
868 entry
= current_history ();
869 history_offset
= history_length
;
871 /* If this was a substring search, then remember the string that
872 we matched for word substitution. */
876 free (search_string
);
877 search_string
= savestring (temp
);
880 return (entry
->line
);
892 /* Expand the string STRING, placing the result into OUTPUT, a pointer
893 to a string. Returns:
895 0) If no expansions took place (or, if the only change in
896 the text was the de-slashifying of the history expansion
898 1) If expansions did take place
899 -1) If there was an error in expansion.
901 If an error ocurred in expansion, then OUTPUT contains a descriptive
904 history_expand (string
, output
)
908 register int j
, l
= strlen (string
);
909 int i
, word_spec_error
= 0;
910 int cc
, modified
= 0;
911 char *word_spec
, *event
;
912 int starting_index
, only_printing
= 0, substitute_globally
= 0;
914 char *get_history_word_specifier (), *rindex ();
916 /* The output string, and its length. */
918 char *result
= (char *)NULL
;
920 /* Used in add_string; */
921 char *temp
, tt
[2], tbl
[3];
923 /* Prepare the buffer for printing error messages. */
924 result
= (char *)xmalloc (len
= 255);
926 result
[0] = tt
[1] = tbl
[2] = '\0';
928 tbl
[1] = history_expansion_char
;
930 /* Grovel the string. Only backslash can quote the history escape
931 character. We also handle arg specifiers. */
933 /* Before we grovel forever, see if the history_expansion_char appears
934 anywhere within the text. */
936 /* The quick substitution character is a history expansion all right. That
937 is to say, "^this^that^" is equivalent to "!!:s^this^that^", and in fact,
938 that is the substitution that we do. */
939 if (string
[0] == history_subst_char
)
941 char *format_string
= (char *)alloca (10 + strlen (string
));
943 sprintf (format_string
, "%c%c:s%s",
944 history_expansion_char
, history_expansion_char
,
946 string
= format_string
;
951 /* If not quick substitution, still maybe have to do expansion. */
953 /* `!' followed by one of the characters in history_no_expand_chars
954 is NOT an expansion. */
955 for (i
= 0; string
[i
]; i
++)
956 if (string
[i
] == history_expansion_char
)
957 if (!string
[i
+ 1] || member (string
[i
+ 1], history_no_expand_chars
))
963 *output
= savestring (string
);
968 for (i
= j
= 0; i
< l
; i
++)
970 int tchar
= string
[i
];
971 if (tchar
== history_expansion_char
)
977 if (string
[i
+ 1] == history_expansion_char
)
986 /* case history_expansion_char: */
988 starting_index
= i
+ 1;
991 /* If the history_expansion_char is followed by one of the
992 characters in history_no_expand_chars, then it is not a
993 candidate for expansion of any kind. */
994 if (member (cc
, history_no_expand_chars
))
997 /* There is something that is listed as a `word specifier' in csh
998 documentation which means `the expanded text to this point'.
999 That is not a word specifier, it is an event specifier. */
1002 goto hack_pound_sign
;
1004 /* If it is followed by something that starts a word specifier,
1005 then !! is implied as the event specifier. */
1007 if (member (cc
, ":$*%^"))
1012 fake_s
[0] = fake_s
[1] = history_expansion_char
;
1014 event
= get_history_event (fake_s
, &fake_i
, 0);
1018 int quoted_search_delimiter
= 0;
1020 /* If the character before this `!' is a double or single
1021 quote, then this expansion takes place inside of the
1022 quoted string. If we have to search for some text ("!foo"),
1023 allow the delimiter to end the search string. */
1024 if (i
&& (string
[i
- 1] == '\'' || string
[i
- 1] == '"'))
1025 quoted_search_delimiter
= string
[i
- 1];
1027 event
= get_history_event (string
, &i
, quoted_search_delimiter
);
1033 int l
= 1 + (i
- starting_index
);
1035 temp
= (char *)alloca (1 + l
);
1036 strncpy (temp
, string
+ starting_index
, l
);
1038 sprintf (result
, "%s: %s.", temp
,
1039 word_spec_error
? "Bad word specifier" : "Event not found");
1045 /* If a word specifier is found, then do what that requires. */
1048 word_spec
= get_history_word_specifier (string
, event
, &i
);
1050 /* There is no such thing as a `malformed word specifier'. However,
1051 it is possible for a specifier that has no match. In that case,
1053 if (word_spec
== (char *)-1)
1057 goto event_not_found
;
1060 /* If no word specifier, than the thing of interest was the event. */
1065 temp
= (char *)alloca (1 + strlen (word_spec
));
1066 strcpy (temp
, word_spec
);
1070 /* Perhaps there are other modifiers involved. Do what they say. */
1074 if (string
[i
] == ':')
1078 switch (string
[i
+ 1])
1080 /* :p means make this the last executed line. So we
1081 return an error state after adding this line to the
1087 /* :t discards all but the last part of the pathname. */
1089 tstr
= rindex (temp
, '/');
1094 /* :h discards the last part of a pathname. */
1096 tstr
= rindex (temp
, '/');
1101 /* :r discards the suffix. */
1103 tstr
= rindex (temp
, '.');
1108 /* :e discards everything but the suffix. */
1110 tstr
= rindex (temp
, '.');
1115 /* :s/this/that substitutes `this' for `that'. */
1116 /* :gs/this/that substitutes `this' for `that' globally. */
1118 if (string
[i
+ 2] == 's')
1121 substitute_globally
= 1;
1129 char *this, *that
, *new_event
;
1131 int si
, l_this
, l_that
, l_temp
= strlen (temp
);
1133 if (i
+ 2 < strlen (string
))
1134 delimiter
= string
[i
+ 2];
1142 for (si
= i
; string
[si
] && string
[si
] != delimiter
; si
++);
1144 this = (char *)alloca (1 + l_this
);
1145 strncpy (this, string
+ i
, l_this
);
1146 this[l_this
] = '\0';
1153 for (si
= i
; string
[si
] && string
[si
] != delimiter
; si
++);
1155 that
= (char *)alloca (1 + l_that
);
1156 strncpy (that
, string
+ i
, l_that
);
1157 that
[l_that
] = '\0';
1160 if (string
[si
]) i
++;
1162 /* Ignore impossible cases. */
1163 if (l_this
> l_temp
)
1164 goto cant_substitute
;
1166 /* Find the first occurrence of THIS in TEMP. */
1168 for (; (si
+ l_this
) <= l_temp
; si
++)
1169 if (strncmp (temp
+ si
, this, l_this
) == 0)
1172 (char *)alloca (1 + (l_that
- l_this
) + l_temp
);
1173 strncpy (new_event
, temp
, si
);
1174 strncpy (new_event
+ si
, that
, l_that
);
1175 strncpy (new_event
+ si
+ l_that
,
1177 l_temp
- (si
+ l_this
));
1178 new_event
[(l_that
- l_this
) + l_temp
] = '\0';
1181 if (substitute_globally
)
1184 l_temp
= strlen (temp
);
1185 substitute_globally
++;
1194 if (substitute_globally
> 1)
1196 substitute_globally
= 0;
1200 goto event_not_found
;
1203 /* :# is the line so far. Note that we have to
1204 alloca () it since RESULT could be realloc ()'ed
1205 below in add_string. */
1210 temp
= (char *)alloca (1 + strlen (result
));
1211 strcpy (temp
, result
);
1222 /* Believe it or not, we have to back the pointer up by one. */
1226 /* A regular character. Just add it to the output string. */
1239 result
= (char *)xrealloc (result
, (len
+= 255));
1241 strcpy (result
+ (j
- strlen (temp
)), temp
);
1249 add_history (result
);
1253 return (modified
!= 0);
1256 /* Return a consed string which is the word specified in SPEC, and found
1257 in FROM. NULL is returned if there is no spec. -1 is returned if
1258 the word specified cannot be found. CALLER_INDEX is the offset in
1259 SPEC to start looking; it is updated to point to just after the last
1260 character parsed. */
1262 get_history_word_specifier (spec
, from
, caller_index
)
1266 register int i
= *caller_index
;
1268 int expecting_word_spec
= 0;
1269 char *history_arg_extract ();
1271 /* The range of words to return doesn't exist yet. */
1274 /* If we found a colon, then this *must* be a word specification. If
1275 it isn't, then it is an error. */
1277 i
++, expecting_word_spec
++;
1279 /* Handle special cases first. */
1281 /* `%' is the word last searched for. */
1284 *caller_index
= i
+ 1;
1286 return (savestring (search_string
));
1288 return (savestring (""));
1291 /* `*' matches all of the arguments, but not the command. */
1296 *caller_index
= i
+ 1;
1297 star_result
= history_arg_extract (1, '$', from
);
1300 star_result
= savestring ("");
1302 return (star_result
);
1305 /* `$' is last arg. */
1308 *caller_index
= i
+ 1;
1309 return (history_arg_extract ('$', '$', from
));
1312 /* Try to get FIRST and LAST figured out. */
1313 if (spec
[i
] == '-' || spec
[i
] == '^')
1320 if (digit (spec
[i
]) && expecting_word_spec
)
1322 sscanf (spec
+ i
, "%d", &first
);
1323 for (; digit (spec
[i
]); i
++);
1326 return ((char *)NULL
);
1344 if (digit (spec
[i
]))
1346 sscanf (spec
+ i
, "%d", &last
);
1347 for (; digit (spec
[i
]); i
++);
1358 char *result
= (char *)NULL
;
1363 result
= history_arg_extract (first
, last
, from
);
1368 return ((char *)-1);
1372 /* Extract the args specified, starting at FIRST, and ending at LAST.
1373 The args are taken from STRING. If either FIRST or LAST is < 0,
1374 then make that arg count from the right (subtract from the number of
1375 tokens, so that FIRST = -1 means the next to last token on the line). */
1377 history_arg_extract (first
, last
, string
)
1381 register int i
, len
;
1382 char *result
= (char *)NULL
;
1383 int size
= 0, offset
= 0;
1385 char **history_tokenize (), **list
;
1387 if (!(list
= history_tokenize (string
)))
1388 return ((char *)NULL
);
1390 for (len
= 0; list
[len
]; len
++);
1393 last
= len
+ last
- 1;
1396 first
= len
+ first
- 1;
1406 if (first
> len
|| last
> len
|| first
< 0 || last
< 0)
1407 result
= ((char *)NULL
);
1410 for (i
= first
; i
< last
; i
++)
1412 int l
= strlen (list
[i
]);
1415 result
= (char *)xmalloc ((size
= (2 + l
)));
1417 result
= (char *)xrealloc (result
, (size
+= (2 + l
)));
1418 strcpy (result
+ offset
, list
[i
]);
1422 strcpy (result
+ offset
, " ");
1428 for (i
= 0; i
< len
; i
++)
1436 #define slashify_in_quotes "\\`\"$"
1438 /* Return an array of tokens, much as the shell might. The tokens are
1439 parsed out of STRING. */
1441 history_tokenize (string
)
1444 char **result
= (char **)NULL
;
1445 register int i
, start
, result_index
, size
;
1448 i
= result_index
= size
= 0;
1450 /* Get a token, and stuff it into RESULT. The tokens are split
1451 exactly where the shell would split them. */
1454 /* Skip leading whitespace. */
1455 for (; string
[i
] && whitespace(string
[i
]); i
++);
1459 if (!string
[i
] || string
[i
] == history_comment_char
)
1462 if (member (string
[i
], "()\n")) {
1467 if (member (string
[i
], "<>;&|")) {
1468 int peek
= string
[i
+ 1];
1470 if (peek
== string
[i
]) {
1472 if (string
[1 + 2] == '-')
1478 if (member (peek
, ">:&|")) {
1484 (string
[i
] == '>' || string
[i
] == '<')) ||
1486 (string
[i
] == '&'))) {
1495 /* Get word from string + i; */
1499 if (member (string
[i
], "\"'`"))
1500 delimiter
= string
[i
++];
1502 for (;string
[i
]; i
++) {
1504 if (string
[i
] == '\\') {
1506 if (string
[i
+ 1] == '\n') {
1510 if (delimiter
!= '\'')
1511 if ((delimiter
!= '"') ||
1512 (member (string
[i
], slashify_in_quotes
))) {
1519 if (delimiter
&& string
[i
] == delimiter
) {
1524 if (!delimiter
&& (member (string
[i
], " \t\n;&()|<>")))
1527 if (!delimiter
&& member (string
[i
], "\"'`")) {
1528 delimiter
= string
[i
];
1535 if (result_index
+ 2 >= size
) {
1537 result
= (char **)xmalloc ((size
= 10) * (sizeof (char *)));
1540 (char **)xrealloc (result
, ((size
+= 10) * (sizeof (char *))));
1542 result
[result_index
] = (char *)xmalloc (1 + len
);
1543 strncpy (result
[result_index
], string
+ start
, len
);
1544 result
[result_index
][len
] = '\0';
1546 result
[result_index
] = (char *)NULL
;
1554 #if defined (STATIC_MALLOC)
1556 /* **************************************************************** */
1558 /* xmalloc and xrealloc () */
1560 /* **************************************************************** */
1562 static void memory_error_and_abort ();
1568 char *temp
= (char *)malloc (bytes
);
1571 memory_error_and_abort ();
1576 xrealloc (pointer
, bytes
)
1583 temp
= (char *)xmalloc (bytes
);
1585 temp
= (char *)realloc (pointer
, bytes
);
1588 memory_error_and_abort ();
1594 memory_error_and_abort ()
1596 fprintf (stderr
, "history: Out of virtual memory!\n");
1599 #endif /* STATIC_MALLOC */
1602 /* **************************************************************** */
1606 /* **************************************************************** */
1610 char line
[1024], *t
;
1617 fprintf (stdout
, "history%% ");
1621 strcpy (line
, "quit");
1630 result
= history_expand (line
, &expansion
);
1631 strcpy (line
, expansion
);
1634 fprintf (stderr
, "%s\n", line
);
1642 if (strcmp (line
, "quit") == 0) done
= 1;
1643 if (strcmp (line
, "save") == 0) write_history (0);
1644 if (strcmp (line
, "read") == 0) read_history (0);
1645 if (strcmp (line
, "list") == 0)
1647 register HIST_ENTRY
**the_list
= history_list ();
1651 for (i
= 0; the_list
[i
]; i
++)
1652 fprintf (stdout
, "%d: %s\n", i
+ history_base
, the_list
[i
]->line
);
1654 if (strncmp (line
, "delete", strlen ("delete")) == 0)
1657 if ((sscanf (line
+ strlen ("delete"), "%d", &which
)) == 1)
1659 HIST_ENTRY
*entry
= remove_history (which
);
1661 fprintf (stderr
, "No such entry %d\n", which
);
1670 fprintf (stderr
, "non-numeric arg given to `delete'\n");
1680 * compile-command: "gcc -g -DTEST -o history history.c"