📄 history.c
字号:
{ int tchar = string[i]; if (passc) { passc = 0; ADD_CHAR (tchar); continue; } if (tchar == history_expansion_char) tchar = -3; switch (tchar) { default: ADD_CHAR (string[i]); break; case '\\': passc++; ADD_CHAR (tchar); break;#if defined (SHELL) case '\'': { /* If this is bash, single quotes inhibit history expansion. */ int quote, slen; quote = i++; rl_string_extract_single_quoted (string, &i); slen = i - quote + 2; temp = xmalloc (slen); strncpy (temp, string + quote, slen); temp[slen - 1] = '\0'; ADD_STRING (temp); free (temp); break; }#endif /* SHELL */ case -3: /* history_expansion_char */ 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)) { ADD_CHAR (string[i]); break; }#if defined (NO_BANG_HASH_MODIFIERS) /* 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 we don't want to allow modifiers with `!#', just stick the current output line in again. */ if (cc == '#') { if (result) { temp = xmalloc (1 + strlen (result)); strcpy (temp, result); ADD_STRING (temp); free (temp); } i++; break; }#endif r = history_expand_internal (string, i, &eindex, &temp, result); if (r < 0) { *output = temp; free (result); if (string != hstring) free (string); return -1; } else { if (temp) { modified++; if (*temp) ADD_STRING (temp); free (temp); } only_printing = r == 1; i = eindex; } break; } } *output = result; if (string != hstring) free (string); if (only_printing) { add_history (result); return (2); } 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. The address of ERROR_POINTER 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. */static 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 *result; /* The range of words to return doesn't exist yet. */ first = last = 0; result = (char *)NULL; /* 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; return (search_match ? savestring (search_match) : savestring ("")); } /* `*' matches all of the arguments, but not the command. */ if (spec[i] == '*') { *caller_index = i + 1; result = history_arg_extract (1, '$', from); return (result ? result : savestring ("")); } /* `$' 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] == '-') first = 0; else if (spec[i] == '^') first = 1; else if (digit_p (spec[i]) && expecting_word_spec) { for (first = 0; digit_p (spec[i]); i++) first = (first * 10) + digit_value (spec[i]); } else return ((char *)NULL); /* no valid `first' for word specifier */ if (spec[i] == '^' || spec[i] == '*') { last = (spec[i] == '^') ? 1 : '$'; /* x* abbreviates x-$ */ i++; } else if (spec[i] != '-') last = first; else { i++; if (digit_p (spec[i])) { for (last = 0; digit_p (spec[i]); i++) last = (last * 10) + digit_value (spec[i]); } else if (spec[i] == '$') { i++; last = '$'; } else if (!spec[i] || spec[i] == ':') /* could be modifier separator */ last = -1; /* x- abbreviates x-$ omitting word `$' */ } *caller_index = i; if (last >= first || last == '$' || last < 0) result = history_arg_extract (first, last, from); return (result ? result : (char *)&error_pointer);}/* Extract the args specified, starting at FIRST, and ending at LAST. The args are taken from STRING. If either FIRST or LAST is < 0, then make that arg count from the right (subtract from the number of tokens, so that FIRST = -1 means the next to last token on the line). If LAST is `$' the last arg from STRING is used. */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 **list; /* XXX - think about making history_tokenize return a struct array, each struct in array being a string and a length to avoid the calls to strlen below. */ if ((list = history_tokenize (string)) == NULL) return ((char *)NULL); for (len = 0; list[len]; len++) ; if (last < 0) last = len + last - 1; if (first < 0) first = len + first - 1; if (last == '$') last = len - 1; if (first == '$') first = len - 1; last++; if (first >= len || last > len || first < 0 || last < 0 || first > last) result = ((char *)NULL); else { for (size = 0, i = first; i < last; i++) size += strlen (list[i]) + 1; result = xmalloc (size + 1); result[0] = '\0'; for (i = first; i < last; i++) { strcpy (result + offset, list[i]); offset += strlen (list[i]); if (i + 1 < last) { result[offset++] = ' '; result[offset] = 0; } } } for (i = 0; i < len; i++) free (list[i]); free (list); return (result);}#define slashify_in_quotes "\\`\"$"/* Parse STRING into tokens and return an array of strings. If WIND is not -1 and INDP is not null, we also want the word surrounding index WIND. The position in the returned array of strings is returned in *INDP. */static char **history_tokenize_internal (string, wind, indp) char *string; int wind, *indp;{ 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. */ while (string[i]) { int delimiter = 0; /* Skip leading whitespace. */ for (; string[i] && whitespace (string[i]); i++) ; if (!string[i] || string[i] == history_comment_char) return (result); start = i; if (member (string[i], "()\n")) { i++; goto got_token; } if (member (string[i], "<>;&|$")) { int peek = string[i + 1]; if (peek == string[i] && peek != '$') { if (peek == '<' && string[i + 2] == '-') i++; i += 2; goto got_token; } else { if ((peek == '&' && (string[i] == '>' || string[i] == '<')) || ((peek == '>') && (string[i] == '&')) || ((peek == '(') && (string[i] == '$'))) { i += 2; goto got_token; } } if (string[i] != '$') { i++; goto got_token; } } /* Get word from string + i; */ if (member (string[i], "\"'`")) delimiter = string[i++]; for (; string[i]; i++) { if (string[i] == '\\' && string[i + 1] == '\n') { i++; continue; } if (string[i] == '\\' && delimiter != '\'' && (delimiter != '"' || member (string[i], slashify_in_quotes))) { i++; continue; } if (delimiter && string[i] == delimiter) { delimiter = 0; continue; } if (!delimiter && (member (string[i], " \t\n;&()|<>"))) break; if (!delimiter && member (string[i], "\"'`")) delimiter = string[i]; } got_token: /* If we are looking for the word in which the character at a particular index falls, remember it. */ if (indp && wind >= 0 && wind >= start && wind < i) *indp = result_index; len = i - start; if (result_index + 2 >= size) result = (char **)xrealloc (result, ((size += 10) * sizeof (char *))); result[result_index] = xmalloc (1 + len); strncpy (result[result_index], string + start, len); result[result_index][len] = '\0'; result[++result_index] = (char *)NULL; } return (result);}/* Return an array of tokens, much as the shell might. The tokens are parsed out of STRING. */char **history_tokenize (string) char *string;{ return (history_tokenize_internal (string, -1, (int *)NULL));}/* Find and return the word which contains the character at index IND in the history line LINE. Used to save the word matched by the last history !?string? search. */static char *history_find_word (line, ind) char *line; int ind;{ char **words, *s; int i, wind; words = history_tokenize_internal (line, ind, &wind); if (wind == -1) return ((char *)NULL); s = words[wind]; for (i = 0; i < wind; i++) free (words[i]); for (i = wind + 1; words[i]; i++) free (words[i]); free (words); return s;}#if defined (STATIC_MALLOC)/* **************************************************************** *//* *//* xmalloc and xrealloc () *//* *//* **************************************************************** */static void memory_error_and_abort ();static char *xmalloc (bytes) int bytes;{ char *temp = (char *)malloc (bytes); if (!temp) memory_error_and_abort (); return (temp);}static char *xrealloc (pointer, bytes) char *pointer; int bytes;{ char *temp; if (!pointer) temp = (char *)xmalloc (bytes); else temp = (char *)realloc (pointer, bytes); if (!temp) memory_error_and_abort (); return (temp);}static voidmemory_error_and_abort (){ fprintf (stderr, "history: Out of virtual memory!\n"); abort ();}#endif /* STATIC_MALLOC *//* **************************************************************** *//* *//* Test Code *//* *//* **************************************************************** */#ifdef TESTmain (){ 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:*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -