summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChet Ramey <chet.ramey@case.edu>2023-03-27 09:28:12 -0400
committerChet Ramey <chet.ramey@case.edu>2023-03-27 09:28:12 -0400
commit64b2b7c08d427796d75411f5d3ea46e585ad2d4b (patch)
tree76be3ef5f55ba9e7420f8106bd7db4c835d47fe7
parentf539a75606a39df0802172a6839099378b5ee65c (diff)
downloadbash-64b2b7c08d427796d75411f5d3ea46e585ad2d4b.tar.gz
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
-rw-r--r--CWRU/CWRU.chlog71
-rw-r--r--MANIFEST1
-rw-r--r--aclocal.m43
-rwxr-xr-xconfigure3
-rw-r--r--examples/loadables/finfo.c96
-rw-r--r--examples/loadables/id.c4
-rw-r--r--examples/loadables/stat.c4
-rw-r--r--examples/loadables/strftime.c6
-rw-r--r--examples/loadables/tee.c2
-rw-r--r--examples/loadables/tty.c2
-rw-r--r--general.h2
-rw-r--r--include/posixtime.h9
-rw-r--r--lib/readline/complete.c8
-rw-r--r--lib/readline/examples/histexamp.c10
-rw-r--r--lib/readline/histfile.c48
-rw-r--r--lib/readline/history.c3
-rw-r--r--lib/readline/misc.c9
-rw-r--r--lib/readline/undo.c2
-rw-r--r--lib/sh/tmpfile.c3
-rw-r--r--parse.y49
-rw-r--r--support/man2html.c13
-rw-r--r--tests/history.right44
-rw-r--r--tests/history.tests1
-rw-r--r--tests/history7.sub73
-rw-r--r--variables.c3
25 files changed, 344 insertions, 125 deletions
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 <grishalevit@gmail.com>
+
+ 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 <grishalevit@gmail.com>
+
+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 <grishalevit@gmail.com>
+
+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 <grishalevit@gmail.com>
+ - 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 <grishalevit@gmail.com>
+
+ 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 <grishalevit@gmail.com>
+
+parse.y
+ - decode_prompt_string: do something rational if localtime() returns
+ NULL (extraordinarily rare)
+ From a report by Paul Eggert <eggert@cs.ucla.edu>
+
+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 <eggert@cs.ucla.edu>
+
+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 <time.h>
+ - 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 <torreemanuele6@gmail.com>
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 <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#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 <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#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 <stdarg.h>
-#else
-# if defined (PREFER_VARARGS)
-# include <varargs.h>
-# endif
-#endif
+#include <stdarg.h>
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 <string.h>
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 <unistd.h>
#endif
+#include "posixtime.h"
#include <errno.h>
@@ -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 <sys/param.h>
# endif
-# include <time.h>
+# include "posixtime.h"
# if defined (TM_IN_SYS_TIME)
# include <sys/types.h>
# include <sys/time.h>
@@ -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 <http://www.gnu.org/licenses/>.
+#
+# 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);