diff options
Diffstat (limited to 'gdb/readline/history.c')
-rw-r--r-- | gdb/readline/history.c | 1462 |
1 files changed, 0 insertions, 1462 deletions
diff --git a/gdb/readline/history.c b/gdb/readline/history.c deleted file mode 100644 index 7087718..0000000 --- a/gdb/readline/history.c +++ /dev/null @@ -1,1462 +0,0 @@ -/* History.c -- standalone history library */ - -/* Copyright (C) 1989 Free Software Foundation, Inc. - - This file contains the GNU History Library (the Library), a set of - routines for managing the text of previously typed lines. - - The Library is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 1, or (at your option) - any later version. - - The Library is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - The GNU General Public License is often shipped with GNU software, and - is generally kept in a file called COPYING or LICENSE. If you do not - have a copy of the license, write to the Free Software Foundation, - 675 Mass Ave, Cambridge, MA 02139, USA. */ - -/* The goal is to make the implementation transparent, so that you - don't have to know what data types are used, just what functions - you can call. I think I have done that. */ - -/* Remove these declarations when we have a complete libgnu.a. */ -#define STATIC_MALLOC -#ifndef STATIC_MALLOC -extern char *xmalloc (), *xrealloc (); -#else -static char *xmalloc (), *xrealloc (); -#endif - -#include <stdio.h> - -#ifdef __GNUC__ -#define alloca __builtin_alloca -#else -#if defined (sparc) && defined (sun) -#include <alloca.h> -#else -extern char *alloca (); -#endif -#endif - -#include "history.h" - -#ifndef savestring -#define savestring(x) (char *)strcpy (xmalloc (1 + strlen (x)), (x)) -#endif - -#ifndef whitespace -#define whitespace(c) (((c) == ' ') || ((c) == '\t')) -#endif - -#ifndef digit -#define digit(c) ((c) >= '0' && (c) <= '9') -#endif - -#ifndef member -#define member(c, s) ((c) ? index ((s), (c)) : 0) -#endif - -/* **************************************************************** */ -/* */ -/* History functions */ -/* */ -/* **************************************************************** */ - -/* An array of HIST_ENTRY. This is where we store the history. */ -static HIST_ENTRY **the_history = (HIST_ENTRY **)NULL; - -/* Non-zero means that we have enforced a limit on the amount of - history that we save. */ -static int history_stifled = 0; - -/* If HISTORY_STIFLED is non-zero, then this is the maximum number of - entries to remember. */ -static int max_input_history; - -/* The current location of the interactive history pointer. Just makes - life easier for outside callers. */ -static int history_offset = 0; - -/* The number of strings currently stored in the input_history list. */ -static int history_length = 0; - -/* The current number of slots allocated to the input_history. */ -static int history_size = 0; - -/* The number of slots to increase the_history by. */ -#define DEFAULT_HISTORY_GROW_SIZE 50 - -/* The character that represents the start of a history expansion - request. This is usually `!'. */ -char history_expansion_char = '!'; - -/* The character that invokes word substitution if found at the start of - a line. This is usually `^'. */ -char history_subst_char = '^'; - -/* During tokenization, if this character is seen as the first character - of a word, then it, and all subsequent characters upto a newline are - ignored. For a Bourne shell, this should be '#'. Bash special cases - the interactive comment character to not be a comment delimiter. */ -char history_comment_char = '\0'; - -/* The list of characters which inhibit the expansion of text if found - immediately following history_expansion_char. */ -char *history_no_expand_chars = " \t\n\r="; - -/* The logical `base' of the history array. It defaults to 1. */ -int history_base = 1; - -/* Begin a session in which the history functions might be used. This - initializes interactive variables. */ -void -using_history () -{ - history_offset = history_length; -} - -/* Place STRING at the end of the history list. The data field - is set to NULL. */ -void -add_history (string) - char *string; -{ - HIST_ENTRY *temp; - - if (history_stifled && (history_length == max_input_history)) { - register int i; - - /* If the history is stifled, and history_length is zero, - and it equals max_input_history, we don't save items. */ - if (!history_length) - return; - - /* If there is something in the slot, then remove it. */ - if (the_history[0]) { - free (the_history[0]->line); - free (the_history[0]); - } - - for (i = 0; i < history_length; i++) - the_history[i] = the_history[i + 1]; - - history_base++; - - } else { - - if (!history_size) { - the_history = - (HIST_ENTRY **)xmalloc ((history_size = DEFAULT_HISTORY_GROW_SIZE) - * sizeof (HIST_ENTRY *)); - history_length = 1; - - } else { - if (history_length == (history_size - 1)) { - the_history = - (HIST_ENTRY **)xrealloc (the_history, - ((history_size += DEFAULT_HISTORY_GROW_SIZE) - * sizeof (HIST_ENTRY *))); - } - history_length++; - } - } - - temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY)); - temp->line = savestring (string); - temp->data = (char *)NULL; - - the_history[history_length] = (HIST_ENTRY *)NULL; - the_history[history_length - 1] = temp; -} - -/* Make the history entry at WHICH have LINE and DATA. This returns - the old entry so you can dispose of the data. In the case of an - invalid WHICH, a NULL pointer is returned. */ -HIST_ENTRY * -replace_history_entry (which, line, data) - int which; - char *line; - char *data; -{ - HIST_ENTRY *temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY)); - HIST_ENTRY *old_value; - - if (which >= history_length) - return ((HIST_ENTRY *)NULL); - - old_value = the_history[which]; - - temp->line = savestring (line); - temp->data = data; - the_history[which] = temp; - - return (old_value); -} - -/* Returns the magic number which says what history element we are - looking at now. In this implementation, it returns history_offset. */ -int -where_history () -{ - return (history_offset); -} - -/* Search the history for STRING, starting at history_offset. - If DIRECTION < 0, then the search is through previous entries, - else through subsequent. If the string is found, then - current_history () is the history entry, and the value of this function - is the offset in the line of that history entry that the string was - found in. Otherwise, nothing is changed, and a -1 is returned. */ -int -history_search (string, direction) - char *string; - int direction; -{ - register int i = history_offset; - register int reverse = (direction < 0); - register char *line; - register int index; - int string_len = strlen (string); - - /* Take care of trivial cases first. */ - - if (!history_length || (i == history_length) && !reverse) - return (-1); - - if (reverse && (i == history_length)) - i--; - - while (1) - { - /* Search each line in the history list for STRING. */ - - /* At limit for direction? */ - if ((reverse && i < 0) || - (!reverse && i == history_length)) - return (-1); - - line = the_history[i]->line; - index = strlen (line); - - /* If STRING is longer than line, no match. */ - if (string_len > index) - goto next_line; - - /* Do the actual search. */ - if (reverse) - { - index -= string_len; - - while (index >= 0) - { - if (strncmp (string, line + index, string_len) == 0) - { - history_offset = i; - return (index); - } - index--; - } - } - else - { - register int limit = (string_len - index) + 1; - index = 0; - - while (index < limit) - { - if (strncmp (string, line + index, string_len) == 0) - { - history_offset = i; - return (index); - } - index++; - } - } - next_line: - if (reverse) - i--; - else - i++; - } -} - -/* Remove history element WHICH from the history. The removed - element is returned to you so you can free the line, data, - and containing structure. */ -HIST_ENTRY * -remove_history (which) - int which; -{ - HIST_ENTRY *return_value; - - if (which >= history_length || !history_length) - return_value = (HIST_ENTRY *)NULL; - else - { - register int i; - return_value = the_history[which]; - - for (i = which; i < history_length; i++) - the_history[i] = the_history[i + 1]; - - history_length--; - } - return (return_value); -} - -/* Stifle the history list, remembering only MAX number of lines. */ -void -stifle_history (max) - int max; -{ - if (history_length > max) - { - register int i, j; - - /* This loses because we cannot free the data. */ - for (i = 0; i < (history_length - max); i++) - { - free (the_history[i]->line); - free (the_history[i]); - } - history_base = i; - for (j = 0, i = history_length - max; j < max; i++, j++) - the_history[j] = the_history[i]; - the_history[j] = (HIST_ENTRY *)NULL; - history_length = j; - } - history_stifled = 1; - max_input_history = max; -} - -/* Stop stifling the history. This returns the previous amount the history - was stifled by. The value is positive if the history was stifled, negative - if it wasn't. */ -int -unstifle_history () -{ - int result = max_input_history; - if (history_stifled) - { - result = - result; - history_stifled = 0; - } - return (result); -} - -/* Return the string that should be used in the place of this - filename. This only matters when you don't specify the - filename to read_history (), or write_history (). */ -static char * -history_filename (filename) - char *filename; -{ - char *return_val = filename ? savestring (filename) : (char *)NULL; - - if (!return_val) - { - char *home = (char *)getenv ("HOME"); - if (!home) home = "."; - return_val = (char *)xmalloc (2 + strlen (home) + strlen (".history")); - strcpy (return_val, home); - strcat (return_val, "/"); - strcat (return_val, ".history"); - } - return (return_val); -} - -/* What to use until the line gets too big. */ -#define TYPICAL_LINE_SIZE 2048 - -/* Add the contents of FILENAME to the history list, a line at a time. - If FILENAME is NULL, then read from ~/.history. Returns 0 if - successful, or errno if not. */ -int -read_history (filename) - char *filename; -{ - char *input = history_filename (filename); - FILE *file = fopen (input, "r"); - char *line = (char *)xmalloc (TYPICAL_LINE_SIZE); - int line_size = TYPICAL_LINE_SIZE; - int done = 0; - - if (!file) - { - extern int errno; - free (line); - return (errno); - } - - while (!done) - { - int c; - int i; - - i = 0; - while (!(done = ((c = getc (file)) == EOF))) - { - if (c == '\n') - break; - - line [i++] = c; - if (i == line_size) - line = (char *)xrealloc (line, line_size += TYPICAL_LINE_SIZE); - } - line[i] = '\0'; - if (line[0]) - add_history (line); - } - free (line); - fclose (file); - return (0); -} - -/* Overwrite FILENAME with the current history. If FILENAME is NULL, - then write the history list to ~/.history. Values returned - are as in read_history ().*/ -int -write_history (filename) - char *filename; -{ - extern int errno; - char *output = history_filename (filename); - FILE *file = fopen (output, "w"); - register int i; - - if (!file) return (errno); - if (!history_length) return (0); - - for (i = 0; i < history_length; i++) - fprintf (file, "%s\n", the_history[i]->line); - - fclose (file); - return (0); -} - -/* Return the history entry at the current position, as determined by - history_offset. If there is no entry there, return a NULL pointer. */ -HIST_ENTRY * -current_history () -{ - if ((history_offset == history_length) || !the_history) - return ((HIST_ENTRY *)NULL); - else - return (the_history[history_offset]); -} - -/* Back up history_offset to the previous history entry, and return - a pointer to that entry. If there is no previous entry then return - a NULL pointer. */ -HIST_ENTRY * -previous_history () -{ - if (!history_offset) - return ((HIST_ENTRY *)NULL); - else - return (the_history[--history_offset]); -} - -/* Move history_offset forward to the next history entry, and return - a pointer to that entry. If there is no next entry then return a - NULL pointer. */ -HIST_ENTRY * -next_history () -{ - if (history_offset == history_length) - return ((HIST_ENTRY *)NULL); - else - return (the_history[++history_offset]); -} - -/* Return the current history array. The caller has to be carefull, since this - is the actual array of data, and could be bashed or made corrupt easily. - The array is terminated with a NULL pointer. */ -HIST_ENTRY ** -history_list () -{ - return (the_history); -} - -/* Return the history entry which is logically at OFFSET in the history array. - OFFSET is relative to history_base. */ -HIST_ENTRY * -history_get (offset) - int offset; -{ - int index = offset - history_base; - - if (index >= history_length || - index < 0 || - !the_history) - return ((HIST_ENTRY *)NULL); - return (the_history[index]); -} - -/* Search for STRING in the history list. DIR is < 0 for searching - backwards. POS is an absolute index into the history list at - which point to begin searching. */ -int -history_search_pos (string, dir, pos) - char *string; - int dir, pos; -{ - int ret, old = where_history (); - history_set_pos (pos); - if (history_search (string, dir) == -1) - { - history_set_pos (old); - return (-1); - } - ret = where_history (); - history_set_pos (old); - return ret; -} - -/* Make the current history item be the one at POS, an absolute index. - Returns zero if POS is out of range, else non-zero. */ -int -history_set_pos (pos) - int pos; -{ - if (pos > history_length || pos < 0 || !the_history) - return (0); - history_offset = pos; - return (1); -} - - -/* **************************************************************** */ -/* */ -/* History Expansion */ -/* */ -/* **************************************************************** */ - -/* Hairy history expansion on text, not tokens. This is of general - use, and thus belongs in this library. */ - -/* The last string searched for in a !?string? search. */ -static char *search_string = (char *)NULL; - -/* Return the event specified at TEXT + OFFSET modifying OFFSET to - point to after the event specifier. Just a pointer to the history - line is returned; NULL is returned in the event of a bad specifier. - You pass STRING with *INDEX equal to the history_expansion_char that - begins this specification. - DELIMITING_QUOTE is a character that is allowed to end the string - specification for what to search for in addition to the normal - characters `:', ` ', `\t', `\n', and sometimes `?'. - So you might call this function like: - line = get_history_event ("!echo:p", &index, 0); */ -char * -get_history_event (string, caller_index, delimiting_quote) - char *string; - int *caller_index; - int delimiting_quote; -{ - register int i = *caller_index; - int which, sign = 1; - HIST_ENTRY *entry; - - /* The event can be specified in a number of ways. - - !! the previous command - !n command line N - !-n current command-line minus N - !str the most recent command starting with STR - !?str[?] - the most recent command containing STR - - All values N are determined via HISTORY_BASE. */ - - if (string[i] != history_expansion_char) - return ((char *)NULL); - - /* Move on to the specification. */ - i++; - - /* Handle !! case. */ - if (string[i] == history_expansion_char) - { - i++; - which = history_base + (history_length - 1); - *caller_index = i; - goto get_which; - } - - /* Hack case of numeric line specification. */ - read_which: - if (string[i] == '-') - { - sign = -1; - i++; - } - - if (digit (string[i])) - { - int start = i; - - /* Get the extent of the digits. */ - for (; digit (string[i]); i++); - - /* Get the digit value. */ - sscanf (string + start, "%d", &which); - - *caller_index = i; - - if (sign < 0) - which = (history_length + history_base) - which; - - get_which: - if (entry = history_get (which)) - return (entry->line); - - return ((char *)NULL); - } - - /* This must be something to search for. If the spec begins with - a '?', then the string may be anywhere on the line. Otherwise, - the string must be found at the start of a line. */ - { - int index; - char *temp; - int substring_okay = 0; - - if (string[i] == '?') - { - substring_okay++; - i++; - } - - for (index = i; string[i]; i++) - if (whitespace (string[i]) || - string[i] == '\n' || - string[i] == ':' || - (substring_okay && string[i] == '?') || - string[i] == delimiting_quote) - break; - - temp = (char *)alloca (1 + (i - index)); - strncpy (temp, &string[index], (i - index)); - temp[i - index] = '\0'; - - if (string[i] == '?') - i++; - - *caller_index = i; - - search_again: - - index = history_search (temp, -1); - - if (index < 0) - search_lost: - { - history_offset = history_length; - return ((char *)NULL); - } - - if (index == 0 || substring_okay || - (strncmp (temp, the_history[history_offset]->line, - strlen (temp)) == 0)) - { - search_won: - entry = current_history (); - history_offset = history_length; - - /* If this was a substring search, then remember the string that - we matched for word substitution. */ - if (substring_okay) - { - if (search_string) - free (search_string); - search_string = savestring (temp); - } - - return (entry->line); - } - - if (history_offset) - history_offset--; - else - goto search_lost; - - goto search_again; - } -} - -/* Expand the string STRING, placing the result into OUTPUT, a pointer - to a string. Returns: - - 0) If no expansions took place (or, if the only change in - the text was the de-slashifying of the history expansion - character) - 1) If expansions did take place - -1) If there was an error in expansion. - - If an error ocurred in expansion, then OUTPUT contains a descriptive - error message. */ -int -history_expand (string, output) - char *string; - char **output; -{ - register int j, l = strlen (string); - int i, word_spec_error = 0; - int cc, modified = 0; - char *word_spec, *event; - int starting_index, only_printing = 0, substitute_globally = 0; - - char *get_history_word_specifier (), *rindex (); - - /* The output string, and its length. */ - int len = 0; - char *result = (char *)NULL; - - /* Used in add_string; */ - char *temp, tt[2], tbl[3]; - - /* Prepare the buffer for printing error messages. */ - result = (char *)xmalloc (len = 255); - - result[0] = tt[1] = tbl[2] = '\0'; - tbl[0] = '\\'; - tbl[1] = history_expansion_char; - - /* Grovel the string. Only backslash can quote the history escape - character. We also handle arg specifiers. */ - - /* Before we grovel forever, see if the history_expansion_char appears - anywhere within the text. */ - - /* The quick substitution character is a history expansion all right. That - is to say, "^this^that^" is equivalent to "!!:s^this^that^", and in fact, - that is the substitution that we do. */ - if (string[0] == history_subst_char) - { - char *format_string = (char *)alloca (10 + strlen (string)); - - sprintf (format_string, "%c%c:s%s", - history_expansion_char, history_expansion_char, - string); - string = format_string; - l += 4; - goto grovel; - } - - /* If not quick substitution, still maybe have to do expansion. */ - - /* `!' followed by one of the characters in history_no_expand_chars - is NOT an expansion. */ - for (i = 0; string[i]; i++) - if (string[i] == history_expansion_char) - if (!string[i + 1] || member (string[i + 1], history_no_expand_chars)) - continue; - else - goto grovel; - - free (result); - *output = savestring (string); - return (0); - - grovel: - - for (i = j = 0; i < l; i++) - { - int tchar = string[i]; - if (tchar == history_expansion_char) - tchar = -3; - - switch (tchar) - { - case '\\': - if (string[i + 1] == history_expansion_char) - { - i++; - temp = tbl; - goto do_add; - } - else - goto add_char; - - /* case history_expansion_char: */ - case -3: - starting_index = i + 1; - cc = string[i + 1]; - - /* If the history_expansion_char is followed by one of the - characters in history_no_expand_chars, then it is not a - candidate for expansion of any kind. */ - if (member (cc, history_no_expand_chars)) - goto add_char; - - /* There is something that is listed as a `word specifier' in csh - documentation which means `the expanded text to this point'. - That is not a word specifier, it is an event specifier. */ - - if (cc == '#') - goto hack_pound_sign; - - /* If it is followed by something that starts a word specifier, - then !! is implied as the event specifier. */ - - if (member (cc, ":$*%^")) - { - char fake_s[2]; - int fake_i = 0; - i++; - fake_s[0] = fake_s[1] = history_expansion_char; - fake_s[2] = '\0'; - event = get_history_event (fake_s, &fake_i); - } - else - { - int quoted_search_delimiter = 0; - - /* If the character before this `!' is a double or single - quote, then this expansion takes place inside of the - quoted string. If we have to search for some text ("!foo"), - allow the delimiter to end the search string. */ - if (i && (string[i - 1] == '\'' || string[i - 1] == '"')) - quoted_search_delimiter = string[i - 1]; - - event = get_history_event (string, &i, quoted_search_delimiter); - } - - if (!event) - event_not_found: - { - int l = 1 + (i - starting_index); - - temp = (char *)alloca (1 + l); - strncpy (temp, string + starting_index, l); - temp[l - 1] = 0; - sprintf (result, "%s: %s.", temp, - word_spec_error ? "Bad word specifier" : "Event not found"); - error_exit: - *output = result; - return (-1); - } - - /* If a word specifier is found, then do what that requires. */ - starting_index = i; - - word_spec = get_history_word_specifier (string, event, &i); - - /* There is no such thing as a `malformed word specifier'. However, - it is possible for a specifier that has no match. In that case, - we complain. */ - if (word_spec == (char *)-1) - bad_word_spec: - { - word_spec_error++; - goto event_not_found; - } - - /* If no word specifier, than the thing of interest was the event. */ - if (!word_spec) - temp = event; - else - { - temp = (char *)alloca (1 + strlen (word_spec)); - strcpy (temp, word_spec); - free (word_spec); - } - - /* Perhaps there are other modifiers involved. Do what they say. */ - - hack_specials: - - if (string[i] == ':') - { - char *tstr; - - switch (string[i + 1]) - { - /* :p means make this the last executed line. So we - return an error state after adding this line to the - history. */ - case 'p': - only_printing++; - goto next_special; - - /* :t discards all but the last part of the pathname. */ - case 't': - tstr = rindex (temp, '/'); - if (tstr) - temp = ++tstr; - goto next_special; - - /* :h discards the last part of a pathname. */ - case 'h': - tstr = rindex (temp, '/'); - if (tstr) - *tstr = '\0'; - goto next_special; - - /* :r discards the suffix. */ - case 'r': - tstr = rindex (temp, '.'); - if (tstr) - *tstr = '\0'; - goto next_special; - - /* :e discards everything but the suffix. */ - case 'e': - tstr = rindex (temp, '.'); - if (tstr) - temp = tstr; - goto next_special; - - /* :s/this/that substitutes `this' for `that'. */ - /* :gs/this/that substitutes `this' for `that' globally. */ - case 'g': - if (string[i + 2] == 's') - { - i++; - substitute_globally = 1; - goto substitute; - } - else - - case 's': - substitute: - { - char *this, *that, *new_event; - int delimiter = 0; - int si, l_this, l_that, l_temp = strlen (temp); - - if (i + 2 < strlen (string)) - delimiter = string[i + 2]; - - if (!delimiter) - break; - - i += 3; - - /* Get THIS. */ - for (si = i; string[si] && string[si] != delimiter; si++); - l_this = (si - i); - this = (char *)alloca (1 + l_this); - strncpy (this, string + i, l_this); - this[l_this] = '\0'; - - i = si; - if (string[si]) - i++; - - /* Get THAT. */ - for (si = i; string[si] && string[si] != delimiter; si++); - l_that = (si - i); - that = (char *)alloca (1 + l_that); - strncpy (that, string + i, l_that); - that[l_that] = '\0'; - - i = si; - if (string[si]) i++; - - /* Ignore impossible cases. */ - if (l_this > l_temp) - goto cant_substitute; - - /* Find the first occurrence of THIS in TEMP. */ - si = 0; - for (; (si + l_this) <= l_temp; si++) - if (strncmp (temp + si, this, l_this) == 0) - { - new_event = - (char *)alloca (1 + (l_that - l_this) + l_temp); - strncpy (new_event, temp, si); - strncpy (new_event + si, that, l_that); - strncpy (new_event + si + l_that, - temp + si + l_this, - l_temp - (si + l_this)); - new_event[(l_that - l_this) + l_temp] = '\0'; - temp = new_event; - - if (substitute_globally) - { - si += l_that; - l_temp = strlen (temp); - substitute_globally++; - continue; - } - - goto hack_specials; - } - - cant_substitute: - - if (substitute_globally > 1) - { - substitute_globally = 0; - goto hack_specials; - } - - goto event_not_found; - } - - /* :# is the line so far. Note that we have to - alloca () it since RESULT could be realloc ()'ed - below in add_string. */ - case '#': - hack_pound_sign: - if (result) - { - temp = (char *)alloca (1 + strlen (result)); - strcpy (temp, result); - } - else - temp = ""; - - next_special: - i += 2; - goto hack_specials; - } - - } - /* Believe it or not, we have to back the pointer up by one. */ - --i; - goto add_string; - - /* A regular character. Just add it to the output string. */ - default: - add_char: - tt[0] = string[i]; - temp = tt; - goto do_add; - - add_string: - modified++; - - do_add: - j += strlen (temp); - while (j > len) - result = (char *)xrealloc (result, (len += 255)); - - strcpy (result + (j - strlen (temp)), temp); - } - } - - *output = result; - - if (only_printing) - { - add_history (result); - return (-1); - } - - return (modified != 0); -} - -/* Return a consed string which is the word specified in SPEC, and found - in FROM. NULL is returned if there is no spec. -1 is returned if - the word specified cannot be found. CALLER_INDEX is the offset in - SPEC to start looking; it is updated to point to just after the last - character parsed. */ -char * -get_history_word_specifier (spec, from, caller_index) - char *spec, *from; - int *caller_index; -{ - register int i = *caller_index; - int first, last; - int expecting_word_spec = 0; - char *history_arg_extract (); - - /* The range of words to return doesn't exist yet. */ - first = last = 0; - - /* If we found a colon, then this *must* be a word specification. If - it isn't, then it is an error. */ - if (spec[i] == ':') - i++, expecting_word_spec++; - - /* Handle special cases first. */ - - /* `%' is the word last searched for. */ - if (spec[i] == '%') - { - *caller_index = i + 1; - if (search_string) - return (savestring (search_string)); - else - return (savestring ("")); - } - - /* `*' matches all of the arguments, but not the command. */ - if (spec[i] == '*') - { - *caller_index = i + 1; - return (history_arg_extract (1, '$', from)); - } - - /* `$' is last arg. */ - if (spec[i] == '$') - { - *caller_index = i + 1; - return (history_arg_extract ('$', '$', from)); - } - - /* Try to get FIRST and LAST figured out. */ - if (spec[i] == '-' || spec[i] == '^') - { - first = 1; - goto get_last; - } - - get_first: - if (digit (spec[i]) && expecting_word_spec) - { - sscanf (spec + i, "%d", &first); - for (; digit (spec[i]); i++); - } - else - return ((char *)NULL); - - get_last: - if (spec[i] == '^') - { - i++; - last = 1; - goto get_args; - } - - if (spec[i] != '-') - { - last = first; - goto get_args; - } - - i++; - - if (digit (spec[i])) - { - sscanf (spec + i, "%d", &last); - for (; digit (spec[i]); i++); - } - else - if (spec[i] == '$') - { - i++; - last = '$'; - } - - get_args: - { - char *result = (char *)NULL; - - *caller_index = i; - - if (last >= first) - result = history_arg_extract (first, last, from); - - if (result) - return (result); - else - return ((char *)-1); - } -} - -/* Extract the args specified, starting at FIRST, and ending at LAST. - The args are taken from STRING. */ -char * -history_arg_extract (first, last, string) - int first, last; - char *string; -{ - register int i, len; - char *result = (char *)NULL; - int size = 0, offset = 0; - - char **history_tokenize (), **list; - - if (!(list = history_tokenize (string))) - return ((char *)NULL); - - for (len = 0; list[len]; len++); - - if (last == '$') - last = len - 1; - - if (first == '$') - first = len - 1; - - last++; - - if (first > len || last > len) - result = ((char *)NULL); - else { - for (i = first; i < last; i++) - { - int l = strlen (list[i]); - - if (!result) - result = (char *)xmalloc ((size = (2 + l))); - else - result = (char *)xrealloc (result, (size += (2 + l))); - strcpy (result + offset, list[i]); - offset += l; - if (i + 1 < last) - { - strcpy (result + offset, " "); - offset++; - } - } - } - - for (i = 0; i < len; i++) - free (list[i]); - - free (list); - - return (result); -} - -#define slashify_in_quotes "\\`\"$" - -/* Return an array of tokens, much as the shell might. The tokens are - parsed out of STRING. */ -char ** -history_tokenize (string) - char *string; -{ - char **result = (char **)NULL; - register int i, start, result_index, size; - int len; - - i = result_index = size = 0; - - /* Get a token, and stuff it into RESULT. The tokens are split - exactly where the shell would split them. */ - get_token: - - /* Skip leading whitespace. */ - for (; string[i] && whitespace(string[i]); i++); - - start = i; - - if (!string[i] || string[i] == history_comment_char) - return (result); - - if (member (string[i], "()\n")) { - i++; - goto got_token; - } - - if (member (string[i], "<>;&|")) { - int peek = string[i + 1]; - - if (peek == string[i]) { - if (peek == '<') { - if (string[1 + 2] == '-') - i++; - i += 2; - goto got_token; - } - - if (member (peek, ">:&|")) { - i += 2; - goto got_token; - } - } else { - if ((peek == '&' && - (string[i] == '>' || string[i] == '<')) || - ((peek == '>') && - (string[i] == '&'))) { - i += 2; - goto got_token; - } - } - i++; - goto got_token; - } - - /* Get word from string + i; */ - { - int delimiter = 0; - - if (member (string[i], "\"'`")) - delimiter = string[i++]; - - for (;string[i]; i++) { - - if (string[i] == '\\') { - - if (string[i + 1] == '\n') { - i++; - continue; - } else { - if (delimiter != '\'') - if ((delimiter != '"') || - (member (string[i], slashify_in_quotes))) { - i++; - continue; - } - } - } - - if (delimiter && string[i] == delimiter) { - delimiter = 0; - continue; - } - - if (!delimiter && (member (string[i], " \t\n;&()|<>"))) - goto got_token; - - if (!delimiter && member (string[i], "\"'`")) { - delimiter = string[i]; - continue; - } - } - got_token: - - len = i - start; - if (result_index + 2 >= size) { - if (!size) - result = (char **)xmalloc ((size = 10) * (sizeof (char *))); - else - result = - (char **)xrealloc (result, ((size += 10) * (sizeof (char *)))); - } - result[result_index] = (char *)xmalloc (1 + len); - strncpy (result[result_index], string + start, len); - result[result_index][len] = '\0'; - result_index++; - result[result_index] = (char *)NULL; - } - if (string[i]) - goto get_token; - - return (result); -} - -#ifdef STATIC_MALLOC - -/* **************************************************************** */ -/* */ -/* xmalloc and xrealloc () */ -/* */ -/* **************************************************************** */ - -static char * -xmalloc (bytes) - int bytes; -{ - static memory_error_and_abort (); - char *temp = (char *)malloc (bytes); - - if (!temp) - memory_error_and_abort (); - return (temp); -} - -static char * -xrealloc (pointer, bytes) - char *pointer; - int bytes; -{ - static memory_error_and_abort (); - char *temp = (char *)realloc (pointer, bytes); - - if (!temp) - memory_error_and_abort (); - return (temp); -} - -static -memory_error_and_abort () -{ - fprintf (stderr, "history: Out of virtual memory!\n"); - abort (); -} -#endif /* STATIC_MALLOC */ - - -/* **************************************************************** */ -/* */ -/* Test Code */ -/* */ -/* **************************************************************** */ -#ifdef TEST -main () -{ - char line[1024], *t; - int done = 0; - - line[0] = 0; - - while (!done) - { - fprintf (stdout, "history%% "); - t = gets (line); - - if (!t) - strcpy (line, "quit"); - - if (line[0]) - { - char *expansion; - int result; - - using_history (); - - result = history_expand (line, &expansion); - strcpy (line, expansion); - free (expansion); - if (result) - fprintf (stderr, "%s\n", line); - - if (result < 0) - continue; - - add_history (line); - } - - if (strcmp (line, "quit") == 0) done = 1; - if (strcmp (line, "save") == 0) write_history (0); - if (strcmp (line, "read") == 0) read_history (0); - if (strcmp (line, "list") == 0) - { - register HIST_ENTRY **the_list = history_list (); - register int i; - - if (the_list) - for (i = 0; the_list[i]; i++) - fprintf (stdout, "%d: %s\n", i + history_base, the_list[i]->line); - } - if (strncmp (line, "delete", strlen ("delete")) == 0) - { - int which; - if ((sscanf (line + strlen ("delete"), "%d", &which)) == 1) - { - HIST_ENTRY *entry = remove_history (which); - if (!entry) - fprintf (stderr, "No such entry %d\n", which); - else - { - free (entry->line); - free (entry); - } - } - else - { - fprintf (stderr, "non-numeric arg given to `delete'\n"); - } - } - } -} - -#endif /* TEST */ - -/* -* Local variables: -* compile-command: "gcc -g -DTEST -o history history.c" -* end: -*/ |