|
|
1.1 root 1: /*
2: * command history
3: *
4: * only implements in-memory history.
5: */
6:
7: static char *RCSid = "$Header: history.c,v 3.1 88/11/03 09:16:05 egisin Exp $";
8:
9: #include <stddef.h>
10: #include <stdio.h>
11: #include <string.h>
12: #include <errno.h>
13: #include <setjmp.h>
14: #include "sh.h"
15: #include "lex.h"
16:
17: char **histget();
18: char *histrpl();
19:
20: c_fc(wp)
21: register char **wp;
22: {
23: register char *id;
24: FILE *f;
25: struct temp *tf;
26: register char **hp;
27: char **hbeg, **hend;
28: int lflag = 0, nflag = 0, sflag = 0;
29:
30: for (wp++; (id = *wp) != NULL && *id == '-' && !sflag; wp++)
31: switch (id[1]) {
32: case 'l':
33: lflag++;
34: break;
35: case 'n':
36: nflag++;
37: break;
38: case 's':
39: sflag++;
40: break;
41: }
42:
43: /* fc -s [pat=rep] [cmd], equivalent to Korn's fc -e - [pat=rep] */
44: if (sflag) {
45: char *pat = NULL, *rep = NULL;
46:
47: hp = histptr - 1;
48: while ((id = *wp++) != NULL)
49: /* todo: multiple substitutions */
50: if ((rep = strchr(id, '=')) != NULL) {
51: pat = id;
52: *rep++ = '\0';
53: } else
54: hp = histget(id);
55:
56: if (hp == NULL || hp < history)
57: errorf("cannot find history\n");
58: if (pat == NULL)
59: strcpy(line, *hp);
60: else
61: histrpl(*hp, pat, rep);
62: histsave(line);
63: histpush--;
64: line[0] = '\0';
65: return 0;
66: }
67:
68: if (*wp != NULL) {
69: hbeg = histget(*wp++); /* first */
70: if (*wp != NULL)
71: hend = histget(*wp++); /* last */
72: else
73: hend = hbeg;
74: } else {
75: if (lflag)
76: hbeg = histptr - 12, hend = histptr;
77: else
78: hbeg = hend = histptr - 1;
79: if (hbeg < history)
80: hbeg = history;
81: }
82: if (hbeg == NULL || hend == NULL)
83: errorf("can't find history\n");
84:
85: if (lflag)
86: f = stdout;
87: else {
88: nflag++;
89: tf = maketemp(ATEMP);
90: tf->next = e.temps; e.temps = tf;
91: f = fopen(tf->name, "w");
92: if (f == NULL)
93: errorf("cannot create temp file %s", tf->name);
94: setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ);
95: }
96:
97: for (hp = hbeg; hp <= hend; hp++) {
98: if (!nflag)
99: fprintf(f, "%3d: ", source->line - (int)(histptr-hp));
100: fprintf(f, "%s\n", *hp);
101: }
102:
103: if (lflag)
104: return 0;
105: else
106: fclose(f);
107:
108: setstr(local("_"), tf->name);
109: command("${FCEDIT:-/bin/ed} $_"); /* edit temp file */
110:
111: f = fopen(tf->name, "r");
112: if (f == NULL)
113: errorf("cannot open temp file %s\n", tf->name);
114: setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ);
115: /* we push the editted lines onto the history list */
116: while (fgets(line, sizeof(line), f) != NULL) {
117: histsave(line);
118: histpush--;
119: }
120: line[0] = '\0';
121: fclose(f);
122:
123: return 0;
124: }
125:
126: /*
127: * save command in history
128: */
129: void
130: histsave(cmd)
131: char *cmd;
132: {
133: register char **hp = histptr;
134: char *cp;
135:
136: if (++hp >= history + HISTORY) { /* remove oldest command */
137: afree((Void*)*history, APERM);
138: for (hp = history; hp < history + HISTORY - 1; hp++)
139: hp[0] = hp[1];
140: }
141: *hp = strsave(cmd, APERM);
142: if ((cp = strchr(*hp, '\n')) != NULL)
143: *cp = '\0';
144: histptr = hp;
145: }
146:
147: /*
148: * get pointer to history given pattern
149: * pattern is a number or string
150: */
151: char **
152: histget(str)
153: char *str;
154: {
155: register char **hp = NULL;
156:
157: if (*str == '-')
158: hp = histptr + getn(str);
159: else
160: if (digit(*str))
161: hp = histptr + (getn(str) - source->line);
162: else
163: if (*str == '?') /* unanchored match */
164: for (hp = histptr-1; hp >= history; hp--)
165: if (strstr(*hp, str+1) != NULL)
166: break;
167: else /* anchored match */
168: for (hp = histptr; hp >= history; hp--)
169: if (strncmp(*hp, str, strlen(str)) == 0)
170: break;
171:
172: return (history <= hp && hp <= histptr) ? hp : NULL;
173: }
174:
175: char *
176: histrpl(s, pat, rep)
177: char *s;
178: char *pat, *rep;
179: {
180: char *s1;
181:
182: if (strlen(s) - strlen(pat) + strlen(rep) >= LINE)
183: errorf("substitution too long\n");
184: s1 = strstr(s, pat);
185: if (s1 == NULL)
186: errorf("substitution failed\n");
187: *s1 = '\0';
188: strcpy(line, s); /* first part */
189: strcat(line, rep); /* replacement */
190: strcat(line, s1 + strlen(pat)); /* last part */
191: return line;
192: }
193:
194: #if 0
195:
196: /* History file management routines (by DPK@BRL) */
197:
198: void
199: hist_init()
200: {
201: register struct namnod *n;
202: int fd;
203:
204: if (hist_fd >= 0 || (flags&oneflg))
205: return;
206: if ((n = findnam(histname)) == (struct namnod *)0
207: || n->namval == (char *)0)
208: return;
209: if ((fd = open(n->namval, O_RDWR)) >= 0) {
210: hist_load(fd);
211: (void)fcntl(fd, F_SETFL, O_APPEND);
212: }
213: hist_fd = fd;
214: }
215:
216: void
217: hist_finish()
218: {
219: if (hist_fd >= 0)
220: (void)close(hist_fd);
221: hist_fd = -1;
222: }
223:
224: void
225: hist_record(buf, len)
226: char *buf;
227: int len;
228: {
229: if (hist_fd >= 0)
230: (void)write(hist_fd, buf, (unsigned)len);
231: }
232:
233: void
234: hist_load(fd)
235: int fd;
236: {
237: extern long lseek();
238: struct stat sb;
239: char *x;
240: register char *cmdp, *end;
241: register int len;
242: register int i;
243:
244: if (fstat(fd, &sb) < 0 || sb.st_size <= 0)
245: return;
246: if (x = alloc((unsigned)(sb.st_size+1))) {
247: (void)lseek(fd, 0L, 0);
248: if ((len = read(fd, x, (unsigned)sb.st_size)) <= 0) {
249: free((struct blk *)x);
250: return;
251: }
252: x[len] = 0;
253: end = x;
254: for (;;) {
255: while(*end == NL)
256: end++; /* Skip NL */
257: if (*end == 0)
258: break;
259: cmdp = end;
260: while(*end && *end != NL)
261: end++; /* Goto NL */
262: if (*end == 0)
263: break;
264: if ((len = (end - cmdp)) < 2)
265: continue;
266: if (len >= BUFSIZ)
267: len = BUFSIZ - 1; /* Protection */
268: i = curhist % NHISTORY;
269: if(histbuf[i])
270: free((struct blk *)histbuf[i]);
271: histbuf[i] = alloc((unsigned)(len+1));
272: (void)strncpy(histbuf[i], cmdp, len);
273: histbuf[i][len] = 0;
274: curhist++;
275: histpc=curhist;
276: }
277: free((struct blk *)x);
278: }
279: return;
280: }
281:
282: #endif
283:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.