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* A copy of the License is available at *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Information and Software Systems Research *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* AT&T Research *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Florham Park NJ *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* David Korn <dgk@research.att.com> *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin***********************************************************************/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * History file manipulation routines
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * David Korn
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * AT&T Labs
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#define HIST_BIG (0100000-1024) /* 1K less than maximum short */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define HIST_LINE 32 /* typical length for history line */
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 off_t histmarker; /* offset of last command marker */ \
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int histflush; /* set if flushed outside of hflush() */\
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin char histbuff[HIST_BSIZE+1]; /* history file buffer */ \
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin off_t histcmds[2]; /* offset for recent commands, must be last */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# include "io.h"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* KSHELL */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# define new_of(type,x) ((type*)malloc((unsigned)sizeof(type)+(x)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# endif /* __STDC__ */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* KSHELL */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* O_BINARY */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic void hist_marker(char*,long);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int hist_check(int);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int hist_clean(int);
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 static int hist_write(Sfio_t*, const void*, int, Sfdisc_t*);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin Namval_t *np = nv_search("ACCTFILE",((Shell_t*)hp->histshell)->var_tree,0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IRUSR|S_IWUSR))>=0 &&
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfsprintf(newfile,sizeof(newfile),"%.8s%d\0",e_devfdNN,acctfd);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_ACCTFILE */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinstatic int sh_checkaudit(History_t *hp, const char *name, char *logbuf, size_t len)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if(!(cp=strchr(logbuf,';')) && !(cp=strchr(logbuf,' ')))
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#endif /*SHOPT_AUDIT*/
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 * 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 return(1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* reuse history file if same name */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((fd=open(cp,O_BINARY|O_APPEND|O_RDWR|O_CREAT,histmode))>=0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* make sure that file has history file format */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* don't allow root a history_file in /tmp */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* KSHELL */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin fd = open(fname,O_BINARY|O_APPEND|O_CREAT|O_RDWR,S_IRUSR|S_IWUSR);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* set the file to close-on-exec */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
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 /* put special characters at front of file */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* initialize history list */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histind = first = hist_nearend(hp,hp->histfp,hsize-size);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((hist_start = (last=(int)hp->histind)-maxlines) <=0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfprintf(sfstderr,"%d: hist_trim hsize=%d\n",getpid(),hsize);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* DEBUG */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* KSHELL */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sh_timeradd(1000L*(HIST_RECENT-30), 1, hist_touch, (void*)hp->histname);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_ACCTFILE */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if(sh_isstate(SH_INTERACTIVE) && (hp->auditmask=sh_checkaudit(hp,SHOPT_AUDITFILE, buff, sizeof(buff))))
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if((fd=sh_open(buff,O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IRUSR|S_IWUSR))>=0 && fd < 10)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin hp->auditfp = sfnew((Sfio_t*)0,NULL,-1,fd,SF_WRITE);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * close the history file and free the space
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#endif /* SHOPT_AUDIT */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_ACCTFILE */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * check history file format to see if it begins with special byte
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((read(fd,(char*)magic,2)!=2) || (magic[0]!=HIST_UNDO))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * clean out history file OK if not modified in HIST_RECENT seconds
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(fstat(fd,&statb)>=0 && (time((time_t*)0)-statb.st_mtime) >= HIST_RECENT);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Copy the last <n> commands to a new file and make this the history file
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* The unlink can fail on windows 95 */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* use the old history file */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(--n < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(hist_new->histcnt > hist_new->histmarker+HIST_BSIZE/2)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hist_new->histmarker = hist_new->histcmds[hist_ind(hist_new,c)] = hist_new->histcnt;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!(buff=(char*)sfreserve(hist_old->histfp,SF_UNBOUND,0)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* copy to null byte */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(*cp++);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(*cp==0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * position history file at size and find next command number
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int hist_nearend(History_t *hp, Sfio_t *iop, register off_t size)
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 /* check for marker */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(*cp++);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(n);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(1);
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 else if(n>=histinit)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin switch(*((unsigned char*)(cp++)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin errormsg(SH_DICT,2,"index=%d marker=%d", hp->histind, n);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(*cp++);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(*cp==0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * This routine will cause the previous command to be cancelled
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int c;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * flush the current history command
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
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic ssize_t hist_write(Sfio_t *iop,const void *buff,register size_t insize,Sfdisc_t* handle)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int hist_write(Sfio_t *iop,const void *buff,register int insize,Sfdisc_t* handle)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin errormsg(SH_DICT,2,"hist_flush: EOF seek failed errno=%d",errno);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* remove whitespace from end of commands */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* don't count empty lines */
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#endif /* SHOPT_AUDIT */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin timechars = sfprintf(staksp, "\t%s\t%x\n",logname,time(NIL(long *)));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_ACCTFILE */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(hp->histflush>HIST_MARKSZ && hp->histcnt > hp->histmarker+HIST_BSIZE/2)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hp->histmarker = hp->histcmds[hist_ind(hp,c)] = hp->histcnt;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Put history sequence number <n> into buffer <buff>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * The buffer must be large enough to hold HIST_MARKSZ chars
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic void hist_marker(register char *buff,register long cmdno)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * return byte offset in history file for command <n>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * seek to the position of command <n>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(sfseek(hp->histfp,hp->histcmds[hist_ind(hp,n)],SEEK_SET));
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>.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinvoid hist_list(register History_t *hp,Sfio_t *outfile, off_t offset,int last, char *nl)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int c;
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
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinHistloc_t hist_find(register History_t*hp,char *string,register int index1,int flag,int direction)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* leading ^ means beginning of line unless escaped */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((location.hist_line=hist_match(hp,offset,string,coffset))>=0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* allow a search to be aborted */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if(((Shell_t*)hp->histshell)->trapnote&SH_SIGSET)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* KSHELL */
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
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinint hist_match(register History_t *hp,off_t offset,char *string,int *coffset)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_MULTIBYTE */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!(cp = first = (unsigned char*)sfgetr(hp->histfp,0,0)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(m > n)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_MULTIBYTE */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(-1);
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 register int c;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(c=='\n')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(line >= 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * return word number <word> from command number <command>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int c;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(NIL(char*));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(c==0 && flag==0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_ESH */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * given the current command and line number,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * and number of lines back or foward,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * compute the new command and line number.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinHistloc_t hist_locate(History_t *hp,register int command,register int line,int lines)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_ESH */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Handle history file exceptions
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int hist_exceptf(Sfio_t* fp, int type, void *data, Sfdisc_t *handle)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int hist_exceptf(Sfio_t* fp, int type, Sfdisc_t *handle)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* write failure could be NFS problem, try to re-open */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((newfd=open(hp->histname,O_BINARY|O_APPEND|O_CREAT|O_RDWR,S_IRUSR|S_IWUSR)) >= 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin errormsg(SH_DICT,2,"History file write error-%d %s: file unrecoverable",errno,hp->histname);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);