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 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 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