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