mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-01-01 05:16:05 +01:00
312 lines
7.4 KiB
C
312 lines
7.4 KiB
C
/*
|
|
* datetime.c - parameter and command interface to date and time utilities
|
|
*
|
|
* This file is part of zsh, the Z shell.
|
|
*
|
|
* Copyright (c) 2002 Peter Stephenson, Clint Adams
|
|
* All rights reserved.
|
|
*
|
|
* Permission is hereby granted, without written agreement and without
|
|
* license or royalty fees, to use, copy, modify, and distribute this
|
|
* software and to distribute modified versions of this software for any
|
|
* purpose, provided that the above copyright notice and the following
|
|
* two paragraphs appear in all copies of this software.
|
|
*
|
|
* In no event shall Peter Stephenson, Clint Adams or the Zsh Development Group
|
|
* be liable to any party for direct, indirect, special, incidental, or
|
|
* consequential damages arising out of the use of this software and its
|
|
* documentation, even if Peter Stephenson, Clint Adams and the Zsh
|
|
* Development Group have been advised of the possibility of such damage.
|
|
*
|
|
* Peter Stephenson, Clint Adams and the Zsh Development Group specifically
|
|
* disclaim any warranties, including, but not limited to, the implied
|
|
* warranties of merchantability and fitness for a particular purpose.
|
|
* The software provided hereunder is on an "as is" basis, and Peter
|
|
* Stephenson, Clint Adams and the Zsh Development Group have no obligation
|
|
* to provide maintenance, support, updates, enhancements, or modifications.
|
|
*
|
|
*/
|
|
|
|
#include "datetime.mdh"
|
|
#include "datetime.pro"
|
|
#include <time.h>
|
|
|
|
#ifndef HAVE_MKTIME
|
|
#ifdef HAVE_TIMELOCAL
|
|
#define mktime(x) timelocal(x)
|
|
#define HAVE_MKTIME 1
|
|
#endif
|
|
#endif
|
|
|
|
static int
|
|
reverse_strftime(char *nam, char **argv, char *scalar, int quiet)
|
|
{
|
|
#if defined(HAVE_STRPTIME) && defined(HAVE_MKTIME)
|
|
struct tm tm;
|
|
zlong mytime;
|
|
char *endp;
|
|
|
|
/*
|
|
* Initialise all parameters to zero; there's no floating point
|
|
* so memset() will do the trick. The exception is that tm_isdst
|
|
* is set to -1 which, if not overridden, will cause mktime()
|
|
* to use the current timezone. This is probably the best guess;
|
|
* it's the one that will cause dates and times output by strftime
|
|
* without the -r option and without an explicit timezone to be
|
|
* converted back correctly. Additionally, tm_mday is set to 1
|
|
* as that and not 0 corresponds to the first of the month.
|
|
*/
|
|
(void)memset(&tm, 0, sizeof(tm));
|
|
tm.tm_isdst = -1;
|
|
tm.tm_mday = 1;
|
|
endp = strptime(argv[1], argv[0], &tm);
|
|
|
|
if (!endp) {
|
|
/* Conversion failed completely. */
|
|
if (!quiet)
|
|
zwarnnam(nam, "format not matched");
|
|
return 1;
|
|
}
|
|
|
|
mytime = (zlong)mktime(&tm);
|
|
|
|
if (scalar)
|
|
setiparam(scalar, mytime);
|
|
else {
|
|
char buf[DIGBUFSIZE];
|
|
convbase(buf, mytime, 10);
|
|
printf("%s\n", buf);
|
|
}
|
|
|
|
if (*endp && !quiet) {
|
|
/*
|
|
* Not everything in the input string was converted.
|
|
* This is probably benign, since the format has been satisfied,
|
|
* but issue a warning unless the quiet flag is set.
|
|
*/
|
|
zwarnnam(nam, "warning: input string not completely matched");
|
|
}
|
|
|
|
return 0;
|
|
#else
|
|
if (!quiet)
|
|
zwarnnam(nam, "not implemented on this system");
|
|
return 2;
|
|
#endif
|
|
}
|
|
|
|
static int
|
|
output_strftime(char *nam, char **argv, Options ops, UNUSED(int func))
|
|
{
|
|
int bufsize, x, len;
|
|
char *endptr = NULL, *scalar = NULL, *buffer;
|
|
time_t secs;
|
|
struct tm *t;
|
|
|
|
if (OPT_ISSET(ops,'s')) {
|
|
scalar = OPT_ARG(ops, 's');
|
|
if (!isident(scalar)) {
|
|
zwarnnam(nam, "not an identifier: %s", scalar);
|
|
return 1;
|
|
}
|
|
}
|
|
if (OPT_ISSET(ops, 'r'))
|
|
return reverse_strftime(nam, argv, scalar, OPT_ISSET(ops, 'q'));
|
|
|
|
errno = 0;
|
|
secs = (time_t)strtoul(argv[1], &endptr, 10);
|
|
if (errno != 0) {
|
|
zwarnnam(nam, "%s: %e", argv[1], errno);
|
|
return 1;
|
|
} else if (*endptr != '\0') {
|
|
zwarnnam(nam, "%s: invalid decimal number", argv[1]);
|
|
return 1;
|
|
}
|
|
|
|
t = localtime(&secs);
|
|
if (!t) {
|
|
zwarnnam(nam, "%s: unable to convert to time", argv[1]);
|
|
return 1;
|
|
}
|
|
bufsize = strlen(argv[0]) * 8;
|
|
buffer = zalloc(bufsize);
|
|
|
|
len = 0;
|
|
for (x=0; x < 4; x++) {
|
|
if ((len = ztrftime(buffer, bufsize, argv[0], t, 0L)) >= 0)
|
|
break;
|
|
buffer = zrealloc(buffer, bufsize *= 2);
|
|
}
|
|
DPUTS(len < 0, "bad output from ztrftime");
|
|
|
|
if (scalar) {
|
|
setsparam(scalar, metafy(buffer, len, META_DUP));
|
|
} else {
|
|
fwrite(buffer, 1, len, stdout);
|
|
putchar('\n');
|
|
}
|
|
zfree(buffer, bufsize);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
bin_strftime(char *nam, char **argv, Options ops, int func)
|
|
{
|
|
int result = 1;
|
|
char *tz = getsparam("TZ");
|
|
|
|
startparamscope();
|
|
if (tz && *tz) {
|
|
Param pm = createparam("TZ", PM_LOCAL|PM_SCALAR|PM_EXPORTED);
|
|
if (pm)
|
|
pm->level = locallevel; /* because createparam() doesn't */
|
|
setsparam("TZ", ztrdup(tz));
|
|
}
|
|
result = output_strftime(nam, argv, ops, func);
|
|
endparamscope();
|
|
|
|
return result;
|
|
}
|
|
|
|
static zlong
|
|
getcurrentsecs(UNUSED(Param pm))
|
|
{
|
|
return (zlong) time(NULL);
|
|
}
|
|
|
|
static double
|
|
getcurrentrealtime(Param pm)
|
|
{
|
|
#ifdef HAVE_CLOCK_GETTIME
|
|
struct timespec now;
|
|
|
|
if (clock_gettime(CLOCK_REALTIME, &now) < 0) {
|
|
zwarn("%s: unable to retrieve time: %e", pm->node.nam, errno);
|
|
return (double)0.0;
|
|
}
|
|
|
|
return (double)now.tv_sec + (double)now.tv_nsec * 1e-9;
|
|
#else
|
|
struct timeval now;
|
|
struct timezone dummy_tz;
|
|
|
|
(void)pm;
|
|
gettimeofday(&now, &dummy_tz);
|
|
|
|
return (double)now.tv_sec + (double)now.tv_usec * 1e-6;
|
|
#endif
|
|
}
|
|
|
|
static char **
|
|
getcurrenttime(Param pm)
|
|
{
|
|
char **arr;
|
|
char buf[DIGBUFSIZE];
|
|
|
|
#ifdef HAVE_CLOCK_GETTIME
|
|
struct timespec now;
|
|
|
|
if (clock_gettime(CLOCK_REALTIME, &now) < 0) {
|
|
zwarn("%s: unable to retrieve time: %e", pm->node.nam, errno);
|
|
return NULL;
|
|
}
|
|
|
|
arr = (char **)zhalloc(3 * sizeof(*arr));
|
|
sprintf(buf, "%ld", (long)now.tv_sec);
|
|
arr[0] = dupstring(buf);
|
|
sprintf(buf, "%ld", now.tv_nsec);
|
|
arr[1] = dupstring(buf);
|
|
arr[2] = NULL;
|
|
|
|
return arr;
|
|
#else
|
|
struct timeval now;
|
|
struct timezone dummy_tz;
|
|
|
|
(void)pm;
|
|
gettimeofday(&now, &dummy_tz);
|
|
|
|
arr = (char **)zhalloc(3 * sizeof(*arr));
|
|
sprintf(buf, "%ld", (long)now.tv_sec);
|
|
arr[0] = dupstring(buf);
|
|
sprintf(buf, "%ld", (long)now.tv_usec * 1000);
|
|
arr[1] = dupstring(buf);
|
|
arr[2] = NULL;
|
|
|
|
return arr;
|
|
#endif
|
|
}
|
|
|
|
static struct builtin bintab[] = {
|
|
BUILTIN("strftime", 0, bin_strftime, 2, 2, 0, "qrs:", NULL),
|
|
};
|
|
|
|
static const struct gsu_integer epochseconds_gsu =
|
|
{ getcurrentsecs, NULL, stdunsetfn };
|
|
|
|
static const struct gsu_float epochrealtime_gsu =
|
|
{ getcurrentrealtime, NULL, stdunsetfn };
|
|
|
|
static const struct gsu_array epochtime_gsu =
|
|
{ getcurrenttime, NULL, stdunsetfn };
|
|
|
|
static struct paramdef patab[] = {
|
|
SPECIALPMDEF("EPOCHSECONDS", PM_INTEGER|PM_READONLY,
|
|
&epochseconds_gsu, NULL, NULL),
|
|
SPECIALPMDEF("EPOCHREALTIME", PM_FFLOAT|PM_READONLY,
|
|
&epochrealtime_gsu, NULL, NULL),
|
|
SPECIALPMDEF("epochtime", PM_ARRAY|PM_READONLY,
|
|
&epochtime_gsu, NULL, NULL)
|
|
};
|
|
|
|
static struct features module_features = {
|
|
bintab, sizeof(bintab)/sizeof(*bintab),
|
|
NULL, 0,
|
|
NULL, 0,
|
|
patab, sizeof(patab)/sizeof(*patab),
|
|
0
|
|
};
|
|
|
|
/**/
|
|
int
|
|
setup_(UNUSED(Module m))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
features_(Module m, char ***features)
|
|
{
|
|
*features = featuresarray(m, &module_features);
|
|
return 0;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
enables_(Module m, int **enables)
|
|
{
|
|
return handlefeatures(m, &module_features, enables);
|
|
}
|
|
|
|
/**/
|
|
int
|
|
boot_(UNUSED(Module m))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
cleanup_(Module m)
|
|
{
|
|
return setfeatureenables(m, &module_features, NULL);
|
|
}
|
|
|
|
/**/
|
|
int
|
|
finish_(UNUSED(Module m))
|
|
{
|
|
return 0;
|
|
}
|