da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/***********************************************************************
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* This software is part of the ast package *
3e14f97f673e8a630f076077de35afdd43dc1587Roger A. Faulkner* Copyright (c) 1982-2010 AT&T Intellectual Property *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* and is licensed under the *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Common Public License, Version 1.0 *
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin* by AT&T Intellectual Property *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* A copy of the License is available at *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* http://www.opensource.org/licenses/cpl1.0.txt *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Information and Software Systems Research *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* AT&T Research *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Florham Park NJ *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* David Korn <dgk@research.att.com> *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin***********************************************************************/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#pragma prototyped
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * History file manipulation routines
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * David Korn
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * AT&T Labs
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Each command in the history file starts on an even byte is null terminated.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * The first byte must contain the special character HIST_UNDO and the second
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * byte is the version number. The sequence HIST_UNDO 0, following a command,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * nullifies the previous command. A six byte sequence starting with
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * HIST_CMDNO is used to store the command number so that it is not necessary
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * to read the file from beginning to end to get to the last block of
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * commands. This format of this sequence is different in version 1
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * then in version 0. Version 1 allows commands to use the full 8 bit
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * character set. It can understand version 0 format files.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define HIST_MAX (sizeof(int)*HIST_BSIZE)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define HIST_BIG (0100000-1024) /* 1K less than maximum short */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define HIST_LINE 32 /* typical length for history line */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define HIST_MARKSZ 6
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define HIST_RECENT 600
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define HIST_UNDO 0201 /* invalidate previous command */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define HIST_CMDNO 0202 /* next 3 bytes give command number */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define HIST_BSIZE 4096 /* size of history file buffer */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define HIST_DFLT 512 /* default size of history list */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#if SHOPT_AUDIT
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# define _HIST_AUDIT Sfio_t *auditfp; \
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin char *tty; \
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin int auditmask;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#else
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# define _HIST_AUDIT
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#endif
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define _HIST_PRIVATE \
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin void *histshell; \
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin off_t histcnt; /* offset into history file */\
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin off_t histmarker; /* offset of last command marker */ \
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int histflush; /* set if flushed outside of hflush() */\
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int histmask; /* power of two mask for histcnt */ \
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin char histbuff[HIST_BSIZE+1]; /* history file buffer */ \
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int histwfail; \
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin _HIST_AUDIT \
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin off_t histcmds[2]; /* offset for recent commands, must be last */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define hist_ind(hp,c) ((int)((c)&(hp)->histmask))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <ast.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sfio.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include "FEATURE/time"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <error.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <ls.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if KSHELL
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include "defs.h"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include "variables.h"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include "path.h"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include "builtins.h"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include "io.h"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz#else
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz# include <ctype.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* KSHELL */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include "history.h"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if !KSHELL
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# define new_of(type,x) ((type*)malloc((unsigned)sizeof(type)+(x)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# define NIL(type) ((type)0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# define path_relative(x) (x)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# ifdef __STDC__
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# define nv_getval(s) getenv(#s)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# define nv_getval(s) getenv("s")
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# endif /* __STDC__ */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# define e_unknown "unknown"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# define sh_translate(x) (x)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin char login_sh = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin char hist_fname[] = "/.history";
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* KSHELL */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifndef O_BINARY
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# define O_BINARY 0
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* O_BINARY */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinint _Hist = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic void hist_marker(char*,long);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinstatic History_t* hist_trim(History_t*, int);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int hist_nearend(History_t*,Sfio_t*, off_t);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int hist_check(int);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int hist_clean(int);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifdef SF_BUFCONST
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin static ssize_t hist_write(Sfio_t*, const void*, size_t, Sfdisc_t*);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin static int hist_exceptf(Sfio_t*, int, void*, Sfdisc_t*);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin static int hist_write(Sfio_t*, const void*, int, Sfdisc_t*);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin static int hist_exceptf(Sfio_t*, int, Sfdisc_t*);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int histinit;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic mode_t histmode;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic History_t *wasopen;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic History_t *hist_ptr;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if SHOPT_ACCTFILE
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin static int acctfd;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin static char *logname;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include <pwd.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin static int acctinit(History_t *hp)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char *cp, *acctfile;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin Namval_t *np = nv_search("ACCTFILE",((Shell_t*)hp->histshell)->var_tree,0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!np || !(acctfile=nv_getval(np)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!(cp = getlogin()))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin struct passwd *userinfo = getpwuid(getuid());
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(userinfo)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp = userinfo->pw_name;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp = "unknown";
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin logname = strdup(cp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((acctfd=sh_open(acctfile,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IRUSR|S_IWUSR))>=0 &&
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (unsigned)acctfd < 10)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int n;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((n = fcntl(acctfd, F_DUPFD, 10)) >= 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin close(acctfd);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin acctfd = n;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(acctfd < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin acctfd = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(strmatch(acctfile,e_devfdNN))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin char newfile[16];
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfsprintf(newfile,sizeof(newfile),"%.8s%d\0",e_devfdNN,acctfd);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin nv_putval(np,newfile,NV_RDONLY);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin fcntl(acctfd,F_SETFD,FD_CLOEXEC);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_ACCTFILE */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#if SHOPT_AUDIT
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinstatic int sh_checkaudit(History_t *hp, const char *name, char *logbuf, size_t len)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin{
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin Shell_t *shp = (Shell_t*)hp->histshell;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin char *buff, *cp, *last;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin int id1, id2, r=0, n, fd;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if((fd=open(name, O_RDONLY)) < 0)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin return(0);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if((n = read(fd, logbuf,len-1)) < 0)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin goto done;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin while(logbuf[n-1]=='\n')
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin n--;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin logbuf[n] = 0;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if(!(cp=strchr(logbuf,';')) && !(cp=strchr(logbuf,' ')))
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin goto done;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin *cp = 0;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin do
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin cp++;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin id1 = id2 = strtol(cp,&last,10);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if(*last=='-')
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin id1 = strtol(last+1,&last,10);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if(shp->euserid >=id1 && shp->euserid <= id2)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin r |= 1;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if(shp->userid >=id1 && shp->userid <= id2)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin r |= 2;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin cp = last;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin while(*cp==';' || *cp==' ');
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chindone:
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin close(fd);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin return(r);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin}
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#endif /*SHOPT_AUDIT*/
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic const unsigned char hist_stamp[2] = { HIST_UNDO, HIST_VERSION };
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic const Sfdisc_t hist_disc = { NULL, hist_write, NULL, hist_exceptf, NULL};
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic void hist_touch(void *handle)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin touch((char*)handle, (time_t)0, (time_t)0, 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * open the history file
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * if HISTNAME is not given and userid==0 then no history file.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * if login_sh and HISTFILE is longer than HIST_MAX bytes then it is
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * cleaned up.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * hist_open() returns 1, if history file is open
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinint sh_histinit(void *sh_context)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin Shell_t *shp = (Shell_t*)sh_context;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int fd;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register History_t *hp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char *histname;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin char *fname=0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int histmask, maxlines, hist_start=0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char *cp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register off_t hsize = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if(shp->hist_ptr=hist_ptr)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!(histname = nv_getval(HISTFILE)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int offset = staktell();
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(cp=nv_getval(HOME))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakputs(cp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakputs(hist_fname);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakputc(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakseek(offset);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin histname = stakptr(offset);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifdef future
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(hp=wasopen)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* reuse history file if same name */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin wasopen = 0;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin shp->hist_ptr = hist_ptr = hp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(strcmp(histname,hp->histname)==0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hist_free();
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinretry:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp = path_relative(histname);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!histinit)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin histmode = S_IRUSR|S_IWUSR;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((fd=open(cp,O_BINARY|O_APPEND|O_RDWR|O_CREAT,histmode))>=0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hsize=lseek(fd,(off_t)0,SEEK_END);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((unsigned)fd <=2)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int n;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((n=fcntl(fd,F_DUPFD,10))>=0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin close(fd);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin fd=n;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* make sure that file has history file format */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(hsize && hist_check(fd))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin close(fd);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hsize = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(unlink(cp)>=0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto retry;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin fd = -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(fd < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if KSHELL
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* don't allow root a history_file in /tmp */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if(shp->userid)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* KSHELL */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!(fname = pathtmp(NIL(char*),0,0,NIL(int*))))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin fd = open(fname,O_BINARY|O_APPEND|O_CREAT|O_RDWR,S_IRUSR|S_IWUSR);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(fd<0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* set the file to close-on-exec */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin fcntl(fd,F_SETFD,FD_CLOEXEC);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(cp=nv_getval(HISTSIZE))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin maxlines = (unsigned)strtol(cp, (char**)0, 10);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin maxlines = HIST_DFLT;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for(histmask=16;histmask <= maxlines; histmask <<=1 );
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!(hp=new_of(History_t,(--histmask)*sizeof(off_t))))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin close(fd);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin shp->hist_ptr = hist_ptr = hp;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin hp->histshell = (void*)shp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histsize = maxlines;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histmask = histmask;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histfp= sfnew(NIL(Sfio_t*),hp->histbuff,HIST_BSIZE,fd,SF_READ|SF_WRITE|SF_APPENDWR|SF_SHARE);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin memset((char*)hp->histcmds,0,sizeof(off_t)*(hp->histmask+1));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histind = 1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histcmds[1] = 2;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histcnt = 2;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histname = strdup(histname);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histdisc = hist_disc;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(hsize==0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* put special characters at front of file */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfwrite(hp->histfp,(char*)hist_stamp,2);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfsync(hp->histfp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* initialize history list */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int first,last;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin off_t mark,size = (HIST_MAX/4)+maxlines*HIST_LINE;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histind = first = hist_nearend(hp,hp->histfp,hsize-size);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hist_eof(hp); /* this sets histind to last command */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((hist_start = (last=(int)hp->histind)-maxlines) <=0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hist_start = 1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mark = hp->histmarker;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(first > hist_start)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin size += size;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin first = hist_nearend(hp,hp->histfp,hsize-size);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histind = first;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin histinit = hist_start;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hist_eof(hp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!histinit)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfseek(hp->histfp,hp->histcnt=hsize,SEEK_SET);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histind = last;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histmarker = mark;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin histinit = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(fname)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin unlink(fname);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin free((void*)fname);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(hist_clean(fd) && hist_start>1 && hsize > HIST_MAX)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifdef DEBUG
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfprintf(sfstderr,"%d: hist_trim hsize=%d\n",getpid(),hsize);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfsync(sfstderr);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* DEBUG */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin hp = hist_trim(hp,(int)hp->histind-maxlines);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfdisc(hp->histfp,&hp->histdisc);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if KSHELL
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (HISTCUR)->nvalue.lp = (&hp->histind);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* KSHELL */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sh_timeradd(1000L*(HIST_RECENT-30), 1, hist_touch, (void*)hp->histname);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if SHOPT_ACCTFILE
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(sh_isstate(SH_INTERACTIVE))
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin acctinit(hp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_ACCTFILE */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#if SHOPT_AUDIT
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin char buff[SF_BUFSIZE];
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin hp->auditfp = 0;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if(sh_isstate(SH_INTERACTIVE) && (hp->auditmask=sh_checkaudit(hp,SHOPT_AUDITFILE, buff, sizeof(buff))))
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if((fd=sh_open(buff,O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IRUSR|S_IWUSR))>=0 && fd < 10)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin int n;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if((n = sh_fcntl(fd,F_DUPFD, 10)) >= 0)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin sh_close(fd);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin fd = n;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if(fd>=0)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin hp->tty = strdup(ttyname(2));
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin hp->auditfp = sfnew((Sfio_t*)0,NULL,-1,fd,SF_WRITE);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * close the history file and free the space
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinvoid hist_close(register History_t *hp)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin Shell_t *shp = (Shell_t*)hp->histshell;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfclose(hp->histfp);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#if SHOPT_AUDIT
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if(hp->auditfp)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if(hp->tty)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin free((void*)hp->tty);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin sfclose(hp->auditfp);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#endif /* SHOPT_AUDIT */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin free((char*)hp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hist_ptr = 0;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin shp->hist_ptr = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if SHOPT_ACCTFILE
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(acctfd)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin close(acctfd);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin acctfd = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_ACCTFILE */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * check history file format to see if it begins with special byte
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int hist_check(register int fd)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin unsigned char magic[2];
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin lseek(fd,(off_t)0,SEEK_SET);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((read(fd,(char*)magic,2)!=2) || (magic[0]!=HIST_UNDO))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * clean out history file OK if not modified in HIST_RECENT seconds
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int hist_clean(int fd)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin struct stat statb;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(fstat(fd,&statb)>=0 && (time((time_t*)0)-statb.st_mtime) >= HIST_RECENT);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Copy the last <n> commands to a new file and make this the history file
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinstatic History_t* hist_trim(History_t *hp, int n)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char *cp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int incmd=1, c=0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register History_t *hist_new, *hist_old = hp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin char *buff, *endbuff, *tmpname=0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin off_t oldp,newp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin struct stat statb;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin unlink(hist_old->histname);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(access(hist_old->histname,F_OK) >= 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* The unlink can fail on windows 95 */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int fd;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin char *last, *name=hist_old->histname;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin close(sffileno(hist_old->histfp));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin tmpname = (char*)malloc(strlen(name)+14);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(last = strrchr(name,'/'))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *last = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin pathtmp(tmpname,name,"hist",NIL(int*));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *last = '/';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin pathtmp(tmpname,".","hist",NIL(int*));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(rename(name,tmpname) < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin tmpname = name;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin fd = open(tmpname,O_RDONLY);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfsetfd(hist_old->histfp,fd);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(tmpname==name)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin tmpname = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin hist_ptr = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(fstat(sffileno(hist_old->histfp),&statb)>=0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin histinit = 1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin histmode = statb.st_mode;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if(!sh_histinit(hp->histshell))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* use the old history file */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin return hist_ptr = hist_old;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hist_new = hist_ptr;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hist_ptr = hist_old;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(--n < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin newp = hist_seek(hist_old,++n);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(1)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!incmd)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin c = hist_ind(hist_new,++hist_new->histind);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hist_new->histcmds[c] = hist_new->histcnt;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(hist_new->histcnt > hist_new->histmarker+HIST_BSIZE/2)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin char locbuff[HIST_MARKSZ];
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hist_marker(locbuff,hist_new->histind);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfwrite(hist_new->histfp,locbuff,HIST_MARKSZ);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hist_new->histcnt += HIST_MARKSZ;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hist_new->histmarker = hist_new->histcmds[hist_ind(hist_new,c)] = hist_new->histcnt;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin oldp = newp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin newp = hist_seek(hist_old,++n);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(newp <=oldp)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!(buff=(char*)sfreserve(hist_old->histfp,SF_UNBOUND,0)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *(endbuff=(cp=buff)+sfvalue(hist_old->histfp)) = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* copy to null byte */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin incmd = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(*cp++);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(cp > endbuff)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin incmd = 1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(*cp==0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp++;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(cp > endbuff)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp = endbuff;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin c = cp-buff;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hist_new->histcnt += c;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfwrite(hist_new->histfp,buff,c);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin hist_cancel(hist_new);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfclose(hist_old->histfp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(tmpname)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin unlink(tmpname);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin free(tmpname);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin free((char*)hist_old);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin return hist_ptr = hist_new;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * position history file at size and find next command number
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int hist_nearend(History_t *hp, Sfio_t *iop, register off_t size)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register unsigned char *cp, *endbuff;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int n, incmd=1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin unsigned char *buff, marker[4];
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(size <= 2L || sfseek(iop,size,SEEK_SET)<0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto begin;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* skip to marker command and return the number */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* numbering commands occur after a null and begin with HIST_CMDNO */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(cp=buff=(unsigned char*)sfreserve(iop,SF_UNBOUND,SF_LOCKR))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = sfvalue(iop);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *(endbuff=cp+n) = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(1)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* check for marker */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!incmd && *cp++==HIST_CMDNO && *cp==0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = cp+1 - buff;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin incmd = -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin incmd = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(*cp++);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(cp>endbuff)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin incmd = 1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(*cp==0 && ++cp>endbuff)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin size += n;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfread(iop,(char*)buff,n);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(incmd < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((n=sfread(iop,(char*)marker,4))==4)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = (marker[0]<<16)|(marker[1]<<8)|marker[2];
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(n < size/2)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histmarker = hp->histcnt = size+4;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(n);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n=4;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(n >0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin size += n;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin incmd = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinbegin:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfseek(iop,(off_t)2,SEEK_SET);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histmarker = hp->histcnt = 2L;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * This routine reads the history file from the present position
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * to the end-of-file and puts the information in the in-core
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * history table
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Note that HIST_CMDNO is only recognized at the beginning of a command
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * and that HIST_UNDO as the first character of a command is skipped
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * unless it is followed by 0. If followed by 0 then it cancels
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * the previous command.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinvoid hist_eof(register History_t *hp)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char *cp,*first,*endbuff;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int incmd = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register off_t count = hp->histcnt;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int n,skip=0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfseek(hp->histfp,count,SEEK_SET);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(cp=(char*)sfreserve(hp->histfp,SF_UNBOUND,0))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = sfvalue(hp->histfp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *(endbuff = cp+n) = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin first = cp += skip;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(1)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(!incmd)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(cp>first)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin count += (cp-first);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = hist_ind(hp, ++hp->histind);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifdef future
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(count==hp->histcmds[n])
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfprintf(sfstderr,"count match n=%d\n",n);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(histinit)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin histinit = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(n>=histinit)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histcmds[n] = count;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin first = cp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin switch(*((unsigned char*)(cp++)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case HIST_CMDNO:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(*cp==0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histmarker=count+2;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp += (HIST_MARKSZ-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histind--;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifdef future
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(cp <= endbuff)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin unsigned char *marker = (unsigned char*)(cp-4);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int n = ((marker[0]<<16)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin|(marker[1]<<8)|marker[2]);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((n<count/2) && n != (hp->histind+1))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin errormsg(SH_DICT,2,"index=%d marker=%d", hp->histind, n);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case HIST_UNDO:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(*cp==0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp+=1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histind-=2;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin default:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp--;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin incmd = 1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(cp > endbuff)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp++;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto refill;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin first = cp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(*cp++);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(cp > endbuff)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin incmd = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(*cp==0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(++cp > endbuff)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto refill;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin refill:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin count += (--cp-first);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin skip = (cp-endbuff);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!incmd && !skip)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histcmds[hist_ind(hp,++hp->histind)] = count;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histcnt = count;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * This routine will cause the previous command to be cancelled
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinvoid hist_cancel(register History_t *hp)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int c;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!hp)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfputc(hp->histfp,HIST_UNDO);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfputc(hp->histfp,0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfsync(hp->histfp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histcnt += 2;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin c = hist_ind(hp,--hp->histind);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histcmds[c] = hp->histcnt;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * flush the current history command
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinvoid hist_flush(register History_t *hp)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char *buff;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(hp)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(buff=(char*)sfreserve(hp->histfp,0,SF_LOCKR))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histflush = sfvalue(hp->histfp)+1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfwrite(hp->histfp,buff,0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histflush=0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(sfsync(hp->histfp)<0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hist_close(hp);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if(!sh_histinit(hp->histshell))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sh_offoption(SH_HISTORY);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histflush = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * This is the write discipline for the history file
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * When called from hist_flush(), trailing newlines are deleted and
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * a zero byte. Line sequencing is added as required
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifdef SF_BUFCONST
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic ssize_t hist_write(Sfio_t *iop,const void *buff,register size_t insize,Sfdisc_t* handle)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int hist_write(Sfio_t *iop,const void *buff,register int insize,Sfdisc_t* handle)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register History_t *hp = (History_t*)handle;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char *bufptr = ((char*)buff)+insize;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int c,size = insize;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register off_t cur;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int saved=0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin char saveptr[HIST_MARKSZ];
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!hp->histflush)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(write(sffileno(iop),(char*)buff,size));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((cur = lseek(sffileno(iop),(off_t)0,SEEK_END)) <0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin errormsg(SH_DICT,2,"hist_flush: EOF seek failed errno=%d",errno);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histcnt = cur;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* remove whitespace from end of commands */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(--bufptr >= (char*)buff)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin c= *bufptr;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!isspace(c))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(c=='\\' && *(bufptr+1)!='\n')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin bufptr++;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* don't count empty lines */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(++bufptr <= (char*)buff)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(insize);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *bufptr++ = '\n';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *bufptr++ = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin size = bufptr - (char*)buff;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#if SHOPT_AUDIT
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if(hp->auditfp)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin Shell_t *shp = (Shell_t*)hp->histshell;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin time_t t=time((time_t*)0);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin sfprintf(hp->auditfp,"%u;%u;%s;%*s%c",sh_isoption(SH_PRIVILEGED)?shp->euserid:shp->userid,t,hp->tty,size,buff,0);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin sfsync(hp->auditfp);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#endif /* SHOPT_AUDIT */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if SHOPT_ACCTFILE
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(acctfd)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int timechars, offset;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin offset = staktell();
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakputs(buff);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakseek(staktell() - 1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin timechars = sfprintf(staksp, "\t%s\t%x\n",logname,time(NIL(long *)));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin lseek(acctfd, (off_t)0, SEEK_END);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin write(acctfd, stakptr(offset), size - 2 + timechars);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin stakseek(offset);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_ACCTFILE */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(size&01)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin size++;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *bufptr++ = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histcnt += size;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin c = hist_ind(hp,++hp->histind);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histcmds[c] = hp->histcnt;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(hp->histflush>HIST_MARKSZ && hp->histcnt > hp->histmarker+HIST_BSIZE/2)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin memcpy((void*)saveptr,(void*)bufptr,HIST_MARKSZ);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin saved=1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histcnt += HIST_MARKSZ;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hist_marker(bufptr,hp->histind);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histmarker = hp->histcmds[hist_ind(hp,c)] = hp->histcnt;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin size += HIST_MARKSZ;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin errno = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin size = write(sffileno(iop),(char*)buff,size);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(saved)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin memcpy((void*)bufptr,(void*)saveptr,HIST_MARKSZ);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(size>=0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histwfail = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(insize);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Put history sequence number <n> into buffer <buff>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * The buffer must be large enough to hold HIST_MARKSZ chars
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic void hist_marker(register char *buff,register long cmdno)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *buff++ = HIST_CMDNO;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *buff++ = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *buff++ = (cmdno>>16);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *buff++ = (cmdno>>8);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *buff++ = cmdno;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *buff++ = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * return byte offset in history file for command <n>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinoff_t hist_tell(register History_t *hp, int n)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(hp->histcmds[hist_ind(hp,n)]);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * seek to the position of command <n>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinoff_t hist_seek(register History_t *hp, int n)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(sfseek(hp->histfp,hp->histcmds[hist_ind(hp,n)],SEEK_SET));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * write the command starting at offset <offset> onto file <outfile>.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * if character <last> appears before newline it is deleted
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * each new-line character is replaced with string <nl>.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinvoid hist_list(register History_t *hp,Sfio_t *outfile, off_t offset,int last, char *nl)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int oldc=0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int c;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(offset<0 || !hp)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfputr(outfile,sh_translate(e_unknown),'\n');
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfseek(hp->histfp,offset,SEEK_SET);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while((c = sfgetc(hp->histfp)) != EOF)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(c && oldc=='\n')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfputr(outfile,nl,-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(last && (c==0 || (c=='\n' && oldc==last)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(oldc)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfputc(outfile,oldc);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin oldc = c;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(c==0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * find index for last line with given string
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * If flag==0 then line must begin with string
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * direction < 1 for backwards search
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin*/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinHistloc_t hist_find(register History_t*hp,char *string,register int index1,int flag,int direction)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int index2;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin off_t offset;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int *coffset=0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Histloc_t location;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin location.hist_command = -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin location.hist_char = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin location.hist_line = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!hp)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(location);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* leading ^ means beginning of line unless escaped */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(flag)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin index2 = *string;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(index2=='\\')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin string++;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(index2=='^')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin flag=0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin string++;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(flag)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin coffset = &location.hist_char;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin index2 = (int)hp->histind;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(direction<0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin index2 -= hp->histsize;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(index2<1)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin index2 = 1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(index1 <= index2)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(location);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(index1 >= index2)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(location);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(index1!=index2)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin direction>0?++index1:--index1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin offset = hist_tell(hp,index1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((location.hist_line=hist_match(hp,offset,string,coffset))>=0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin location.hist_command = index1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(location);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if KSHELL
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* allow a search to be aborted */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if(((Shell_t*)hp->histshell)->trapnote&SH_SIGSET)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* KSHELL */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(location);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * search for <string> in history file starting at location <offset>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * If coffset==0 then line must begin with string
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * returns the line number of the match if successful, otherwise -1
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinint hist_match(register History_t *hp,off_t offset,char *string,int *coffset)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register unsigned char *first, *cp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int m,n,c=1,line=0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if SHOPT_MULTIBYTE
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mbinit();
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_MULTIBYTE */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfseek(hp->histfp,offset,SEEK_SET);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!(cp = first = (unsigned char*)sfgetr(hp->histfp,0,0)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin m = sfvalue(hp->histfp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = strlen(string);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(m > n)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(*cp==*string && memcmp(cp,string,n)==0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(coffset)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *coffset = (cp-first);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(line);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!coffset)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(*cp=='\n')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin line++;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if SHOPT_MULTIBYTE
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((c=mbsize(cp)) < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin c = 1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_MULTIBYTE */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp += c;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin m -= c;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if SHOPT_ESH || SHOPT_VSH
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * copy command <command> from history file to s1
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * at most <size> characters copied
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * if s1==0 the number of lines for the command is returned
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * line=linenumber for emacs copy and only this line of command will be copied
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * line < 0 for full command copy
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * -1 returned if there is no history file
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinint hist_copy(char *s1,int size,int command,int line)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int c;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register History_t *hp = sh_getinterp()->hist_ptr;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int count = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char *s1max = s1+size;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!hp)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hist_seek(hp,command);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while ((c = sfgetc(hp->histfp)) && c!=EOF)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(c=='\n')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(count++ ==line)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(line >= 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin continue;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(s1 && (line<0 || line==count))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(s1 >= s1max)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *--s1 = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *s1++ = c;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfseek(hp->histfp,(off_t)0,SEEK_END);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(s1==0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(count);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(count && (c= *(s1-1)) == '\n')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s1--;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *s1 = '\0';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(count);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * return word number <word> from command number <command>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinchar *hist_word(char *string,int size,int word)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int c;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char *s1 = string;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register unsigned char *cp = (unsigned char*)s1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int flag = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin History_t *hp = hist_ptr;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!hp)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(NIL(char*));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hist_copy(string,size,(int)hp->histind-1,-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for(;c = *cp;cp++)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin c = isspace(c);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(c && flag)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *cp = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(--word==0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin flag = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(c==0 && flag==0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s1 = (char*)cp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin flag++;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *cp = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(s1 != string)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin strcpy(string,s1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(string);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_ESH */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if SHOPT_ESH
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * given the current command and line number,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * and number of lines back or foward,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * compute the new command and line number.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinHistloc_t hist_locate(History_t *hp,register int command,register int line,int lines)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Histloc_t next;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin line += lines;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!hp)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin command = -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto done;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(lines > 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int count;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(command <= hp->histind)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin count = hist_copy(NIL(char*),0, command,-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(count > line)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto done;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin line -= count;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin command++;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int least = (int)hp->histind-hp->histsize;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(1)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(line >=0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto done;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(--command < least)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin line += hist_copy(NIL(char*),0, command,-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin command = -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chindone:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin next.hist_line = line;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin next.hist_command = command;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(next);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_ESH */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Handle history file exceptions
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifdef SF_BUFCONST
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int hist_exceptf(Sfio_t* fp, int type, void *data, Sfdisc_t *handle)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int hist_exceptf(Sfio_t* fp, int type, Sfdisc_t *handle)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int newfd,oldfd;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin History_t *hp = (History_t*)handle;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(type==SF_WRITE)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(errno==ENOSPC || hp->histwfail++ >= 10)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* write failure could be NFS problem, try to re-open */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin close(oldfd=sffileno(fp));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((newfd=open(hp->histname,O_BINARY|O_APPEND|O_CREAT|O_RDWR,S_IRUSR|S_IWUSR)) >= 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(fcntl(newfd, F_DUPFD, oldfd) !=oldfd)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin fcntl(oldfd,F_SETFD,FD_CLOEXEC);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin close(newfd);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(lseek(oldfd,(off_t)0,SEEK_END) < hp->histcnt)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int index = hp->histind;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin lseek(oldfd,(off_t)2,SEEK_SET);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histcnt = 2;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histind = 1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histcmds[1] = 2;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hist_eof(hp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histmarker = hp->histcnt;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histind = index;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin errormsg(SH_DICT,2,"History file write error-%d %s: file unrecoverable",errno,hp->histname);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}