when using persistent history (and not MKSH_SMALL), let the shells

concurrently accessing the same $HISTFILE be more synchronised with
each other: empty lines (just pressing Return) and duplicates (that
are split and written twice by the lines loaded from $HISTFILE in
the meantime); requested by Maximilian “mxey” Gaß in #!/bin/mksh
This commit is contained in:
tg 2010-01-25 16:12:57 +00:00
parent f3b3b4b1fb
commit 2765a07564
4 changed files with 65 additions and 27 deletions

View File

@ -2,7 +2,7 @@
/* $OpenBSD: trap.c,v 1.22 2005/03/30 17:16:37 deraadt Exp $ */
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
* Thorsten Glaser <tg@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@ -26,7 +26,7 @@
#include <sys/file.h>
#endif
__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.90 2009/12/12 22:27:08 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.91 2010/01/25 16:12:55 tg Exp $");
/*-
* MirOS: This is the default mapping type, and need not be specified.
@ -51,7 +51,7 @@ static int sprinkle(int);
static int hist_execute(char *);
static int hist_replace(char **, const char *, const char *, int);
static char **hist_get(const char *, int, int);
static char **hist_get(const char *, bool, bool);
static char **hist_get_oldest(void);
static void histbackup(void);
@ -368,7 +368,7 @@ hist_replace(char **hp, const char *pat, const char *rep, int globr)
* pattern is a number or string
*/
static char **
hist_get(const char *str, int approx, int allow_cur)
hist_get(const char *str, bool approx, bool allow_cur)
{
char **hp = NULL;
int n;
@ -407,7 +407,7 @@ hist_get(const char *str, int approx, int allow_cur)
/* Return a pointer to the newest command in the history */
char **
hist_get_newest(int allow_cur)
hist_get_newest(bool allow_cur)
{
if (histptr < history || (!allow_cur && histptr == history)) {
bi_errorf("no history (yet)");
@ -592,6 +592,27 @@ init_histvec(void)
* It turns out that there is a lot of ghastly hackery here
*/
#if !defined(MKSH_SMALL) && HAVE_PERSISTENT_HISTORY
/* do not save command in history but possibly sync */
bool
histsync(void)
{
bool changed = false;
if (histfd) {
int lno = hist_source->line;
hist_source->line++;
writehistfile(0, NULL);
hist_source->line--;
if (lno != hist_source->line)
changed = true;
}
return (changed);
}
#endif
/*
* save command in history
@ -606,7 +627,11 @@ histsave(int *lnp, const char *cmd, bool dowrite MKSH_A_UNUSED, bool ignoredups)
if ((cp = strchr(c, '\n')) != NULL)
*cp = '\0';
if (ignoredups && !strcmp(c, *histptr)) {
if (ignoredups && !strcmp(c, *histptr)
#if !defined(MKSH_SMALL) && HAVE_PERSISTENT_HISTORY
&& !histsync()
#endif
) {
afree(c, APERM);
return;
}
@ -962,19 +987,21 @@ writehistfile(int lno, char *cmd)
goto bad;
}
}
/*
* we can write our bit now
*/
hdr[0] = COMMAND;
hdr[1] = (lno>>24)&0xff;
hdr[2] = (lno>>16)&0xff;
hdr[3] = (lno>>8)&0xff;
hdr[4] = lno&0xff;
bytes = strlen(cmd) + 1;
if ((write(histfd, hdr, 5) != 5) ||
(write(histfd, cmd, bytes) != bytes))
goto bad;
hsize = lseek(histfd, (off_t)0, SEEK_END);
if (cmd) {
/*
* we can write our bit now
*/
hdr[0] = COMMAND;
hdr[1] = (lno>>24)&0xff;
hdr[2] = (lno>>16)&0xff;
hdr[3] = (lno>>8)&0xff;
hdr[4] = lno&0xff;
bytes = strlen(cmd) + 1;
if ((write(histfd, hdr, 5) != 5) ||
(write(histfd, cmd, bytes) != bytes))
goto bad;
hsize = lseek(histfd, (off_t)0, SEEK_END);
}
(void)flock(histfd, LOCK_UN);
return;
bad:

15
lex.c
View File

@ -22,7 +22,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.103 2009/12/05 20:17:59 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.104 2010/01/25 16:12:56 tg Exp $");
/*
* states while lexing word
@ -1321,7 +1321,7 @@ static void
getsc_line(Source *s)
{
char *xp = Xstring(s->xs, xp), *cp;
int interactive = Flag(FTALKING) && s->type == SSTDIN;
bool interactive = Flag(FTALKING) && s->type == SSTDIN;
int have_tty = interactive && (s->flags & SF_TTY);
/* Done here to ensure nothing odd happens when a timeout occurs */
@ -1413,8 +1413,17 @@ getsc_line(Source *s)
shf_fdclose(s->u.shf);
s->str = NULL;
} else if (interactive && *s->str &&
(cur_prompt != PS1 || !ctype(*s->str, C_IFS | C_IFSWS)))
(cur_prompt != PS1 || !ctype(*s->str, C_IFS | C_IFSWS))) {
histsave(&s->line, s->str, true, true);
#if !defined(MKSH_SMALL) && HAVE_PERSISTENT_HISTORY
} else if (interactive && cur_prompt == PS1) {
cp = Xstring(s->xs, xp);
while (*cp && ctype(*cp, C_IFSWS))
++cp;
if (!*cp)
histsync();
#endif
}
if (interactive)
set_prompt(PS2, NULL);
}

5
mksh.1
View File

@ -1,4 +1,4 @@
.\" $MirOS: src/bin/mksh/mksh.1,v 1.208 2010/01/25 14:25:15 tg Exp $
.\" $MirOS: src/bin/mksh/mksh.1,v 1.209 2010/01/25 16:12:56 tg Exp $
.\" $OpenBSD: ksh.1,v 1.129 2009/05/28 06:09:06 jmc Exp $
.\"-
.\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
@ -1727,8 +1727,7 @@ below for more information.
.It Ev HISTFILE
The name of the file used to store command history.
When assigned to, history is loaded from the specified file.
Also, several invocations of the shell
running on the same machine will share history if their
Also, several invocations of the shell will share history if their
.Ev HISTFILE
parameters all point to the same file.
.Pp

7
sh.h
View File

@ -148,7 +148,7 @@
#endif
#ifdef EXTERN
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.375 2010/01/25 14:38:03 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.376 2010/01/25 16:12:57 tg Exp $");
#endif
#define MKSH_VERSION "R39 2010/01/08"
@ -1432,6 +1432,9 @@ void hist_init(Source *);
void hist_finish(void);
#endif
void histsave(int *, const char *, bool, bool);
#if !defined(MKSH_SMALL) && HAVE_PERSISTENT_HISTORY
bool histsync(void);
#endif
int c_fc(const char **);
void sethistsize(int);
#if HAVE_PERSISTENT_HISTORY
@ -1441,7 +1444,7 @@ char **histpos(void);
int histnum(int);
int findhist(int, int, const char *, int);
int findhistrel(const char *);
char **hist_get_newest(int);
char **hist_get_newest(bool);
void inittraps(void);
void alarm_init(void);
Trap *gettrap(const char *, int);