1
0
mirror of https://frontier.innolan.net/rainlance/amiga-tz.git synced 2025-11-22 19:40:44 +00:00

Add FreeBSD-style -r option to 'date'.

* date.1: Document -r.
* date.c (main, usage): Support -r.
(main, reset): Remove EBUG code.
(display): New argument NOW.  Do not exit; that's now the
caller's responsibility.  All callers changed.
(display, timeout, convert, checkfinal, iffy):
Don't assume that localtime and gmtime succeed.
This prevents a core dump for, e.g., 'date -r 0xffffffffffffffff'.
* private.h: Include float.h.
(strtoimax): New macro, for pre-C99 systems that lack strtoimax.
(time_t_min, time_t_max): New constants, from zdump, with
different names to avoid a clash when zdump.c includes private.h.
This commit is contained in:
Paul Eggert
2013-08-09 00:40:14 -07:00
parent fae3f9c2e8
commit b90b803c05
3 changed files with 125 additions and 55 deletions

11
date.1
View File

@ -10,6 +10,9 @@ date \- show and set date and time
] [
.B \-c
] [
.B \-r
seconds
] [
.B \-n
] [
.B \-d
@ -133,6 +136,14 @@ These options are available:
.BR \-u " or " \-c
Use UTC when setting and showing the date and time.
.TP
.BI "\-r " seconds
Output the date that corresponds to
.I seconds
past the epoch of 1970-01-01 00:00:00 UTC, where
.I seconds
should be an integer, either decimal, octal (leading 0), or
hexadecimal (leading 0x), preceded by an optional sign.
.TP
.B \-n
Do not notify other networked systems of the time change.
.TP

142
date.c
View File

@ -63,7 +63,7 @@ static int retval = EXIT_SUCCESS;
static void checkfinal(const char *, int, time_t, time_t);
static time_t convert(const char *, int, time_t);
static void display(const char *);
static void display(const char *, time_t);
static void dogmt(void);
static void errensure(void);
static void iffy(time_t, time_t, const char *, const char *);
@ -89,11 +89,14 @@ main(const int argc, char *argv[])
register int dflag = 0;
register int nflag = 0;
register int tflag = 0;
register int rflag = 0;
register int minuteswest;
register int dsttime;
register double adjust;
time_t now;
time_t t;
intmax_t secs;
char * endarg;
INITIALIZE(dousg);
INITIALIZE(minuteswest);
@ -109,9 +112,9 @@ main(const int argc, char *argv[])
#endif /* defined(TEXTDOMAINDIR) */
(void) textdomain(TZ_DOMAIN);
#endif /* HAVE_GETTEXT */
(void) time(&now);
t = now = time(NULL);
format = value = NULL;
while ((ch = getopt(argc, argv, "ucnd:t:a:")) != EOF && ch != -1) {
while ((ch = getopt(argc, argv, "ucr:nd:t:a:")) != EOF && ch != -1) {
switch (ch) {
default:
usage();
@ -119,6 +122,26 @@ main(const int argc, char *argv[])
case 'c':
dogmt();
break;
case 'r': /* seconds since 1970 */
if (rflag) {
(void) fprintf(stderr,
_("date: error: multiple -r's used"));
usage();
}
rflag = 1;
errno = 0;
secs = strtoimax (optarg, &endarg, 0);
if (*endarg || optarg == endarg)
errno = EINVAL;
else if (! (time_t_min <= secs && secs <= time_t_max))
errno = ERANGE;
if (errno) {
perror(optarg);
errensure();
exit(retval);
}
t = secs;
break;
case 'n': /* don't set network */
nflag = 1;
break;
@ -183,7 +206,7 @@ main(const int argc, char *argv[])
_("date: error: multiple formats in command line\n"));
usage();
}
else if (value == NULL)
else if (value == NULL && !rflag)
value = cp;
else {
(void) fprintf(stderr,
@ -272,28 +295,14 @@ _("date: warning: kernel doesn't keep -d/-t information, option ignored\n"));
#endif /* HAVE_SETTIMEOFDAY != 2 */
}
if (value == NULL)
display(format);
reset(t, nflag);
checkfinal(value, dousg, t, now);
#ifdef EBUG
{
struct tm tm;
tm = *localtime(&t);
timeout(stdout, "%c\n", &tm);
exit(retval);
if (value) {
reset(t, nflag);
checkfinal(value, dousg, t, now);
t = time(NULL);
}
#endif /* defined EBUG */
display(format);
/* gcc -Wall pacifier */
for ( ; ; )
continue;
display(format, t);
return retval;
}
static void
@ -449,9 +458,6 @@ reset(const time_t newt, const int nflag)
register const char * username;
static struct timeval tv; /* static so tv_usec is 0 */
#ifdef EBUG
return;
#endif /* defined EBUG */
username = getlogin();
if (username == NULL || *username == '\0') /* single-user or no tty */
username = "root";
@ -502,8 +508,10 @@ nondigit(register const char *cp)
static void
usage(void)
{
(void) fprintf(stderr, _("date: usage is date [-u] [-c] [-n] [-d dst] \
[-t min-west] [-a sss.fff] [[yyyy]mmddhhmm[yyyy][.ss]] [+format]\n"));
(void) fprintf(stderr,
_("date: usage: date [-u] [-c] [-r seconds] [-n]"
" [-d dst] [-t min-west] [-a sss.fff]"
" [[yyyy]mmddhhmm[yyyy][.ss]] [+format]\n"));
errensure();
exit(retval);
}
@ -517,18 +525,23 @@ oops(const char *const string)
errno = e;
(void) perror(string);
errensure();
display(NULL);
display(NULL, time(NULL));
exit(retval);
}
static void
display(const char *const format)
display(const char *const format, time_t const now)
{
struct tm tm;
time_t now;
struct tm *tmp;
(void) time(&now);
tm = *localtime(&now);
timeout(stdout, format ? format : "%+", &tm);
tmp = localtime(&now);
if (!tmp) {
(void) fprintf(stderr,
_("date: error: time out of range\n"));
errensure();
return;
}
timeout(stdout, format ? format : "%+", tmp);
(void) putchar('\n');
(void) fflush(stdout);
(void) fflush(stderr);
@ -537,20 +550,27 @@ display(const char *const format)
_("date: error: couldn't write results\n"));
errensure();
}
exit(retval);
}
#define INCR 1024
static void
timeout(FILE *const fp, const char *const format, const struct tm *const tmp)
timeout(FILE *const fp, const char *const format, const struct tm *tmp)
{
char * cp;
size_t result;
size_t size;
struct tm tm;
if (*format == '\0')
return;
if (!tmp) {
(void) fprintf(stderr, _("date: error: time out of range\n"));
errensure();
return;
}
tm = *tmp;
tmp = &tm;
size = INCR;
cp = malloc(size);
for ( ; ; ) {
@ -596,10 +616,13 @@ convert(register const char * const value, const int dousg, const time_t t)
register const char * cp;
register const char * dotp;
register int cent, year_in_cent, month, hour, day, mins, secs;
struct tm tm, outtm;
struct tm tm, outtm, *tmp;
time_t outt;
tm = *localtime(&t);
tmp = localtime(&t);
if (!tmp)
return -1;
tm = *tmp;
#define DIVISOR 100
year_in_cent = tm.tm_year % DIVISOR + TM_YEAR_BASE % DIVISOR;
cent = tm.tm_year / DIVISOR + TM_YEAR_BASE / DIVISOR +
@ -701,7 +724,7 @@ checkfinal(const char * const value,
const time_t oldnow)
{
time_t othert;
struct tm tm;
struct tm tm, *tmp;
struct tm othertm;
register int pass, offset;
@ -714,8 +737,10 @@ checkfinal(const char * const value,
/*
** See if there's both a DST and a STD version.
*/
tm = *localtime(&t);
othertm = tm;
tmp = localtime(&t);
if (!tmp)
iffy(t, othert, value, _("time out of range"));
othertm = tm = *tmp;
othertm.tm_isdst = !tm.tm_isdst;
othert = mktime(&othertm);
if (othert != -1 && othertm.tm_isdst != tm.tm_isdst &&
@ -748,7 +773,11 @@ checkfinal(const char * const value,
else if (pass == 3)
othert = t + 60 * offset;
else othert = t - 60 * offset;
othertm = *localtime(&othert);
tmp = localtime(&othert);
if (!tmp)
iffy(t, othert, value,
_("time out of range"));
othertm = *tmp;
if (sametm(&tm, &othertm))
iffy(t, othert, value,
_("multiple matching times exist"));
@ -759,29 +788,32 @@ static void
iffy(const time_t thist, const time_t thatt,
const char * const value, const char * const reason)
{
struct tm tm;
struct tm *tmp;
int dst;
(void) fprintf(stderr, _("date: warning: ambiguous time \"%s\", %s.\n"),
value, reason);
tm = *gmtime(&thist);
tmp = gmtime(&thist);
/*
** Avoid running afoul of SCCS!
*/
timeout(stderr, _("Time was set as if you used\n\tdate -u %m%d%H\
%M\
%Y.%S\n"), &tm);
tm = *localtime(&thist);
timeout(stderr, _("to get %c"), &tm);
%Y.%S\n"), tmp);
tmp = localtime(&thist);
dst = tmp ? tmp->tm_isdst : 0;
timeout(stderr, _("to get %c"), tmp);
(void) fprintf(stderr, _(" (%s). Use\n"),
tm.tm_isdst ? _("summer time") : _("standard time"));
tm = *gmtime(&thatt);
dst ? _("summer time") : _("standard time"));
tmp = gmtime(&thatt);
timeout(stderr, _("\tdate -u %m%d%H\
%M\
%Y.%S\n"), &tm);
tm = *localtime(&thatt);
timeout(stderr, _("to get %c"), &tm);
%Y.%S\n"), tmp);
tmp = localtime(&thatt);
dst = tmp ? tmp->tm_isdst : 0;
timeout(stderr, _("to get %c"), tmp);
(void) fprintf(stderr, _(" (%s).\n"),
tm.tm_isdst ? _("summer time") : _("standard time"));
dst ? _("summer time") : _("standard time"));
errensure();
exit(retval);
}

View File

@ -74,6 +74,7 @@
#include "sys/types.h" /* for time_t */
#include "stdio.h"
#include "errno.h"
#include "float.h" /* for FLT_MAX and DBL_MAX */
#include "string.h"
#include "limits.h" /* for CHAR_BIT et al. */
#include "time.h"
@ -166,6 +167,7 @@ typedef int int_fast32_t;
#ifndef INTMAX_MAX
# if defined LLONG_MAX || defined __LONG_LONG_MAX__
typedef long long intmax_t;
# define strtoimax strtoll
# define PRIdMAX "lld"
# ifdef LLONG_MAX
# define INTMAX_MAX LLONG_MAX
@ -176,6 +178,7 @@ typedef long long intmax_t;
# endif
# else
typedef long intmax_t;
# define strtoimax strtol
# define PRIdMAX "ld"
# define INTMAX_MAX LONG_MAX
# define INTMAX_MIN LONG_MIN
@ -313,6 +316,30 @@ const char * scheck(const char * string, const char * format);
#define TYPE_SIGNED(type) (((type) -1) < 0)
#endif /* !defined TYPE_SIGNED */
/* The minimum and maximum finite time values. */
static time_t const time_t_min =
((time_t) 0.5 == 0.5
? (sizeof (time_t) == sizeof (float) ? (time_t) -FLT_MAX
: sizeof (time_t) == sizeof (double) ? (time_t) -DBL_MAX
: sizeof (time_t) == sizeof (long double) ? (time_t) -LDBL_MAX
: 0)
#ifndef TIME_T_FLOATING
: (time_t) -1 < 0
? (time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1)
#endif
: 0);
static time_t const time_t_max =
((time_t) 0.5 == 0.5
? (sizeof (time_t) == sizeof (float) ? (time_t) FLT_MAX
: sizeof (time_t) == sizeof (double) ? (time_t) DBL_MAX
: sizeof (time_t) == sizeof (long double) ? (time_t) LDBL_MAX
: -1)
#ifndef TIME_T_FLOATING
: (time_t) -1 < 0
? - (~ 0 < 0) - ((time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1))
#endif
: -1);
/*
** Since the definition of TYPE_INTEGRAL contains floating point numbers,
** it cannot be used in preprocessor directives.