/* vi:set ts=8 sts=4 sw=4 noet:
*
* VIM - Vi IMproved by Bram Moolenaar
*
* Do ":help uganda" in Vim to read copying and usage conditions.
* Do ":help credits" in Vim to see a list of people who contributed.
* See README.txt for an overview of the Vim source code.
*/
/*
* time.c: functions related to time and timers
*/
#include "vim.h"
/*
* Cache of the current timezone name as retrieved from TZ, or an empty string
* where unset, up to 64 octets long including trailing null byte.
*/
#if defined(HAVE_LOCALTIME_R) && defined(HAVE_TZSET)
static char tz_cache[64];
#endif
#define FOR_ALL_TIMERS(t) \
for ((t) = first_timer; (t) != NULL; (t) = (t)->tr_next)
/*
* Call either localtime(3) or localtime_r(3) from POSIX libc time.h, with the
* latter version preferred for reentrancy.
*
* If we use localtime_r(3) and we have tzset(3) available, check to see if the
* environment variable TZ has changed since the last run, and call tzset(3) to
* update the global timezone variables if it has. This is because the POSIX
* standard doesn't require localtime_r(3) implementations to do that as it
* does with localtime(3), and we don't want to call tzset(3) every time.
*/
static struct tm *
vim_localtime(
const time_t *timep, // timestamp for local representation
struct tm *result UNUSED) // pointer to caller return buffer
{
#ifdef HAVE_LOCALTIME_R
# ifdef HAVE_TZSET
char *tz; // pointer for TZ environment var
tz = (char *)mch_getenv((char_u *)"TZ");
if (tz == NULL)
tz = "";
if (STRNCMP(tz_cache, tz, sizeof(tz_cache) - 1) != 0)
{
tzset();
vim_strncpy((char_u *)tz_cache, (char_u *)tz, sizeof(tz_cache) - 1);
}
# endif // HAVE_TZSET
return localtime_r(timep, result);
#else
return localtime(timep);
#endif // HAVE_LOCALTIME_R
}
/*
* Return the current time in seconds. Calls time(), unless test_settime()
* was used.
*/
time_T
vim_time(void)
{
# ifdef FEAT_EVAL
return time_for_testing == 0 ? time(NULL) : time_for_testing;
# else
return time(NULL);
# endif
}
/*
* Replacement for ctime(), which is not safe to use.
* Requires strftime(), otherwise returns "(unknown)".
* If "thetime" is invalid returns "(invalid)". Never returns NULL.
* When "add_newline" is TRUE add a newline like ctime() does.
* Uses a static buffer.
*/
char *
get_ctime(time_t thetime, int add_newline)
{
static char buf[100]; // hopefully enough for every language
#ifdef HAVE_STRFTIME
struct tm tmval;
struct tm *curtime;
curtime = vim_localtime(&thetime, &tmval);
// MSVC returns NULL for an invalid value of seconds.
if (curtime == NULL)
vim_strncpy((char_u *)buf, (char_u *)_("(Invalid)"), sizeof(buf) - 2);
else
{
// xgettext:no-c-format
if (strftime(buf, sizeof(buf) - 2, _("%a %b %d %H:%M:%S %Y"), curtime)
== 0)
{
// Quoting "man strftime":
// > If the length of the result string (including the terminating
// > null byte) would exceed max bytes, then strftime() returns 0,
// > and the contents of the array are undefined.
vim_strncpy((char_u *)buf, (char_u *)_("(Invalid)"),
sizeof(buf) - 2);
}
# ifdef MSWIN
if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
{
char_u *to_free = NULL;
int len;
acp_to_enc((char_u *)buf, (int)strlen(buf), &to_free, &len);
if (to_free != NULL)
{
STRNCPY(buf, to_free, sizeof(buf) - 2);
vim_free(to_free);
}
}
# endif
}
#else
STRCPY(buf, "(unknown)");
#endif
if (add_newline)
STRCAT(buf, "\n");
return buf;
}
#if defined(FEAT_EVAL) || defined(PROTO)
#if defined(MACOS_X)
# include <time.h> // for time_t
#endif
/*
* "localtime()" function
*/
void
f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
{
rettv->vval.v_number = (varnumber_T)time(NULL);