10a8fed62SBram Moolenaar /* vi:set ts=8 sts=4 sw=4 noet:
20a8fed62SBram Moolenaar *
30a8fed62SBram Moolenaar * VIM - Vi IMproved by Bram Moolenaar
40a8fed62SBram Moolenaar *
50a8fed62SBram Moolenaar * Do ":help uganda" in Vim to read copying and usage conditions.
60a8fed62SBram Moolenaar * Do ":help credits" in Vim to see a list of people who contributed.
70a8fed62SBram Moolenaar * See README.txt for an overview of the Vim source code.
80a8fed62SBram Moolenaar */
90a8fed62SBram Moolenaar
100a8fed62SBram Moolenaar /*
110a8fed62SBram Moolenaar * time.c: functions related to time and timers
120a8fed62SBram Moolenaar */
130a8fed62SBram Moolenaar
140a8fed62SBram Moolenaar #include "vim.h"
150a8fed62SBram Moolenaar
160a8fed62SBram Moolenaar /*
170a8fed62SBram Moolenaar * Cache of the current timezone name as retrieved from TZ, or an empty string
180a8fed62SBram Moolenaar * where unset, up to 64 octets long including trailing null byte.
190a8fed62SBram Moolenaar */
200a8fed62SBram Moolenaar #if defined(HAVE_LOCALTIME_R) && defined(HAVE_TZSET)
210a8fed62SBram Moolenaar static char tz_cache[64];
220a8fed62SBram Moolenaar #endif
230a8fed62SBram Moolenaar
2400d253e2SBram Moolenaar #define FOR_ALL_TIMERS(t) \
2500d253e2SBram Moolenaar for ((t) = first_timer; (t) != NULL; (t) = (t)->tr_next)
2600d253e2SBram Moolenaar
270a8fed62SBram Moolenaar /*
280a8fed62SBram Moolenaar * Call either localtime(3) or localtime_r(3) from POSIX libc time.h, with the
290a8fed62SBram Moolenaar * latter version preferred for reentrancy.
300a8fed62SBram Moolenaar *
310a8fed62SBram Moolenaar * If we use localtime_r(3) and we have tzset(3) available, check to see if the
320a8fed62SBram Moolenaar * environment variable TZ has changed since the last run, and call tzset(3) to
330a8fed62SBram Moolenaar * update the global timezone variables if it has. This is because the POSIX
340a8fed62SBram Moolenaar * standard doesn't require localtime_r(3) implementations to do that as it
350a8fed62SBram Moolenaar * does with localtime(3), and we don't want to call tzset(3) every time.
360a8fed62SBram Moolenaar */
370a8fed62SBram Moolenaar static struct tm *
vim_localtime(const time_t * timep,struct tm * result UNUSED)380a8fed62SBram Moolenaar vim_localtime(
390a8fed62SBram Moolenaar const time_t *timep, // timestamp for local representation
400a8fed62SBram Moolenaar struct tm *result UNUSED) // pointer to caller return buffer
410a8fed62SBram Moolenaar {
420a8fed62SBram Moolenaar #ifdef HAVE_LOCALTIME_R
430a8fed62SBram Moolenaar # ifdef HAVE_TZSET
440a8fed62SBram Moolenaar char *tz; // pointer for TZ environment var
450a8fed62SBram Moolenaar
460a8fed62SBram Moolenaar tz = (char *)mch_getenv((char_u *)"TZ");
470a8fed62SBram Moolenaar if (tz == NULL)
480a8fed62SBram Moolenaar tz = "";
490a8fed62SBram Moolenaar if (STRNCMP(tz_cache, tz, sizeof(tz_cache) - 1) != 0)
500a8fed62SBram Moolenaar {
510a8fed62SBram Moolenaar tzset();
520a8fed62SBram Moolenaar vim_strncpy((char_u *)tz_cache, (char_u *)tz, sizeof(tz_cache) - 1);
530a8fed62SBram Moolenaar }
540a8fed62SBram Moolenaar # endif // HAVE_TZSET
550a8fed62SBram Moolenaar return localtime_r(timep, result);
560a8fed62SBram Moolenaar #else
570a8fed62SBram Moolenaar return localtime(timep);
580a8fed62SBram Moolenaar #endif // HAVE_LOCALTIME_R
590a8fed62SBram Moolenaar }
600a8fed62SBram Moolenaar
610a8fed62SBram Moolenaar /*
620a8fed62SBram Moolenaar * Return the current time in seconds. Calls time(), unless test_settime()
630a8fed62SBram Moolenaar * was used.
640a8fed62SBram Moolenaar */
650a8fed62SBram Moolenaar time_T
vim_time(void)660a8fed62SBram Moolenaar vim_time(void)
670a8fed62SBram Moolenaar {
680a8fed62SBram Moolenaar # ifdef FEAT_EVAL
690a8fed62SBram Moolenaar return time_for_testing == 0 ? time(NULL) : time_for_testing;
700a8fed62SBram Moolenaar # else
710a8fed62SBram Moolenaar return time(NULL);
720a8fed62SBram Moolenaar # endif
730a8fed62SBram Moolenaar }
740a8fed62SBram Moolenaar
750a8fed62SBram Moolenaar /*
760a8fed62SBram Moolenaar * Replacement for ctime(), which is not safe to use.
770a8fed62SBram Moolenaar * Requires strftime(), otherwise returns "(unknown)".
780a8fed62SBram Moolenaar * If "thetime" is invalid returns "(invalid)". Never returns NULL.
790a8fed62SBram Moolenaar * When "add_newline" is TRUE add a newline like ctime() does.
800a8fed62SBram Moolenaar * Uses a static buffer.
810a8fed62SBram Moolenaar */
820a8fed62SBram Moolenaar char *
get_ctime(time_t thetime,int add_newline)830a8fed62SBram Moolenaar get_ctime(time_t thetime, int add_newline)
840a8fed62SBram Moolenaar {
850a8fed62SBram Moolenaar static char buf[50];
860a8fed62SBram Moolenaar #ifdef HAVE_STRFTIME
870a8fed62SBram Moolenaar struct tm tmval;
880a8fed62SBram Moolenaar struct tm *curtime;
890a8fed62SBram Moolenaar
900a8fed62SBram Moolenaar curtime = vim_localtime(&thetime, &tmval);
910a8fed62SBram Moolenaar // MSVC returns NULL for an invalid value of seconds.
920a8fed62SBram Moolenaar if (curtime == NULL)
930a8fed62SBram Moolenaar vim_strncpy((char_u *)buf, (char_u *)_("(Invalid)"), sizeof(buf) - 1);
940a8fed62SBram Moolenaar else
950a8fed62SBram Moolenaar {
960a8fed62SBram Moolenaar (void)strftime(buf, sizeof(buf) - 1, _("%a %b %d %H:%M:%S %Y"),
970a8fed62SBram Moolenaar curtime);
980a8fed62SBram Moolenaar # ifdef MSWIN
990a8fed62SBram Moolenaar if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
1000a8fed62SBram Moolenaar {
1010a8fed62SBram Moolenaar char_u *to_free = NULL;
1020a8fed62SBram Moolenaar int len;
1030a8fed62SBram Moolenaar
1040a8fed62SBram Moolenaar acp_to_enc((char_u *)buf, (int)strlen(buf), &to_free, &len);
1050a8fed62SBram Moolenaar if (to_free != NULL)
1060a8fed62SBram Moolenaar {
1070a8fed62SBram Moolenaar STRCPY(buf, to_free);
1080a8fed62SBram Moolenaar vim_free(to_free);
1090a8fed62SBram Moolenaar }
1100a8fed62SBram Moolenaar }
1110a8fed62SBram Moolenaar # endif
1120a8fed62SBram Moolenaar }
1130a8fed62SBram Moolenaar #else
1140a8fed62SBram Moolenaar STRCPY(buf, "(unknown)");
1150a8fed62SBram Moolenaar #endif
1160a8fed62SBram Moolenaar if (add_newline)
1170a8fed62SBram Moolenaar STRCAT(buf, "\n");
1180a8fed62SBram Moolenaar return buf;
1190a8fed62SBram Moolenaar }
1200a8fed62SBram Moolenaar
1210a8fed62SBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
1220a8fed62SBram Moolenaar
1230a8fed62SBram Moolenaar #if defined(MACOS_X)
1240a8fed62SBram Moolenaar # include <time.h> // for time_t
1250a8fed62SBram Moolenaar #endif
1260a8fed62SBram Moolenaar
1270a8fed62SBram Moolenaar /*
1280a8fed62SBram Moolenaar * "localtime()" function
1290a8fed62SBram Moolenaar */
1300a8fed62SBram Moolenaar void
f_localtime(typval_T * argvars UNUSED,typval_T * rettv)1310a8fed62SBram Moolenaar f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
1320a8fed62SBram Moolenaar {
1330a8fed62SBram Moolenaar rettv->vval.v_number = (varnumber_T)time(NULL);
1340a8fed62SBram Moolenaar }
1350a8fed62SBram Moolenaar
1360a8fed62SBram Moolenaar # if defined(FEAT_RELTIME)
1370a8fed62SBram Moolenaar /*
1380a8fed62SBram Moolenaar * Convert a List to proftime_T.
1390a8fed62SBram Moolenaar * Return FAIL when there is something wrong.
1400a8fed62SBram Moolenaar */
1410a8fed62SBram Moolenaar static int
list2proftime(typval_T * arg,proftime_T * tm)1420a8fed62SBram Moolenaar list2proftime(typval_T *arg, proftime_T *tm)
1430a8fed62SBram Moolenaar {
1440a8fed62SBram Moolenaar long n1, n2;
1450a8fed62SBram Moolenaar int error = FALSE;
1460a8fed62SBram Moolenaar
1470a8fed62SBram Moolenaar if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
1480a8fed62SBram Moolenaar || arg->vval.v_list->lv_len != 2)
1490a8fed62SBram Moolenaar return FAIL;
1500a8fed62SBram Moolenaar n1 = list_find_nr(arg->vval.v_list, 0L, &error);
1510a8fed62SBram Moolenaar n2 = list_find_nr(arg->vval.v_list, 1L, &error);
1520a8fed62SBram Moolenaar # ifdef MSWIN
1530a8fed62SBram Moolenaar tm->HighPart = n1;
1540a8fed62SBram Moolenaar tm->LowPart = n2;
1550a8fed62SBram Moolenaar # else
1560a8fed62SBram Moolenaar tm->tv_sec = n1;
1570a8fed62SBram Moolenaar tm->tv_usec = n2;
1580a8fed62SBram Moolenaar # endif
1590a8fed62SBram Moolenaar return error ? FAIL : OK;
1600a8fed62SBram Moolenaar }
1610a8fed62SBram Moolenaar # endif // FEAT_RELTIME
1620a8fed62SBram Moolenaar
1630a8fed62SBram Moolenaar /*
1640a8fed62SBram Moolenaar * "reltime()" function
1650a8fed62SBram Moolenaar */
1660a8fed62SBram Moolenaar void
f_reltime(typval_T * argvars UNUSED,typval_T * rettv UNUSED)1670a8fed62SBram Moolenaar f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1680a8fed62SBram Moolenaar {
1690a8fed62SBram Moolenaar # ifdef FEAT_RELTIME
1700a8fed62SBram Moolenaar proftime_T res;
1710a8fed62SBram Moolenaar proftime_T start;
1721a71d31bSYegappan Lakshmanan long n1, n2;
1731a71d31bSYegappan Lakshmanan
1741a71d31bSYegappan Lakshmanan if (rettv_list_alloc(rettv) != OK)
1751a71d31bSYegappan Lakshmanan return;
1760a8fed62SBram Moolenaar
1774490ec4eSYegappan Lakshmanan if (in_vim9script()
1784490ec4eSYegappan Lakshmanan && (check_for_opt_list_arg(argvars, 0) == FAIL
1794490ec4eSYegappan Lakshmanan || (argvars[0].v_type != VAR_UNKNOWN
1804490ec4eSYegappan Lakshmanan && check_for_opt_list_arg(argvars, 1) == FAIL)))
1814490ec4eSYegappan Lakshmanan return;
1824490ec4eSYegappan Lakshmanan
1830a8fed62SBram Moolenaar if (argvars[0].v_type == VAR_UNKNOWN)
1840a8fed62SBram Moolenaar {
1850a8fed62SBram Moolenaar // No arguments: get current time.
1860a8fed62SBram Moolenaar profile_start(&res);
1870a8fed62SBram Moolenaar }
1880a8fed62SBram Moolenaar else if (argvars[1].v_type == VAR_UNKNOWN)
1890a8fed62SBram Moolenaar {
1900a8fed62SBram Moolenaar if (list2proftime(&argvars[0], &res) == FAIL)
191c816a2c2SBram Moolenaar {
192c816a2c2SBram Moolenaar if (in_vim9script())
193c816a2c2SBram Moolenaar emsg(_(e_invarg));
1940a8fed62SBram Moolenaar return;
195c816a2c2SBram Moolenaar }
1960a8fed62SBram Moolenaar profile_end(&res);
1970a8fed62SBram Moolenaar }
1980a8fed62SBram Moolenaar else
1990a8fed62SBram Moolenaar {
2000a8fed62SBram Moolenaar // Two arguments: compute the difference.
2010a8fed62SBram Moolenaar if (list2proftime(&argvars[0], &start) == FAIL
2020a8fed62SBram Moolenaar || list2proftime(&argvars[1], &res) == FAIL)
203c816a2c2SBram Moolenaar {
204c816a2c2SBram Moolenaar if (in_vim9script())
205c816a2c2SBram Moolenaar emsg(_(e_invarg));
2060a8fed62SBram Moolenaar return;
207c816a2c2SBram Moolenaar }
2080a8fed62SBram Moolenaar profile_sub(&res, &start);
2090a8fed62SBram Moolenaar }
2100a8fed62SBram Moolenaar
2110a8fed62SBram Moolenaar # ifdef MSWIN
2120a8fed62SBram Moolenaar n1 = res.HighPart;
2130a8fed62SBram Moolenaar n2 = res.LowPart;
2140a8fed62SBram Moolenaar # else
2150a8fed62SBram Moolenaar n1 = res.tv_sec;
2160a8fed62SBram Moolenaar n2 = res.tv_usec;
2170a8fed62SBram Moolenaar # endif
2180a8fed62SBram Moolenaar list_append_number(rettv->vval.v_list, (varnumber_T)n1);
2190a8fed62SBram Moolenaar list_append_number(rettv->vval.v_list, (varnumber_T)n2);
2200a8fed62SBram Moolenaar # endif
2210a8fed62SBram Moolenaar }
2220a8fed62SBram Moolenaar
2230a8fed62SBram Moolenaar # ifdef FEAT_FLOAT
2240a8fed62SBram Moolenaar /*
2250a8fed62SBram Moolenaar * "reltimefloat()" function
2260a8fed62SBram Moolenaar */
2270a8fed62SBram Moolenaar void
f_reltimefloat(typval_T * argvars UNUSED,typval_T * rettv)2280a8fed62SBram Moolenaar f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
2290a8fed62SBram Moolenaar {
2300a8fed62SBram Moolenaar # ifdef FEAT_RELTIME
2310a8fed62SBram Moolenaar proftime_T tm;
2320a8fed62SBram Moolenaar # endif
2330a8fed62SBram Moolenaar
2340a8fed62SBram Moolenaar rettv->v_type = VAR_FLOAT;
2350a8fed62SBram Moolenaar rettv->vval.v_float = 0;
2360a8fed62SBram Moolenaar # ifdef FEAT_RELTIME
2374490ec4eSYegappan Lakshmanan if (in_vim9script() && check_for_list_arg(argvars, 0) == FAIL)
2384490ec4eSYegappan Lakshmanan return;
2394490ec4eSYegappan Lakshmanan
2400a8fed62SBram Moolenaar if (list2proftime(&argvars[0], &tm) == OK)
2410a8fed62SBram Moolenaar rettv->vval.v_float = profile_float(&tm);
242c816a2c2SBram Moolenaar else if (in_vim9script())
243c816a2c2SBram Moolenaar emsg(_(e_invarg));
2440a8fed62SBram Moolenaar # endif
2450a8fed62SBram Moolenaar }
2460a8fed62SBram Moolenaar # endif
2470a8fed62SBram Moolenaar
2480a8fed62SBram Moolenaar /*
2490a8fed62SBram Moolenaar * "reltimestr()" function
2500a8fed62SBram Moolenaar */
2510a8fed62SBram Moolenaar void
f_reltimestr(typval_T * argvars UNUSED,typval_T * rettv)2520a8fed62SBram Moolenaar f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
2530a8fed62SBram Moolenaar {
2540a8fed62SBram Moolenaar # ifdef FEAT_RELTIME
2550a8fed62SBram Moolenaar proftime_T tm;
2560a8fed62SBram Moolenaar # endif
2570a8fed62SBram Moolenaar
2580a8fed62SBram Moolenaar rettv->v_type = VAR_STRING;
2590a8fed62SBram Moolenaar rettv->vval.v_string = NULL;
2600a8fed62SBram Moolenaar # ifdef FEAT_RELTIME
2614490ec4eSYegappan Lakshmanan if (in_vim9script() && check_for_list_arg(argvars, 0) == FAIL)
2624490ec4eSYegappan Lakshmanan return;
2634490ec4eSYegappan Lakshmanan
2640a8fed62SBram Moolenaar if (list2proftime(&argvars[0], &tm) == OK)
2650a8fed62SBram Moolenaar rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
266c816a2c2SBram Moolenaar else if (in_vim9script())
267c816a2c2SBram Moolenaar emsg(_(e_invarg));
2680a8fed62SBram Moolenaar # endif
2690a8fed62SBram Moolenaar }
2700a8fed62SBram Moolenaar
2710a8fed62SBram Moolenaar # if defined(HAVE_STRFTIME) || defined(PROTO)
2720a8fed62SBram Moolenaar /*
2730a8fed62SBram Moolenaar * "strftime({format}[, {time}])" function
2740a8fed62SBram Moolenaar */
2750a8fed62SBram Moolenaar void
f_strftime(typval_T * argvars,typval_T * rettv)2760a8fed62SBram Moolenaar f_strftime(typval_T *argvars, typval_T *rettv)
2770a8fed62SBram Moolenaar {
2780a8fed62SBram Moolenaar struct tm tmval;
2790a8fed62SBram Moolenaar struct tm *curtime;
2800a8fed62SBram Moolenaar time_t seconds;
2810a8fed62SBram Moolenaar char_u *p;
2820a8fed62SBram Moolenaar
2831a71d31bSYegappan Lakshmanan if (in_vim9script()
2841a71d31bSYegappan Lakshmanan && (check_for_string_arg(argvars, 0) == FAIL
28583494b4aSYegappan Lakshmanan || check_for_opt_number_arg(argvars, 1) == FAIL))
2861a71d31bSYegappan Lakshmanan return;
2871a71d31bSYegappan Lakshmanan
2880a8fed62SBram Moolenaar rettv->v_type = VAR_STRING;
2890a8fed62SBram Moolenaar
2900a8fed62SBram Moolenaar p = tv_get_string(&argvars[0]);
2910a8fed62SBram Moolenaar if (argvars[1].v_type == VAR_UNKNOWN)
2920a8fed62SBram Moolenaar seconds = time(NULL);
2930a8fed62SBram Moolenaar else
2940a8fed62SBram Moolenaar seconds = (time_t)tv_get_number(&argvars[1]);
2950a8fed62SBram Moolenaar curtime = vim_localtime(&seconds, &tmval);
2960a8fed62SBram Moolenaar // MSVC returns NULL for an invalid value of seconds.
2970a8fed62SBram Moolenaar if (curtime == NULL)
2980a8fed62SBram Moolenaar rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
2990a8fed62SBram Moolenaar else
3000a8fed62SBram Moolenaar {
3012c4a1d0aSK.Takata # ifdef MSWIN
3022c4a1d0aSK.Takata WCHAR result_buf[256];
3032c4a1d0aSK.Takata WCHAR *wp;
3042c4a1d0aSK.Takata
3052c4a1d0aSK.Takata wp = enc_to_utf16(p, NULL);
3062c4a1d0aSK.Takata if (wp != NULL)
307eeec2548SK.Takata (void)wcsftime(result_buf, ARRAY_LENGTH(result_buf), wp, curtime);
3082c4a1d0aSK.Takata else
3092c4a1d0aSK.Takata result_buf[0] = NUL;
3102c4a1d0aSK.Takata rettv->vval.v_string = utf16_to_enc(result_buf, NULL);
3112c4a1d0aSK.Takata vim_free(wp);
3122c4a1d0aSK.Takata # else
3132c4a1d0aSK.Takata char_u result_buf[256];
3140a8fed62SBram Moolenaar vimconv_T conv;
3150a8fed62SBram Moolenaar char_u *enc;
3160a8fed62SBram Moolenaar
3170a8fed62SBram Moolenaar conv.vc_type = CONV_NONE;
3180a8fed62SBram Moolenaar enc = enc_locale();
3190a8fed62SBram Moolenaar convert_setup(&conv, p_enc, enc);
3200a8fed62SBram Moolenaar if (conv.vc_type != CONV_NONE)
3210a8fed62SBram Moolenaar p = string_convert(&conv, p, NULL);
3220a8fed62SBram Moolenaar if (p != NULL)
3230a8fed62SBram Moolenaar (void)strftime((char *)result_buf, sizeof(result_buf),
3240a8fed62SBram Moolenaar (char *)p, curtime);
3250a8fed62SBram Moolenaar else
3260a8fed62SBram Moolenaar result_buf[0] = NUL;
3270a8fed62SBram Moolenaar
3280a8fed62SBram Moolenaar if (conv.vc_type != CONV_NONE)
3290a8fed62SBram Moolenaar vim_free(p);
3300a8fed62SBram Moolenaar convert_setup(&conv, enc, p_enc);
3310a8fed62SBram Moolenaar if (conv.vc_type != CONV_NONE)
3320a8fed62SBram Moolenaar rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
3330a8fed62SBram Moolenaar else
3340a8fed62SBram Moolenaar rettv->vval.v_string = vim_strsave(result_buf);
3350a8fed62SBram Moolenaar
3360a8fed62SBram Moolenaar // Release conversion descriptors
3370a8fed62SBram Moolenaar convert_setup(&conv, NULL, NULL);
3380a8fed62SBram Moolenaar vim_free(enc);
3392c4a1d0aSK.Takata # endif
3400a8fed62SBram Moolenaar }
3410a8fed62SBram Moolenaar }
3420a8fed62SBram Moolenaar # endif
3430a8fed62SBram Moolenaar
3440a8fed62SBram Moolenaar # if defined(HAVE_STRPTIME) || defined(PROTO)
3450a8fed62SBram Moolenaar /*
3460a8fed62SBram Moolenaar * "strptime({format}, {timestring})" function
3470a8fed62SBram Moolenaar */
3480a8fed62SBram Moolenaar void
f_strptime(typval_T * argvars,typval_T * rettv)3490a8fed62SBram Moolenaar f_strptime(typval_T *argvars, typval_T *rettv)
3500a8fed62SBram Moolenaar {
3510a8fed62SBram Moolenaar struct tm tmval;
3520a8fed62SBram Moolenaar char_u *fmt;
3530a8fed62SBram Moolenaar char_u *str;
3540a8fed62SBram Moolenaar vimconv_T conv;
3550a8fed62SBram Moolenaar char_u *enc;
3560a8fed62SBram Moolenaar
3574490ec4eSYegappan Lakshmanan if (in_vim9script()
3584490ec4eSYegappan Lakshmanan && (check_for_string_arg(argvars, 0) == FAIL
3594490ec4eSYegappan Lakshmanan || check_for_string_arg(argvars, 1) == FAIL))
3604490ec4eSYegappan Lakshmanan return;
3614490ec4eSYegappan Lakshmanan
362a80faa89SBram Moolenaar CLEAR_FIELD(tmval);
363ea1233fcSBram Moolenaar tmval.tm_isdst = -1;
3640a8fed62SBram Moolenaar fmt = tv_get_string(&argvars[0]);
3650a8fed62SBram Moolenaar str = tv_get_string(&argvars[1]);
3660a8fed62SBram Moolenaar
3670a8fed62SBram Moolenaar conv.vc_type = CONV_NONE;
3680a8fed62SBram Moolenaar enc = enc_locale();
3690a8fed62SBram Moolenaar convert_setup(&conv, p_enc, enc);
3700a8fed62SBram Moolenaar if (conv.vc_type != CONV_NONE)
3710a8fed62SBram Moolenaar fmt = string_convert(&conv, fmt, NULL);
3720a8fed62SBram Moolenaar if (fmt == NULL
3730a8fed62SBram Moolenaar || strptime((char *)str, (char *)fmt, &tmval) == NULL
3740a8fed62SBram Moolenaar || (rettv->vval.v_number = mktime(&tmval)) == -1)
3750a8fed62SBram Moolenaar rettv->vval.v_number = 0;
3760a8fed62SBram Moolenaar
3770a8fed62SBram Moolenaar if (conv.vc_type != CONV_NONE)
3780a8fed62SBram Moolenaar vim_free(fmt);
3790a8fed62SBram Moolenaar convert_setup(&conv, NULL, NULL);
3800a8fed62SBram Moolenaar vim_free(enc);
3810a8fed62SBram Moolenaar }
3820a8fed62SBram Moolenaar # endif
3830a8fed62SBram Moolenaar
3840a8fed62SBram Moolenaar # if defined(FEAT_TIMERS) || defined(PROTO)
3850a8fed62SBram Moolenaar static timer_T *first_timer = NULL;
3860a8fed62SBram Moolenaar static long last_timer_id = 0;
3870a8fed62SBram Moolenaar
3880a8fed62SBram Moolenaar /*
3890a8fed62SBram Moolenaar * Return time left until "due". Negative if past "due".
3900a8fed62SBram Moolenaar */
3910a8fed62SBram Moolenaar long
proftime_time_left(proftime_T * due,proftime_T * now)3920a8fed62SBram Moolenaar proftime_time_left(proftime_T *due, proftime_T *now)
3930a8fed62SBram Moolenaar {
3940a8fed62SBram Moolenaar # ifdef MSWIN
3950a8fed62SBram Moolenaar LARGE_INTEGER fr;
3960a8fed62SBram Moolenaar
3970a8fed62SBram Moolenaar if (now->QuadPart > due->QuadPart)
3980a8fed62SBram Moolenaar return 0;
3990a8fed62SBram Moolenaar QueryPerformanceFrequency(&fr);
4000a8fed62SBram Moolenaar return (long)(((double)(due->QuadPart - now->QuadPart)
4010a8fed62SBram Moolenaar / (double)fr.QuadPart) * 1000);
4020a8fed62SBram Moolenaar # else
4030a8fed62SBram Moolenaar if (now->tv_sec > due->tv_sec)
4040a8fed62SBram Moolenaar return 0;
4050a8fed62SBram Moolenaar return (due->tv_sec - now->tv_sec) * 1000
4060a8fed62SBram Moolenaar + (due->tv_usec - now->tv_usec) / 1000;
4070a8fed62SBram Moolenaar # endif
4080a8fed62SBram Moolenaar }
4090a8fed62SBram Moolenaar
4100a8fed62SBram Moolenaar /*
4110a8fed62SBram Moolenaar * Insert a timer in the list of timers.
4120a8fed62SBram Moolenaar */
4130a8fed62SBram Moolenaar static void
insert_timer(timer_T * timer)4140a8fed62SBram Moolenaar insert_timer(timer_T *timer)
4150a8fed62SBram Moolenaar {
4160a8fed62SBram Moolenaar timer->tr_next = first_timer;
4170a8fed62SBram Moolenaar timer->tr_prev = NULL;
4180a8fed62SBram Moolenaar if (first_timer != NULL)
4190a8fed62SBram Moolenaar first_timer->tr_prev = timer;
4200a8fed62SBram Moolenaar first_timer = timer;
4210a8fed62SBram Moolenaar did_add_timer = TRUE;
4220a8fed62SBram Moolenaar }
4230a8fed62SBram Moolenaar
4240a8fed62SBram Moolenaar /*
4250a8fed62SBram Moolenaar * Take a timer out of the list of timers.
4260a8fed62SBram Moolenaar */
4270a8fed62SBram Moolenaar static void
remove_timer(timer_T * timer)4280a8fed62SBram Moolenaar remove_timer(timer_T *timer)
4290a8fed62SBram Moolenaar {
4300a8fed62SBram Moolenaar if (timer->tr_prev == NULL)
4310a8fed62SBram Moolenaar first_timer = timer->tr_next;
4320a8fed62SBram Moolenaar else
4330a8fed62SBram Moolenaar timer->tr_prev->tr_next = timer->tr_next;
4340a8fed62SBram Moolenaar if (timer->tr_next != NULL)
4350a8fed62SBram Moolenaar timer->tr_next->tr_prev = timer->tr_prev;
4360a8fed62SBram Moolenaar }
4370a8fed62SBram Moolenaar
4380a8fed62SBram Moolenaar static void
free_timer(timer_T * timer)4390a8fed62SBram Moolenaar free_timer(timer_T *timer)
4400a8fed62SBram Moolenaar {
4410a8fed62SBram Moolenaar free_callback(&timer->tr_callback);
4420a8fed62SBram Moolenaar vim_free(timer);
4430a8fed62SBram Moolenaar }
4440a8fed62SBram Moolenaar
4450a8fed62SBram Moolenaar /*
4460a8fed62SBram Moolenaar * Create a timer and return it. NULL if out of memory.
4470a8fed62SBram Moolenaar * Caller should set the callback.
4480a8fed62SBram Moolenaar */
4490a8fed62SBram Moolenaar timer_T *
create_timer(long msec,int repeat)4500a8fed62SBram Moolenaar create_timer(long msec, int repeat)
4510a8fed62SBram Moolenaar {
4520a8fed62SBram Moolenaar timer_T *timer = ALLOC_CLEAR_ONE(timer_T);
4530a8fed62SBram Moolenaar long prev_id = last_timer_id;
4540a8fed62SBram Moolenaar
4550a8fed62SBram Moolenaar if (timer == NULL)
4560a8fed62SBram Moolenaar return NULL;
4570a8fed62SBram Moolenaar if (++last_timer_id <= prev_id)
4580a8fed62SBram Moolenaar // Overflow! Might cause duplicates...
4590a8fed62SBram Moolenaar last_timer_id = 0;
4600a8fed62SBram Moolenaar timer->tr_id = last_timer_id;
4610a8fed62SBram Moolenaar insert_timer(timer);
4620a8fed62SBram Moolenaar if (repeat != 0)
4630a8fed62SBram Moolenaar timer->tr_repeat = repeat - 1;
4640a8fed62SBram Moolenaar timer->tr_interval = msec;
4650a8fed62SBram Moolenaar
4660a8fed62SBram Moolenaar profile_setlimit(msec, &timer->tr_due);
4670a8fed62SBram Moolenaar return timer;
4680a8fed62SBram Moolenaar }
4690a8fed62SBram Moolenaar
4700a8fed62SBram Moolenaar /*
4710a8fed62SBram Moolenaar * Invoke the callback of "timer".
4720a8fed62SBram Moolenaar */
4730a8fed62SBram Moolenaar static void
timer_callback(timer_T * timer)4740a8fed62SBram Moolenaar timer_callback(timer_T *timer)
4750a8fed62SBram Moolenaar {
4760a8fed62SBram Moolenaar typval_T rettv;
4770a8fed62SBram Moolenaar typval_T argv[2];
4780a8fed62SBram Moolenaar
4790a8fed62SBram Moolenaar argv[0].v_type = VAR_NUMBER;
4800a8fed62SBram Moolenaar argv[0].vval.v_number = (varnumber_T)timer->tr_id;
4810a8fed62SBram Moolenaar argv[1].v_type = VAR_UNKNOWN;
4820a8fed62SBram Moolenaar
4830a8fed62SBram Moolenaar call_callback(&timer->tr_callback, -1, &rettv, 1, argv);
4840a8fed62SBram Moolenaar clear_tv(&rettv);
4850a8fed62SBram Moolenaar }
4860a8fed62SBram Moolenaar
4870a8fed62SBram Moolenaar /*
4880a8fed62SBram Moolenaar * Call timers that are due.
4890a8fed62SBram Moolenaar * Return the time in msec until the next timer is due.
4900a8fed62SBram Moolenaar * Returns -1 if there are no pending timers.
4910a8fed62SBram Moolenaar */
4920a8fed62SBram Moolenaar long
check_due_timer(void)4930a8fed62SBram Moolenaar check_due_timer(void)
4940a8fed62SBram Moolenaar {
4950a8fed62SBram Moolenaar timer_T *timer;
4960a8fed62SBram Moolenaar timer_T *timer_next;
4970a8fed62SBram Moolenaar long this_due;
4980a8fed62SBram Moolenaar long next_due = -1;
4990a8fed62SBram Moolenaar proftime_T now;
5000a8fed62SBram Moolenaar int did_one = FALSE;
5010a8fed62SBram Moolenaar int need_update_screen = FALSE;
5020a8fed62SBram Moolenaar long current_id = last_timer_id;
5030a8fed62SBram Moolenaar
5040a8fed62SBram Moolenaar // Don't run any timers while exiting or dealing with an error.
5050a8fed62SBram Moolenaar if (exiting || aborting())
5060a8fed62SBram Moolenaar return next_due;
5070a8fed62SBram Moolenaar
5080a8fed62SBram Moolenaar profile_start(&now);
5090a8fed62SBram Moolenaar for (timer = first_timer; timer != NULL && !got_int; timer = timer_next)
5100a8fed62SBram Moolenaar {
5110a8fed62SBram Moolenaar timer_next = timer->tr_next;
5120a8fed62SBram Moolenaar
5130a8fed62SBram Moolenaar if (timer->tr_id == -1 || timer->tr_firing || timer->tr_paused)
5140a8fed62SBram Moolenaar continue;
5150a8fed62SBram Moolenaar this_due = proftime_time_left(&timer->tr_due, &now);
5160a8fed62SBram Moolenaar if (this_due <= 1)
5170a8fed62SBram Moolenaar {
5180a8fed62SBram Moolenaar // Save and restore a lot of flags, because the timer fires while
5190a8fed62SBram Moolenaar // waiting for a character, which might be halfway a command.
5200a8fed62SBram Moolenaar int save_timer_busy = timer_busy;
5210a8fed62SBram Moolenaar int save_vgetc_busy = vgetc_busy;
5220a8fed62SBram Moolenaar int save_did_emsg = did_emsg;
523*88c89c77SBram Moolenaar int prev_uncaught_emsg = uncaught_emsg;
5240a8fed62SBram Moolenaar int save_called_emsg = called_emsg;
5250a8fed62SBram Moolenaar int save_must_redraw = must_redraw;
5260a8fed62SBram Moolenaar int save_trylevel = trylevel;
5270a8fed62SBram Moolenaar int save_did_throw = did_throw;
528a0f7f73eSBram Moolenaar int save_need_rethrow = need_rethrow;
5290a8fed62SBram Moolenaar int save_ex_pressedreturn = get_pressedreturn();
5300a8fed62SBram Moolenaar int save_may_garbage_collect = may_garbage_collect;
5310a8fed62SBram Moolenaar except_T *save_current_exception = current_exception;
5320a8fed62SBram Moolenaar vimvars_save_T vvsave;
5330a8fed62SBram Moolenaar
5340a8fed62SBram Moolenaar // Create a scope for running the timer callback, ignoring most of
5350a8fed62SBram Moolenaar // the current scope, such as being inside a try/catch.
5360a8fed62SBram Moolenaar timer_busy = timer_busy > 0 || vgetc_busy > 0;
5370a8fed62SBram Moolenaar vgetc_busy = 0;
5380a8fed62SBram Moolenaar called_emsg = 0;
5390a8fed62SBram Moolenaar did_emsg = FALSE;
5400a8fed62SBram Moolenaar must_redraw = 0;
5410a8fed62SBram Moolenaar trylevel = 0;
5420a8fed62SBram Moolenaar did_throw = FALSE;
543a0f7f73eSBram Moolenaar need_rethrow = FALSE;
5440a8fed62SBram Moolenaar current_exception = NULL;
5450a8fed62SBram Moolenaar may_garbage_collect = FALSE;
5460a8fed62SBram Moolenaar save_vimvars(&vvsave);
5470a8fed62SBram Moolenaar
54822286895SBram Moolenaar // Invoke the callback.
5490a8fed62SBram Moolenaar timer->tr_firing = TRUE;
5500a8fed62SBram Moolenaar timer_callback(timer);
5510a8fed62SBram Moolenaar timer->tr_firing = FALSE;
5520a8fed62SBram Moolenaar
55322286895SBram Moolenaar // Restore stuff.
5540a8fed62SBram Moolenaar timer_next = timer->tr_next;
5550a8fed62SBram Moolenaar did_one = TRUE;
5560a8fed62SBram Moolenaar timer_busy = save_timer_busy;
5570a8fed62SBram Moolenaar vgetc_busy = save_vgetc_busy;
558*88c89c77SBram Moolenaar if (uncaught_emsg > prev_uncaught_emsg)
5590a8fed62SBram Moolenaar ++timer->tr_emsg_count;
5600a8fed62SBram Moolenaar did_emsg = save_did_emsg;
5610a8fed62SBram Moolenaar called_emsg = save_called_emsg;
5620a8fed62SBram Moolenaar trylevel = save_trylevel;
5630a8fed62SBram Moolenaar did_throw = save_did_throw;
564a0f7f73eSBram Moolenaar need_rethrow = save_need_rethrow;
5650a8fed62SBram Moolenaar current_exception = save_current_exception;
5660a8fed62SBram Moolenaar restore_vimvars(&vvsave);
5670a8fed62SBram Moolenaar if (must_redraw != 0)
5680a8fed62SBram Moolenaar need_update_screen = TRUE;
5690a8fed62SBram Moolenaar must_redraw = must_redraw > save_must_redraw
5700a8fed62SBram Moolenaar ? must_redraw : save_must_redraw;
5710a8fed62SBram Moolenaar set_pressedreturn(save_ex_pressedreturn);
5720a8fed62SBram Moolenaar may_garbage_collect = save_may_garbage_collect;
5730a8fed62SBram Moolenaar
5740a8fed62SBram Moolenaar // Only fire the timer again if it repeats and stop_timer() wasn't
5750a8fed62SBram Moolenaar // called while inside the callback (tr_id == -1).
5760a8fed62SBram Moolenaar if (timer->tr_repeat != 0 && timer->tr_id != -1
5770a8fed62SBram Moolenaar && timer->tr_emsg_count < 3)
5780a8fed62SBram Moolenaar {
5790a8fed62SBram Moolenaar profile_setlimit(timer->tr_interval, &timer->tr_due);
5800a8fed62SBram Moolenaar this_due = proftime_time_left(&timer->tr_due, &now);
5810a8fed62SBram Moolenaar if (this_due < 1)
5820a8fed62SBram Moolenaar this_due = 1;
5830a8fed62SBram Moolenaar if (timer->tr_repeat > 0)
5840a8fed62SBram Moolenaar --timer->tr_repeat;
5850a8fed62SBram Moolenaar }
5860a8fed62SBram Moolenaar else
5870a8fed62SBram Moolenaar {
5880a8fed62SBram Moolenaar this_due = -1;
5890a8fed62SBram Moolenaar remove_timer(timer);
5900a8fed62SBram Moolenaar free_timer(timer);
5910a8fed62SBram Moolenaar }
5920a8fed62SBram Moolenaar }
5930a8fed62SBram Moolenaar if (this_due > 0 && (next_due == -1 || next_due > this_due))
5940a8fed62SBram Moolenaar next_due = this_due;
5950a8fed62SBram Moolenaar }
5960a8fed62SBram Moolenaar
5970a8fed62SBram Moolenaar if (did_one)
5980a8fed62SBram Moolenaar redraw_after_callback(need_update_screen);
5990a8fed62SBram Moolenaar
6000a8fed62SBram Moolenaar #ifdef FEAT_BEVAL_TERM
6010a8fed62SBram Moolenaar if (bevalexpr_due_set)
6020a8fed62SBram Moolenaar {
6030a8fed62SBram Moolenaar this_due = proftime_time_left(&bevalexpr_due, &now);
6040a8fed62SBram Moolenaar if (this_due <= 1)
6050a8fed62SBram Moolenaar {
6060a8fed62SBram Moolenaar bevalexpr_due_set = FALSE;
6070a8fed62SBram Moolenaar if (balloonEval == NULL)
6080a8fed62SBram Moolenaar {
6090a8fed62SBram Moolenaar balloonEval = ALLOC_CLEAR_ONE(BalloonEval);
6100a8fed62SBram Moolenaar balloonEvalForTerm = TRUE;
6110a8fed62SBram Moolenaar }
6120a8fed62SBram Moolenaar if (balloonEval != NULL)
6130a8fed62SBram Moolenaar {
6140a8fed62SBram Moolenaar general_beval_cb(balloonEval, 0);
6150a8fed62SBram Moolenaar setcursor();
6160a8fed62SBram Moolenaar out_flush();
6170a8fed62SBram Moolenaar }
6180a8fed62SBram Moolenaar }
6190a8fed62SBram Moolenaar else if (next_due == -1 || next_due > this_due)
6200a8fed62SBram Moolenaar next_due = this_due;
6210a8fed62SBram Moolenaar }
6220a8fed62SBram Moolenaar #endif
6230a8fed62SBram Moolenaar #ifdef FEAT_TERMINAL
6240a8fed62SBram Moolenaar // Some terminal windows may need their buffer updated.
6250a8fed62SBram Moolenaar next_due = term_check_timers(next_due, &now);
6260a8fed62SBram Moolenaar #endif
6270a8fed62SBram Moolenaar
6280a8fed62SBram Moolenaar return current_id != last_timer_id ? 1 : next_due;
6290a8fed62SBram Moolenaar }
6300a8fed62SBram Moolenaar
6310a8fed62SBram Moolenaar /*
6320a8fed62SBram Moolenaar * Find a timer by ID. Returns NULL if not found;
6330a8fed62SBram Moolenaar */
6340a8fed62SBram Moolenaar static timer_T *
find_timer(long id)6350a8fed62SBram Moolenaar find_timer(long id)
6360a8fed62SBram Moolenaar {
6370a8fed62SBram Moolenaar timer_T *timer;
6380a8fed62SBram Moolenaar
6390a8fed62SBram Moolenaar if (id >= 0)
6400a8fed62SBram Moolenaar {
64100d253e2SBram Moolenaar FOR_ALL_TIMERS(timer)
6420a8fed62SBram Moolenaar if (timer->tr_id == id)
6430a8fed62SBram Moolenaar return timer;
6440a8fed62SBram Moolenaar }
6450a8fed62SBram Moolenaar return NULL;
6460a8fed62SBram Moolenaar }
6470a8fed62SBram Moolenaar
6480a8fed62SBram Moolenaar
6490a8fed62SBram Moolenaar /*
6500a8fed62SBram Moolenaar * Stop a timer and delete it.
6510a8fed62SBram Moolenaar */
6520a8fed62SBram Moolenaar void
stop_timer(timer_T * timer)6530a8fed62SBram Moolenaar stop_timer(timer_T *timer)
6540a8fed62SBram Moolenaar {
6550a8fed62SBram Moolenaar if (timer->tr_firing)
6560a8fed62SBram Moolenaar // Free the timer after the callback returns.
6570a8fed62SBram Moolenaar timer->tr_id = -1;
6580a8fed62SBram Moolenaar else
6590a8fed62SBram Moolenaar {
6600a8fed62SBram Moolenaar remove_timer(timer);
6610a8fed62SBram Moolenaar free_timer(timer);
6620a8fed62SBram Moolenaar }
6630a8fed62SBram Moolenaar }
6640a8fed62SBram Moolenaar
6650a8fed62SBram Moolenaar static void
stop_all_timers(void)6660a8fed62SBram Moolenaar stop_all_timers(void)
6670a8fed62SBram Moolenaar {
6680a8fed62SBram Moolenaar timer_T *timer;
6690a8fed62SBram Moolenaar timer_T *timer_next;
6700a8fed62SBram Moolenaar
6710a8fed62SBram Moolenaar for (timer = first_timer; timer != NULL; timer = timer_next)
6720a8fed62SBram Moolenaar {
6730a8fed62SBram Moolenaar timer_next = timer->tr_next;
6740a8fed62SBram Moolenaar stop_timer(timer);
6750a8fed62SBram Moolenaar }
6760a8fed62SBram Moolenaar }
6770a8fed62SBram Moolenaar
6780a8fed62SBram Moolenaar static void
add_timer_info(typval_T * rettv,timer_T * timer)6790a8fed62SBram Moolenaar add_timer_info(typval_T *rettv, timer_T *timer)
6800a8fed62SBram Moolenaar {
6810a8fed62SBram Moolenaar list_T *list = rettv->vval.v_list;
6820a8fed62SBram Moolenaar dict_T *dict = dict_alloc();
6830a8fed62SBram Moolenaar dictitem_T *di;
6840a8fed62SBram Moolenaar long remaining;
6850a8fed62SBram Moolenaar proftime_T now;
6860a8fed62SBram Moolenaar
6870a8fed62SBram Moolenaar if (dict == NULL)
6880a8fed62SBram Moolenaar return;
6890a8fed62SBram Moolenaar list_append_dict(list, dict);
6900a8fed62SBram Moolenaar
6910a8fed62SBram Moolenaar dict_add_number(dict, "id", timer->tr_id);
6920a8fed62SBram Moolenaar dict_add_number(dict, "time", (long)timer->tr_interval);
6930a8fed62SBram Moolenaar
6940a8fed62SBram Moolenaar profile_start(&now);
6950a8fed62SBram Moolenaar remaining = proftime_time_left(&timer->tr_due, &now);
6960a8fed62SBram Moolenaar dict_add_number(dict, "remaining", (long)remaining);
6970a8fed62SBram Moolenaar
6980a8fed62SBram Moolenaar dict_add_number(dict, "repeat",
6990a8fed62SBram Moolenaar (long)(timer->tr_repeat < 0 ? -1 : timer->tr_repeat + 1));
7000a8fed62SBram Moolenaar dict_add_number(dict, "paused", (long)(timer->tr_paused));
7010a8fed62SBram Moolenaar
7020a8fed62SBram Moolenaar di = dictitem_alloc((char_u *)"callback");
7030a8fed62SBram Moolenaar if (di != NULL)
7040a8fed62SBram Moolenaar {
7050a8fed62SBram Moolenaar if (dict_add(dict, di) == FAIL)
7060a8fed62SBram Moolenaar vim_free(di);
7070a8fed62SBram Moolenaar else
7080a8fed62SBram Moolenaar put_callback(&timer->tr_callback, &di->di_tv);
7090a8fed62SBram Moolenaar }
7100a8fed62SBram Moolenaar }
7110a8fed62SBram Moolenaar
7120a8fed62SBram Moolenaar static void
add_timer_info_all(typval_T * rettv)7130a8fed62SBram Moolenaar add_timer_info_all(typval_T *rettv)
7140a8fed62SBram Moolenaar {
7150a8fed62SBram Moolenaar timer_T *timer;
7160a8fed62SBram Moolenaar
71700d253e2SBram Moolenaar FOR_ALL_TIMERS(timer)
7180a8fed62SBram Moolenaar if (timer->tr_id != -1)
7190a8fed62SBram Moolenaar add_timer_info(rettv, timer);
7200a8fed62SBram Moolenaar }
7210a8fed62SBram Moolenaar
7220a8fed62SBram Moolenaar /*
7230a8fed62SBram Moolenaar * Mark references in partials of timers.
7240a8fed62SBram Moolenaar */
7250a8fed62SBram Moolenaar int
set_ref_in_timer(int copyID)7260a8fed62SBram Moolenaar set_ref_in_timer(int copyID)
7270a8fed62SBram Moolenaar {
7280a8fed62SBram Moolenaar int abort = FALSE;
7290a8fed62SBram Moolenaar timer_T *timer;
7300a8fed62SBram Moolenaar typval_T tv;
7310a8fed62SBram Moolenaar
7320a8fed62SBram Moolenaar for (timer = first_timer; !abort && timer != NULL; timer = timer->tr_next)
7330a8fed62SBram Moolenaar {
7340a8fed62SBram Moolenaar if (timer->tr_callback.cb_partial != NULL)
7350a8fed62SBram Moolenaar {
7360a8fed62SBram Moolenaar tv.v_type = VAR_PARTIAL;
7370a8fed62SBram Moolenaar tv.vval.v_partial = timer->tr_callback.cb_partial;
7380a8fed62SBram Moolenaar }
7390a8fed62SBram Moolenaar else
7400a8fed62SBram Moolenaar {
7410a8fed62SBram Moolenaar tv.v_type = VAR_FUNC;
7420a8fed62SBram Moolenaar tv.vval.v_string = timer->tr_callback.cb_name;
7430a8fed62SBram Moolenaar }
7440a8fed62SBram Moolenaar abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
7450a8fed62SBram Moolenaar }
7460a8fed62SBram Moolenaar return abort;
7470a8fed62SBram Moolenaar }
7480a8fed62SBram Moolenaar
7490a8fed62SBram Moolenaar # if defined(EXITFREE) || defined(PROTO)
7500a8fed62SBram Moolenaar void
timer_free_all()7510a8fed62SBram Moolenaar timer_free_all()
7520a8fed62SBram Moolenaar {
7530a8fed62SBram Moolenaar timer_T *timer;
7540a8fed62SBram Moolenaar
7550a8fed62SBram Moolenaar while (first_timer != NULL)
7560a8fed62SBram Moolenaar {
7570a8fed62SBram Moolenaar timer = first_timer;
7580a8fed62SBram Moolenaar remove_timer(timer);
7590a8fed62SBram Moolenaar free_timer(timer);
7600a8fed62SBram Moolenaar }
7610a8fed62SBram Moolenaar }
7620a8fed62SBram Moolenaar # endif
7630a8fed62SBram Moolenaar
7640a8fed62SBram Moolenaar /*
7650a8fed62SBram Moolenaar * "timer_info([timer])" function
7660a8fed62SBram Moolenaar */
7670a8fed62SBram Moolenaar void
f_timer_info(typval_T * argvars,typval_T * rettv)7680a8fed62SBram Moolenaar f_timer_info(typval_T *argvars, typval_T *rettv)
7690a8fed62SBram Moolenaar {
7700a8fed62SBram Moolenaar timer_T *timer = NULL;
7710a8fed62SBram Moolenaar
7720a8fed62SBram Moolenaar if (rettv_list_alloc(rettv) != OK)
7730a8fed62SBram Moolenaar return;
7744490ec4eSYegappan Lakshmanan
7754490ec4eSYegappan Lakshmanan if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL)
7764490ec4eSYegappan Lakshmanan return;
7774490ec4eSYegappan Lakshmanan
7780a8fed62SBram Moolenaar if (argvars[0].v_type != VAR_UNKNOWN)
7790a8fed62SBram Moolenaar {
7800a8fed62SBram Moolenaar if (argvars[0].v_type != VAR_NUMBER)
781e29a27f6SBram Moolenaar emsg(_(e_number_expected));
7820a8fed62SBram Moolenaar else
7830a8fed62SBram Moolenaar {
7840a8fed62SBram Moolenaar timer = find_timer((int)tv_get_number(&argvars[0]));
7850a8fed62SBram Moolenaar if (timer != NULL)
7860a8fed62SBram Moolenaar add_timer_info(rettv, timer);
7870a8fed62SBram Moolenaar }
7880a8fed62SBram Moolenaar }
7890a8fed62SBram Moolenaar else
7900a8fed62SBram Moolenaar add_timer_info_all(rettv);
7910a8fed62SBram Moolenaar }
7920a8fed62SBram Moolenaar
7930a8fed62SBram Moolenaar /*
7940a8fed62SBram Moolenaar * "timer_pause(timer, paused)" function
7950a8fed62SBram Moolenaar */
7960a8fed62SBram Moolenaar void
f_timer_pause(typval_T * argvars,typval_T * rettv UNUSED)7970a8fed62SBram Moolenaar f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
7980a8fed62SBram Moolenaar {
7990a8fed62SBram Moolenaar timer_T *timer = NULL;
80083494b4aSYegappan Lakshmanan
80183494b4aSYegappan Lakshmanan if (in_vim9script()
80283494b4aSYegappan Lakshmanan && (check_for_number_arg(argvars, 0) == FAIL
80383494b4aSYegappan Lakshmanan || check_for_bool_arg(argvars, 1) == FAIL))
80483494b4aSYegappan Lakshmanan return;
8050a8fed62SBram Moolenaar
8060a8fed62SBram Moolenaar if (argvars[0].v_type != VAR_NUMBER)
807e29a27f6SBram Moolenaar emsg(_(e_number_expected));
8080a8fed62SBram Moolenaar else
8090a8fed62SBram Moolenaar {
81083494b4aSYegappan Lakshmanan int paused = (int)tv_get_bool(&argvars[1]);
8110a8fed62SBram Moolenaar timer = find_timer((int)tv_get_number(&argvars[0]));
8120a8fed62SBram Moolenaar if (timer != NULL)
8130a8fed62SBram Moolenaar timer->tr_paused = paused;
8140a8fed62SBram Moolenaar }
8150a8fed62SBram Moolenaar }
8160a8fed62SBram Moolenaar
8170a8fed62SBram Moolenaar /*
8180a8fed62SBram Moolenaar * "timer_start(time, callback [, options])" function
8190a8fed62SBram Moolenaar */
8200a8fed62SBram Moolenaar void
f_timer_start(typval_T * argvars,typval_T * rettv)8210a8fed62SBram Moolenaar f_timer_start(typval_T *argvars, typval_T *rettv)
8220a8fed62SBram Moolenaar {
8237973de35SYegappan Lakshmanan long msec;
8240a8fed62SBram Moolenaar timer_T *timer;
8250a8fed62SBram Moolenaar int repeat = 0;
8260a8fed62SBram Moolenaar callback_T callback;
8270a8fed62SBram Moolenaar dict_T *dict;
8280a8fed62SBram Moolenaar
8290a8fed62SBram Moolenaar rettv->vval.v_number = -1;
8300a8fed62SBram Moolenaar if (check_secure())
8310a8fed62SBram Moolenaar return;
8327973de35SYegappan Lakshmanan
8337973de35SYegappan Lakshmanan if (in_vim9script()
8347973de35SYegappan Lakshmanan && (check_for_number_arg(argvars, 0) == FAIL
8357973de35SYegappan Lakshmanan || check_for_opt_dict_arg(argvars, 2) == FAIL))
8367973de35SYegappan Lakshmanan return;
8377973de35SYegappan Lakshmanan
8387973de35SYegappan Lakshmanan msec = (long)tv_get_number(&argvars[0]);
8390a8fed62SBram Moolenaar if (argvars[2].v_type != VAR_UNKNOWN)
8400a8fed62SBram Moolenaar {
8410a8fed62SBram Moolenaar if (argvars[2].v_type != VAR_DICT
8420a8fed62SBram Moolenaar || (dict = argvars[2].vval.v_dict) == NULL)
8430a8fed62SBram Moolenaar {
8440a8fed62SBram Moolenaar semsg(_(e_invarg2), tv_get_string(&argvars[2]));
8450a8fed62SBram Moolenaar return;
8460a8fed62SBram Moolenaar }
8470a8fed62SBram Moolenaar if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
8480a8fed62SBram Moolenaar repeat = dict_get_number(dict, (char_u *)"repeat");
8490a8fed62SBram Moolenaar }
8500a8fed62SBram Moolenaar
8510a8fed62SBram Moolenaar callback = get_callback(&argvars[1]);
8520a8fed62SBram Moolenaar if (callback.cb_name == NULL)
8530a8fed62SBram Moolenaar return;
8540a8fed62SBram Moolenaar
8550a8fed62SBram Moolenaar timer = create_timer(msec, repeat);
8560a8fed62SBram Moolenaar if (timer == NULL)
8570a8fed62SBram Moolenaar free_callback(&callback);
8580a8fed62SBram Moolenaar else
8590a8fed62SBram Moolenaar {
8600a8fed62SBram Moolenaar set_callback(&timer->tr_callback, &callback);
8610a8fed62SBram Moolenaar rettv->vval.v_number = (varnumber_T)timer->tr_id;
8620a8fed62SBram Moolenaar }
8630a8fed62SBram Moolenaar }
8640a8fed62SBram Moolenaar
8650a8fed62SBram Moolenaar /*
8660a8fed62SBram Moolenaar * "timer_stop(timer)" function
8670a8fed62SBram Moolenaar */
8680a8fed62SBram Moolenaar void
f_timer_stop(typval_T * argvars,typval_T * rettv UNUSED)8690a8fed62SBram Moolenaar f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
8700a8fed62SBram Moolenaar {
8710a8fed62SBram Moolenaar timer_T *timer;
8720a8fed62SBram Moolenaar
8734490ec4eSYegappan Lakshmanan if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL)
8744490ec4eSYegappan Lakshmanan return;
8754490ec4eSYegappan Lakshmanan
8760a8fed62SBram Moolenaar if (argvars[0].v_type != VAR_NUMBER)
8770a8fed62SBram Moolenaar {
878e29a27f6SBram Moolenaar emsg(_(e_number_expected));
8790a8fed62SBram Moolenaar return;
8800a8fed62SBram Moolenaar }
8810a8fed62SBram Moolenaar timer = find_timer((int)tv_get_number(&argvars[0]));
8820a8fed62SBram Moolenaar if (timer != NULL)
8830a8fed62SBram Moolenaar stop_timer(timer);
8840a8fed62SBram Moolenaar }
8850a8fed62SBram Moolenaar
8860a8fed62SBram Moolenaar /*
8870a8fed62SBram Moolenaar * "timer_stopall()" function
8880a8fed62SBram Moolenaar */
8890a8fed62SBram Moolenaar void
f_timer_stopall(typval_T * argvars UNUSED,typval_T * rettv UNUSED)8900a8fed62SBram Moolenaar f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8910a8fed62SBram Moolenaar {
8920a8fed62SBram Moolenaar stop_all_timers();
8930a8fed62SBram Moolenaar }
8940a8fed62SBram Moolenaar
8950a8fed62SBram Moolenaar # endif // FEAT_TIMERS
8960a8fed62SBram Moolenaar
8970a8fed62SBram Moolenaar # if defined(STARTUPTIME) || defined(PROTO)
8980a8fed62SBram Moolenaar static struct timeval prev_timeval;
8990a8fed62SBram Moolenaar
9000a8fed62SBram Moolenaar # ifdef MSWIN
9010a8fed62SBram Moolenaar /*
9020a8fed62SBram Moolenaar * Windows doesn't have gettimeofday(), although it does have struct timeval.
9030a8fed62SBram Moolenaar */
9040a8fed62SBram Moolenaar static int
gettimeofday(struct timeval * tv,char * dummy UNUSED)9050a8fed62SBram Moolenaar gettimeofday(struct timeval *tv, char *dummy UNUSED)
9060a8fed62SBram Moolenaar {
9070a8fed62SBram Moolenaar long t = clock();
9080a8fed62SBram Moolenaar tv->tv_sec = t / CLOCKS_PER_SEC;
9090a8fed62SBram Moolenaar tv->tv_usec = (t - tv->tv_sec * CLOCKS_PER_SEC) * 1000000 / CLOCKS_PER_SEC;
9100a8fed62SBram Moolenaar return 0;
9110a8fed62SBram Moolenaar }
9120a8fed62SBram Moolenaar # endif
9130a8fed62SBram Moolenaar
9140a8fed62SBram Moolenaar /*
9150a8fed62SBram Moolenaar * Save the previous time before doing something that could nest.
9160a8fed62SBram Moolenaar * set "*tv_rel" to the time elapsed so far.
9170a8fed62SBram Moolenaar */
9180a8fed62SBram Moolenaar void
time_push(void * tv_rel,void * tv_start)9190a8fed62SBram Moolenaar time_push(void *tv_rel, void *tv_start)
9200a8fed62SBram Moolenaar {
9210a8fed62SBram Moolenaar *((struct timeval *)tv_rel) = prev_timeval;
9220a8fed62SBram Moolenaar gettimeofday(&prev_timeval, NULL);
9230a8fed62SBram Moolenaar ((struct timeval *)tv_rel)->tv_usec = prev_timeval.tv_usec
9240a8fed62SBram Moolenaar - ((struct timeval *)tv_rel)->tv_usec;
9250a8fed62SBram Moolenaar ((struct timeval *)tv_rel)->tv_sec = prev_timeval.tv_sec
9260a8fed62SBram Moolenaar - ((struct timeval *)tv_rel)->tv_sec;
9270a8fed62SBram Moolenaar if (((struct timeval *)tv_rel)->tv_usec < 0)
9280a8fed62SBram Moolenaar {
9290a8fed62SBram Moolenaar ((struct timeval *)tv_rel)->tv_usec += 1000000;
9300a8fed62SBram Moolenaar --((struct timeval *)tv_rel)->tv_sec;
9310a8fed62SBram Moolenaar }
9320a8fed62SBram Moolenaar *(struct timeval *)tv_start = prev_timeval;
9330a8fed62SBram Moolenaar }
9340a8fed62SBram Moolenaar
9350a8fed62SBram Moolenaar /*
9360a8fed62SBram Moolenaar * Compute the previous time after doing something that could nest.
9370a8fed62SBram Moolenaar * Subtract "*tp" from prev_timeval;
9380a8fed62SBram Moolenaar * Note: The arguments are (void *) to avoid trouble with systems that don't
9390a8fed62SBram Moolenaar * have struct timeval.
9400a8fed62SBram Moolenaar */
9410a8fed62SBram Moolenaar void
time_pop(void * tp)9420a8fed62SBram Moolenaar time_pop(
9430a8fed62SBram Moolenaar void *tp) // actually (struct timeval *)
9440a8fed62SBram Moolenaar {
9450a8fed62SBram Moolenaar prev_timeval.tv_usec -= ((struct timeval *)tp)->tv_usec;
9460a8fed62SBram Moolenaar prev_timeval.tv_sec -= ((struct timeval *)tp)->tv_sec;
9470a8fed62SBram Moolenaar if (prev_timeval.tv_usec < 0)
9480a8fed62SBram Moolenaar {
9490a8fed62SBram Moolenaar prev_timeval.tv_usec += 1000000;
9500a8fed62SBram Moolenaar --prev_timeval.tv_sec;
9510a8fed62SBram Moolenaar }
9520a8fed62SBram Moolenaar }
9530a8fed62SBram Moolenaar
9540a8fed62SBram Moolenaar static void
time_diff(struct timeval * then,struct timeval * now)9550a8fed62SBram Moolenaar time_diff(struct timeval *then, struct timeval *now)
9560a8fed62SBram Moolenaar {
9570a8fed62SBram Moolenaar long usec;
9580a8fed62SBram Moolenaar long msec;
9590a8fed62SBram Moolenaar
9600a8fed62SBram Moolenaar usec = now->tv_usec - then->tv_usec;
9610a8fed62SBram Moolenaar msec = (now->tv_sec - then->tv_sec) * 1000L + usec / 1000L,
9620a8fed62SBram Moolenaar usec = usec % 1000L;
9630a8fed62SBram Moolenaar fprintf(time_fd, "%03ld.%03ld", msec, usec >= 0 ? usec : usec + 1000L);
9640a8fed62SBram Moolenaar }
9650a8fed62SBram Moolenaar
9660a8fed62SBram Moolenaar void
time_msg(char * mesg,void * tv_start)9670a8fed62SBram Moolenaar time_msg(
9680a8fed62SBram Moolenaar char *mesg,
9690a8fed62SBram Moolenaar void *tv_start) // only for do_source: start time; actually
9700a8fed62SBram Moolenaar // (struct timeval *)
9710a8fed62SBram Moolenaar {
9720a8fed62SBram Moolenaar static struct timeval start;
9730a8fed62SBram Moolenaar struct timeval now;
9740a8fed62SBram Moolenaar
9750a8fed62SBram Moolenaar if (time_fd != NULL)
9760a8fed62SBram Moolenaar {
9770a8fed62SBram Moolenaar if (strstr(mesg, "STARTING") != NULL)
9780a8fed62SBram Moolenaar {
9790a8fed62SBram Moolenaar gettimeofday(&start, NULL);
9800a8fed62SBram Moolenaar prev_timeval = start;
9810a8fed62SBram Moolenaar fprintf(time_fd, "\n\ntimes in msec\n");
9820a8fed62SBram Moolenaar fprintf(time_fd, " clock self+sourced self: sourced script\n");
9830a8fed62SBram Moolenaar fprintf(time_fd, " clock elapsed: other lines\n\n");
9840a8fed62SBram Moolenaar }
9850a8fed62SBram Moolenaar gettimeofday(&now, NULL);
9860a8fed62SBram Moolenaar time_diff(&start, &now);
9870a8fed62SBram Moolenaar if (((struct timeval *)tv_start) != NULL)
9880a8fed62SBram Moolenaar {
9890a8fed62SBram Moolenaar fprintf(time_fd, " ");
9900a8fed62SBram Moolenaar time_diff(((struct timeval *)tv_start), &now);
9910a8fed62SBram Moolenaar }
9920a8fed62SBram Moolenaar fprintf(time_fd, " ");
9930a8fed62SBram Moolenaar time_diff(&prev_timeval, &now);
9940a8fed62SBram Moolenaar prev_timeval = now;
9950a8fed62SBram Moolenaar fprintf(time_fd, ": %s\n", mesg);
9960a8fed62SBram Moolenaar }
9970a8fed62SBram Moolenaar }
9980a8fed62SBram Moolenaar # endif // STARTUPTIME
9990a8fed62SBram Moolenaar #endif // FEAT_EVAL
10000a8fed62SBram Moolenaar
10010a8fed62SBram Moolenaar #if defined(FEAT_SPELL) || defined(FEAT_PERSISTENT_UNDO) || defined(PROTO)
10020a8fed62SBram Moolenaar /*
10030a8fed62SBram Moolenaar * Read 8 bytes from "fd" and turn them into a time_T, MSB first.
10040a8fed62SBram Moolenaar * Returns -1 when encountering EOF.
10050a8fed62SBram Moolenaar */
10060a8fed62SBram Moolenaar time_T
get8ctime(FILE * fd)10070a8fed62SBram Moolenaar get8ctime(FILE *fd)
10080a8fed62SBram Moolenaar {
10090a8fed62SBram Moolenaar int c;
10100a8fed62SBram Moolenaar time_T n = 0;
10110a8fed62SBram Moolenaar int i;
10120a8fed62SBram Moolenaar
10130a8fed62SBram Moolenaar for (i = 0; i < 8; ++i)
10140a8fed62SBram Moolenaar {
10150a8fed62SBram Moolenaar c = getc(fd);
10160a8fed62SBram Moolenaar if (c == EOF) return -1;
10170a8fed62SBram Moolenaar n = (n << 8) + c;
10180a8fed62SBram Moolenaar }
10190a8fed62SBram Moolenaar return n;
10200a8fed62SBram Moolenaar }
10210a8fed62SBram Moolenaar
10220a8fed62SBram Moolenaar #ifdef _MSC_VER
10230a8fed62SBram Moolenaar # if (_MSC_VER <= 1200)
10240a8fed62SBram Moolenaar // This line is required for VC6 without the service pack. Also see the
10250a8fed62SBram Moolenaar // matching #pragma below.
10260a8fed62SBram Moolenaar # pragma optimize("", off)
10270a8fed62SBram Moolenaar # endif
10280a8fed62SBram Moolenaar #endif
10290a8fed62SBram Moolenaar
10300a8fed62SBram Moolenaar /*
10310a8fed62SBram Moolenaar * Write time_T to file "fd" in 8 bytes.
10320a8fed62SBram Moolenaar * Returns FAIL when the write failed.
10330a8fed62SBram Moolenaar */
10340a8fed62SBram Moolenaar int
put_time(FILE * fd,time_T the_time)10350a8fed62SBram Moolenaar put_time(FILE *fd, time_T the_time)
10360a8fed62SBram Moolenaar {
10370a8fed62SBram Moolenaar char_u buf[8];
10380a8fed62SBram Moolenaar
10390a8fed62SBram Moolenaar time_to_bytes(the_time, buf);
10400a8fed62SBram Moolenaar return fwrite(buf, (size_t)8, (size_t)1, fd) == 1 ? OK : FAIL;
10410a8fed62SBram Moolenaar }
10420a8fed62SBram Moolenaar
10430a8fed62SBram Moolenaar /*
10440a8fed62SBram Moolenaar * Write time_T to "buf[8]".
10450a8fed62SBram Moolenaar */
10460a8fed62SBram Moolenaar void
time_to_bytes(time_T the_time,char_u * buf)10470a8fed62SBram Moolenaar time_to_bytes(time_T the_time, char_u *buf)
10480a8fed62SBram Moolenaar {
10490a8fed62SBram Moolenaar int c;
10500a8fed62SBram Moolenaar int i;
10510a8fed62SBram Moolenaar int bi = 0;
10520a8fed62SBram Moolenaar time_T wtime = the_time;
10530a8fed62SBram Moolenaar
10540a8fed62SBram Moolenaar // time_T can be up to 8 bytes in size, more than long_u, thus we
10550a8fed62SBram Moolenaar // can't use put_bytes() here.
10560a8fed62SBram Moolenaar // Another problem is that ">>" may do an arithmetic shift that keeps the
10570a8fed62SBram Moolenaar // sign. This happens for large values of wtime. A cast to long_u may
10580a8fed62SBram Moolenaar // truncate if time_T is 8 bytes. So only use a cast when it is 4 bytes,
10590a8fed62SBram Moolenaar // it's safe to assume that long_u is 4 bytes or more and when using 8
10600a8fed62SBram Moolenaar // bytes the top bit won't be set.
10610a8fed62SBram Moolenaar for (i = 7; i >= 0; --i)
10620a8fed62SBram Moolenaar {
10630a8fed62SBram Moolenaar if (i + 1 > (int)sizeof(time_T))
10640a8fed62SBram Moolenaar // ">>" doesn't work well when shifting more bits than avail
10650a8fed62SBram Moolenaar buf[bi++] = 0;
10660a8fed62SBram Moolenaar else
10670a8fed62SBram Moolenaar {
10680a8fed62SBram Moolenaar #if defined(SIZEOF_TIME_T) && SIZEOF_TIME_T > 4
10690a8fed62SBram Moolenaar c = (int)(wtime >> (i * 8));
10700a8fed62SBram Moolenaar #else
10710a8fed62SBram Moolenaar c = (int)((long_u)wtime >> (i * 8));
10720a8fed62SBram Moolenaar #endif
10730a8fed62SBram Moolenaar buf[bi++] = c;
10740a8fed62SBram Moolenaar }
10750a8fed62SBram Moolenaar }
10760a8fed62SBram Moolenaar }
10770a8fed62SBram Moolenaar
10780a8fed62SBram Moolenaar #ifdef _MSC_VER
10790a8fed62SBram Moolenaar # if (_MSC_VER <= 1200)
10800a8fed62SBram Moolenaar # pragma optimize("", on)
10810a8fed62SBram Moolenaar # endif
10820a8fed62SBram Moolenaar #endif
10830a8fed62SBram Moolenaar
10840a8fed62SBram Moolenaar #endif
10850a8fed62SBram Moolenaar
10860a8fed62SBram Moolenaar /*
10870a8fed62SBram Moolenaar * Put timestamp "tt" in "buf[buflen]" in a nice format.
10880a8fed62SBram Moolenaar */
10890a8fed62SBram Moolenaar void
add_time(char_u * buf,size_t buflen,time_t tt)10900a8fed62SBram Moolenaar add_time(char_u *buf, size_t buflen, time_t tt)
10910a8fed62SBram Moolenaar {
10920a8fed62SBram Moolenaar #ifdef HAVE_STRFTIME
10930a8fed62SBram Moolenaar struct tm tmval;
10940a8fed62SBram Moolenaar struct tm *curtime;
10950a8fed62SBram Moolenaar
10960a8fed62SBram Moolenaar if (vim_time() - tt >= 100)
10970a8fed62SBram Moolenaar {
10980a8fed62SBram Moolenaar curtime = vim_localtime(&tt, &tmval);
10990a8fed62SBram Moolenaar if (vim_time() - tt < (60L * 60L * 12L))
11000a8fed62SBram Moolenaar // within 12 hours
11010a8fed62SBram Moolenaar (void)strftime((char *)buf, buflen, "%H:%M:%S", curtime);
11020a8fed62SBram Moolenaar else
11030a8fed62SBram Moolenaar // longer ago
11040a8fed62SBram Moolenaar (void)strftime((char *)buf, buflen, "%Y/%m/%d %H:%M:%S", curtime);
11050a8fed62SBram Moolenaar }
11060a8fed62SBram Moolenaar else
11070a8fed62SBram Moolenaar #endif
11080a8fed62SBram Moolenaar {
11090a8fed62SBram Moolenaar long seconds = (long)(vim_time() - tt);
11100a8fed62SBram Moolenaar
11110a8fed62SBram Moolenaar vim_snprintf((char *)buf, buflen,
11120a8fed62SBram Moolenaar NGETTEXT("%ld second ago", "%ld seconds ago", seconds),
11130a8fed62SBram Moolenaar seconds);
11140a8fed62SBram Moolenaar }
11150a8fed62SBram Moolenaar }
1116