?? history.c
字號:
/* History.c -- standalone history library *//* Copyright (C) 1989, 1992 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. */#define READLINE_LIBRARY#if defined (HAVE_CONFIG_H)# include "config.h"#endif#include <stdio.h>#include <sys/types.h>#include <sys/file.h>#include <sys/stat.h>#include <fcntl.h>#if defined (HAVE_STDLIB_H)# include <stdlib.h>#else# include "ansi_stdlib.h"#endif /* HAVE_STDLIB_H */#if defined (HAVE_UNISTD_H)# include <unistd.h>#endif#if defined (HAVE_STRING_H)# include <string.h>#else# include <strings.h>#endif /* !HAVE_STRING_H */#include <errno.h>/* Not all systems declare ERRNO in errno.h... and some systems #define it! */#if !defined (errno)extern int errno;#endif /* !errno */#include "memalloc.h"#include "history.h"#if defined (STATIC_MALLOC)static char *xmalloc (), *xrealloc ();#elseextern char *xmalloc (), *xrealloc ();#endif /* STATIC_MALLOC */#define STREQ(a, b) (((a)[0] == (b)[0]) && (strcmp ((a), (b)) == 0))#define STREQN(a, b, n) (((a)[0] == (b)[0]) && (strncmp ((a), (b), (n)) == 0))#ifndef savestring# ifndef strcpyextern char *strcpy ();# endif#define savestring(x) strcpy (xmalloc (1 + strlen (x)), (x))#endif#ifndef whitespace#define whitespace(c) (((c) == ' ') || ((c) == '\t'))#endif#ifndef digit_p#define digit_p(c) ((c) >= '0' && (c) <= '9')#endif#ifndef digit_value#define digit_value(c) ((c) - '0')#endif#ifndef member# ifndef strchrextern char *strchr ();# endif#define member(c, s) ((c) ? ((char *)strchr ((s), (c)) != (char *)NULL) : 0)#endif/* Possible history errors passed to hist_error. */#define EVENT_NOT_FOUND 0#define BAD_WORD_SPEC 1#define SUBST_FAILED 2#define BAD_MODIFIER 3static char error_pointer;static char *subst_lhs;static char *subst_rhs;static int subst_lhs_len = 0;static int subst_rhs_len = 0;static char *get_history_word_specifier ();#if defined (SHELL)extern char *single_quote ();#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. */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. */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;/* Return the current HISTORY_STATE of the history. */HISTORY_STATE *history_get_history_state (){ HISTORY_STATE *state; state = (HISTORY_STATE *)xmalloc (sizeof (HISTORY_STATE)); state->entries = the_history; state->offset = history_offset; state->length = history_length; state->size = history_size; state->flags = 0; if (history_stifled) state->flags |= HS_STIFLED; return (state);}/* Set the state of the current history array to STATE. */voidhistory_set_history_state (state) HISTORY_STATE *state;{ the_history = state->entries; history_offset = state->offset; history_length = state->length; history_size = state->size; if (state->flags & HS_STIFLED) history_stifled = 1;}/* Begin a session in which the history functions might be used. This initializes interactive variables. */voidusing_history (){ history_offset = history_length;}/* Return the number of bytes that the primary history entries are using. This just adds up the lengths of the_history->lines. */inthistory_total_bytes (){ register int i, result; result = 0; for (i = 0; the_history && the_history[i]; i++) result += strlen (the_history[i]->line); return (result);}/* Place STRING at the end of the history list. The data field is set to NULL. */voidadd_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 == 0) return; /* If there is something in the slot, then remove it. */ if (the_history[0]) { free (the_history[0]->line); free (the_history[0]); } /* Copy the rest of the entries, moving down one slot. */ for (i = 0; i < history_length; i++) the_history[i] = the_history[i + 1]; history_base++; } else { if (!history_size) { history_size = DEFAULT_HISTORY_GROW_SIZE; the_history = (HIST_ENTRY **)xmalloc (history_size * sizeof (HIST_ENTRY *)); history_length = 1; } else { if (history_length == (history_size - 1)) { history_size += DEFAULT_HISTORY_GROW_SIZE; the_history = (HIST_ENTRY **) xrealloc (the_history, history_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. */intwhere_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 ANCHORED is non-zero, the string must appear at the beginning of a history line, otherwise, the string may appear anywhere in the line. 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. */#define ANCHORED_SEARCH 1#define NON_ANCHORED_SEARCH 0static inthistory_search_internal (string, direction, anchored) char *string; int direction, anchored;{ register int i, reverse; register char *line; register int line_index; int string_len; i = history_offset; reverse = (direction < 0); /* Take care of trivial cases first. */ if (!history_length || ((i == history_length) && !reverse)) return (-1); if (reverse && (i == history_length)) i--;#define NEXT_LINE() do { if (reverse) i--; else i++; } while (0) string_len = strlen (string); 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; line_index = strlen (line); /* If STRING is longer than line, no match. */ if (string_len > line_index) { NEXT_LINE (); continue; } /* Handle anchored searches first. */ if (anchored == ANCHORED_SEARCH) { if (STREQN (string, line, string_len)) { history_offset = i; return (0); } NEXT_LINE (); continue; } /* Do substring search. */ if (reverse) { line_index -= string_len; while (line_index >= 0) { if (STREQN (string, line + line_index, string_len)) { history_offset = i; return (line_index); } line_index--; } } else { register int limit = line_index - string_len + 1; line_index = 0; while (line_index < limit) { if (STREQN (string, line + line_index, string_len)) { history_offset = i; return (line_index); } line_index++; } } NEXT_LINE (); }}/* Do a non-anchored search for STRING through the history in DIRECTION. */inthistory_search (string, direction) char *string; int direction;{ return (history_search_internal (string, direction, NON_ANCHORED_SEARCH));}/* Do an anchored search for string through the history in DIRECTION. */inthistory_search_prefix (string, direction) char *string; int direction;{ return (history_search_internal (string, direction, ANCHORED_SEARCH));}/* 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. */voidstifle_history (max) int max;{ if (max < 0) max = 0; 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. */intunstifle_history (){ int result = max_input_history; if (history_stifled) { result = -result; history_stifled = 0; } return (result);}inthistory_is_stifled (){ return (history_stifled);}/* 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; int home_len; home = getenv ("HOME"); if (!home) home = "."; home_len = strlen (home); /* strlen(".history") == 8 */ return_val = xmalloc (2 + home_len + 8); strcpy (return_val, home); return_val[home_len] = '/'; strcpy (return_val + home_len + 1, ".history"); } return (return_val);}/* 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
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -