lineedit: add support for history saving on exit
authorDenys Vlasenko <vda.linux@googlemail.com>
Sun, 4 Sep 2011 14:12:33 +0000 (16:12 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Sun, 4 Sep 2011 14:12:33 +0000 (16:12 +0200)
Based on the patch by Dennis Groenen <tj.groenen@gmail.com>

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
include/libbb.h
libbb/Config.src
libbb/lineedit.c
shell/ash.c
shell/hush.c

index 63d0419576afe73d694bbcb52db86f23ace94e00..91343a95e27fb37faa7b1331b841266d2429846c 100644 (file)
@@ -1421,6 +1421,12 @@ typedef struct line_input_t {
        int cur_history;
        int max_history; /* must never be <= 0 */
 #  if ENABLE_FEATURE_EDITING_SAVEHISTORY
+       /* meaning of this field depends on FEATURE_EDITING_SAVE_ON_EXIT:
+        * if !FEATURE_EDITING_SAVE_ON_EXIT: "how many lines are
+        * in on-disk history"
+        * if FEATURE_EDITING_SAVE_ON_EXIT: "how many in-memory lines are
+        * also in on-disk history (and thus need to be skipped on save)"
+        */
        unsigned cnt_history_in_file;
        const char *hist_file;
 #  endif
@@ -1446,6 +1452,9 @@ line_input_t *new_line_input_t(int flags) FAST_FUNC;
  * >0 length of input string, including terminating '\n'
  */
 int read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout) FAST_FUNC;
+# if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
+void save_history(line_input_t *st);
+# endif
 #else
 #define MAX_HISTORY 0
 int read_line_input(const char* prompt, char* command, int maxsize) FAST_FUNC;
index aa442365abeba2072f621c52c58f4b01593f5c80..f6f88b9ce449fb183685df199e36a914d3dec8ee 100644 (file)
@@ -94,6 +94,13 @@ config FEATURE_EDITING_SAVEHISTORY
        help
          Enable history saving in shells.
 
+config FEATURE_EDITING_SAVE_ON_EXIT
+       bool "Save history on shell exit, not after every command"
+       default n
+       depends on FEATURE_EDITING_SAVEHISTORY
+       help
+         Save history on shell exit, not after every command.
+
 config FEATURE_REVERSE_SEARCH
        bool "Reverse history search"
        default y
index 5d139043a659dca8513933f0d524a8a0e544fb0e..0786f9ae6bd7c0ab676b67339c2f40b469cd3ace 100644 (file)
@@ -1351,7 +1351,9 @@ static void load_history(line_input_t *st_parm)
 
                /* fill temp_h[], retaining only last MAX_HISTORY lines */
                memset(temp_h, 0, sizeof(temp_h));
-               st_parm->cnt_history_in_file = idx = 0;
+               idx = 0;
+               if (!ENABLE_FEATURE_EDITING_SAVE_ON_EXIT)
+                       st_parm->cnt_history_in_file = 0;
                while ((line = xmalloc_fgetline(fp)) != NULL) {
                        if (line[0] == '\0') {
                                free(line);
@@ -1359,7 +1361,8 @@ static void load_history(line_input_t *st_parm)
                        }
                        free(temp_h[idx]);
                        temp_h[idx] = line;
-                       st_parm->cnt_history_in_file++;
+                       if (!ENABLE_FEATURE_EDITING_SAVE_ON_EXIT)
+                               st_parm->cnt_history_in_file++;
                        idx++;
                        if (idx == st_parm->max_history)
                                idx = 0;
@@ -1389,15 +1392,66 @@ static void load_history(line_input_t *st_parm)
                        st_parm->history[i++] = line;
                }
                st_parm->cnt_history = i;
+               if (ENABLE_FEATURE_EDITING_SAVE_ON_EXIT)
+                       st_parm->cnt_history_in_file = i;
        }
 }
 
