|
|
1.1 root 1: /*% cc -O %
2: * =, == -- redo commands from history
3: */
4: #include <stdio.h>
5: #define TRUE 1
6: #define FALSE 0
7: #define LBSIZE 512
8:
9: char *malloc(), *realloc();
10:
11: #define Malloc(type,size) ((type *)malloc((size)*sizeof(type)))
12: #define Realloc(type,ptr,size) ((type *)realloc(ptr,(size)*sizeof(type)))
13:
14: char linebuf[LBSIZE];
15: char *linebp;
16: char *getenv();
17: char *cmd;
18: char genbuf[LBSIZE];
19: #define RHSIZE 512
20: char rhsbuf[RHSIZE];
21: int nextcol(col,cp,input)
22: register col;
23: register char *cp;
24: int input;
25: {
26: register char c;
27: c = *cp;
28: if (c=='\t')
29: col |= 07;
30: else if (c<' ' || c=='\177')
31: error("Invalid character in command");
32: return (++col);
33: }
34: xform(hfile)
35: FILE *hfile;
36: {
37: register char *i, *m, *o;
38: int *line, insert, ic, mc, c;
39: char *tf, *tl;
40: for(;;){
41: dumpline();
42: m=rhsbuf;
43: while ((c = getchar())!='\n') {
44: if (c == EOF)
45: exit(0);
46: *m++ = c;
47: if (m==rhsbuf+RHSIZE-1)
48: error("Out of space");
49: }
50: *m='\0';
51: if (m==rhsbuf)
52: break;
53: if (rhsbuf[0] == '=' && rhsbuf[1] == 0) {
54: prevline(hfile);
55: continue;
56: }
57: i=linebuf;
58: o=genbuf;
59: do ; while (*o++ = *i++);
60: if (i+(m-rhsbuf) > linebuf+LBSIZE)
61: error("Out of space");
62: i=genbuf;
63: o=linebuf;
64: m=rhsbuf;
65: insert=FALSE;
66: ic=0;
67: mc=0;
68: while (*i && *m && !insert) {
69: if(*i=='\t' && *m!='#' && *m!='^' && *m!='$') {
70: ic=nextcol(ic,i,FALSE);
71: tf=m;
72: tl=m;
73: do {
74: if (*m!=' ' && *m!='\t') {
75: if(*m=='%')
76: *m=' ';
77: tl=m+1;
78: }
79: mc=nextcol(mc,m++,TRUE);
80: } while (ic>mc && *m && *m!='#' &&
81: *m!='^' && *m!='$');
82: if (ic>mc) {
83: ic=mc;
84: if (*m)
85: tl=m;
86: } else {
87: if (tl==m)
88: i++;
89: else
90: ic--;
91: }
92: while (tf!=tl)
93: *o++ = *tf++;
94: } else {
95: mc=nextcol(mc,m,TRUE);
96: *o = *m;
97: switch (*m++) {
98: case ' ':
99: case '\t':
100: break;
101: case '^':
102: mc=ic;
103: insert++;
104: break;
105: case '$':
106: i="";
107: break;
108: case '#':
109: ic=nextcol(ic,i++,FALSE);
110: while(*m=='#' && ic>mc)
111: mc=nextcol(mc,m++,TRUE);
112: if (ic!=mc)
113: error("Partly deleted tab");
114: break;
115: case '%':
116: *o = ' ';
117: /* fall through */
118: default:
119: o++;
120: ic=nextcol(ic,i++,FALSE);
121: }
122: }
123: for (;;) {
124: if (ic>mc && *m) {
125: if (*m!=' ' && *m!='\t')
126: error("Skipped non-blank");
127: mc=nextcol(mc,m++,TRUE);
128: } else if (mc>ic && *i) {
129: ic=nextcol(ic,i,FALSE);
130: *o++ = *i++;
131: } else
132: break;
133: }
134: }
135: if (mc>ic && m[-1]=='\t')
136: *o++ = '\t';
137: while (*m)
138: *o++ = *m++;
139: do ; while (*o++ = *i++);
140: }
141: }
142: error(s)
143: char *s;
144: {
145: fprintf(stderr, "%s: %s\n", cmd, s);
146: exit(1);
147: }
148: char *histname;
149: main(argc, argv)
150: char *argv[];
151: {
152: register FILE *f; FILE *getline();
153: register nsubst, i;
154: char *strchr();
155: int edit=argv[0][1]!='\0';
156: cmd=argv[0];
157: for(nsubst=0;argc>1 && strchr(argv[argc-1], cmd[0])!=NULL;nsubst++){
158: --argc;
159: edit=0;
160: }
161: histname=getenv("HISTORY");
162: f = getline(argc, argv);
163: for(i=0;i!=nsubst;i++)
164: alter(argv[argc+i]);
165: if(edit)
166: xform(f);
167: else
168: dumpline();
169: fclose(f);
170: if((f=fopen(histname, "a"))!=NULL){
171: fprintf(f, "%s\n", linebuf);
172: fclose(f);
173: }
174: execl("/bin/sh", "sh", "-c", linebuf, (char *)0);
175: error("No shell!\n");
176: }
177: dumpline(){
178: /* write on 2 directly for speed */
179: write(2, linebuf, strlen(linebuf));
180: write(2, "\n", 1);
181: }
182: /*
183: * Look at $HISTORY. If argc==1 get the last non-blank line in the file.
184: * Otherwise, argv[1] is a pattern to match against the lines of the history
185: * file. The last matching line wins.
186: */
187: FILE *
188: getline(argc, argv)
189: char *argv[];
190: {
191: char history[LBSIZE];
192: char pat[LBSIZE];
193: register char *hp;
194: register FILE *f;
195: register i;
196: int nmatch=0, ntell;
197: if(histname==NULL)
198: error("Environment lacks HISTORY\n");
199: if((f=fopen(histname, "r"))==NULL){
200: perror(histname);
201: exit(1);
202: }
203: pat[0]='\0';
204: for(i=1;i!=argc && argv[i][0]!=cmd[0];i++){
205: strcat(pat, argv[i]);
206: strcat(pat, " ");
207: }
208: pat[strlen(pat)-1]='\0'; /* annul the extra space */
209: while(ntell=ftell(f), fgets(history, LBSIZE, f)){
210: /*
211: * Skip leading blanks or tabs
212: */
213: for(hp=history;*hp==' '||*hp=='\t';hp++)
214: ;
215: if(anyequals(hp))
216: continue;
217: /*
218: * Welcome to the land of snakey logic
219: */
220: if(pat[0]=='\0'?!empty(hp):match(hp, pat)){
221: linesave(ntell, nmatch++);
222: strncpy(linebuf, hp, LBSIZE);
223: }
224: }
225: if(nmatch==0)
226: error("Can't find a line to redo");
227: linebuf[strlen(linebuf)-1]='\0'; /* delete a newline */
228: return f;
229: }
230:
231: #define VECSIZE 512
232: int *matchvec, *matchend, *lastmatch, *lastuniq, vecsize;
233:
234: linesave(adr, i)
235: {
236: if (matchvec == 0)
237: matchend = matchvec = Malloc(int, vecsize = VECSIZE);
238: if (i >= vecsize)
239: matchvec = Realloc(int, matchvec, vecsize += VECSIZE);
240: if (matchvec == 0)
241: return;
242: *matchend++ = adr;
243: }
244:
245: prevline(f)
246: FILE *f;
247: {
248: char history[LBSIZE]; char *strchr(), *savestr();
249: register char *hp; register int *ip;
250: if (matchvec == 0)
251: return;
252: if (lastmatch == 0)
253: lastuniq = matchend, lastmatch = --matchend;
254: *--lastuniq = (int)savestr(linebuf);
255: do {
256: if (--lastmatch < matchvec) {
257: matchvec = 0;
258: return;
259: }
260: fseek(f, *lastmatch, 0);
261: fgets(history, LBSIZE, f);
262: for(hp=history;*hp==' '||*hp=='\t';hp++)
263: ;
264: *strchr(hp,'\n') = '\0';
265: for (ip=lastuniq; ip <= matchend; ip++)
266: if (strcmp((char *)(*ip), hp) == 0) break;
267: } while (ip <= matchend);
268: strncpy(linebuf, hp, LBSIZE);
269: }
270:
271: char *
272: savestr(str) /* Place string into permanent storage. */
273: register char *str;
274: {
275: static int nchleft; static char *strpt;
276: register int len; char *strcpy();
277:
278: if ((len = strlen(str)+1) > nchleft) {
279: strpt = malloc(nchleft = 2*LBSIZE);
280: }
281: if (strpt == 0)
282: return 0;
283: str = strcpy(strpt, str);
284: strpt += len; nchleft -= len;
285: return str;
286: }
287:
288: /*
289: * Throw away any command with an = or == word
290: */
291: anyequals(line)
292: register char *line;
293: {
294: register char *p, *q;
295: for(p=line; *p; p++)
296: if(*p=='=' && (p==line || p[-1]==' ' || p[-1]=='\t')){
297: if(p[1]=='=')
298: p++;
299: if(p[1]=='\n' || p[1]==' ' || p[1]=='\t')
300: return 1;
301: }
302: return 0;
303: }
304: match(s, p)
305: register char *s, *p;
306: {
307: register char *h;
308: for(h=s;*s!='\n' && *s!=' ' && *s!='\t' && *s!='\0';s++)
309: if(*s=='/')
310: h=s+1;
311: return(startis(h, p));
312: }
313: startis(s, p)
314: register char *s, *p;
315: {
316: while(*p!='\0')
317: if(*p==' '){
318: if(*s!=' ' && *s!='\t')
319: return(0);
320: while(*s==' ' || *s=='\t')
321: s++;
322: p++;
323: }
324: else if(*s++ != *p++)
325: return(0);
326: return(1);
327: }
328: empty(s)
329: register char *s;
330: {
331: if(*s==cmd[0])
332: return(1);
333: while(*s!='\0'){
334: if(*s!=' ' && *s!='\t' && *s!='\n')
335: return(0);
336: s++;
337: }
338: return(1);
339: }
340: alter(pat)
341: register char *pat;
342: {
343: register char *sub, *s=linebuf, *t=genbuf;
344: int patlen, sublen, matched=0;
345: for(sub=pat;*sub!=cmd[0] && *sub!='\0';sub++);
346: if(*sub!=cmd[0])
347: error("Bad Substitution");
348: patlen=sub-pat;
349: if(*sub==cmd[0])
350: *sub++='\0';
351: sublen=strlen(sub);
352: while(*s)
353: if(!matched && startis(s, pat)){
354: matched++;
355: s+=patlen;
356: strcpy(t, sub);
357: t+=sublen;
358: }
359: else
360: *t++ = *s++;
361: if(!matched)
362: error("No pattern match");
363: *t='\0';
364: strcpy(linebuf, genbuf);
365: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.