From 64b2b7c08d427796d75411f5d3ea46e585ad2d4b Mon Sep 17 00:00:00 2001 From: Chet Ramey Date: Mon, 27 Mar 2023 09:28:12 -0400 Subject: fixes for glibc time/gettimeofday issue; fix issue with history file containing one line too few if saving timestamps; fix for signal arriving while displaying readline completions --- CWRU/CWRU.chlog | 71 +++++++++++++++++++++++++++++ MANIFEST | 1 + aclocal.m4 | 3 ++ configure | 3 ++ examples/loadables/finfo.c | 96 +++++++++------------------------------ examples/loadables/id.c | 4 +- examples/loadables/stat.c | 4 +- examples/loadables/strftime.c | 6 +++ examples/loadables/tee.c | 2 +- examples/loadables/tty.c | 2 +- general.h | 2 +- include/posixtime.h | 9 ++++ lib/readline/complete.c | 8 ++-- lib/readline/examples/histexamp.c | 10 ++-- lib/readline/histfile.c | 48 +++++++++++++++----- lib/readline/history.c | 3 +- lib/readline/misc.c | 9 ++-- lib/readline/undo.c | 2 + lib/sh/tmpfile.c | 3 +- parse.y | 49 ++++++++++++++------ support/man2html.c | 13 +++++- tests/history.right | 44 ++++++++++++++++++ tests/history.tests | 1 + tests/history7.sub | 73 +++++++++++++++++++++++++++++ variables.c | 3 +- 25 files changed, 344 insertions(+), 125 deletions(-) create mode 100644 tests/history7.sub diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 58fb8733..f6a14756 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -5748,3 +5748,74 @@ pcomplete.c - gen_globpat_matches: set noglob_dot_filenames here since we're not calling shell_glob_filename to do it From a report by Grisha Levit + + 3/22 + ---- +lib/readline/misc.c + - rl_maybe_replace_line: if we're replacing a history entry with the + current line buffer and undo list, then zero out any undo list in + _rl_saved_line_for_history, since we're not going to use it any more + Fixes asan error reported by Grisha Levit + +lib/readline/undo.c + - rl_free_undo_list: if we're freeing rl_undo_list, it can't be a + valid value for data in _rl_saved_line_for_history + Fixes asan error reported by Grisha Levit + +lib/readline/complete.c + - display_matches: don't call rl_display_match_list if we received a + signal during get_y_or_n and didn't jump out for some reason + From a report by Grisha Levit + - rl_display_match_list: return if we received a signal during + _rl_internal_pager (via get_y_or_n) and didn't jump out + From a report by Grisha Levit + + 3/23 + ---- +lib/readline/history.c + - history_truncate_file: don't bother trying to read the existing + history file if we're just truncating it to 0 lines + + 3/24 + ---- +lib/readline/history.c + - history_truncate_file: fix off-by-one error that resulted in the + timestamp associated with the first history entry not being written + to the truncated history file + From a report by Grisha Levit + +parse.y + - decode_prompt_string: do something rational if localtime() returns + NULL (extraordinarily rare) + From a report by Paul Eggert + +examples/loadables/stat.c + - stattime: ditto + +examples/loadables/strftime.c + - strftime_builtin: ditto + +lib/readline/examples/histexamp.c + - main: ditto + +include/posixtime.h + - getnow(): new inline function, calls gettimeofday and returns tv_sec; + replacement for time(0). From Paul Eggert + +general.h + - NOW: use a call to getnow() to standardize on gettimeofday for time + information + +lib/readline/history.c + - include #posixtime.h for getnow() + - hist_inittime: use getnow() instead of calling time(0) + +parse.y + - posixtime.h: include instead of + - decode_prompt_string: use getnow() instead of calling time(0) + + 3/27 + ---- +parse.y + - count_all_jobs: add extern definition if JOB_CONTROL is not defined. + From Emanuele Torre diff --git a/MANIFEST b/MANIFEST index 24cd4eeb..14c2e0f1 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1208,6 +1208,7 @@ tests/history3.sub f tests/history4.sub f tests/history5.sub f tests/history6.sub f +tests/history7.sub f tests/ifs.tests f tests/ifs.right f tests/ifs1.sub f diff --git a/aclocal.m4 b/aclocal.m4 index 37546c6c..93251a76 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -238,6 +238,9 @@ AC_CACHE_VAL(bash_cv_dup2_broken, #include #include #include +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ int main() { diff --git a/configure b/configure index 78e55ecf..f5d1fad2 100755 --- a/configure +++ b/configure @@ -18135,6 +18135,9 @@ else $as_nop #include #include #include +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ int main() { diff --git a/examples/loadables/finfo.c b/examples/loadables/finfo.c index 6491ef0e..64a9e910 100644 --- a/examples/loadables/finfo.c +++ b/examples/loadables/finfo.c @@ -6,7 +6,7 @@ */ /* - Copyright (C) 1999-2009,2022 Free Software Foundation, Inc. + Copyright (C) 1999-2009,2022,2023 Free Software Foundation, Inc. This file is part of GNU Bash. Bash is free software: you can redistribute it and/or modify @@ -96,8 +96,7 @@ static int pmask; #define OPTIONS "acdgiflmnopsuACGMP:U" static int -octal(s) -char *s; +octal(char *s) { int r; @@ -108,9 +107,7 @@ char *s; } static int -finfo_main(argc, argv) -int argc; -char **argv; +finfo_main(int argc, char **argv) { register int i; int mode, flags, opt; @@ -162,8 +159,7 @@ char **argv; } static struct stat * -getstat(f) -char *f; +getstat(char *f) { static struct stat st; int fd, r; @@ -190,8 +186,7 @@ char *f; } static int -printfinfo(f) -char *f; +printfinfo(char *f) { struct stat *st; @@ -200,15 +195,13 @@ char *f; } static int -getperm(m) -int m; +getperm(int m) { return (m & (S_IRWXU|S_IRWXG|S_IRWXO|S_ISUID|S_ISGID)); } static void -perms(m) -int m; +perms(int m) { char ubits[4], gbits[4], obits[4]; /* u=rwx,g=rwx,o=rwx */ int i; @@ -251,8 +244,7 @@ int m; } static void -printmode(mode) -int mode; +printmode(int mode) { if (S_ISBLK(mode)) printf("S_IFBLK "); @@ -277,8 +269,7 @@ int mode; } static int -printst(st) -struct stat *st; +printst(struct stat *st) { struct passwd *pw; struct group *gr; @@ -314,9 +305,7 @@ struct stat *st; } static int -printsome(f, flags) -char *f; -int flags; +printsome(char *f, int flags) { struct stat *st; struct passwd *pw; @@ -400,8 +389,7 @@ int flags; #ifndef NOBUILTIN int -finfo_builtin(list) - WORD_LIST *list; +finfo_builtin(WORD_LIST *list) { int c, r; char **v; @@ -456,34 +444,26 @@ struct builtin finfo_struct = { #endif #ifdef NOBUILTIN -#if defined (PREFER_STDARG) -# include -#else -# if defined (PREFER_VARARGS) -# include -# endif -#endif +#include char *this_command_name; -main(argc, argv) -int argc; -char **argv; +int +main(int argc, char **argv) { this_command_name = argv[0]; exit(finfo_main(argc, argv)); } void -builtin_usage() +builtin_usage(void) { fprintf(stderr, "%s: usage: %s [-%s] [file ...]\n", prog, prog, OPTIONS); } #ifndef HAVE_STRERROR char * -strerror(e) -int e; +strerror(int e) { static char ebuf[40]; extern int sys_nerr; @@ -497,23 +477,20 @@ int e; } #endif -char * -xmalloc(s) -size_t s; +PTR_T +xmalloc(size_t s) { char *ret; - extern char *malloc(); ret = malloc(s); if (ret) return (ret); - fprintf(stderr, "%s: cannot malloc %d bytes\n", prog, s); + fprintf(stderr, "%s: cannot malloc %zu bytes\n", prog, s); exit(1); } char * -base_pathname(p) -char *p; +base_pathname(char *p) { char *t; @@ -523,9 +500,7 @@ char *p; } int -legal_number (string, result) - char *string; - long *result; +legal_number (char *string, long result) { int sign; long value; @@ -584,9 +559,7 @@ extern int optind; extern char *optarg; int -sh_getopt(c, v, o) -int c; -char **v, *o; +sh_getopt(int c, char **v, char *o) { int r; @@ -596,43 +569,18 @@ char **v, *o; return r; } -#if defined (USE_VARARGS) void -#if defined (PREFER_STDARG) builtin_error (const char *format, ...) -#else -builtin_error (format, va_alist) - const char *format; - va_dcl -#endif { va_list args; if (this_command_name && *this_command_name) fprintf (stderr, "%s: ", this_command_name); -#if defined (PREFER_STDARG) va_start (args, format); -#else - va_start (args); -#endif vfprintf (stderr, format, args); va_end (args); fprintf (stderr, "\n"); } -#else -void -builtin_error (format, arg1, arg2, arg3, arg4, arg5) - char *format, *arg1, *arg2, *arg3, *arg4, *arg5; -{ - if (this_command_name && *this_command_name) - fprintf (stderr, "%s: ", this_command_name); - - fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5); - fprintf (stderr, "\n"); - fflush (stderr); -} -#endif /* !USE_VARARGS */ - #endif diff --git a/examples/loadables/id.c b/examples/loadables/id.c index f46f75ce..98c37ea3 100644 --- a/examples/loadables/id.c +++ b/examples/loadables/id.c @@ -41,9 +41,9 @@ #endif #if !defined (HAVE_GETPW_DECLS) -extern struct passwd *getpwuid (); +extern struct passwd *getpwuid (uid_t); #endif -extern struct group *getgrgid (); +extern struct group *getgrgid (gid_t); #include "shell.h" #include "builtins.h" diff --git a/examples/loadables/stat.c b/examples/loadables/stat.c index 3ca1a589..1093f7b0 100644 --- a/examples/loadables/stat.c +++ b/examples/loadables/stat.c @@ -3,7 +3,7 @@ /* See Makefile for compilation details. */ /* - Copyright (C) 2016,2022 Free Software Foundation, Inc. + Copyright (C) 2016,2022-2023 Free Software Foundation, Inc. This file is part of GNU Bash. Bash is free software: you can redistribute it and/or modify @@ -261,6 +261,8 @@ stattime (time_t t, const char *timefmt) fmt = timefmt ? timefmt : DEFTIMEFMT; tm = localtime (&t); + if (tm == 0) + return (itos (t)); ret = xmalloc (TIMELEN_MAX); diff --git a/examples/loadables/strftime.c b/examples/loadables/strftime.c index e6c8141e..506b3301 100644 --- a/examples/loadables/strftime.c +++ b/examples/loadables/strftime.c @@ -80,6 +80,12 @@ strftime_builtin (WORD_LIST *list) secs = NOW; t = localtime (&secs); + if (t == 0) + { + builtin_error ("%s: timestamp out of range", list && list->word->word ? list->word->word : "now"); + return (EXECUTION_FAILURE); + } + tbsize = strlen (format) * 4; tbuf = 0; diff --git a/examples/loadables/tee.c b/examples/loadables/tee.c index 9f26b2d4..c74cb647 100644 --- a/examples/loadables/tee.c +++ b/examples/loadables/tee.c @@ -58,7 +58,7 @@ static FLIST *tee_flist; extern int interrupt_immediately; -extern char *strerror (); +extern char *strerror (int); int tee_builtin (WORD_LIST *list) diff --git a/examples/loadables/tty.c b/examples/loadables/tty.c index b717766a..27a851bf 100644 --- a/examples/loadables/tty.c +++ b/examples/loadables/tty.c @@ -28,7 +28,7 @@ #include "bashgetopt.h" #include "common.h" -extern char *ttyname (); +extern char *ttyname (int); int tty_builtin (WORD_LIST *list) diff --git a/general.h b/general.h index fa57251a..74b97f42 100644 --- a/general.h +++ b/general.h @@ -242,7 +242,7 @@ typedef int sh_builtin_func_t (WORD_LIST *); /* sh_wlist_func_t */ #endif /* SH_FUNCTION_TYPEDEF */ -#define NOW ((time_t) time ((time_t *) 0)) +#define NOW getnow() #define GETTIME(tv) gettimeofday(&(tv), NULL) /* Some defines for calling file status functions. */ diff --git a/include/posixtime.h b/include/posixtime.h index 319cb168..a731b006 100644 --- a/include/posixtime.h +++ b/include/posixtime.h @@ -52,6 +52,15 @@ struct timeval extern int gettimeofday (struct timeval * restrict, void * restrict); #endif +/* consistently use gettimeofday for time information */ +static inline time_t +getnow(void) +{ + struct timeval now; + gettimeofday (&now, 0); + return now.tv_sec; +} + /* These exist on BSD systems, at least. */ #if !defined (timerclear) # define timerclear(tvp) do { (tvp)->tv_sec = 0; (tvp)->tv_usec = 0; } while (0) diff --git a/lib/readline/complete.c b/lib/readline/complete.c index 2016d393..ce9b8cd0 100644 --- a/lib/readline/complete.c +++ b/lib/readline/complete.c @@ -1630,7 +1630,7 @@ rl_display_match_list (char **matches, int len, int max) if (_rl_page_completions && lines >= (_rl_screenheight - 1) && i < count) { lines = _rl_internal_pager (lines); - if (lines < 0) + if (lines < 0 || _rl_complete_display_matches_interrupt) return; } } @@ -1658,7 +1658,7 @@ rl_display_match_list (char **matches, int len, int max) if (_rl_page_completions && lines >= _rl_screenheight - 1) { lines = _rl_internal_pager (lines); - if (lines < 0) + if (lines < 0 || _rl_complete_display_matches_interrupt) return; } } @@ -1745,7 +1745,9 @@ display_matches (char **matches) } } - rl_display_match_list (matches, len, max); + /* We rely on the caller to set MATCHES to 0 when this returns. */ + if (_rl_complete_display_matches_interrupt == 0) + rl_display_match_list (matches, len, max); rl_forced_update_display (); rl_display_fixed = 1; diff --git a/lib/readline/examples/histexamp.c b/lib/readline/examples/histexamp.c index 309d769b..2e946aca 100644 --- a/lib/readline/examples/histexamp.c +++ b/lib/readline/examples/histexamp.c @@ -32,9 +32,7 @@ #include int -main (argc, argv) - int argc; - char **argv; +main (int argc, char **argv) { char line[1024], *t; int len, done; @@ -91,6 +89,7 @@ main (argc, argv) register HIST_ENTRY **the_list; register int i; time_t tt; + struct tm *tm; char timestr[128]; the_list = history_list (); @@ -98,8 +97,9 @@ main (argc, argv) for (i = 0; the_list[i]; i++) { tt = history_get_time (the_list[i]); - if (tt) - strftime (timestr, sizeof (timestr), "%a %R", localtime(&tt)); + tm = tt ? localtime (&tt) : 0; + if (tm) + strftime (timestr, sizeof (timestr), "%a %R", tm); else strcpy (timestr, "??"); printf ("%d: %s: %s\n", i + history_base, timestr, the_list[i]->line); diff --git a/lib/readline/histfile.c b/lib/readline/histfile.c index a3c8d9bf..2af71d35 100644 --- a/lib/readline/histfile.c +++ b/lib/readline/histfile.c @@ -1,6 +1,6 @@ /* histfile.c - functions to manipulate the history file. */ -/* Copyright (C) 1989-2019 Free Software Foundation, Inc. +/* Copyright (C) 1989-2019,2023 Free Software Foundation, Inc. This file contains the GNU History Library (History), a set of routines for managing the text of previously typed lines. @@ -578,6 +578,15 @@ history_truncate_file (const char *fname, int lines) goto truncate_exit; } + /* Don't bother with any of this if we're truncating to zero length. */ + if (lines == 0) + { + close (file); + buffer[chars_read = 0] = '\0'; + bp = buffer; + goto truncate_write; + } + chars_read = read (file, buffer, file_size); close (file); @@ -586,30 +595,38 @@ history_truncate_file (const char *fname, int lines) rv = (chars_read < 0) ? errno : 0; goto truncate_exit; } + buffer[chars_read] = '\0'; /* for the initial check of bp1[1] */ /* Count backwards from the end of buffer until we have passed LINES lines. bp1 is set funny initially. But since bp[1] can't be a comment character (since it's off the end) and *bp can't be - both a newline and the history comment character, it should be OK. */ - for (bp1 = bp = buffer + chars_read - 1; lines && bp > buffer; bp--) + both a newline and the history comment character, it should be OK. + If we are writing history timestamps, we need to add one to LINES + because we decrement it one extra time the first time through the loop + and we need the final timestamp line. */ + lines += history_write_timestamps; + for (bp1 = bp = buffer + chars_read - 1; lines > 0 && bp > buffer; bp--) { if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0) lines--; bp1 = bp; } - /* If this is the first line, then the file contains exactly the + /* This is the right line, so move to its start. If we're writing history + timestamps, we want to go back until *bp == '\n' and bp1 starts a + history timestamp. If we're not, just move back to *bp == '\n'. + If this is the first line, then the file contains exactly the number of lines we want to truncate to, so we don't need to do - anything. It's the first line if we don't find a newline between - the current value of i and 0. Otherwise, write from the start of - this line until the end of the buffer. */ + anything, and we'll end up with bp == buffer. + Otherwise, write from the start of this line until the end of the + buffer. */ for ( ; bp > buffer; bp--) { - if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0) - { + if (*bp == '\n' && (history_write_timestamps == 0 || HIST_TIMESTAMP_START(bp1))) + { bp++; break; - } + } bp1 = bp; } @@ -623,15 +640,22 @@ history_truncate_file (const char *fname, int lines) goto truncate_exit; } +truncate_write: tempname = history_tempfile (filename); if ((file = open (tempname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0600)) != -1) { if (write (file, bp, chars_read - (bp - buffer)) < 0) - rv = errno; + { + rv = errno; + close (file); + } if (rv == 0 && fstat (file, &nfinfo) < 0) - rv = errno; + { + rv = errno; + close (file); + } if (rv == 0 && close (file) < 0) rv = errno; diff --git a/lib/readline/history.c b/lib/readline/history.c index 42580301..ee52e829 100644 --- a/lib/readline/history.c +++ b/lib/readline/history.c @@ -42,6 +42,7 @@ # endif # include #endif +#include "posixtime.h" #include @@ -261,7 +262,7 @@ hist_inittime (void) time_t t; char ts[64], *ret; - t = (time_t) time ((time_t *)0); + t = getnow (); #if defined (HAVE_VSNPRINTF) /* assume snprintf if vsnprintf exists */ snprintf (ts, sizeof (ts) - 1, "X%lu", (unsigned long) t); #else diff --git a/lib/readline/misc.c b/lib/readline/misc.c index 764482a0..e1ccecae 100644 --- a/lib/readline/misc.c +++ b/lib/readline/misc.c @@ -340,13 +340,14 @@ rl_maybe_replace_line (void) xfree (temp->line); FREE (temp->timestamp); xfree (temp); + /* What about _rl_saved_line_for_history? if the saved undo list is + rl_undo_list, and we just put that into a history entry, should + we set the saved undo list to NULL? */ + if (_rl_saved_line_for_history && (UNDO_LIST *)_rl_saved_line_for_history->data == rl_undo_list) + _rl_saved_line_for_history->data = 0; /* Do we want to set rl_undo_list = 0 here since we just saved it into a history entry? */ rl_undo_list = 0; - - /* XXX - what about _rl_saved_line_for_history? if the saved undo list - is rl_undo_list, and we just put that into a history entry, should - we set the saved undo list to NULL? */ } return 0; } diff --git a/lib/readline/undo.c b/lib/readline/undo.c index c9c2a5b2..492894c3 100644 --- a/lib/readline/undo.c +++ b/lib/readline/undo.c @@ -122,6 +122,8 @@ rl_free_undo_list (void) _rl_free_undo_list (rl_undo_list); rl_undo_list = (UNDO_LIST *)NULL; _hs_replace_history_data (-1, (histdata_t *)orig_list, (histdata_t *)NULL); + if (_rl_saved_line_for_history && (UNDO_LIST *)_rl_saved_line_for_history->data == orig_list) + _rl_saved_line_for_history->data = 0; } UNDO_LIST * diff --git a/lib/sh/tmpfile.c b/lib/sh/tmpfile.c index 18582b10..50267609 100644 --- a/lib/sh/tmpfile.c +++ b/lib/sh/tmpfile.c @@ -279,10 +279,11 @@ char * sh_mktmpdir (const char *nameroot, int flags) { char *filename; + int fd; #ifdef USE_MKDTEMP char *tdir, *dirname; const char *lroot; - int fd, tdlen; + int tdlen; filename = (char *)xmalloc (PATH_MAX + 1); tdir = get_tmpdir (flags); diff --git a/parse.y b/parse.y index 639912b6..a4c4c07c 100644 --- a/parse.y +++ b/parse.y @@ -73,6 +73,7 @@ # include "jobs.h" #else extern int cleanup_dead_jobs (void); +extern int count_all_jobs (void); #endif /* JOB_CONTROL */ #if defined (ALIAS) @@ -85,7 +86,7 @@ typedef void *alias_t; # ifndef _MINIX # include # endif -# include +# include "posixtime.h" # if defined (TM_IN_SYS_TIME) # include # include @@ -5976,13 +5977,17 @@ decode_prompt_string (char *string) case '@': case 'A': /* Make the current time/date into a string. */ - (void) time (&the_time); + the_time = getnow (); #if defined (HAVE_TZSET) sv_tz ("TZ"); /* XXX -- just make sure */ #endif tm = localtime (&the_time); - - if (c == 'd') + if (tm == 0) + { + strcpy (timebuf, "??"); + tslen = 2; + } + else if (c == 'd') tslen = strftime (timebuf, sizeof (timebuf), "%a %b %d", tm); else if (c == 't') tslen = strftime (timebuf, sizeof (timebuf), "%H:%M:%S", tm); @@ -6005,22 +6010,36 @@ decode_prompt_string (char *string) if (string[1] != '{') /* } */ goto not_escape; - (void) time (&the_time); + the_time = getnow (); tm = localtime (&the_time); string += 2; /* skip { */ - timefmt = xmalloc (strlen (string) + 3); - for (t = timefmt; *string && *string != '}'; ) - *t++ = *string++; - *t = '\0'; + t = string; + while (*string && *string != '}') + string++; c = *string; /* tested at add_string */ - if (timefmt[0] == '\0') + if (tm) + { + size_t tflen; + tflen = string - t; + timefmt = xmalloc (tflen + 3); + memcpy (timefmt, t, tflen); + timefmt[tflen] = '\0'; + + if (timefmt[0] == '\0') + { + timefmt[0] = '%'; + timefmt[1] = 'X'; /* locale-specific current time */ + timefmt[2] = '\0'; + } + + tslen = strftime (timebuf, sizeof (timebuf), timefmt, tm); + free (timefmt); + } + else { - timefmt[0] = '%'; - timefmt[1] = 'X'; /* locale-specific current time */ - timefmt[2] = '\0'; + strcpy (timebuf, "??"); + tslen = 2; } - tslen = strftime (timebuf, sizeof (timebuf), timefmt, tm); - free (timefmt); if (tslen == 0) timebuf[0] = '\0'; diff --git a/support/man2html.c b/support/man2html.c index e6f441b4..097f48ee 100644 --- a/support/man2html.c +++ b/support/man2html.c @@ -452,10 +452,19 @@ print_sig(void) struct tm *timetm; time_t clock; - datbuf[0] = '\0'; +#ifdef HAVE_GETTIMEOFDAY + struct timeval tv; + gettimeofday (&tv, 0); + clock = tv.tv_sec; +#else clock = time(NULL); +#endif timetm = localtime(&clock); - strftime(datbuf, MED_STR_MAX, TIMEFORMAT, timetm); + datbuf[0] = '\0'; + if (timetm) + strftime(datbuf, MED_STR_MAX, TIMEFORMAT, timetm); + else + strcpy (datbuf, "??"); printf(signature, manpage, datbuf); } diff --git a/tests/history.right b/tests/history.right index 5273de6b..82e576fc 100644 --- a/tests/history.right +++ b/tests/history.right @@ -297,3 +297,47 @@ out of range 4 7 echo 9 8 echo 10 5 echo 10 +$ 1 +$ 2 +$ 3 +$ exit + 6 +$ 1 +$ 2 +$ 3 +$ 4 +$ 5 +$ exit + 6 +$ 1 +$ 2 +$ exit + 4 +$ e 1 +$ e 2 +$ e 3 +$ exit + 3 +e 1 +e 2 +e 3 +$ x 1 +$ x 2 +$ x 3 +$ x 4 +$ x 5 +$ exit + 3 +x 3 +x 4 +x 5 +$ y 1 +$ y 2 +$ exit + 2 +y 1 +y 2 +$ 1 +$ 2 +$ exit + 0 diff --git a/tests/history.tests b/tests/history.tests index 5826d130..2bff8811 100644 --- a/tests/history.tests +++ b/tests/history.tests @@ -131,3 +131,4 @@ ${THIS_SH} ./history3.sub ${THIS_SH} ./history4.sub ${THIS_SH} ./history5.sub ${THIS_SH} ./history6.sub +${THIS_SH} ./history7.sub diff --git a/tests/history7.sub b/tests/history7.sub new file mode 100644 index 00000000..ad651a03 --- /dev/null +++ b/tests/history7.sub @@ -0,0 +1,73 @@ +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# test history file truncation for various values of $HISTFILESIZE + +: ${THIS_SH:=./bash} +: ${TMPDIR:=/var/tmp} + +export HISTTIMEFORMAT= +export HISTFILESIZE=3 +export HISTFILE=$TMPDIR/hist-$$ +export PS1='$ ' + +rm -f $HISTFILE + +# exactly the number of lines +${THIS_SH} --norc -in <<<$'1\n2\n3' +wc -l < $HISTFILE + +rm -f $HISTFILE + +# truncating to fewer lines +${THIS_SH} --norc -in <<<$'1\n2\n3\n4\n5' +wc -l < $HISTFILE + +rm -f $HISTFILE + +# the history file contains fewer lines than $HISTFILESIZE +${THIS_SH} --norc -in <<<$'1\n2' +wc -l < $HISTFILE + +rm -f $HISTFILE + +# now we try it without timestamps +unset HISTTIMEFORMAT + +# exactly the number of lines +${THIS_SH} --norc -in <<<$'e 1\ne 2\ne 3' +wc -l < $HISTFILE +cat $HISTFILE + +rm -f $HISTFILE + +# truncating to fewer lines +${THIS_SH} --norc -in <<<$'x 1\nx 2\nx 3\nx 4\nx 5' +wc -l < $HISTFILE +cat $HISTFILE + +rm -f $HISTFILE + +# the history file contains fewer lines than $HISTFILESIZE +${THIS_SH} --norc -in <<<$'y 1\ny 2' +wc -l < $HISTFILE +cat $HISTFILE + +rm -f $HISTFILE + +# we want to truncate the history file to zero length +HISTFILESIZE=0 +${THIS_SH} --norc -in <<<$'1\n2' +wc -l < $HISTFILE + +rm -f $HISTFILE diff --git a/variables.c b/variables.c index 9f944067..1d67cc8c 100644 --- a/variables.c +++ b/variables.c @@ -2445,8 +2445,7 @@ find_function_def (const char *name) /* Return the value of VAR. VAR is assumed to have been the result of a lookup without any subscript, if arrays are compiled into the shell. */ char * -get_variable_value (var) - SHELL_VAR *var; +get_variable_value (SHELL_VAR *var) { if (var == 0) return ((char *)NULL); -- cgit v1.2.1