1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1982-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * David Korn <dgk@research.att.com> *
19 ***********************************************************************/
25 #include "variables.h"
34 #define HIST_RECURSE 5
36 static void hist_subst(const char*, int fd
, char*);
39 /* for the benefit of the dictionary generator */
40 int b_fc(int argc
,char *argv
[], void *extra
){}
42 int b_hist(int argc
,char *argv
[], void *extra
)
44 register History_t
*hp
;
46 register int flag
,fdo
;
47 register Shell_t
*shp
= ((Shbltin_t
*)extra
)->shp
;
50 int range
[2], incr
, index2
, indx
= -1;
51 char *edit
= 0; /* name of editor */
52 char *replace
= 0; /* replace old=new */
53 int lflag
= 0, nflag
= 0, rflag
= 0;
59 if(!sh_histinit((void*)shp
))
60 errormsg(SH_DICT
,ERROR_system(1),e_histopen
);
62 while((flag
= optget(argv
,sh_opthist
))) switch(flag
)
87 if((flag
= hist_max(hp
) - opt_info
.num
-1) < 0)
93 errormsg(SH_DICT
,2, "%s", opt_info
.arg
);
96 errormsg(SH_DICT
,ERROR_usage(2), "%s", opt_info
.arg
);
100 errormsg(SH_DICT
,ERROR_usage(2),"%s",optusage((char*)0));
101 argv
+= (opt_info
.index
-1);
109 flag
= hist_expand(arg
,&replace
);
110 if(!(flag
& HIST_ERROR
))
111 sfputr(sfstdout
, replace
, '\n');
122 while(flag
<1 && (arg
=argv
[1]))
124 /* look for old=new argument */
125 if(!replace
&& strchr(arg
+1,'='))
131 else if(isdigit(*arg
) || *arg
== '-')
133 /* see if completely numeric */
135 while(isdigit(*arg
));
139 range
[++flag
] = (int)strtol(arg
, (char**)0, 10);
141 range
[flag
] += (hist_max(hp
)-1);
146 /* search for last line starting with string */
147 location
= hist_find(hp
,argv
[1],hist_max(hp
)-1,0,-1);
148 if((range
[++flag
] = location
.hist_command
) < 0)
149 errormsg(SH_DICT
,ERROR_exit(1),e_found
,argv
[1]);
154 /* set default starting range */
157 flag
= hist_max(hp
)-16;
162 flag
= hist_max(hp
)-2;
166 index2
= hist_min(hp
);
170 /* set default termination range */
171 range
[1] = ((lflag
&& !edit
)?hist_max(hp
)-1:range
[0]);
172 if(range
[1]>=(flag
=(hist_max(hp
) - !lflag
)))
174 /* check for valid ranges */
175 if(range
[1]<index2
|| range
[0]>=flag
)
176 errormsg(SH_DICT
,ERROR_exit(1),e_badrange
,range
[0],range
[1]);
177 if(edit
&& *edit
=='-' && range
[0]!=range
[1])
178 errormsg(SH_DICT
,ERROR_exit(1),e_eneedsarg
);
179 /* now list commands from range[rflag] to range[1-rflag] */
182 if(range
[1-flag
] < range
[flag
])
191 if(!(fname
=pathtmp(NIL(char*),0,0,NIL(int*))))
192 errormsg(SH_DICT
,ERROR_exit(1),e_create
,"");
193 if((fdo
=open(fname
,O_CREAT
|O_RDWR
,S_IRUSR
|S_IWUSR
)) < 0)
194 errormsg(SH_DICT
,ERROR_system(1),e_create
,fname
);
195 outfile
= sfnew(NIL(Sfio_t
*),shp
->outbuff
,IOBSIZE
,fdo
,SF_WRITE
);
202 sfprintf(outfile
,"%d\t",range
[flag
]);
204 sfputc(outfile
,'\t');
205 hist_list(shp
->hist_ptr
,outfile
,hist_tell(shp
->hist_ptr
,range
[flag
]),0,arg
);
208 if(range
[flag
] == range
[1-flag
])
217 if(!arg
&& !(arg
=nv_getval(sh_scoped(shp
,HISTEDIT
))) && !(arg
=nv_getval(sh_scoped(shp
,FCEDNOD
))))
218 arg
= (char*)e_defedit
;
221 * Code to support the FC using the pad editor.
222 * Exampled of how to use: HISTEDIT=pad
224 if (strcmp (arg
, "pad") == 0)
226 extern int pad_create(char*);
228 fdo
= pad_create(fname
);
231 strcat(fname
, ".bak");
233 lseek(fdo
,(off_t
)0,SEEK_SET
);
244 error_info
.errors
= sh_eval(sh_sfeval(com
),0);
246 fdo
= sh_chkopen(fname
);
252 /* don't history fc itself unless forked */
253 error_info
.flags
|= ERROR_SILENT
;
254 if(!sh_isstate(SH_FORKED
))
256 sh_onstate(SH_HISTORY
);
257 sh_onstate(SH_VERBOSE
); /* echo lines as read */
259 hist_subst(error_info
.id
,fdo
,replace
);
260 else if(error_info
.errors
== 0)
262 char buff
[IOBSIZE
+1];
263 Sfio_t
*iop
= sfnew(NIL(Sfio_t
*),buff
,IOBSIZE
,fdo
,SF_READ
);
264 /* read in and run the command */
265 if(shp
->hist_depth
++ > HIST_RECURSE
)
266 errormsg(SH_DICT
,ERROR_exit(1),e_toodeep
,"history");
273 if(!sh_isoption(SH_VERBOSE
))
274 sh_offstate(SH_VERBOSE
);
275 sh_offstate(SH_HISTORY
);
277 return(shp
->exitval
);
282 * given a file containing a command and a string of the form old=new,
283 * execute the command with the string old replaced by new
286 static void hist_subst(const char *command
,int fd
,char *replace
)
288 register char *newp
=replace
;
293 while(*++newp
!= '='); /* skip to '=' */
294 if((size
= lseek(fd
,(off_t
)0,SEEK_END
)) < 0)
296 lseek(fd
,(off_t
)0,SEEK_SET
);
298 string
= stakalloc(c
+1);
299 if(read(fd
,string
,c
)!=c
)
303 if((sp
=sh_substitute(string
,replace
,newp
))==0)
304 errormsg(SH_DICT
,ERROR_exit(1),e_subst
,command
);
306 sh_eval(sfopen(NIL(Sfio_t
*),sp
,"s"),1);