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