aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/eval.c10
-rw-r--r--src/log.c17
-rw-r--r--src/os/time.c25
-rw-r--r--src/os/time.h11
-rw-r--r--src/undo.c9
5 files changed, 51 insertions, 21 deletions
diff --git a/src/eval.c b/src/eval.c
index df11174898..fba95789ac 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -65,6 +65,7 @@
#include "os/job.h"
#include "os/rstream.h"
#include "os/rstream_defs.h"
+#include "os/time.h"
#if defined(FEAT_FLOAT)
# include <math.h>
@@ -14163,7 +14164,6 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv)
static void f_strftime(typval_T *argvars, typval_T *rettv)
{
char_u result_buf[256];
- struct tm *curtime;
time_t seconds;
char_u *p;
@@ -14174,9 +14174,11 @@ static void f_strftime(typval_T *argvars, typval_T *rettv)
seconds = time(NULL);
else
seconds = (time_t)get_tv_number(&argvars[1]);
- curtime = localtime(&seconds);
+
+ struct tm curtime;
+ struct tm *curtime_ptr = os_localtime_r(&seconds, &curtime);
/* MSVC returns NULL for an invalid value of seconds. */
- if (curtime == NULL)
+ if (curtime_ptr == NULL)
rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
else {
vimconv_T conv;
@@ -14189,7 +14191,7 @@ static void f_strftime(typval_T *argvars, typval_T *rettv)
p = string_convert(&conv, p, NULL);
if (p != NULL)
(void)strftime((char *)result_buf, sizeof(result_buf),
- (char *)p, curtime);
+ (char *)p, curtime_ptr);
else
result_buf[0] = NUL;
diff --git a/src/log.c b/src/log.c
index d67851c2d4..5d536c62e5 100644
--- a/src/log.c
+++ b/src/log.c
@@ -11,6 +11,7 @@
#include "misc1.h"
#include "types.h"
#include "os/os.h"
+#include "os/time.h"
#define USR_LOG_FILE "$HOME/.nvimlog"
@@ -117,23 +118,13 @@ static bool v_do_log_to_file(FILE *log_file, int log_level,
assert(log_level >= DEBUG_LOG_LEVEL && log_level <= ERROR_LOG_LEVEL);
// format current timestamp in local time
- struct timeval tv;
- if (gettimeofday(&tv, NULL) < 0) {
+ struct tm local_time;
+ if (os_get_localtime(&local_time) == NULL) {
return false;
}
-#ifdef UNIX
- // localtime() is not thread-safe. POSIX provides localtime_r() as a
- // thread-safe version.
- struct tm local_time_allocated;
- struct tm *local_time = localtime_r(&tv.tv_sec, &local_time_allocated);
-#else
- // Windows version of localtime() is thread-safe.
- // See http://msdn.microsoft.com/en-us/library/bf12f0hc%28VS.80%29.aspx
- struct tm *local_time = localtime(&tv.tv_sec); // NOLINT
-#endif
char date_time[20];
if (strftime(date_time, sizeof(date_time), "%Y/%m/%d %H:%M:%S",
- local_time) == 0) {
+ &local_time) == 0) {
return false;
}
diff --git a/src/os/time.c b/src/os/time.c
index 0f7c990e23..1dc7ca68d4 100644
--- a/src/os/time.c
+++ b/src/os/time.c
@@ -1,5 +1,6 @@
#include <stdint.h>
#include <stdbool.h>
+#include <sys/time.h>
#include <uv.h>
@@ -59,3 +60,27 @@ static void microdelay(uint64_t microseconds)
uv_mutex_unlock(&delay_mutex);
}
+
+struct tm *os_localtime_r(const time_t *clock, struct tm *result)
+{
+#ifdef UNIX
+ // POSIX provides localtime_r() as a thread-safe version of localtime().
+ return localtime_r(clock, result);
+#else
+ // Windows version of localtime() is thread-safe.
+ // See http://msdn.microsoft.com/en-us/library/bf12f0hc%28VS.80%29.aspx
+ struct tm *local_time = localtime(clock); // NOLINT
+ *result = *local_time;
+return result;
+#endif
+}
+
+struct tm *os_get_localtime(struct tm *result)
+{
+ struct timeval tv;
+ if (gettimeofday(&tv, NULL) < 0) {
+ return NULL;
+ }
+
+ return os_localtime_r(&tv.tv_sec, result);
+}
diff --git a/src/os/time.h b/src/os/time.h
index 42feaa3eba..ef795d03be 100644
--- a/src/os/time.h
+++ b/src/os/time.h
@@ -19,6 +19,17 @@ void os_delay(uint64_t milliseconds, bool ignoreinput);
/// @param ignoreinput If true, allow a SIGINT to interrupt us
void os_microdelay(uint64_t microseconds, bool ignoreinput);
+/// Portable version of POSIX localtime_r()
+///
+/// @return NULL in case of error
+struct tm *os_localtime_r(const time_t *clock, struct tm *result);
+
+/// Obtains the current UNIX timestamp and adjusts it to local time
+///
+/// @param result Pointer to a 'struct tm' where the result should be placed
+/// @return A pointer to a 'struct tm' in the current time zone (the 'result'
+/// argument) or NULL in case of error
+struct tm *os_get_localtime(struct tm *result);
#endif // NEOVIM_OS_TIME_H
diff --git a/src/undo.c b/src/undo.c
index 243d865513..5e00d58d77 100644
--- a/src/undo.c
+++ b/src/undo.c
@@ -103,6 +103,7 @@
#include "screen.h"
#include "sha256.h"
#include "os/os.h"
+#include "os/time.h"
static long get_undolevel(void);
static void u_unch_branch(u_header_T *uhp);
@@ -2455,16 +2456,16 @@ void ex_undolist(exarg_T *eap)
*/
static void u_add_time(char_u *buf, size_t buflen, time_t tt)
{
- struct tm *curtime;
+ struct tm curtime;
if (time(NULL) - tt >= 100) {
- curtime = localtime(&tt);
+ os_localtime_r(&tt, &curtime);
if (time(NULL) - tt < (60L * 60L * 12L))
/* within 12 hours */
- (void)strftime((char *)buf, buflen, "%H:%M:%S", curtime);
+ (void)strftime((char *)buf, buflen, "%H:%M:%S", &curtime);
else
/* longer ago */
- (void)strftime((char *)buf, buflen, "%Y/%m/%d %H:%M:%S", curtime);
+ (void)strftime((char *)buf, buflen, "%Y/%m/%d %H:%M:%S", &curtime);
} else
vim_snprintf((char *)buf, buflen, _("%" PRId64 " seconds ago"),
(int64_t)(time(NULL) - tt));