1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin * *
3da2e3ebdSchin * This software is part of the ast package *
4*3e14f97fSRoger A. Faulkner * Copyright (c) 1982-2010 AT&T Intellectual Property *
5da2e3ebdSchin * and is licensed under the *
6da2e3ebdSchin * Common Public License, Version 1.0 *
77c2fbfb3SApril Chin * by AT&T Intellectual Property *
8da2e3ebdSchin * *
9da2e3ebdSchin * A copy of the License is available at *
10da2e3ebdSchin * http://www.opensource.org/licenses/cpl1.0.txt *
11da2e3ebdSchin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12da2e3ebdSchin * *
13da2e3ebdSchin * Information and Software Systems Research *
14da2e3ebdSchin * AT&T Research *
15da2e3ebdSchin * Florham Park NJ *
16da2e3ebdSchin * *
17da2e3ebdSchin * David Korn <dgk@research.att.com> *
18da2e3ebdSchin * *
19da2e3ebdSchin ***********************************************************************/
20da2e3ebdSchin #pragma prototyped
21da2e3ebdSchin #include "defs.h"
22da2e3ebdSchin #include <stak.h>
23da2e3ebdSchin #include <ls.h>
24da2e3ebdSchin #include <error.h>
25da2e3ebdSchin #include "variables.h"
26da2e3ebdSchin #include "io.h"
27da2e3ebdSchin #include "name.h"
28da2e3ebdSchin #include "history.h"
29da2e3ebdSchin #include "builtins.h"
30da2e3ebdSchin #if SHOPT_HISTEXPAND
31da2e3ebdSchin # include "edit.h"
32da2e3ebdSchin #endif
33da2e3ebdSchin
34da2e3ebdSchin #define HIST_RECURSE 5
35da2e3ebdSchin
36da2e3ebdSchin static void hist_subst(const char*, int fd, char*);
37da2e3ebdSchin
38da2e3ebdSchin #if 0
39da2e3ebdSchin /* for the benefit of the dictionary generator */
40da2e3ebdSchin int b_fc(int argc,char *argv[], void *extra){}
41da2e3ebdSchin #endif
b_hist(int argc,char * argv[],void * extra)42da2e3ebdSchin int b_hist(int argc,char *argv[], void *extra)
43da2e3ebdSchin {
44da2e3ebdSchin register History_t *hp;
45da2e3ebdSchin register char *arg;
46da2e3ebdSchin register int flag,fdo;
477c2fbfb3SApril Chin register Shell_t *shp = ((Shbltin_t*)extra)->shp;
48da2e3ebdSchin Sfio_t *outfile;
49da2e3ebdSchin char *fname;
50da2e3ebdSchin int range[2], incr, index2, indx= -1;
51da2e3ebdSchin char *edit = 0; /* name of editor */
52da2e3ebdSchin char *replace = 0; /* replace old=new */
53da2e3ebdSchin int lflag = 0, nflag = 0, rflag = 0;
54da2e3ebdSchin #if SHOPT_HISTEXPAND
55da2e3ebdSchin int pflag = 0;
56da2e3ebdSchin #endif
57da2e3ebdSchin Histloc_t location;
58da2e3ebdSchin NOT_USED(argc);
597c2fbfb3SApril Chin if(!sh_histinit((void*)shp))
60da2e3ebdSchin errormsg(SH_DICT,ERROR_system(1),e_histopen);
61da2e3ebdSchin hp = shp->hist_ptr;
62da2e3ebdSchin while((flag = optget(argv,sh_opthist))) switch(flag)
63da2e3ebdSchin {
64da2e3ebdSchin case 'e':
65da2e3ebdSchin edit = opt_info.arg;
66da2e3ebdSchin break;
67da2e3ebdSchin case 'n':
68da2e3ebdSchin nflag++;
69da2e3ebdSchin break;
70da2e3ebdSchin case 'l':
71da2e3ebdSchin lflag++;
72da2e3ebdSchin break;
73da2e3ebdSchin case 'r':
74da2e3ebdSchin rflag++;
75da2e3ebdSchin break;
76da2e3ebdSchin case 's':
77da2e3ebdSchin edit = "-";
78da2e3ebdSchin break;
79da2e3ebdSchin #if SHOPT_HISTEXPAND
80da2e3ebdSchin case 'p':
81da2e3ebdSchin pflag++;
82da2e3ebdSchin break;
83da2e3ebdSchin #endif
84da2e3ebdSchin case 'N':
85da2e3ebdSchin if(indx<=0)
86da2e3ebdSchin {
87da2e3ebdSchin if((flag = hist_max(hp) - opt_info.num-1) < 0)
88da2e3ebdSchin flag = 1;
89da2e3ebdSchin range[++indx] = flag;
90da2e3ebdSchin break;
91da2e3ebdSchin }
92da2e3ebdSchin case ':':
93da2e3ebdSchin errormsg(SH_DICT,2, "%s", opt_info.arg);
94da2e3ebdSchin break;
95da2e3ebdSchin case '?':
96da2e3ebdSchin errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
97da2e3ebdSchin break;
98da2e3ebdSchin }
99da2e3ebdSchin if(error_info.errors)
100da2e3ebdSchin errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
101da2e3ebdSchin argv += (opt_info.index-1);
102da2e3ebdSchin #if SHOPT_HISTEXPAND
103da2e3ebdSchin if(pflag)
104da2e3ebdSchin {
105da2e3ebdSchin hist_cancel(hp);
106da2e3ebdSchin pflag = 0;
107da2e3ebdSchin while(arg=argv[1])
108da2e3ebdSchin {
109da2e3ebdSchin flag = hist_expand(arg,&replace);
110da2e3ebdSchin if(!(flag & HIST_ERROR))
111da2e3ebdSchin sfputr(sfstdout, replace, '\n');
112da2e3ebdSchin else
113da2e3ebdSchin pflag = 1;
114da2e3ebdSchin if(replace)
115da2e3ebdSchin free(replace);
116da2e3ebdSchin argv++;
117da2e3ebdSchin }
118da2e3ebdSchin return pflag;
119da2e3ebdSchin }
120da2e3ebdSchin #endif
121da2e3ebdSchin flag = indx;
122da2e3ebdSchin while(flag<1 && (arg=argv[1]))
123da2e3ebdSchin {
124da2e3ebdSchin /* look for old=new argument */
125da2e3ebdSchin if(!replace && strchr(arg+1,'='))
126da2e3ebdSchin {
127da2e3ebdSchin replace = arg;
128da2e3ebdSchin argv++;
129da2e3ebdSchin continue;
130da2e3ebdSchin }
131da2e3ebdSchin else if(isdigit(*arg) || *arg == '-')
132da2e3ebdSchin {
133da2e3ebdSchin /* see if completely numeric */
134da2e3ebdSchin do arg++;
135da2e3ebdSchin while(isdigit(*arg));
136da2e3ebdSchin if(*arg==0)
137da2e3ebdSchin {
138da2e3ebdSchin arg = argv[1];
139da2e3ebdSchin range[++flag] = (int)strtol(arg, (char**)0, 10);
140da2e3ebdSchin if(*arg == '-')
141da2e3ebdSchin range[flag] += (hist_max(hp)-1);
142da2e3ebdSchin argv++;
143da2e3ebdSchin continue;
144da2e3ebdSchin }
145da2e3ebdSchin }
146da2e3ebdSchin /* search for last line starting with string */
147da2e3ebdSchin location = hist_find(hp,argv[1],hist_max(hp)-1,0,-1);
148da2e3ebdSchin if((range[++flag] = location.hist_command) < 0)
149da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),e_found,argv[1]);
150da2e3ebdSchin argv++;
151da2e3ebdSchin }
152da2e3ebdSchin if(flag <0)
153da2e3ebdSchin {
154da2e3ebdSchin /* set default starting range */
155da2e3ebdSchin if(lflag)
156da2e3ebdSchin {
157da2e3ebdSchin flag = hist_max(hp)-16;
158da2e3ebdSchin if(flag<1)
159da2e3ebdSchin flag = 1;
160da2e3ebdSchin }
161da2e3ebdSchin else
162da2e3ebdSchin flag = hist_max(hp)-2;
163da2e3ebdSchin range[0] = flag;
164da2e3ebdSchin flag = 0;
165da2e3ebdSchin }
166da2e3ebdSchin index2 = hist_min(hp);
167da2e3ebdSchin if(range[0]<index2)
168da2e3ebdSchin range[0] = index2;
169da2e3ebdSchin if(flag==0)
170da2e3ebdSchin /* set default termination range */
1717c2fbfb3SApril Chin range[1] = ((lflag && !edit)?hist_max(hp)-1:range[0]);
172da2e3ebdSchin if(range[1]>=(flag=(hist_max(hp) - !lflag)))
173da2e3ebdSchin range[1] = flag;
174da2e3ebdSchin /* check for valid ranges */
175da2e3ebdSchin if(range[1]<index2 || range[0]>=flag)
176da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),e_badrange,range[0],range[1]);
177da2e3ebdSchin if(edit && *edit=='-' && range[0]!=range[1])
178da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),e_eneedsarg);
179da2e3ebdSchin /* now list commands from range[rflag] to range[1-rflag] */
180da2e3ebdSchin incr = 1;
181da2e3ebdSchin flag = rflag>0;
182da2e3ebdSchin if(range[1-flag] < range[flag])
183da2e3ebdSchin incr = -1;
184da2e3ebdSchin if(lflag)
185da2e3ebdSchin {
186da2e3ebdSchin outfile = sfstdout;
187da2e3ebdSchin arg = "\n\t";
188da2e3ebdSchin }
189da2e3ebdSchin else
190da2e3ebdSchin {
191da2e3ebdSchin if(!(fname=pathtmp(NIL(char*),0,0,NIL(int*))))
192da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),e_create,"");
193da2e3ebdSchin if((fdo=open(fname,O_CREAT|O_RDWR,S_IRUSR|S_IWUSR)) < 0)
194da2e3ebdSchin errormsg(SH_DICT,ERROR_system(1),e_create,fname);
195da2e3ebdSchin outfile= sfnew(NIL(Sfio_t*),shp->outbuff,IOBSIZE,fdo,SF_WRITE);
196da2e3ebdSchin arg = "\n";
197da2e3ebdSchin nflag++;
198da2e3ebdSchin }
199da2e3ebdSchin while(1)
200da2e3ebdSchin {
201da2e3ebdSchin if(nflag==0)
202da2e3ebdSchin sfprintf(outfile,"%d\t",range[flag]);
203da2e3ebdSchin else if(lflag)
204da2e3ebdSchin sfputc(outfile,'\t');
205da2e3ebdSchin hist_list(shp->hist_ptr,outfile,hist_tell(shp->hist_ptr,range[flag]),0,arg);
206da2e3ebdSchin if(lflag)
207da2e3ebdSchin sh_sigcheck();
208da2e3ebdSchin if(range[flag] == range[1-flag])
209da2e3ebdSchin break;
210da2e3ebdSchin range[flag] += incr;
211da2e3ebdSchin }
212da2e3ebdSchin if(lflag)
213da2e3ebdSchin return(0);
214da2e3ebdSchin sfclose(outfile);
215da2e3ebdSchin hist_eof(hp);
216da2e3ebdSchin arg = edit;
2177c2fbfb3SApril Chin if(!arg && !(arg=nv_getval(sh_scoped(shp,HISTEDIT))) && !(arg=nv_getval(sh_scoped(shp,FCEDNOD))))
218da2e3ebdSchin arg = (char*)e_defedit;
219da2e3ebdSchin #ifdef apollo
220da2e3ebdSchin /*
221da2e3ebdSchin * Code to support the FC using the pad editor.
222da2e3ebdSchin * Exampled of how to use: HISTEDIT=pad
223da2e3ebdSchin */
224da2e3ebdSchin if (strcmp (arg, "pad") == 0)
225da2e3ebdSchin {
226da2e3ebdSchin extern int pad_create(char*);
227da2e3ebdSchin sh_close(fdo);
228da2e3ebdSchin fdo = pad_create(fname);
229da2e3ebdSchin pad_wait(fdo);
230da2e3ebdSchin unlink(fname);
231da2e3ebdSchin strcat(fname, ".bak");
232da2e3ebdSchin unlink(fname);
233da2e3ebdSchin lseek(fdo,(off_t)0,SEEK_SET);
234da2e3ebdSchin }
235da2e3ebdSchin else
236da2e3ebdSchin {
237da2e3ebdSchin #endif /* apollo */
238da2e3ebdSchin if(*arg != '-')
239da2e3ebdSchin {
240da2e3ebdSchin char *com[3];
241da2e3ebdSchin com[0] = arg;
242da2e3ebdSchin com[1] = fname;
243da2e3ebdSchin com[2] = 0;
244da2e3ebdSchin error_info.errors = sh_eval(sh_sfeval(com),0);
245da2e3ebdSchin }
246da2e3ebdSchin fdo = sh_chkopen(fname);
247da2e3ebdSchin unlink(fname);
248da2e3ebdSchin free((void*)fname);
249da2e3ebdSchin #ifdef apollo
250da2e3ebdSchin }
251da2e3ebdSchin #endif /* apollo */
252da2e3ebdSchin /* don't history fc itself unless forked */
253da2e3ebdSchin error_info.flags |= ERROR_SILENT;
254da2e3ebdSchin if(!sh_isstate(SH_FORKED))
255da2e3ebdSchin hist_cancel(hp);
256da2e3ebdSchin sh_onstate(SH_HISTORY);
257da2e3ebdSchin sh_onstate(SH_VERBOSE); /* echo lines as read */
258da2e3ebdSchin if(replace)
259da2e3ebdSchin hist_subst(error_info.id,fdo,replace);
260da2e3ebdSchin else if(error_info.errors == 0)
261da2e3ebdSchin {
262da2e3ebdSchin char buff[IOBSIZE+1];
263da2e3ebdSchin Sfio_t *iop = sfnew(NIL(Sfio_t*),buff,IOBSIZE,fdo,SF_READ);
264da2e3ebdSchin /* read in and run the command */
265da2e3ebdSchin if(shp->hist_depth++ > HIST_RECURSE)
266da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),e_toodeep,"history");
267da2e3ebdSchin sh_eval(iop,1);
268da2e3ebdSchin shp->hist_depth--;
269da2e3ebdSchin }
270da2e3ebdSchin else
271da2e3ebdSchin {
272da2e3ebdSchin sh_close(fdo);
273da2e3ebdSchin if(!sh_isoption(SH_VERBOSE))
274da2e3ebdSchin sh_offstate(SH_VERBOSE);
275da2e3ebdSchin sh_offstate(SH_HISTORY);
276da2e3ebdSchin }
277da2e3ebdSchin return(shp->exitval);
278da2e3ebdSchin }
279da2e3ebdSchin
280da2e3ebdSchin
281da2e3ebdSchin /*
282da2e3ebdSchin * given a file containing a command and a string of the form old=new,
283da2e3ebdSchin * execute the command with the string old replaced by new
284da2e3ebdSchin */
285da2e3ebdSchin
hist_subst(const char * command,int fd,char * replace)286da2e3ebdSchin static void hist_subst(const char *command,int fd,char *replace)
287da2e3ebdSchin {
288da2e3ebdSchin register char *newp=replace;
289da2e3ebdSchin register char *sp;
290da2e3ebdSchin register int c;
291da2e3ebdSchin off_t size;
292da2e3ebdSchin char *string;
293da2e3ebdSchin while(*++newp != '='); /* skip to '=' */
294da2e3ebdSchin if((size = lseek(fd,(off_t)0,SEEK_END)) < 0)
295da2e3ebdSchin return;
296da2e3ebdSchin lseek(fd,(off_t)0,SEEK_SET);
297da2e3ebdSchin c = (int)size;
298da2e3ebdSchin string = stakalloc(c+1);
299da2e3ebdSchin if(read(fd,string,c)!=c)
300da2e3ebdSchin return;
301da2e3ebdSchin string[c] = 0;
302da2e3ebdSchin *newp++ = 0;
303da2e3ebdSchin if((sp=sh_substitute(string,replace,newp))==0)
304da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),e_subst,command);
305da2e3ebdSchin *(newp-1) = '=';
306da2e3ebdSchin sh_eval(sfopen(NIL(Sfio_t*),sp,"s"),1);
307da2e3ebdSchin }
308da2e3ebdSchin
309