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');
121 while(flag
<1 && (arg
=argv
[1]))
123 /* look for old=new argument */
124 if(!replace
&& strchr(arg
+1,'='))
130 else if(isdigit(*arg
) || *arg
== '-')
132 /* see if completely numeric */
134 while(isdigit(*arg
));
138 range
[++flag
] = (int)strtol(arg
, (char**)0, 10);
140 range
[flag
] += (hist_max(hp
)-1);
145 /* search for last line starting with string */
146 location
= hist_find(hp
,argv
[1],hist_max(hp
)-1,0,-1);
147 if((range
[++flag
] = location
.hist_command
) < 0)
148 errormsg(SH_DICT
,ERROR_exit(1),e_found
,argv
[1]);
153 /* set default starting range */
156 flag
= hist_max(hp
)-16;
161 flag
= hist_max(hp
)-2;
165 index2
= hist_min(hp
);
169 /* set default termination range */
170 range
[1] = ((lflag
&& !edit
)?hist_max(hp
)-1:range
[0]);
171 if(range
[1]>=(flag
=(hist_max(hp
) - !lflag
)))
173 /* check for valid ranges */
174 if(range
[1]<index2
|| range
[0]>=flag
)
175 errormsg(SH_DICT
,ERROR_exit(1),e_badrange
,range
[0],range
[1]);
176 if(edit
&& *edit
=='-' && range
[0]!=range
[1])
177 errormsg(SH_DICT
,ERROR_exit(1),e_eneedsarg
);
178 /* now list commands from range[rflag] to range[1-rflag] */
181 if(range
[1-flag
] < range
[flag
])
190 if(!(fname
=pathtmp(NIL(char*),0,0,NIL(int*))))
191 errormsg(SH_DICT
,ERROR_exit(1),e_create
,"");
192 if((fdo
=open(fname
,O_CREAT
|O_RDWR
,S_IRUSR
|S_IWUSR
)) < 0)
193 errormsg(SH_DICT
,ERROR_system(1),e_create
,fname
);
194 outfile
= sfnew(NIL(Sfio_t
*),shp
->outbuff
,IOBSIZE
,fdo
,SF_WRITE
);
201 sfprintf(outfile
,"%d\t",range
[flag
]);
203 sfputc(outfile
,'\t');
204 hist_list(shp
->hist_ptr
,outfile
,hist_tell(shp
->hist_ptr
,range
[flag
]),0,arg
);
207 if(range
[flag
] == range
[1-flag
])
216 if(!arg
&& !(arg
=nv_getval(sh_scoped(shp
,HISTEDIT
))) && !(arg
=nv_getval(sh_scoped(shp
,FCEDNOD
))))
217 arg
= (char*)e_defedit
;
220 * Code to support the FC using the pad editor.
221 * Exampled of how to use: HISTEDIT=pad
223 if (strcmp (arg
, "pad") == 0)
225 extern int pad_create(char*);
227 fdo
= pad_create(fname
);
230 strcat(fname
, ".bak");
232 lseek(fdo
,(off_t
)0,SEEK_SET
);
243 error_info
.errors
= sh_eval(sh_sfeval(com
),0);
245 fdo
= sh_chkopen(fname
);
251 /* don't history fc itself unless forked */
252 error_info
.flags
|= ERROR_SILENT
;
253 if(!sh_isstate(SH_FORKED
))
255 sh_onstate(SH_HISTORY
);
256 sh_onstate(SH_VERBOSE
); /* echo lines as read */
258 hist_subst(error_info
.id
,fdo
,replace
);
259 else if(error_info
.errors
== 0)
261 char buff
[IOBSIZE
+1];
262 Sfio_t
*iop
= sfnew(NIL(Sfio_t
*),buff
,IOBSIZE
,fdo
,SF_READ
);
263 /* read in and run the command */
264 if(shp
->hist_depth
++ > HIST_RECURSE
)
265 errormsg(SH_DICT
,ERROR_exit(1),e_toodeep
,"history");
272 if(!sh_isoption(SH_VERBOSE
))
273 sh_offstate(SH_VERBOSE
);
274 sh_offstate(SH_HISTORY
);
276 return(shp
->exitval
);
281 * given a file containing a command and a string of the form old=new,
282 * execute the command with the string old replaced by new
285 static void hist_subst(const char *command
,int fd
,char *replace
)
287 register char *newp
=replace
;
292 while(*++newp
!= '='); /* skip to '=' */
293 if((size
= lseek(fd
,(off_t
)0,SEEK_END
)) < 0)
295 lseek(fd
,(off_t
)0,SEEK_SET
);
297 string
= stakalloc(c
+1);
298 if(read(fd
,string
,c
)!=c
)
302 if((sp
=sh_substitute(string
,replace
,newp
))==0)
303 errormsg(SH_DICT
,ERROR_exit(1),e_subst
,command
);
305 sh_eval(sfopen(NIL(Sfio_t
*),sp
,"s"),1);