xref: /vim-8.2.3635/src/time.c (revision 88c89c77)
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