This implements a feature I miss from bash.  What I care about:
- not clog the history with repeated commands
- easily prevent some commands to go in the history

The diff below implements HISTCONTROL for this, user-facing behavior
based on bash.  The default ksh behavior doesn't change.

I did not implement:
- "ignoreboth", which is a shorthand for "ignoredups:ignorespace";
   trivial, but not really useful
- "erasedups", I have no use for this and it's not as trivial

I have yet to put this in an mkr (dunno yet if the space savings of the
setlocale removal positively affects the ramdisks).

Thoughts?  ok?


Index: history.c
===================================================================
RCS file: /d/cvs/src/bin/ksh/history.c,v
retrieving revision 1.68
diff -u -p -r1.68 history.c
--- history.c   28 Aug 2017 19:41:55 -0000      1.68
+++ history.c   30 Aug 2017 10:38:43 -0000
@@ -42,6 +42,8 @@ static FILE   *histfh;
 static char   **current;       /* current position in history[] */
 static char    *hname;         /* current name of history file */
 static int     hstarted;       /* set after hist_init() called */
+static int     ignoredups;     /* ditch duplicated history lines? */
+static int     ignorespace;    /* ditch lines starting with a space? */
 static Source  *hist_source;
 static uint32_t        line_co;
 
@@ -513,6 +515,28 @@ findhistrel(const char *str)
        return start + rec + 1;
 }
 
+void
+sethistcontrol(const char *str)
+{
+       char *spec, *tok, *state;
+
+       ignorespace = 0;
+       ignoredups = 0;
+
+       if (str == NULL)
+               return;
+
+       spec = str_save(str, ATEMP);
+       for (tok = strtok_r(spec, ":", &state); tok != NULL;
+            tok = strtok_r(NULL, ":", &state)) {
+               if (strcmp(tok, "ignoredups") == 0)
+                       ignoredups = 1;
+               else if (strcmp(tok, "ignorespace") == 0)
+                       ignorespace = 1;
+       }
+       afree(spec, ATEMP);
+}
+
 /*
  *     set history
  *     this means reallocating the dataspace
@@ -608,6 +632,18 @@ histsave(int lno, const char *cmd, int d
 {
        char            *c, *cp;
 
+       if (ignorespace && cmd[0] == ' ')
+               return;
+
+       c = str_save(cmd, APERM);
+       if ((cp = strrchr(c, '\n')) != NULL)
+               *cp = '\0';
+
+       if (ignoredups && histptr >= history && strcmp(*histptr, c) == 0) {
+               afree(c, APERM);
+               return;
+       }
+
        if (dowrite && histfh) {
 #ifndef SMALL
                struct stat     sb;
@@ -623,10 +659,6 @@ histsave(int lno, const char *cmd, int d
                }
 #endif
        }
-
-       c = str_save(cmd, APERM);
-       if ((cp = strrchr(c, '\n')) != NULL)
-               *cp = '\0';
 
        if (histptr < history + histsize - 1)
                histptr++;
Index: ksh.1
===================================================================
RCS file: /d/cvs/src/bin/ksh/ksh.1,v
retrieving revision 1.193
diff -u -p -r1.193 ksh.1
--- ksh.1       19 Aug 2017 06:19:42 -0000      1.193
+++ ksh.1       30 Aug 2017 10:38:43 -0000
@@ -1407,6 +1407,15 @@ It is also searched when a command can't
 See
 .Sx Functions
 below for more information.
+.It Ev HISTCONTROL
+A colon separated list of history settings.
+If
+.Li ignoredups
+is present, lines identical to the previous history line will not be saved.
+If
+.Li ignorespace
+is present, lines starting with a space will not be saved.
+Unknown settings are ignored.
 .It Ev HISTFILE
 The name of the file used to store command history.
 When assigned to, history is loaded from the specified file.
Index: sh.h
===================================================================
RCS file: /d/cvs/src/bin/ksh/sh.h,v
retrieving revision 1.61
diff -u -p -r1.61 sh.h
--- sh.h        4 Jul 2017 11:46:15 -0000       1.61
+++ sh.h        30 Aug 2017 10:38:43 -0000
@@ -457,6 +457,7 @@ void        hist_finish(void);
 void   histsave(int, const char *, int);
 #ifdef HISTORY
 int    c_fc(char **);
+void   sethistcontrol(const char *);
 void   sethistsize(int);
 void   sethistfile(const char *);
 char **        histpos(void);
Index: table.h
===================================================================
RCS file: /d/cvs/src/bin/ksh/table.h,v
retrieving revision 1.11
diff -u -p -r1.11 table.h
--- table.h     10 Oct 2015 07:35:16 -0000      1.11
+++ table.h     30 Aug 2017 10:38:43 -0000
@@ -160,15 +160,16 @@ extern const struct builtin shbuiltins [
 #define        V_MAILPATH              6
 #define        V_MAILCHECK             7
 #define        V_RANDOM                8
-#define V_HISTSIZE             9
-#define V_HISTFILE             10
-#define V_VISUAL               11
-#define V_EDITOR               12
-#define V_COLUMNS              13
-#define V_POSIXLY_CORRECT      14
-#define V_TMOUT                        15
-#define V_TMPDIR               16
-#define V_LINENO               17
+#define        V_HISTCONTROL           9
+#define        V_HISTSIZE              10
+#define        V_HISTFILE              11
+#define        V_VISUAL                12
+#define        V_EDITOR                13
+#define        V_COLUMNS               14
+#define        V_POSIXLY_CORRECT       15
+#define        V_TMOUT                 16
+#define        V_TMPDIR                17
+#define        V_LINENO                18
 
 /* values for set_prompt() */
 #define PS1    0               /* command */
Index: var.c
===================================================================
RCS file: /d/cvs/src/bin/ksh/var.c,v
retrieving revision 1.57
diff -u -p -r1.57 var.c
--- var.c       8 Sep 2016 15:50:50 -0000       1.57
+++ var.c       30 Aug 2017 10:38:43 -0000
@@ -98,6 +98,7 @@ initvar(void)
                { "POSIXLY_CORRECT",    V_POSIXLY_CORRECT },
                { "TMPDIR",             V_TMPDIR },
 #ifdef HISTORY
+               { "HISTCONTROL",        V_HISTCONTROL },
                { "HISTFILE",           V_HISTFILE },
                { "HISTSIZE",           V_HISTSIZE },
 #endif /* HISTORY */
@@ -993,6 +994,9 @@ setspec(struct tbl *vp)
                }
                break;
 #ifdef HISTORY
+       case V_HISTCONTROL:
+               sethistcontrol(str_val(vp));
+               break;
        case V_HISTSIZE:
                vp->flag &= ~SPECIAL;
                sethistsize((int) intval(vp));
@@ -1086,6 +1090,11 @@ unsetspec(struct tbl *vp)
        case V_MAILPATH:
                mpset(NULL);
                break;
+#ifdef HISTORY
+       case V_HISTCONTROL:
+               sethistcontrol(NULL);
+               break;
+#endif
        case V_LINENO:
        case V_MAILCHECK:       /* at&t ksh leaves previous value in place */
        case V_RANDOM:

-- 
jca | PGP : 0x1524E7EE / 5135 92C1 AD36 5293 2BDF  DDCC 0DFA 74AE 1524 E7EE

Reply via email to