📄 history.c
字号:
{ 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] == '*') { char *star_result; *caller_index = i + 1; star_result = history_arg_extract (1, '$', from); if (!star_result) star_result = savestring (""); return (star_result); } /* `$' 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. 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). */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 < 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) 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);}#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 + -