1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*b30d1939SAndy Fiddaman *          Copyright (c) 1982-2012 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6*b30d1939SAndy Fiddaman *                 Eclipse Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10*b30d1939SAndy Fiddaman *          http://www.eclipse.org/org/documents/epl-v10.html           *
11*b30d1939SAndy Fiddaman *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
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 */
40*b30d1939SAndy Fiddaman     int	b_fc(int argc,char *argv[], Shbltin_t *context){}
41da2e3ebdSchin #endif
b_hist(int argc,char * argv[],Shbltin_t * context)42*b30d1939SAndy Fiddaman int	b_hist(int argc,char *argv[], Shbltin_t *context)
43da2e3ebdSchin {
44da2e3ebdSchin 	register History_t *hp;
45da2e3ebdSchin 	register char *arg;
46da2e3ebdSchin 	register int flag,fdo;
47*b30d1939SAndy Fiddaman 	register Shell_t *shp = context->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);
61*b30d1939SAndy Fiddaman 	hp = shp->gd->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 		}
925ae8bd53SToomas Soome 		/* FALLTHROUGH */
93da2e3ebdSchin 	    case ':':
94da2e3ebdSchin 		errormsg(SH_DICT,2, "%s", opt_info.arg);
95da2e3ebdSchin 		break;
96da2e3ebdSchin 	    case '?':
97da2e3ebdSchin 		errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
98da2e3ebdSchin 		break;
99da2e3ebdSchin 	}
100da2e3ebdSchin 	if(error_info.errors)
101da2e3ebdSchin 		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
102da2e3ebdSchin 	argv += (opt_info.index-1);
103da2e3ebdSchin #if SHOPT_HISTEXPAND
104da2e3ebdSchin 	if(pflag)
105da2e3ebdSchin 	{
106da2e3ebdSchin 		hist_cancel(hp);
107da2e3ebdSchin 		pflag = 0;
108da2e3ebdSchin 		while(arg=argv[1])
109da2e3ebdSchin 		{
110da2e3ebdSchin 			flag = hist_expand(arg,&replace);
111da2e3ebdSchin 			if(!(flag & HIST_ERROR))
112da2e3ebdSchin 				sfputr(sfstdout, replace, '\n');
113da2e3ebdSchin 			else
114da2e3ebdSchin 				pflag = 1;
115da2e3ebdSchin 			if(replace)
116da2e3ebdSchin 				free(replace);
117da2e3ebdSchin 			argv++;
118da2e3ebdSchin 		}
119da2e3ebdSchin 		return pflag;
120da2e3ebdSchin 	}
121da2e3ebdSchin #endif
122da2e3ebdSchin 	flag = indx;
123da2e3ebdSchin 	while(flag<1 && (arg=argv[1]))
124da2e3ebdSchin 	{
125da2e3ebdSchin 		/* look for old=new argument */
126da2e3ebdSchin 		if(!replace && strchr(arg+1,'='))
127da2e3ebdSchin 		{
128da2e3ebdSchin 			replace = arg;
129da2e3ebdSchin 			argv++;
130da2e3ebdSchin 			continue;
131da2e3ebdSchin 		}
132da2e3ebdSchin 		else if(isdigit(*arg) || *arg == '-')
133da2e3ebdSchin 		{
134da2e3ebdSchin 			/* see if completely numeric */
135da2e3ebdSchin 			do	arg++;
136da2e3ebdSchin 			while(isdigit(*arg));
137da2e3ebdSchin 			if(*arg==0)
138da2e3ebdSchin 			{
139da2e3ebdSchin 				arg = argv[1];
140da2e3ebdSchin 				range[++flag] = (int)strtol(arg, (char**)0, 10);
141da2e3ebdSchin 				if(*arg == '-')
142da2e3ebdSchin 					range[flag] += (hist_max(hp)-1);
143da2e3ebdSchin 				argv++;
144da2e3ebdSchin 				continue;
145da2e3ebdSchin 			}
146da2e3ebdSchin 		}
147da2e3ebdSchin 		/* search for last line starting with string */
148da2e3ebdSchin 		location = hist_find(hp,argv[1],hist_max(hp)-1,0,-1);
149da2e3ebdSchin 		if((range[++flag] = location.hist_command) < 0)
150da2e3ebdSchin 			errormsg(SH_DICT,ERROR_exit(1),e_found,argv[1]);
151da2e3ebdSchin 		argv++;
152da2e3ebdSchin 	}
153da2e3ebdSchin 	if(flag <0)
154da2e3ebdSchin 	{
155da2e3ebdSchin 		/* set default starting range */
156da2e3ebdSchin 		if(lflag)
157da2e3ebdSchin 		{
158da2e3ebdSchin 			flag = hist_max(hp)-16;
159da2e3ebdSchin 			if(flag<1)
160da2e3ebdSchin 				flag = 1;
161da2e3ebdSchin 		}
162da2e3ebdSchin 		else
163da2e3ebdSchin 			flag = hist_max(hp)-2;
164da2e3ebdSchin 		range[0] = flag;
165da2e3ebdSchin 		flag = 0;
166da2e3ebdSchin 	}
167da2e3ebdSchin 	index2 = hist_min(hp);
168da2e3ebdSchin 	if(range[0]<index2)
169da2e3ebdSchin 		range[0] = index2;
170da2e3ebdSchin 	if(flag==0)
171da2e3ebdSchin 		/* set default termination range */
1727c2fbfb3SApril Chin 		range[1] = ((lflag && !edit)?hist_max(hp)-1:range[0]);
173da2e3ebdSchin 	if(range[1]>=(flag=(hist_max(hp) - !lflag)))
174da2e3ebdSchin 		range[1] = flag;
175da2e3ebdSchin 	/* check for valid ranges */
176da2e3ebdSchin 	if(range[1]<index2 || range[0]>=flag)
177da2e3ebdSchin 		errormsg(SH_DICT,ERROR_exit(1),e_badrange,range[0],range[1]);
178da2e3ebdSchin 	if(edit && *edit=='-' && range[0]!=range[1])
179da2e3ebdSchin 		errormsg(SH_DICT,ERROR_exit(1),e_eneedsarg);
180da2e3ebdSchin 	/* now list commands from range[rflag] to range[1-rflag] */
181da2e3ebdSchin 	incr = 1;
182da2e3ebdSchin 	flag = rflag>0;
183da2e3ebdSchin 	if(range[1-flag] < range[flag])
184da2e3ebdSchin 		incr = -1;
185da2e3ebdSchin 	if(lflag)
186da2e3ebdSchin 	{
187da2e3ebdSchin 		outfile = sfstdout;
188da2e3ebdSchin 		arg = "\n\t";
189da2e3ebdSchin 	}
190da2e3ebdSchin 	else
191da2e3ebdSchin 	{
192da2e3ebdSchin 		if(!(fname=pathtmp(NIL(char*),0,0,NIL(int*))))
193da2e3ebdSchin 			errormsg(SH_DICT,ERROR_exit(1),e_create,"");
194da2e3ebdSchin 		if((fdo=open(fname,O_CREAT|O_RDWR,S_IRUSR|S_IWUSR)) < 0)
195da2e3ebdSchin 			errormsg(SH_DICT,ERROR_system(1),e_create,fname);
196da2e3ebdSchin 		outfile= sfnew(NIL(Sfio_t*),shp->outbuff,IOBSIZE,fdo,SF_WRITE);
197da2e3ebdSchin 		arg = "\n";
198da2e3ebdSchin 		nflag++;
199da2e3ebdSchin 	}
200da2e3ebdSchin 	while(1)
201da2e3ebdSchin 	{
202da2e3ebdSchin 		if(nflag==0)
203da2e3ebdSchin 			sfprintf(outfile,"%d\t",range[flag]);
204da2e3ebdSchin 		else if(lflag)
205da2e3ebdSchin 			sfputc(outfile,'\t');
206*b30d1939SAndy Fiddaman 		hist_list(shp->gd->hist_ptr,outfile,hist_tell(shp->gd->hist_ptr,range[flag]),0,arg);
207da2e3ebdSchin 		if(lflag)
208*b30d1939SAndy Fiddaman 			sh_sigcheck(shp);
209da2e3ebdSchin 		if(range[flag] == range[1-flag])
210da2e3ebdSchin 			break;
211da2e3ebdSchin 		range[flag] += incr;
212da2e3ebdSchin 	}
213da2e3ebdSchin 	if(lflag)
214da2e3ebdSchin 		return(0);
215da2e3ebdSchin 	sfclose(outfile);
216da2e3ebdSchin 	hist_eof(hp);
217da2e3ebdSchin 	arg = edit;
2187c2fbfb3SApril Chin 	if(!arg && !(arg=nv_getval(sh_scoped(shp,HISTEDIT))) && !(arg=nv_getval(sh_scoped(shp,FCEDNOD))))
219*b30d1939SAndy Fiddaman 	{
220da2e3ebdSchin 		arg = (char*)e_defedit;
221*b30d1939SAndy Fiddaman 		if(*arg!='/')
222*b30d1939SAndy Fiddaman 			errormsg(SH_DICT,ERROR_exit(1),"ed not found set FCEDIT");
223*b30d1939SAndy Fiddaman 	}
224da2e3ebdSchin #ifdef apollo
225da2e3ebdSchin 	/*
226da2e3ebdSchin 	 * Code to support the FC using the pad editor.
227da2e3ebdSchin 	 * Exampled of how to use: HISTEDIT=pad
228da2e3ebdSchin 	 */
229da2e3ebdSchin 	if (strcmp (arg, "pad") == 0)
230da2e3ebdSchin 	{
231da2e3ebdSchin 		extern int pad_create(char*);
232da2e3ebdSchin 		sh_close(fdo);
233da2e3ebdSchin 		fdo = pad_create(fname);
234da2e3ebdSchin 		pad_wait(fdo);
235da2e3ebdSchin 		unlink(fname);
236da2e3ebdSchin 		strcat(fname, ".bak");
237da2e3ebdSchin 		unlink(fname);
238da2e3ebdSchin 		lseek(fdo,(off_t)0,SEEK_SET);
239da2e3ebdSchin 	}
240da2e3ebdSchin 	else
241da2e3ebdSchin 	{
242da2e3ebdSchin #endif /* apollo */
243da2e3ebdSchin 	if(*arg != '-')
244da2e3ebdSchin 	{
245da2e3ebdSchin 		char *com[3];
246da2e3ebdSchin 		com[0] =  arg;
247da2e3ebdSchin 		com[1] =  fname;
248da2e3ebdSchin 		com[2] = 0;
249da2e3ebdSchin 		error_info.errors = sh_eval(sh_sfeval(com),0);
250da2e3ebdSchin 	}
251da2e3ebdSchin 	fdo = sh_chkopen(fname);
252da2e3ebdSchin 	unlink(fname);
253da2e3ebdSchin 	free((void*)fname);
254da2e3ebdSchin #ifdef apollo
255da2e3ebdSchin 	}
256da2e3ebdSchin #endif /* apollo */
257da2e3ebdSchin 	/* don't history fc itself unless forked */
258da2e3ebdSchin 	error_info.flags |= ERROR_SILENT;
259da2e3ebdSchin 	if(!sh_isstate(SH_FORKED))
260da2e3ebdSchin 		hist_cancel(hp);
261da2e3ebdSchin 	sh_onstate(SH_HISTORY);
262da2e3ebdSchin 	sh_onstate(SH_VERBOSE);	/* echo lines as read */
263da2e3ebdSchin 	if(replace)
264da2e3ebdSchin 		hist_subst(error_info.id,fdo,replace);
265da2e3ebdSchin 	else if(error_info.errors == 0)
266da2e3ebdSchin 	{
267da2e3ebdSchin 		char buff[IOBSIZE+1];
268da2e3ebdSchin 		Sfio_t *iop = sfnew(NIL(Sfio_t*),buff,IOBSIZE,fdo,SF_READ);
269da2e3ebdSchin 		/* read in and run the command */
270da2e3ebdSchin 		if(shp->hist_depth++ > HIST_RECURSE)
271da2e3ebdSchin 			errormsg(SH_DICT,ERROR_exit(1),e_toodeep,"history");
272da2e3ebdSchin 		sh_eval(iop,1);
273da2e3ebdSchin 		shp->hist_depth--;
274da2e3ebdSchin 	}
275da2e3ebdSchin 	else
276da2e3ebdSchin 	{
277da2e3ebdSchin 		sh_close(fdo);
278da2e3ebdSchin 		if(!sh_isoption(SH_VERBOSE))
279da2e3ebdSchin 			sh_offstate(SH_VERBOSE);
280da2e3ebdSchin 		sh_offstate(SH_HISTORY);
281da2e3ebdSchin 	}
282da2e3ebdSchin 	return(shp->exitval);
283da2e3ebdSchin }
284da2e3ebdSchin 
285da2e3ebdSchin 
286da2e3ebdSchin /*
287da2e3ebdSchin  * given a file containing a command and a string of the form old=new,
288da2e3ebdSchin  * execute the command with the string old replaced by new
289da2e3ebdSchin  */
290da2e3ebdSchin 
hist_subst(const char * command,int fd,char * replace)291da2e3ebdSchin static void hist_subst(const char *command,int fd,char *replace)
292da2e3ebdSchin {
293da2e3ebdSchin 	register char *newp=replace;
294da2e3ebdSchin 	register char *sp;
295da2e3ebdSchin 	register int c;
296da2e3ebdSchin 	off_t size;
297da2e3ebdSchin 	char *string;
298da2e3ebdSchin 	while(*++newp != '='); /* skip to '=' */
299da2e3ebdSchin 	if((size = lseek(fd,(off_t)0,SEEK_END)) < 0)
300da2e3ebdSchin 		return;
301da2e3ebdSchin 	lseek(fd,(off_t)0,SEEK_SET);
302da2e3ebdSchin 	c =  (int)size;
303da2e3ebdSchin 	string = stakalloc(c+1);
304da2e3ebdSchin 	if(read(fd,string,c)!=c)
305da2e3ebdSchin 		return;
306da2e3ebdSchin 	string[c] = 0;
307da2e3ebdSchin 	*newp++ =  0;
308da2e3ebdSchin 	if((sp=sh_substitute(string,replace,newp))==0)
309da2e3ebdSchin 		errormsg(SH_DICT,ERROR_exit(1),e_subst,command);
310da2e3ebdSchin 	*(newp-1) =  '=';
311da2e3ebdSchin 	sh_eval(sfopen(NIL(Sfio_t*),sp,"s"),1);
312da2e3ebdSchin }
313da2e3ebdSchin 
314