sh: implement persistent history storage
Implement persistent history storage: the strategy is simple at start: loads the existing .sh_history file at exit dump it. The implementation respects the HISTFILE variable and its POSIX definition: ~/.sh_history is used if HISTFILE is not set. to avoid sh to create the history file, set HISTSIZE to 0 or HISTFILE to en empty value Co-authored-by: pstef Reviewed by: jilles Differential Revision: https://reviews.freebsd.org/D29493
This commit is contained in:
parent
9867224bab
commit
988b1bb0c5
@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <paths.h>
|
||||
#include <stdio.h>
|
||||
@ -78,6 +79,64 @@ static int comparator(const void *, const void *, void *);
|
||||
static char **sh_matches(const char *, int, int);
|
||||
static unsigned char sh_complete(EditLine *, int);
|
||||
|
||||
static const char *
|
||||
get_histfile(void)
|
||||
{
|
||||
const char *histfile;
|
||||
|
||||
/* don't try to save if the history size is 0 */
|
||||
if (hist == NULL || histsizeval() == 0)
|
||||
return (NULL);
|
||||
histfile = expandstr("${HISTFILE-${HOME-}/.sh_history}");
|
||||
|
||||
if (histfile[0] == '\0')
|
||||
return (NULL);
|
||||
return (histfile);
|
||||
}
|
||||
|
||||
void
|
||||
histsave(void)
|
||||
{
|
||||
HistEvent he;
|
||||
char *histtmpname = NULL;
|
||||
const char *histfile;
|
||||
int fd;
|
||||
FILE *f;
|
||||
|
||||
if ((histfile = get_histfile()) == NULL)
|
||||
return;
|
||||
INTOFF;
|
||||
asprintf(&histtmpname, "%s.XXXXXXXXXX", histfile);
|
||||
if (histtmpname == NULL) {
|
||||
INTON;
|
||||
return;
|
||||
}
|
||||
fd = mkstemp(histtmpname);
|
||||
if (fd == -1 || (f = fdopen(fd, "w")) == NULL) {
|
||||
free(histtmpname);
|
||||
INTON;
|
||||
return;
|
||||
}
|
||||
if (history(hist, &he, H_SAVE_FP, f) < 1 ||
|
||||
rename(histtmpname, histfile) == -1)
|
||||
unlink(histtmpname);
|
||||
fclose(f);
|
||||
free(histtmpname);
|
||||
INTON;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
histload(void)
|
||||
{
|
||||
const char *histfile;
|
||||
HistEvent he;
|
||||
|
||||
if ((histfile = get_histfile()) == NULL)
|
||||
return;
|
||||
history(hist, &he, H_LOAD, histfile);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set history and editing status. Called whenever the status may
|
||||
* have changed (figures out what to do).
|
||||
|
@ -75,6 +75,9 @@ __FBSDID("$FreeBSD$");
|
||||
#include "cd.h"
|
||||
#include "redir.h"
|
||||
#include "builtins.h"
|
||||
#ifndef NO_HISTORY
|
||||
#include "myhistedit.h"
|
||||
#endif
|
||||
|
||||
int rootpid;
|
||||
int rootshell;
|
||||
@ -157,6 +160,10 @@ main(int argc, char *argv[])
|
||||
read_profile(shinit);
|
||||
}
|
||||
}
|
||||
#ifndef NO_HISTORY
|
||||
if (iflag)
|
||||
histload();
|
||||
#endif
|
||||
state3:
|
||||
state = 4;
|
||||
popstackmark(&smark2);
|
||||
|
@ -43,4 +43,5 @@ extern int displayhist;
|
||||
void histedit(void);
|
||||
void sethistsize(const char *);
|
||||
void setterm(const char *);
|
||||
|
||||
void histload(void);
|
||||
void histsave(void);
|
||||
|
11
bin/sh/sh.1
11
bin/sh/sh.1
@ -32,7 +32,7 @@
|
||||
.\" from: @(#)sh.1 8.6 (Berkeley) 5/4/95
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd July 6, 2020
|
||||
.Dd May 10, 2021
|
||||
.Dt SH 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -1351,6 +1351,15 @@ If not set, the default editor is
|
||||
The default editor used with the
|
||||
.Ic fc
|
||||
built-in.
|
||||
.It Va HISTFILE
|
||||
File used for persistent history storage.
|
||||
If unset
|
||||
.Pa ~/.sh_history
|
||||
will be used.
|
||||
If set but empty or
|
||||
.Va HISTSIZE
|
||||
is set to 0
|
||||
the shell will not load and save the history.
|
||||
.It Va HISTSIZE
|
||||
The number of previous commands that are accessible.
|
||||
.It Va HOME
|
||||
|
@ -535,6 +535,9 @@ exitshell_savedstatus(void)
|
||||
flushall();
|
||||
#if JOBS
|
||||
setjobctl(0);
|
||||
#endif
|
||||
#ifndef NO_HISTORY
|
||||
histsave();
|
||||
#endif
|
||||
}
|
||||
if (sig != 0 && sig != SIGSTOP && sig != SIGTSTP && sig != SIGTTIN &&
|
||||
|
Loading…
Reference in New Issue
Block a user