14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1982-2010 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.Chin@Sun.COM * by AT&T Intellectual Property *
84887Schin * *
94887Schin * A copy of the License is available at *
104887Schin * http://www.opensource.org/licenses/cpl1.0.txt *
114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
124887Schin * *
134887Schin * Information and Software Systems Research *
144887Schin * AT&T Research *
154887Schin * Florham Park NJ *
164887Schin * *
174887Schin * David Korn <dgk@research.att.com> *
184887Schin * *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin #include "defs.h"
224887Schin #include <stak.h>
234887Schin #include <ls.h>
244887Schin #include <error.h>
254887Schin #include "variables.h"
264887Schin #include "io.h"
274887Schin #include "name.h"
284887Schin #include "history.h"
294887Schin #include "builtins.h"
304887Schin #if SHOPT_HISTEXPAND
314887Schin # include "edit.h"
324887Schin #endif
334887Schin
344887Schin #define HIST_RECURSE 5
354887Schin
364887Schin static void hist_subst(const char*, int fd, char*);
374887Schin
384887Schin #if 0
394887Schin /* for the benefit of the dictionary generator */
404887Schin int b_fc(int argc,char *argv[], void *extra){}
414887Schin #endif
b_hist(int argc,char * argv[],void * extra)424887Schin int b_hist(int argc,char *argv[], void *extra)
434887Schin {
444887Schin register History_t *hp;
454887Schin register char *arg;
464887Schin register int flag,fdo;
478462SApril.Chin@Sun.COM register Shell_t *shp = ((Shbltin_t*)extra)->shp;
484887Schin Sfio_t *outfile;
494887Schin char *fname;
504887Schin int range[2], incr, index2, indx= -1;
514887Schin char *edit = 0; /* name of editor */
524887Schin char *replace = 0; /* replace old=new */
534887Schin int lflag = 0, nflag = 0, rflag = 0;
544887Schin #if SHOPT_HISTEXPAND
554887Schin int pflag = 0;
564887Schin #endif
574887Schin Histloc_t location;
584887Schin NOT_USED(argc);
598462SApril.Chin@Sun.COM if(!sh_histinit((void*)shp))
604887Schin errormsg(SH_DICT,ERROR_system(1),e_histopen);
614887Schin hp = shp->hist_ptr;
624887Schin while((flag = optget(argv,sh_opthist))) switch(flag)
634887Schin {
644887Schin case 'e':
654887Schin edit = opt_info.arg;
664887Schin break;
674887Schin case 'n':
684887Schin nflag++;
694887Schin break;
704887Schin case 'l':
714887Schin lflag++;
724887Schin break;
734887Schin case 'r':
744887Schin rflag++;
754887Schin break;
764887Schin case 's':
774887Schin edit = "-";
784887Schin break;
794887Schin #if SHOPT_HISTEXPAND
804887Schin case 'p':
814887Schin pflag++;
824887Schin break;
834887Schin #endif
844887Schin case 'N':
854887Schin if(indx<=0)
864887Schin {
874887Schin if((flag = hist_max(hp) - opt_info.num-1) < 0)
884887Schin flag = 1;
894887Schin range[++indx] = flag;
904887Schin break;
914887Schin }
924887Schin case ':':
934887Schin errormsg(SH_DICT,2, "%s", opt_info.arg);
944887Schin break;
954887Schin case '?':
964887Schin errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
974887Schin break;
984887Schin }
994887Schin if(error_info.errors)
1004887Schin errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
1014887Schin argv += (opt_info.index-1);
1024887Schin #if SHOPT_HISTEXPAND
1034887Schin if(pflag)
1044887Schin {
1054887Schin hist_cancel(hp);
1064887Schin pflag = 0;
1074887Schin while(arg=argv[1])
1084887Schin {
1094887Schin flag = hist_expand(arg,&replace);
1104887Schin if(!(flag & HIST_ERROR))
1114887Schin sfputr(sfstdout, replace, '\n');
1124887Schin else
1134887Schin pflag = 1;
1144887Schin if(replace)
1154887Schin free(replace);
1164887Schin argv++;
1174887Schin }
1184887Schin return pflag;
1194887Schin }
1204887Schin #endif
1214887Schin flag = indx;
1224887Schin while(flag<1 && (arg=argv[1]))
1234887Schin {
1244887Schin /* look for old=new argument */
1254887Schin if(!replace && strchr(arg+1,'='))
1264887Schin {
1274887Schin replace = arg;
1284887Schin argv++;
1294887Schin continue;
1304887Schin }
1314887Schin else if(isdigit(*arg) || *arg == '-')
1324887Schin {
1334887Schin /* see if completely numeric */
1344887Schin do arg++;
1354887Schin while(isdigit(*arg));
1364887Schin if(*arg==0)
1374887Schin {
1384887Schin arg = argv[1];
1394887Schin range[++flag] = (int)strtol(arg, (char**)0, 10);
1404887Schin if(*arg == '-')
1414887Schin range[flag] += (hist_max(hp)-1);
1424887Schin argv++;
1434887Schin continue;
1444887Schin }
1454887Schin }
1464887Schin /* search for last line starting with string */
1474887Schin location = hist_find(hp,argv[1],hist_max(hp)-1,0,-1);
1484887Schin if((range[++flag] = location.hist_command) < 0)
1494887Schin errormsg(SH_DICT,ERROR_exit(1),e_found,argv[1]);
1504887Schin argv++;
1514887Schin }
1524887Schin if(flag <0)
1534887Schin {
1544887Schin /* set default starting range */
1554887Schin if(lflag)
1564887Schin {
1574887Schin flag = hist_max(hp)-16;
1584887Schin if(flag<1)
1594887Schin flag = 1;
1604887Schin }
1614887Schin else
1624887Schin flag = hist_max(hp)-2;
1634887Schin range[0] = flag;
1644887Schin flag = 0;
1654887Schin }
1664887Schin index2 = hist_min(hp);
1674887Schin if(range[0]<index2)
1684887Schin range[0] = index2;
1694887Schin if(flag==0)
1704887Schin /* set default termination range */
1718462SApril.Chin@Sun.COM range[1] = ((lflag && !edit)?hist_max(hp)-1:range[0]);
1724887Schin if(range[1]>=(flag=(hist_max(hp) - !lflag)))
1734887Schin range[1] = flag;
1744887Schin /* check for valid ranges */
1754887Schin if(range[1]<index2 || range[0]>=flag)
1764887Schin errormsg(SH_DICT,ERROR_exit(1),e_badrange,range[0],range[1]);
1774887Schin if(edit && *edit=='-' && range[0]!=range[1])
1784887Schin errormsg(SH_DICT,ERROR_exit(1),e_eneedsarg);
1794887Schin /* now list commands from range[rflag] to range[1-rflag] */
1804887Schin incr = 1;
1814887Schin flag = rflag>0;
1824887Schin if(range[1-flag] < range[flag])
1834887Schin incr = -1;
1844887Schin if(lflag)
1854887Schin {
1864887Schin outfile = sfstdout;
1874887Schin arg = "\n\t";
1884887Schin }
1894887Schin else
1904887Schin {
1914887Schin if(!(fname=pathtmp(NIL(char*),0,0,NIL(int*))))
1924887Schin errormsg(SH_DICT,ERROR_exit(1),e_create,"");
1934887Schin if((fdo=open(fname,O_CREAT|O_RDWR,S_IRUSR|S_IWUSR)) < 0)
1944887Schin errormsg(SH_DICT,ERROR_system(1),e_create,fname);
1954887Schin outfile= sfnew(NIL(Sfio_t*),shp->outbuff,IOBSIZE,fdo,SF_WRITE);
1964887Schin arg = "\n";
1974887Schin nflag++;
1984887Schin }
1994887Schin while(1)
2004887Schin {
2014887Schin if(nflag==0)
2024887Schin sfprintf(outfile,"%d\t",range[flag]);
2034887Schin else if(lflag)
2044887Schin sfputc(outfile,'\t');
2054887Schin hist_list(shp->hist_ptr,outfile,hist_tell(shp->hist_ptr,range[flag]),0,arg);
2064887Schin if(lflag)
2074887Schin sh_sigcheck();
2084887Schin if(range[flag] == range[1-flag])
2094887Schin break;
2104887Schin range[flag] += incr;
2114887Schin }
2124887Schin if(lflag)
2134887Schin return(0);
2144887Schin sfclose(outfile);
2154887Schin hist_eof(hp);
2164887Schin arg = edit;
2178462SApril.Chin@Sun.COM if(!arg && !(arg=nv_getval(sh_scoped(shp,HISTEDIT))) && !(arg=nv_getval(sh_scoped(shp,FCEDNOD))))
2184887Schin arg = (char*)e_defedit;
2194887Schin #ifdef apollo
2204887Schin /*
2214887Schin * Code to support the FC using the pad editor.
2224887Schin * Exampled of how to use: HISTEDIT=pad
2234887Schin */
2244887Schin if (strcmp (arg, "pad") == 0)
2254887Schin {
2264887Schin extern int pad_create(char*);
2274887Schin sh_close(fdo);
2284887Schin fdo = pad_create(fname);
2294887Schin pad_wait(fdo);
2304887Schin unlink(fname);
2314887Schin strcat(fname, ".bak");
2324887Schin unlink(fname);
2334887Schin lseek(fdo,(off_t)0,SEEK_SET);
2344887Schin }
2354887Schin else
2364887Schin {
2374887Schin #endif /* apollo */
2384887Schin if(*arg != '-')
2394887Schin {
2404887Schin char *com[3];
2414887Schin com[0] = arg;
2424887Schin com[1] = fname;
2434887Schin com[2] = 0;
2444887Schin error_info.errors = sh_eval(sh_sfeval(com),0);
2454887Schin }
2464887Schin fdo = sh_chkopen(fname);
2474887Schin unlink(fname);
2484887Schin free((void*)fname);
2494887Schin #ifdef apollo
2504887Schin }
2514887Schin #endif /* apollo */
2524887Schin /* don't history fc itself unless forked */
2534887Schin error_info.flags |= ERROR_SILENT;
2544887Schin if(!sh_isstate(SH_FORKED))
2554887Schin hist_cancel(hp);
2564887Schin sh_onstate(SH_HISTORY);
2574887Schin sh_onstate(SH_VERBOSE); /* echo lines as read */
2584887Schin if(replace)
2594887Schin hist_subst(error_info.id,fdo,replace);
2604887Schin else if(error_info.errors == 0)
2614887Schin {
2624887Schin char buff[IOBSIZE+1];
2634887Schin Sfio_t *iop = sfnew(NIL(Sfio_t*),buff,IOBSIZE,fdo,SF_READ);
2644887Schin /* read in and run the command */
2654887Schin if(shp->hist_depth++ > HIST_RECURSE)
2664887Schin errormsg(SH_DICT,ERROR_exit(1),e_toodeep,"history");
2674887Schin sh_eval(iop,1);
2684887Schin shp->hist_depth--;
2694887Schin }
2704887Schin else
2714887Schin {
2724887Schin sh_close(fdo);
2734887Schin if(!sh_isoption(SH_VERBOSE))
2744887Schin sh_offstate(SH_VERBOSE);
2754887Schin sh_offstate(SH_HISTORY);
2764887Schin }
2774887Schin return(shp->exitval);
2784887Schin }
2794887Schin
2804887Schin
2814887Schin /*
2824887Schin * given a file containing a command and a string of the form old=new,
2834887Schin * execute the command with the string old replaced by new
2844887Schin */
2854887Schin
hist_subst(const char * command,int fd,char * replace)2864887Schin static void hist_subst(const char *command,int fd,char *replace)
2874887Schin {
2884887Schin register char *newp=replace;
2894887Schin register char *sp;
2904887Schin register int c;
2914887Schin off_t size;
2924887Schin char *string;
2934887Schin while(*++newp != '='); /* skip to '=' */
2944887Schin if((size = lseek(fd,(off_t)0,SEEK_END)) < 0)
2954887Schin return;
2964887Schin lseek(fd,(off_t)0,SEEK_SET);
2974887Schin c = (int)size;
2984887Schin string = stakalloc(c+1);
2994887Schin if(read(fd,string,c)!=c)
3004887Schin return;
3014887Schin string[c] = 0;
3024887Schin *newp++ = 0;
3034887Schin if((sp=sh_substitute(string,replace,newp))==0)
3044887Schin errormsg(SH_DICT,ERROR_exit(1),e_subst,command);
3054887Schin *(newp-1) = '=';
3064887Schin sh_eval(sfopen(NIL(Sfio_t*),sp,"s"),1);
3074887Schin }
3084887Schin
309