📄 com_history.c
字号:
/**********Copyright 1990 Regents of the University of California. All rights reserved.Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group$Id: com_history.c,v 1.8 2005/05/21 13:25:28 sjborley Exp $**********//* Do history substitutions. */#include <ngspice.h>#include <cpdefs.h>#include "com_history.h"#ifdef HAVE_GNUREADLINE/* Added GNU Readline Support -- Andrew Veliath <veliaa@rpi.edu> */#include <readline/readline.h>#include <readline/history.h>#endif /* HAVE_GNUREADLINE */#ifdef HAVE_BSDEDITLINE/* SJB added edit line support 2005-05-05 */#include <editline/readline.h>#endif /* HAVE_BSDEDITLINE *//* static declarations */static wordlist * dohsubst(char *string);static wordlist * dohmod(char **string, wordlist *wl);static wordlist * hpattern(char *buf);static wordlist * hprefix(char *buf);static wordlist * getevent(int num);#if !defined(HAVE_GNUREADLINE) && !defined(HAVE_BSDEDITLINE)static void freehist(int num);#endifstatic char * dohs(char *pat, char *str);struct histent *cp_lastone = NULL;int cp_maxhistlength = 10000; /* Chris Inbody */char cp_hat = '^';char cp_bang = '!';bool cp_didhsubst;static struct histent *histlist = NULL;static int histlength = 0;/* First check for a ^ at the beginning of the line, and then search * each word for !. Following this can be any of string, number, * ?string, -number ; then there may be a word specifier, the same as * csh, and then the : modifiers. For the :s modifier, the syntax is * :sXoooXnnnX, where X is any character, and ooo and nnn are strings * not containing X. */wordlist *cp_histsubst(wordlist *wlist){ wordlist *nwl, *w, *n; char buf[BSIZE_SP], *s, *b; /* Replace ^old^new with !:s^old^new. */ cp_didhsubst = FALSE; if (*wlist->wl_word == cp_hat) { (void) sprintf(buf, "%c%c:s%s", cp_bang, cp_bang, wlist->wl_word); tfree(wlist->wl_word); wlist->wl_word = copy(buf); } for (w = wlist; w; w = w->wl_next) { b = w->wl_word; for (s = b; *s; s++) if (*s == cp_bang) { cp_didhsubst = TRUE; n = dohsubst(s + 1); if (!n) { wlist->wl_word = NULL; return (wlist); } if (b < s) { (void) sprintf(buf, "%.*s%s", (int)(s-b), b, n->wl_word); tfree(n->wl_word); n->wl_word = copy(buf); } nwl = wl_splice(w, n); if (wlist == w) wlist = n; w = nwl; break; } } return (wlist);}/* Do a history substitution on one word. Figure out which event is * being referenced, then do word selections and modifications, and * then stick anything left over on the end of the last word. */static wordlist *dohsubst(char *string){ wordlist *wl, *nwl; char buf[BSIZE_SP], *s, *r = NULL, *t; if (*string == cp_bang) { if (cp_lastone) { wl = cp_lastone->hi_wlist; string++; } else { fprintf(cp_err, "0: event not found.\n"); return (NULL); } } else { switch(*string) { case '-': wl = getevent(cp_event - scannum(++string)); if (!wl) return (NULL); while (isdigit(*string)) string++; break; case '?': (void) strcpy(buf, string + 1); if ((s =strchr(buf, '?'))) *s = '\0'; wl = hpattern(buf); if (!wl) return (NULL); if (s == NULL) /* No modifiers on this one. */ return (wl_copy(wl)); break; case '\0': /* Maybe this should be cp_event. */ wl = alloc(struct wordlist); wl->wl_word = copy("!"); wl->wl_next = NULL; wl->wl_prev = NULL; cp_didhsubst = FALSE; return (wl); default: if (isdigit(*string)) { wl = getevent(scannum(string)); if (!wl) return (NULL); while (isdigit(*string)) string++; } else { (void) strcpy(buf, string); for (s = ":^$*-%"; *s; s++) { t =strchr(buf, *s); if (t && ((t < r) || !r)) { r = t; string += r - buf; } } if (r) *r = '\0'; else while (*string) string++; if ((buf[0] == '\0') && cp_lastone) wl = cp_lastone->hi_wlist; else wl = hprefix(buf); if (!wl) return (NULL); } } } if (wl == NULL) { /* Shouldn't happen. */ fprintf(cp_err, "Event not found.\n"); return (NULL); } nwl = dohmod(&string, wl_copy(wl)); if (!nwl) return (NULL); if (*string) { for (wl = nwl; wl->wl_next; wl = wl->wl_next) ; (void) sprintf(buf, "%s%s", wl->wl_word, string); tfree(wl->wl_word); wl->wl_word = copy(buf); } return (nwl);}static wordlist *dohmod(char **string, wordlist *wl){ wordlist *w; char *s; char *r = NULL, *t; int numwords, eventlo, eventhi, i; bool globalsubst;anothermod: numwords = wl_length(wl); globalsubst = FALSE; eventlo = 0; eventhi = numwords - 1; /* Now we know what wordlist we want. Take care of modifiers now. */ r = NULL; for (s = ":^$*-%"; *s; s++) { t =strchr(*string, *s); if (t && ((t < r) || (r == NULL))) r = t; } if (!r) /* No more modifiers. */ return (wl); *string = r; if (**string == ':') (*string)++; switch(**string) { case '$': /* Last word. */ eventhi = eventlo = numwords - 1; break; case '*': /* Words 1 through $ */ if (numwords == 1) return (NULL); eventlo = 1; eventhi = numwords - 1; break; case '-': /* Words 0 through ... */ eventlo = 0; if (*(*string + 1)) eventhi = scannum(*string + 1); else eventhi = numwords - 1; if (eventhi > numwords - 1) eventhi = numwords - 1; break; case 'p': /* Print the command and don't execute it. * This doesn't work quite like csh. */ wl_print(wl, cp_out); (void) putc('\n', cp_out); return (NULL); case 's': /* Do a substitution. */ for (w = wl; w; w = w->wl_next) { s = dohs(*string + 1, w->wl_word); if (s) { tfree(w->wl_word); w->wl_word = s; if (globalsubst == FALSE) { while (**string) (*string)++; break; } } } /* In case globalsubst is TRUE... */ while (**string) (*string)++; break; default: if (!isdigit(**string)) { fprintf(cp_err, "Error: %s: bad modifier.\n", *string); return (NULL); } i = scannum(*string); if (i > eventhi) { fprintf(cp_err, "Error: bad event number %d\n", i); return (NULL); } eventhi = eventlo = i; while (isdigit(**string)) (*string)++; if (**string == '*') eventhi = numwords - 1; if (**string == '-') { if (!isdigit(*(*string + 1))) eventhi = numwords - 1; else { eventhi = scannum(++*string); while (isdigit(**string)) (*string)++; } } } /* Now change the word list accordingly and make another pass * if there is more of the substitute left. */ wl = wl_range(wl, eventlo, eventhi); numwords = wl_length(wl); if (**string && *++*string) goto anothermod; return (wl);}/* Look for an event with a pattern in it... */static wordlist *hpattern(char *buf){ struct histent *hi; wordlist *wl; if (*buf == '\0') { fprintf(cp_err, "Bad pattern specification.\n"); return (NULL); } for (hi = cp_lastone; hi; hi = hi->hi_prev) for (wl = hi->hi_wlist; wl; wl = wl->wl_next) if (substring(buf, wl->wl_word)) return (hi->hi_wlist); fprintf(cp_err, "%s: event not found.\n", buf); return (NULL);}static wordlist *hprefix(char *buf){ struct histent *hi; if (*buf == '\0') { fprintf(cp_err, "Bad pattern specification.\n"); return (NULL); } for (hi = cp_lastone; hi; hi = hi->hi_prev) if (hi->hi_wlist && prefix(buf, hi->hi_wlist->wl_word)) return (hi->hi_wlist); fprintf(cp_err, "%s: event not found.\n", buf); return (NULL);}/* Add a wordlist to the history list. (Done after the first parse.) Note * that if event numbers are given in a random order that's how they'll * show up in the history list. */voidcp_addhistent(int event, wordlist *wlist){ /* MW. This test is not needed if everything works right if (cp_lastone && !cp_lastone->hi_wlist) fprintf(cp_err, "Internal error: bad history list\n"); */ if (cp_lastone == NULL) {/* MW. the begging - initialize histlength*/ histlength = 1; cp_lastone = histlist = alloc(struct histent); cp_lastone->hi_prev = NULL; } else { cp_lastone->hi_next = alloc(struct histent); cp_lastone->hi_next->hi_prev = cp_lastone; cp_lastone = cp_lastone->hi_next; } cp_lastone->hi_next = NULL; cp_lastone->hi_event = event; cp_lastone->hi_wlist = wl_copy(wlist);#if !defined(HAVE_GNUREADLINE) && !defined(HAVE_BSDEDITLINE) freehist(histlength - cp_maxhistlength); histlength++;#endif return;}/* Get a copy of the wordlist associated with an event. Error if out * of range. */static wordlist *getevent(int num){ struct histent *hi; for (hi = histlist; hi; hi = hi->hi_next) if (hi->hi_event == num) break; if (hi == NULL) { fprintf(cp_err, "%d: event not found.\n", num); return (NULL); } return (wl_copy(hi->hi_wlist));}/* Print out history between eventhi and eventlo. * This doesn't remember quoting, so 'hodedo' prints as hodedo. */voidcp_hprint(int eventhi, int eventlo, bool rev){ struct histent *hi; if (rev) { for (hi = histlist; hi->hi_next; hi = hi->hi_next) ; for (; hi; hi = hi->hi_prev) if ((hi->hi_event <= eventhi) && (hi->hi_event >= eventlo) && hi->hi_wlist) { fprintf(cp_out, "%d\t", hi->hi_event); wl_print(hi->hi_wlist, cp_out); (void) putc('\n', cp_out); } } else { for (hi = histlist; hi; hi = hi->hi_next) if ((hi->hi_event <= eventhi) && (hi->hi_event >= eventlo) && hi->hi_wlist) { fprintf(cp_out, "%d\t", hi->hi_event); wl_print(hi->hi_wlist, cp_out); (void) putc('\n', cp_out); } } return;}#if !defined(HAVE_GNUREADLINE) && !defined(HAVE_BSDEDITLINE)/* This just gets rid of the first num entries on the history list, and * decrements histlength. */static voidfreehist(int num){ struct histent *hi; if (num < 1) return; histlength -= num; hi = histlist; while (num-- && histlist->hi_next) histlist = histlist->hi_next; if (histlist->hi_prev) { histlist->hi_prev->hi_next = NULL; histlist->hi_prev = NULL; } else { fprintf(cp_err, "Internal error: history list mangled\n"); exit(0); /* Chris Inbody */ } while (hi->hi_next) { wl_free(hi->hi_wlist); hi = hi->hi_next; tfree(hi->hi_prev); } wl_free(hi->hi_wlist); tfree(hi); return;}#endif /* !defined(HAVE_GNUREADLINE) && !defined(HAVE_BSDEDITLINE) *//* Do a :s substitution. */static char *dohs(char *pat, char *str){ char schar, *s, *p, buf[BSIZE_SP]; int i = 0, plen; bool ok = FALSE; pat = copy(pat); /* Don't want to mangle anything. */ schar = *pat++; s =strchr(pat, schar); if (s == NULL) { fprintf(cp_err, "Bad substitute.\n"); return (NULL); } *s++ = '\0'; p =strchr(s, schar); if (p) *p = '\0'; plen = strlen(pat) - 1; for (i = 0; *str; str++) { if ((*str == *pat) && prefix(pat, str) && (ok == FALSE)) { for (p = s; *p; p++) buf[i++] = *p; str += plen; ok = TRUE; } else buf[i++] = *str; } buf[i] = '\0'; if (ok) return (copy(buf)); else return (NULL);}/* The "history" command. history [-r] [number] */voidcom_history(wordlist *wl){ bool rev = FALSE; if (wl && eq(wl->wl_word, "-r")) { wl = wl->wl_next; rev = TRUE; }#if defined(HAVE_GNUREADLINE) || defined(HAVE_BSDEDITLINE) /* Added GNU Readline Support -- Andrew Veliath <veliaa@rpi.edu> */ { HIST_ENTRY *he; int i, N; N = (wl == NULL) ? history_length : atoi(wl->wl_word); if (N < 0) N = 0; if (N > history_length) N = history_length; if (rev) for (i = history_length; i > 0 && N; --i, --N) { he = history_get(i); if (!he) return; fprintf(cp_out, "%d\t%s\n", i, he->line); } else for (i = history_length - N + 1; i <= history_length; ++i) { he = history_get(i); if (!he) return; fprintf(cp_out, "%d\t%s\n", i, he->line); } }#else if (wl == NULL) cp_hprint(cp_event - 1, cp_event - histlength, rev); else cp_hprint(cp_event - 1, cp_event - 1 - atoi(wl->wl_word), rev);#endif /* defined(HAVE_GNUREADLINE) || defined(HAVE_BSDEDITLINE) */ return;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -