📄 bashhist.c
字号:
/* Return 1 if this line needs history expansion. */static inthistory_expansion_p (line) char *line;{ register char *s; for (s = line; *s; s++) if (*s == history_expansion_char || *s == history_subst_char) return 1; return 0;}/* Do pre-processing on LINE. If PRINT_CHANGES is non-zero, then print the results of expanding the line if there were any changes. If there is an error, return NULL, otherwise the expanded line is returned. If ADDIT is non-zero the line is added to the history list after history expansion. ADDIT is just a suggestion; REMEMBER_ON_HISTORY can veto, and does. Right now this does history expansion. */char *pre_process_line (line, print_changes, addit) char *line; int print_changes, addit;{ char *history_value; char *return_value; int expanded; return_value = line; expanded = 0;# if defined (BANG_HISTORY) /* History expand the line. If this results in no errors, then add that line to the history if ADDIT is non-zero. */ if (!history_expansion_inhibited && history_expansion && history_expansion_p (line)) { expanded = history_expand (line, &history_value); if (expanded) { if (print_changes) { if (expanded < 0) internal_error ("%s", history_value);#if defined (READLINE) else if (hist_verify == 0 || expanded == 2)#else else#endif fprintf (stderr, "%s\n", history_value); } /* If there was an error, return NULL. */ if (expanded < 0 || expanded == 2) /* 2 == print only */ {# if defined (READLINE) if (expanded == 2 && rl_dispatching == 0 && *history_value)# else if (expanded == 2 && *history_value)# endif /* !READLINE */ maybe_add_history (history_value); free (history_value);# if defined (READLINE) /* New hack. We can allow the user to edit the failed history expansion. */ if (history_reediting && expanded < 0 && rl_done) re_edit (line);# endif /* READLINE */ return ((char *)NULL); }# if defined (READLINE) if (hist_verify && expanded == 1) { re_edit (history_value); return ((char *)NULL); }# endif } /* Let other expansions know that return_value can be free'ed, and that a line has been added to the history list. Note that we only add lines that have something in them. */ expanded = 1; return_value = history_value; }# endif /* BANG_HISTORY */ if (addit && remember_on_history && *return_value) maybe_add_history (return_value);#if 0 if (expanded == 0) return_value = savestring (line);#endif return (return_value);}/* Return 1 if the first non-whitespace character in LINE is a `#', indicating * that the line is a shell comment. */static intshell_comment (line) char *line;{ char *p; for (p = line; p && *p && whitespace (*p); p++) ; return (p && *p == '#');}#ifdef INCLUDE_UNUSED/* Remove shell comments from LINE. A `#' and anything after it is a comment. This isn't really useful yet, since it doesn't handle quoting. */static char *filter_comments (line) char *line;{ char *p; for (p = line; p && *p && *p != '#'; p++) ; if (p && *p == '#') *p = '\0'; return (line);}#endif/* Check LINE against what HISTCONTROL says to do. Returns 1 if the line should be saved; 0 if it should be discarded. */static intcheck_history_control (line) char *line;{ HIST_ENTRY *temp; int r; if (history_control == 0) return 1; /* ignorespace or ignoreboth */ if ((history_control & HC_IGNSPACE) && *line == ' ') return 0; /* ignoredups or ignoreboth */ if (history_control & HC_IGNDUPS) { using_history (); temp = previous_history (); r = (temp == 0 || STREQ (temp->line, line) == 0); using_history (); if (r == 0) return r; } return 1;}/* Remove all entries matching LINE from the history list. Triggered when HISTCONTROL includes `erasedups'. */static voidhc_erasedups (line) char *line;{ HIST_ENTRY *temp; int r; using_history (); while (temp = previous_history ()) { if (STREQ (temp->line, line)) { r = where_history (); remove_history (r); } } using_history ();}/* Add LINE to the history list, handling possibly multi-line compound commands. We note whether or not we save the first line of each command (which is usually the entire command and history entry), and don't add the second and subsequent lines of a multi-line compound command if we didn't save the first line. We don't usually save shell comment lines in compound commands in the history, because they could have the effect of commenting out the rest of the command when the entire command is saved as a single history entry (when COMMAND_ORIENTED_HISTORY is enabled). If LITERAL_HISTORY is set, we're saving lines in the history with embedded newlines, so it's OK to save comment lines. We also make sure to save multiple-line quoted strings or other constructs. */voidmaybe_add_history (line) char *line;{ hist_last_line_added = 0; /* Don't use the value of history_control to affect the second and subsequent lines of a multi-line command (old code did this only when command_oriented_history is enabled). */ if (current_command_line_count > 1) { if (current_command_first_line_saved && (literal_history || dstack.delimiter_depth != 0 || shell_comment (line) == 0)) bash_add_history (line); return; } /* This is the first line of a (possible multi-line) command. Note whether or not we should save the first line and remember it. */ current_command_first_line_saved = check_add_history (line, 0);}/* Just check LINE against HISTCONTROL and HISTIGNORE and add it to the history if it's OK. Used by `history -s' as well as maybe_add_history(). Returns 1 if the line was saved in the history, 0 otherwise. */intcheck_add_history (line, force) char *line; int force;{ if (check_history_control (line) && history_should_ignore (line) == 0) { /* We're committed to saving the line. If the user has requested it, remove other matching lines from the history. */ if (history_control & HC_ERASEDUPS) hc_erasedups (line); if (force) { really_add_history (line); using_history (); } else bash_add_history (line); return 1; } return 0;}#if defined (SYSLOG_HISTORY)#define SYSLOG_MAXLEN 600voidbash_syslog_history (line) const char *line;{ char trunc[SYSLOG_MAXLEN]; if (strlen(line) < SYSLOG_MAXLEN) syslog (SYSLOG_FACILITY|SYSLOG_LEVEL, "HISTORY: PID=%d UID=%d %s", getpid(), current_user.uid, line); else { strncpy (trunc, line, SYSLOG_MAXLEN); trunc[SYSLOG_MAXLEN - 1] = '\0'; syslog (SYSLOG_FACILITY|SYSLOG_LEVEL, "HISTORY (TRUNCATED): PID=%d UID=%d %s", getpid(), current_user.uid, trunc); }}#endif /* Add a line to the history list. The variable COMMAND_ORIENTED_HISTORY controls the style of history remembering; when non-zero, and LINE is not the first line of a complete parser construct, append LINE to the last history line instead of adding it as a new line. */voidbash_add_history (line) char *line;{ int add_it, offset, curlen; HIST_ENTRY *current, *old; char *chars_to_add, *new_line; add_it = 1; if (command_oriented_history && current_command_line_count > 1) { chars_to_add = literal_history ? "\n" : history_delimiting_chars (line); using_history (); current = previous_history (); if (current) { /* If the previous line ended with an escaped newline (escaped with backslash, but otherwise unquoted), then remove the quoted newline, since that is what happens when the line is parsed. */ curlen = strlen (current->line); if (dstack.delimiter_depth == 0 && current->line[curlen - 1] == '\\' && current->line[curlen - 2] != '\\') { current->line[curlen - 1] = '\0'; curlen--; chars_to_add = ""; } /* If we're not in some kind of quoted construct, the current history entry ends with a newline, and we're going to add a semicolon, don't. In some cases, it results in a syntax error (e.g., before a close brace), and it should not be needed. */ if (dstack.delimiter_depth == 0 && current->line[curlen - 1] == '\n' && *chars_to_add == ';') chars_to_add++; new_line = (char *)xmalloc (1 + curlen + strlen (line) + strlen (chars_to_add)); sprintf (new_line, "%s%s%s", current->line, chars_to_add, line); offset = where_history (); old = replace_history_entry (offset, new_line, current->data); free (new_line); if (old) free_history_entry (old); add_it = 0; } } if (add_it) really_add_history (line);#if defined (SYSLOG_HISTORY) bash_syslog_history (line);#endif using_history ();}static voidreally_add_history (line) char *line;{ hist_last_line_added = 1; hist_last_line_pushed = 0; add_history (line); history_lines_this_session++;}inthistory_number (){ using_history (); return (remember_on_history ? history_base + where_history () : 1);}static intshould_expand (s) char *s;{ char *p; for (p = s; p && *p; p++) { if (*p == '\\') p++; else if (*p == '&') return 1; } return 0;}static inthistignore_item_func (ign) struct ign *ign;{ if (should_expand (ign->val)) ign->flags |= HIGN_EXPAND; return (0);}voidsetup_history_ignore (varname) char *varname;{ setup_ignore_patterns (&histignore);}static HIST_ENTRY *last_history_entry (){ HIST_ENTRY *he; using_history (); he = previous_history (); using_history (); return he;}char *last_history_line (){ HIST_ENTRY *he; he = last_history_entry (); if (he == 0) return ((char *)NULL); return he->line;}static char *expand_histignore_pattern (pat) char *pat;{ HIST_ENTRY *phe; char *ret; phe = last_history_entry (); if (phe == (HIST_ENTRY *)0) return (savestring (pat)); ret = strcreplace (pat, '&', phe->line, 1); return ret;}/* Return 1 if we should not put LINE into the history according to the patterns in HISTIGNORE. */static inthistory_should_ignore (line) char *line;{ register int i, match; char *npat; if (histignore.num_ignores == 0) return 0; for (i = match = 0; i < histignore.num_ignores; i++) { if (histignore.ignores[i].flags & HIGN_EXPAND) npat = expand_histignore_pattern (histignore.ignores[i].val); else npat = histignore.ignores[i].val; match = strmatch (npat, line, FNMATCH_EXTFLAG) != FNM_NOMATCH; if (histignore.ignores[i].flags & HIGN_EXPAND) free (npat); if (match) break; } return match;}#endif /* HISTORY */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -