1*35144Smarc /*
2*35144Smarc
3*35144Smarc * Copyright (c) 1984, 1985, 1986 AT&T
4*35144Smarc * All Rights Reserved
5*35144Smarc
6*35144Smarc * THIS IS UNPUBLISHED PROPRIETARY SOURCE
7*35144Smarc * CODE OF AT&T.
8*35144Smarc * The copyright notice above does not
9*35144Smarc * evidence any actual or intended
10*35144Smarc * publication of such source code.
11*35144Smarc
12*35144Smarc */
13*35144Smarc /* @(#)history.c 1.1 */
14*35144Smarc
15*35144Smarc /*
16*35144Smarc * History file manipulation routines
17*35144Smarc *
18*35144Smarc * David Korn
19*35144Smarc * AT&T Bell Laboratories
20*35144Smarc * Room 5D-112
21*35144Smarc * Murray Hill, N. J. 07974
22*35144Smarc * Tel. x7975
23*35144Smarc *
24*35144Smarc */
25*35144Smarc
26*35144Smarc
27*35144Smarc /*
28*35144Smarc * Each command in the history file starts on an even byte is null terminated.
29*35144Smarc * The first byte must contain the special character H_UNDO and the second
30*35144Smarc * byte is the version number. The sequence H_UNDO 0, following a command,
31*35144Smarc * nullifies the previous command. A six byte sequence starting with
32*35144Smarc * H_CMDNO is used to store the command number so that it is not necessary
33*35144Smarc * to read the file from beginning to end to get to the last block of
34*35144Smarc * commands. This format of this sequence is different in version 1
35*35144Smarc * then in version 0. Version 1 allows commands to use the full 8 bit
36*35144Smarc * character set. It can understand version 0 format files.
37*35144Smarc */
38*35144Smarc
39*35144Smarc
40*35144Smarc #ifdef KSHELL
41*35144Smarc #include "defs.h"
42*35144Smarc #include "io.h"
43*35144Smarc #include "flags.h"
44*35144Smarc #include "name.h"
45*35144Smarc #include "shtype.h"
46*35144Smarc #include "stak.h"
47*35144Smarc #include "brkincr.h"
48*35144Smarc #include "builtins.h"
49*35144Smarc #else
50*35144Smarc #include <stdio.h>
51*35144Smarc #include <setjmp.h>
52*35144Smarc #include <signal.h>
53*35144Smarc #include <ctype.h>
54*35144Smarc #endif /* KSHELL */
55*35144Smarc
56*35144Smarc #include "history.h"
57*35144Smarc #ifdef MULTIBYTE
58*35144Smarc #include "national.h"
59*35144Smarc #endif /* MULTIBYTE */
60*35144Smarc
61*35144Smarc int hist_open();
62*35144Smarc void hist_close();
63*35144Smarc long hist_list();
64*35144Smarc void hist_flush();
65*35144Smarc void hist_cancel();
66*35144Smarc void hist_eof();
67*35144Smarc histloc hist_find();
68*35144Smarc #ifdef ESH
69*35144Smarc histloc hist_locate();
70*35144Smarc #endif /* ESH */
71*35144Smarc long hist_position();
72*35144Smarc #ifdef KSHELL
73*35144Smarc void hist_subst();
74*35144Smarc #endif /* KSHELL */
75*35144Smarc
76*35144Smarc #ifdef KSHELL
77*35144Smarc extern char *valup();
78*35144Smarc extern long aeval();
79*35144Smarc extern FILE *chkrdwr();
80*35144Smarc extern FILE *create();
81*35144Smarc extern void failed();
82*35144Smarc extern void p_str();
83*35144Smarc #else
84*35144Smarc #define frenumber hist_rename
85*35144Smarc #define tmp_open(s) tmpfile()
86*35144Smarc #define p_str(s,c) (fputs(s,stderr),putc(c,stderr))
87*35144Smarc #define closefd(f) fclose(f)
88*35144Smarc #define aeval(str) atoi(str)
89*35144Smarc #define TMPSIZ 20
90*35144Smarc #define NL '\n'
91*35144Smarc #define output stderr
92*35144Smarc struct fixcmd *fc_fix;
93*35144Smarc extern char *getenv();
94*35144Smarc extern FILE *hist_rename();
95*35144Smarc char login_sh = 0;
96*35144Smarc MSG histfname = "./history";
97*35144Smarc #define unknown "unknown"
98*35144Smarc #endif /* KSHELL */
99*35144Smarc extern char *substitute();
100*35144Smarc extern FILE *tmp_open();
101*35144Smarc extern long lseek();
102*35144Smarc extern char *malloc();
103*35144Smarc extern char *movstr();
104*35144Smarc extern void free();
105*35144Smarc
106*35144Smarc static int fixmask;
107*35144Smarc static void hist_trim();
108*35144Smarc static int hist_nearend();
109*35144Smarc static int hist_check();
110*35144Smarc static int hist_version;
111*35144Smarc static int heof;
112*35144Smarc
113*35144Smarc
114*35144Smarc /*
115*35144Smarc * open the history file
116*35144Smarc * if HISTNAME is not given and userid==0 then no history file.
117*35144Smarc * if login_sh and HISTFILE is longer than HISTMAX bytes then it is
118*35144Smarc * cleaned up.
119*35144Smarc */
hist_open()120*35144Smarc int hist_open()
121*35144Smarc {
122*35144Smarc register FILE *fd;
123*35144Smarc register struct fixcmd *fp;
124*35144Smarc register char *histname;
125*35144Smarc char fname[TMPSIZ];
126*35144Smarc char hname[256];
127*35144Smarc int maxlines;
128*35144Smarc register char *cp;
129*35144Smarc register long hsize = 0;
130*35144Smarc int his_start;
131*35144Smarc
132*35144Smarc if(fc_fix)
133*35144Smarc return(0);
134*35144Smarc histname = valup(HISTFILE);
135*35144Smarc if(histname==NULL)
136*35144Smarc {
137*35144Smarc #ifdef KSHELL
138*35144Smarc if(userid==0 && login_sh)
139*35144Smarc return(-1);
140*35144Smarc #endif /* KSHELL */
141*35144Smarc cp = movstr(valup(HOME),hname);
142*35144Smarc movstr(histfname,cp);
143*35144Smarc histname = hname;
144*35144Smarc }
145*35144Smarc *fname = 0;
146*35144Smarc retry:
147*35144Smarc /* first try to open the current file */
148*35144Smarc #ifdef KSHELL
149*35144Smarc if((fd=fdopen(open(histname,012),"a+"))==NULL)
150*35144Smarc {
151*35144Smarc /* if you can't then try to create it */
152*35144Smarc if(fd=create(histname))
153*35144Smarc {
154*35144Smarc fd = chkrdwr(histname,fd);
155*35144Smarc chmod(histname,0600);
156*35144Smarc }
157*35144Smarc }
158*35144Smarc else
159*35144Smarc hsize=lseek(fileno(fd),0L,2);
160*35144Smarc #else
161*35144Smarc if(fd=fopen(histname,"a+"))
162*35144Smarc {
163*35144Smarc chmod(histname,0600);
164*35144Smarc hsize=lseek(fileno(fd),0L,2);
165*35144Smarc }
166*35144Smarc #endif /* KSHELL */
167*35144Smarc /* make sure that file has history file format */
168*35144Smarc if(hsize && hist_check(fd))
169*35144Smarc {
170*35144Smarc fclose(fd);
171*35144Smarc unlink(histname);
172*35144Smarc hsize = 0;
173*35144Smarc goto retry;
174*35144Smarc }
175*35144Smarc if(fd == NULL)
176*35144Smarc fd = tmp_open(fname);
177*35144Smarc if(fd==NULL)
178*35144Smarc return(-1);
179*35144Smarc fd = frenumber(fd,FCIO);
180*35144Smarc if(cp=valup(HISTSIZE))
181*35144Smarc maxlines = (unsigned)aeval(cp);
182*35144Smarc else
183*35144Smarc maxlines = HIS_DFLT;
184*35144Smarc for(fixmask=16;fixmask <= maxlines; fixmask <<=1 );
185*35144Smarc if((fp=(struct fixcmd*)malloc(sizeof(struct fixcmd)+ (--fixmask)*sizeof(long)))==NULL)
186*35144Smarc {
187*35144Smarc fclose(fd);
188*35144Smarc return(-1);
189*35144Smarc }
190*35144Smarc fc_fix = fp;
191*35144Smarc fp->fixfd = fd;
192*35144Smarc fp->fixmax = maxlines;
193*35144Smarc setbuf(fd,malloc(BUFSIZ));
194*35144Smarc fp->fixind = 1;
195*35144Smarc fp->fixline = 0;
196*35144Smarc fp->fixcmds[1] = 2;
197*35144Smarc fp->fixcnt = 2;
198*35144Smarc if(hsize==0)
199*35144Smarc {
200*35144Smarc /* put special characters at front of file */
201*35144Smarc putc(H_UNDO,fd);
202*35144Smarc putc(H_VERSION,fd);
203*35144Smarc fflush(fd);
204*35144Smarc }
205*35144Smarc /* initialize history list */
206*35144Smarc if(hsize)
207*35144Smarc {
208*35144Smarc int nlines = maxlines;
209*35144Smarc long size = hsize - (HISMAX/4);
210*35144Smarc do
211*35144Smarc {
212*35144Smarc size -= ((HISMAX/4) + nlines*HISLINE);
213*35144Smarc his_start = fp->fixind = hist_nearend(fd,size);
214*35144Smarc hist_eof();
215*35144Smarc nlines = maxlines - (fp->fixind-his_start);
216*35144Smarc }
217*35144Smarc while(his_start >1 && nlines>0);
218*35144Smarc }
219*35144Smarc if(*fname)
220*35144Smarc unlink(fname);
221*35144Smarc if(login_sh && his_start>1 && hsize > HISMAX)
222*35144Smarc {
223*35144Smarc FILE *fdo;
224*35144Smarc if((fdo=fdopen(open(histname,0),"r"))==NULL)
225*35144Smarc return(0);
226*35144Smarc unlink(histname);
227*35144Smarc hist_trim(fdo,fp->fixind-maxlines);
228*35144Smarc }
229*35144Smarc return(0);
230*35144Smarc }
231*35144Smarc
232*35144Smarc /*
233*35144Smarc * check history file format to see if it begins with special byte
234*35144Smarc */
235*35144Smarc
hist_check(fd)236*35144Smarc static int hist_check(fd)
237*35144Smarc register FILE *fd;
238*35144Smarc {
239*35144Smarc setbuf(fd,NULL);
240*35144Smarc fseek(fd,0L,0);
241*35144Smarc if(getc(fd) != H_UNDO)
242*35144Smarc return(1);
243*35144Smarc hist_version = getc(fd);
244*35144Smarc return(0);
245*35144Smarc }
246*35144Smarc
247*35144Smarc /*
248*35144Smarc * Copy the last <n> commands to a new file and make this the history file
249*35144Smarc */
250*35144Smarc
hist_trim(fdo,n)251*35144Smarc static void hist_trim(fdo,n)
252*35144Smarc register FILE *fdo;
253*35144Smarc {
254*35144Smarc register FILE *fd;
255*35144Smarc register int c;
256*35144Smarc register struct fixcmd *fp = fc_fix;
257*35144Smarc struct fixcmd *fsave;
258*35144Smarc /* use the old history I/O buffer for fdo */
259*35144Smarc setbuf(fdo,fp->fixfd->_base);
260*35144Smarc setbuf(fp->fixfd,NULL);
261*35144Smarc fc_fix = 0;
262*35144Smarc hist_open();
263*35144Smarc if(fc_fix==0)
264*35144Smarc return;
265*35144Smarc fsave = fc_fix;
266*35144Smarc fd = fc_fix->fixfd;
267*35144Smarc do
268*35144Smarc {
269*35144Smarc fc_fix = fp;
270*35144Smarc fseek(fdo,hist_position(++n),0);
271*35144Smarc fc_fix = fsave;
272*35144Smarc while((c=getc(fdo))!=EOF && c)
273*35144Smarc {
274*35144Smarc putc(c,fd);
275*35144Smarc }
276*35144Smarc #ifdef KSHELL
277*35144Smarc states |= FIXFLG;
278*35144Smarc #endif /* KSHELL */
279*35144Smarc hist_flush();
280*35144Smarc }
281*35144Smarc while(c!=EOF);
282*35144Smarc fclose(fdo);
283*35144Smarc free((char*)fdo->_base);
284*35144Smarc free((char*)fp);
285*35144Smarc }
286*35144Smarc
287*35144Smarc /*
288*35144Smarc * position history file at size and find next command number
289*35144Smarc */
290*35144Smarc
hist_nearend(fd,size)291*35144Smarc static int hist_nearend(fd,size)
292*35144Smarc register FILE *fd;
293*35144Smarc long size;
294*35144Smarc {
295*35144Smarc register int n = 0;
296*35144Smarc register int state = -1;
297*35144Smarc register int c;
298*35144Smarc if(size <=0)
299*35144Smarc goto begin;
300*35144Smarc fseek(fd,size,0);
301*35144Smarc /* skip to numbered command and return the number */
302*35144Smarc /* numbering commands occur after a null and begin with H_CMDNO */
303*35144Smarc while((c=getc(fd))!=EOF)
304*35144Smarc {
305*35144Smarc if(state==5)
306*35144Smarc {
307*35144Smarc return(n);
308*35144Smarc }
309*35144Smarc else if(state>0)
310*35144Smarc {
311*35144Smarc if(state==1)
312*35144Smarc {
313*35144Smarc /* see if H_CMDNO is followed by 0 */
314*35144Smarc if(hist_version && c)
315*35144Smarc {
316*35144Smarc n += 2;
317*35144Smarc state = -1;
318*35144Smarc continue;
319*35144Smarc }
320*35144Smarc n = 0;
321*35144Smarc }
322*35144Smarc if(hist_version)
323*35144Smarc n = (n<<8) + c;
324*35144Smarc else if(state < 3)
325*35144Smarc n = (n<<7) + (c&0177);
326*35144Smarc state++;
327*35144Smarc }
328*35144Smarc else if(state==0 && c==H_CMDNO)
329*35144Smarc {
330*35144Smarc fc_fix->fixcnt = size + n + 6;
331*35144Smarc state = 1;
332*35144Smarc }
333*35144Smarc else
334*35144Smarc {
335*35144Smarc state = (c==0?0:-1);
336*35144Smarc n++;
337*35144Smarc }
338*35144Smarc }
339*35144Smarc begin:
340*35144Smarc fseek(fd,2L,0);
341*35144Smarc fc_fix->fixcnt = 2;
342*35144Smarc return(1);
343*35144Smarc }
344*35144Smarc
345*35144Smarc /*
346*35144Smarc * This routine unlinks the history file if the file is a temp file
347*35144Smarc */
348*35144Smarc
hist_close()349*35144Smarc void hist_close()
350*35144Smarc {
351*35144Smarc if(fc_fix)
352*35144Smarc fclose(fc_fix->fixfd);
353*35144Smarc }
354*35144Smarc
355*35144Smarc /*
356*35144Smarc * This routine reads the history file from the present position
357*35144Smarc * to the end-of-file and puts the information in the in-core
358*35144Smarc * history table
359*35144Smarc * Note that H_CMDNO is only recognized at the beginning of a command
360*35144Smarc * and that H_UNDO as the first character of a command is skipped
361*35144Smarc * unless it is followed by 0. If followed by 0 then it cancels
362*35144Smarc * the previous command.
363*35144Smarc */
364*35144Smarc
hist_eof()365*35144Smarc void hist_eof()
366*35144Smarc {
367*35144Smarc register struct fixcmd *fp = fc_fix;
368*35144Smarc register int c;
369*35144Smarc register int incr = 0;
370*35144Smarc register int oldc = 0;
371*35144Smarc register long count = fp->fixcnt;
372*35144Smarc int skip = 0;
373*35144Smarc heof++; /* don't add line number markers */
374*35144Smarc fseek(fp->fixfd,count,0);
375*35144Smarc while((c=getc(fp->fixfd))!=EOF)
376*35144Smarc {
377*35144Smarc count++;
378*35144Smarc if(skip-- > 0)
379*35144Smarc {
380*35144Smarc oldc = 0;
381*35144Smarc continue;
382*35144Smarc }
383*35144Smarc if(c == 0)
384*35144Smarc {
385*35144Smarc if(oldc==H_CMDNO && incr==0)
386*35144Smarc skip = 3;
387*35144Smarc fp->fixind += incr;
388*35144Smarc fp->fixcmds[fp->fixind&fixmask] = count;
389*35144Smarc incr = 0;
390*35144Smarc }
391*35144Smarc else if(oldc == 0)
392*35144Smarc {
393*35144Smarc if(c == H_CMDNO)
394*35144Smarc {
395*35144Smarc /* old format history file */
396*35144Smarc if(hist_version==0)
397*35144Smarc skip = 4;
398*35144Smarc incr = 0;
399*35144Smarc }
400*35144Smarc else if(c==H_UNDO)
401*35144Smarc incr = -1;
402*35144Smarc }
403*35144Smarc else
404*35144Smarc incr = 1;
405*35144Smarc oldc = c;
406*35144Smarc }
407*35144Smarc fp->fixline = 0;
408*35144Smarc fp->fixcnt = count;
409*35144Smarc heof = 0;
410*35144Smarc }
411*35144Smarc
412*35144Smarc /*
413*35144Smarc * This routine will cause the previous command to be cancelled
414*35144Smarc */
415*35144Smarc
hist_cancel()416*35144Smarc void hist_cancel()
417*35144Smarc {
418*35144Smarc register struct fixcmd *fp = fc_fix;
419*35144Smarc register FILE *fd;
420*35144Smarc register int c;
421*35144Smarc if(fp==NULL)
422*35144Smarc return;
423*35144Smarc fd = fp->fixfd;
424*35144Smarc putc(H_UNDO,fd);
425*35144Smarc putc(0,fd);
426*35144Smarc fflush(fd);
427*35144Smarc fp->fixcnt += 2;
428*35144Smarc c = (--fp->fixind)&fixmask;
429*35144Smarc fp->fixcmds[c] = fp->fixcnt;
430*35144Smarc }
431*35144Smarc
432*35144Smarc /*
433*35144Smarc * This routine adds one or two null bytes and flushes the history buffer
434*35144Smarc */
435*35144Smarc
hist_flush()436*35144Smarc void hist_flush()
437*35144Smarc {
438*35144Smarc register struct fixcmd *fp = fc_fix;
439*35144Smarc register FILE *fd;
440*35144Smarc register int c;
441*35144Smarc if(fp==NULL)
442*35144Smarc return;
443*35144Smarc #ifdef KSHELL
444*35144Smarc if((states&FIXFLG) == 0)
445*35144Smarc return;
446*35144Smarc states &= ~FIXFLG;
447*35144Smarc #endif /* KSHELL */
448*35144Smarc fd = fp->fixfd;
449*35144Smarc fp->fixline = 0;
450*35144Smarc /* remove whitespace from end of commands */
451*35144Smarc while(--fd->_ptr >= fd->_base)
452*35144Smarc {
453*35144Smarc if((c= *fd->_ptr)!=NL && !isspace(c))
454*35144Smarc break;
455*35144Smarc }
456*35144Smarc fd->_cnt = ++fd->_ptr - fd->_base;
457*35144Smarc if(fd->_cnt<=0)
458*35144Smarc {
459*35144Smarc fp->fixind--;
460*35144Smarc goto set_count;
461*35144Smarc }
462*35144Smarc putc(NL,fd);
463*35144Smarc putc('\0',fd);
464*35144Smarc fflush(fd);
465*35144Smarc set_count:
466*35144Smarc fp->fixcnt = lseek(fileno(fd),0L,2);
467*35144Smarc /* start each command on an even byte boundary */
468*35144Smarc if(fp->fixcnt&01)
469*35144Smarc {
470*35144Smarc fp->fixcnt++;
471*35144Smarc putc('\0',fd);
472*35144Smarc fflush(fd);
473*35144Smarc }
474*35144Smarc c = (++fp->fixind)&fixmask;
475*35144Smarc fp->fixcmds[c] = fp->fixcnt;
476*35144Smarc if((c = fp->fixcmds[c])> (HISMAX/4) && !heof)
477*35144Smarc {
478*35144Smarc /* put line number in file */
479*35144Smarc fp->fixcnt += 6;
480*35144Smarc putc(H_CMDNO,fd);
481*35144Smarc putc(0,fd);
482*35144Smarc c = (fp->fixind>>16);
483*35144Smarc putc(c,fd);
484*35144Smarc c = (fp->fixind>>8);
485*35144Smarc putc(c,fd);
486*35144Smarc c = fp->fixind;
487*35144Smarc putc(c,fd);
488*35144Smarc putc(0,fd);
489*35144Smarc fflush(fd);
490*35144Smarc fp->fixcmds[c&fixmask] = fp->fixcnt;
491*35144Smarc }
492*35144Smarc }
493*35144Smarc
494*35144Smarc /*
495*35144Smarc * return byte offset in history file for command <n>
496*35144Smarc */
497*35144Smarc
hist_position(n)498*35144Smarc long hist_position(n)
499*35144Smarc int n;
500*35144Smarc {
501*35144Smarc register struct fixcmd *fp = fc_fix;
502*35144Smarc return(fp->fixcmds[n&fixmask]);
503*35144Smarc }
504*35144Smarc
505*35144Smarc /*
506*35144Smarc * write the command starting at offset <offset> onto file <fd>.
507*35144Smarc * listing stops when character <last> is encountered or end-of-string.
508*35144Smarc * each new-line character is replaced with string <nl>.
509*35144Smarc */
510*35144Smarc
hist_list(offset,last,nl)511*35144Smarc long hist_list(offset,last,nl)
512*35144Smarc long offset;
513*35144Smarc int last;
514*35144Smarc char *nl;
515*35144Smarc {
516*35144Smarc register int oldc;
517*35144Smarc register FILE *fd;
518*35144Smarc register int c;
519*35144Smarc if(offset<0)
520*35144Smarc {
521*35144Smarc p_str(unknown,NL);
522*35144Smarc return(-1);
523*35144Smarc }
524*35144Smarc fd = fc_fix->fixfd;
525*35144Smarc fseek(fd,offset,0);
526*35144Smarc oldc=getc(fd);
527*35144Smarc for(offset++;oldc && oldc!=last;oldc=c,offset++)
528*35144Smarc {
529*35144Smarc if((c = getc(fd)) == EOF)
530*35144Smarc return(offset);
531*35144Smarc if(oldc=='\n')
532*35144Smarc {
533*35144Smarc if(c)
534*35144Smarc {
535*35144Smarc fputs(nl,output);
536*35144Smarc continue;
537*35144Smarc }
538*35144Smarc /* don't print trailing newline for job control */
539*35144Smarc else if(last=='&')
540*35144Smarc return(offset);
541*35144Smarc }
542*35144Smarc putc(oldc,output);
543*35144Smarc }
544*35144Smarc return(offset);
545*35144Smarc }
546*35144Smarc
547*35144Smarc /*
548*35144Smarc * find index for last line with given string
549*35144Smarc * If flag==0 then line must begin with string
550*35144Smarc * direction < 1 for backwards search
551*35144Smarc */
552*35144Smarc
hist_find(string,index1,flag,direction)553*35144Smarc histloc hist_find(string,index1,flag,direction)
554*35144Smarc char *string;
555*35144Smarc int index1;
556*35144Smarc int direction;
557*35144Smarc {
558*35144Smarc register struct fixcmd *fp = fc_fix;
559*35144Smarc register char *cp;
560*35144Smarc register int c;
561*35144Smarc long offset;
562*35144Smarc int count;
563*35144Smarc int index2;
564*35144Smarc histloc location;
565*35144Smarc #ifdef MULTIBYTE
566*35144Smarc int nbytes = 0;
567*35144Smarc #endif /* MULTIBYTE */
568*35144Smarc location.his_command = -1;
569*35144Smarc if(fp==NULL)
570*35144Smarc return(location);
571*35144Smarc index2 = fp->fixind;
572*35144Smarc if(direction<0)
573*35144Smarc {
574*35144Smarc index2 -= fp->fixmax;
575*35144Smarc if(index2<1)
576*35144Smarc index2 = 1;
577*35144Smarc if(index1 <= index2)
578*35144Smarc return(location);
579*35144Smarc }
580*35144Smarc else if(index1 >= index2)
581*35144Smarc return(location);
582*35144Smarc while(index1!=index2)
583*35144Smarc {
584*35144Smarc direction>0?++index1:--index1;
585*35144Smarc offset = hist_position(index1);
586*35144Smarc location.his_line = 0;
587*35144Smarc #ifdef KSHELL
588*35144Smarc /* allow a search to be aborted */
589*35144Smarc if(trapnote&SIGSET)
590*35144Smarc exitsh(SIGFAIL);
591*35144Smarc #endif /* KSHELL */
592*35144Smarc do
593*35144Smarc {
594*35144Smarc if(offset>=0)
595*35144Smarc {
596*35144Smarc fseek(fp->fixfd,offset,0);
597*35144Smarc count = offset;
598*35144Smarc }
599*35144Smarc offset = -1;
600*35144Smarc for(cp=string;*cp;cp++)
601*35144Smarc {
602*35144Smarc if((c=getc(fp->fixfd)) == EOF)
603*35144Smarc break;
604*35144Smarc if(c == 0)
605*35144Smarc break;
606*35144Smarc count++;
607*35144Smarc #ifdef MULTIBYTE
608*35144Smarc /* always position at character boundary */
609*35144Smarc if(--nbytes > 0)
610*35144Smarc {
611*35144Smarc if(cp==string)
612*35144Smarc {
613*35144Smarc cp--;
614*35144Smarc continue;
615*35144Smarc }
616*35144Smarc }
617*35144Smarc else
618*35144Smarc {
619*35144Smarc nbytes = echarset(c);
620*35144Smarc nbytes = in_csize(nbytes) + (nbytes>=2);
621*35144Smarc }
622*35144Smarc #endif /* MULTIBYTE */
623*35144Smarc if(c == '\n')
624*35144Smarc location.his_line++;
625*35144Smarc /* save earliest possible matching character */
626*35144Smarc if(flag && c == *string && offset<0)
627*35144Smarc offset = count;
628*35144Smarc if(*cp != c )
629*35144Smarc break;
630*35144Smarc }
631*35144Smarc if(*cp==0)
632*35144Smarc /* match found */
633*35144Smarc {
634*35144Smarc location.his_command = index1;
635*35144Smarc return(location);
636*35144Smarc }
637*35144Smarc }
638*35144Smarc while(flag && c && c != EOF);
639*35144Smarc }
640*35144Smarc fseek(fp->fixfd,0L,2);
641*35144Smarc return(location);
642*35144Smarc }
643*35144Smarc
644*35144Smarc #if ESH || VSH
645*35144Smarc /*
646*35144Smarc * copy command <command> from history file to s1
647*35144Smarc * at most MAXLINE characters copied
648*35144Smarc * if s1==0 the number of lines for the command is returned
649*35144Smarc * line=linenumber for emacs copy and only this line of command will be copied
650*35144Smarc * line < 0 for full command copy
651*35144Smarc * -1 returned if there is no history file
652*35144Smarc */
653*35144Smarc
hist_copy(s1,command,line)654*35144Smarc int hist_copy(s1,command,line)
655*35144Smarc register char *s1;
656*35144Smarc {
657*35144Smarc register int c;
658*35144Smarc register struct fixcmd *fp = fc_fix;
659*35144Smarc register int count = 0;
660*35144Smarc register char *s1max = s1+MAXLINE;
661*35144Smarc long offset;
662*35144Smarc if(fp==NULL)
663*35144Smarc return(-1);
664*35144Smarc offset = hist_position(command);
665*35144Smarc fseek(fp->fixfd,offset,0);
666*35144Smarc while ((c = getc(fp->fixfd)) && c!=EOF)
667*35144Smarc {
668*35144Smarc if(c=='\n')
669*35144Smarc {
670*35144Smarc if(count++ ==line)
671*35144Smarc break;
672*35144Smarc else if(line >= 0)
673*35144Smarc continue;
674*35144Smarc }
675*35144Smarc if(s1 && (line<0 || line==count))
676*35144Smarc {
677*35144Smarc if(s1 >= s1max)
678*35144Smarc {
679*35144Smarc *--s1 = 0;
680*35144Smarc break;
681*35144Smarc }
682*35144Smarc *s1++ = c;
683*35144Smarc }
684*35144Smarc
685*35144Smarc }
686*35144Smarc if(s1==0)
687*35144Smarc return(count);
688*35144Smarc if((c= *(s1-1)) == '\n')
689*35144Smarc s1--;
690*35144Smarc *s1 = '\0';
691*35144Smarc fseek(fp->fixfd,0L,2);
692*35144Smarc return(count);
693*35144Smarc }
694*35144Smarc
695*35144Smarc /*
696*35144Smarc * return word number <word> from command number <command>
697*35144Smarc */
698*35144Smarc
hist_word(s1,word)699*35144Smarc char *hist_word(s1,word)
700*35144Smarc char *s1;
701*35144Smarc {
702*35144Smarc register int c;
703*35144Smarc register char *cp = s1;
704*35144Smarc register int flag = 0;
705*35144Smarc if(fc_fix==0)
706*35144Smarc #ifdef KSHELL
707*35144Smarc return(lastarg);
708*35144Smarc #else
709*35144Smarc return(NULL);
710*35144Smarc #endif /* KSHELL */
711*35144Smarc hist_copy(s1,fc_fix->fixind-1,-1);
712*35144Smarc for(;c = *cp;cp++)
713*35144Smarc {
714*35144Smarc c = isspace(c);
715*35144Smarc if(c && flag)
716*35144Smarc {
717*35144Smarc *cp = 0;
718*35144Smarc if(--word==0)
719*35144Smarc break;
720*35144Smarc flag = 0;
721*35144Smarc }
722*35144Smarc else if(c==0 && flag==0)
723*35144Smarc {
724*35144Smarc s1 = cp;
725*35144Smarc flag++;
726*35144Smarc }
727*35144Smarc }
728*35144Smarc *cp = 0;
729*35144Smarc return(s1);
730*35144Smarc }
731*35144Smarc
732*35144Smarc #endif /* ESH */
733*35144Smarc
734*35144Smarc #ifdef ESH
735*35144Smarc /*
736*35144Smarc * given the current command and line number,
737*35144Smarc * and number of lines back or foward,
738*35144Smarc * compute the new command and line number.
739*35144Smarc */
740*35144Smarc
hist_locate(command,line,lines)741*35144Smarc histloc hist_locate(command,line,lines)
742*35144Smarc register int command;
743*35144Smarc register int line;
744*35144Smarc int lines;
745*35144Smarc {
746*35144Smarc histloc next;
747*35144Smarc line += lines;
748*35144Smarc if(fc_fix==NULL)
749*35144Smarc {
750*35144Smarc command = -1;
751*35144Smarc goto done;
752*35144Smarc }
753*35144Smarc if(lines > 0)
754*35144Smarc {
755*35144Smarc register int count;
756*35144Smarc while(command <= fc_fix->fixind)
757*35144Smarc {
758*35144Smarc count = hist_copy(NIL,command,-1);
759*35144Smarc if(count > line)
760*35144Smarc goto done;
761*35144Smarc line -= count;
762*35144Smarc command++;
763*35144Smarc }
764*35144Smarc }
765*35144Smarc else
766*35144Smarc {
767*35144Smarc register int least = fc_fix->fixind-fc_fix->fixmax;
768*35144Smarc while(1)
769*35144Smarc {
770*35144Smarc if(line >=0)
771*35144Smarc goto done;
772*35144Smarc if(--command < least)
773*35144Smarc break;
774*35144Smarc line += hist_copy(NIL,command,-1);
775*35144Smarc }
776*35144Smarc command = -1;
777*35144Smarc }
778*35144Smarc next.his_command = command;
779*35144Smarc return(next);
780*35144Smarc done:
781*35144Smarc next.his_line = line;
782*35144Smarc next.his_command = command;
783*35144Smarc return(next);
784*35144Smarc }
785*35144Smarc #endif /* ESH */
786*35144Smarc
787*35144Smarc #ifdef KSHELL
788*35144Smarc
789*35144Smarc /*
790*35144Smarc * given a file containing a command and a string of the form old=new,
791*35144Smarc * execute the command with the string old replaced by new
792*35144Smarc */
hist_subst(command,fd,replace)793*35144Smarc void hist_subst(command,fd,replace)
794*35144Smarc char *command;
795*35144Smarc FILE *fd;
796*35144Smarc char *replace;
797*35144Smarc {
798*35144Smarc register char *new=replace;
799*35144Smarc register char *sp = locstak();
800*35144Smarc register int c;
801*35144Smarc char *string;
802*35144Smarc while(*++new != '='); /* skip to '=' */
803*35144Smarc while ((c=getc(fd)) != EOF)
804*35144Smarc *sp++ = c;
805*35144Smarc string = endstak(sp);
806*35144Smarc fclose(fd);
807*35144Smarc *new++ = 0;
808*35144Smarc if(substitute(string,replace,new,(sp=locstak())))
809*35144Smarc endstak(sp+strlen(sp));
810*35144Smarc else
811*35144Smarc failed(command,badsub);
812*35144Smarc *(new-1) = '=';
813*35144Smarc fputs(sp,fc_fix->fixfd);
814*35144Smarc hist_flush();
815*35144Smarc fputs(sp,output);
816*35144Smarc execexp(sp,(FILE*)0);
817*35144Smarc }
818*35144Smarc #endif /* KSHELL */
819