-/* state->flags is already checked to be nonzero */
+#  if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
+void save_history(line_input_t *st)
+{
+       FILE *fp;
+
+       if (!(st->flags & SAVE_HISTORY))
+               return;
+       if (!st->hist_file)
+               return;
+       if (st->cnt_history <= st->cnt_history_in_file)
+               return;
+
+       fp = fopen(st->hist_file, "a");
+       if (fp) {
+               int i, fd;
+               char *new_name;
+               line_input_t *st_temp;
+
+               for (i = st->cnt_history_in_file; i < st->cnt_history; i++)
+                       fprintf(fp, "%s\n", st->history[i]);
+               fclose(fp);
+
+               /* we may have concurrently written entries from others.
+                * load them */
+               st_temp = new_line_input_t(st->flags);
+               st_temp->hist_file = st->hist_file;
+               st_temp->max_history = st->max_history;
+               load_history(st_temp);
+
+               /* write out temp file and replace hist_file atomically */
+               new_name = xasprintf("%s.%u.new", st->hist_file, (int) getpid());
+               fd = open(new_name, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+               if (fd >= 0) {
+                       fp = xfdopen_for_write(fd);
+                       for (i = 0; i < st_temp->cnt_history; i++)
+                               fprintf(fp, "%s\n", st_temp->history[i]);
+                       fclose(fp);
+                       if (rename(new_name, st->hist_file) == 0)
+                               st->cnt_history_in_file = st_temp->cnt_history;
+               }
+               free(new_name);
+               free_line_input_t(st_temp);
+       }
+}
+#  else
 static void save_history(char *str)
 {
        int fd;
        int len, len2;
 
+       if (!(state->flags & SAVE_HISTORY))
+               return;
+       if (!state->hist_file)
+               return;
+
        fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0600);
        if (fd < 0)
                return;
@@ -1441,6 +1495,7 @@ static void save_history(char *str)
                free_line_input_t(st_temp);
        }
 }
+#  endif
 # else
 #  define load_history(a) ((void)0)
 #  define save_history(a) ((void)0)
@@ -1469,15 +1524,16 @@ static void remember_in_history(char *str)
                for (i = 0; i < state->max_history-1; i++)
                        state->history[i] = state->history[i+1];
                /* i == state->max_history-1 */
+               if (ENABLE_FEATURE_EDITING_SAVE_ON_EXIT && state->cnt_history_in_file)
+                       state->cnt_history_in_file--;
        }
        /* i <= state->max_history-1 */
        state->history[i++] = xstrdup(str);
        /* i <= state->max_history */
        state->cur_history = i;
        state->cnt_history = i;
-# if ENABLE_FEATURE_EDITING_SAVEHISTORY
-       if ((state->flags & SAVE_HISTORY) && state->hist_file)
-               save_history(str);
+# if ENABLE_FEATURE_EDITING_SAVEHISTORY && !ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
+       save_history(str);
 # endif
        IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines++;)
 }
index bf376bd0dcf738eae89530869632127adea07d3a..14472cb614042cd8779f34a961c8502a8d30d9f5 100644 (file)
@@ -12888,6 +12888,10 @@ exitshell(void)
        char *p;
        int status;
 
+#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
+       save_history(line_input_state);
+#endif
+
        status = exitstatus;
        TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
        if (setjmp(loc.loc)) {
index 42143fd9e7dcfa93a1ba6d05c0388323d185cadb..a9e2dd3117bc1458296960c64a6b40dd452323cf 100644 (file)
@@ -1541,6 +1541,10 @@ static sighandler_t pick_sighandler(unsigned sig)
 static void hush_exit(int exitcode) NORETURN;
 static void hush_exit(int exitcode)
 {
+#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
+       save_history(G.line_input_state);
+#endif
+
        fflush_all();
        if (G.exiting <= 0 && G.traps && G.traps[0] && G.traps[0][0]) {
                char *argv[3];