xref: /vim-8.2.3635/src/time.c (revision bc93cebb)
1 /* vi:set ts=8 sts=4 sw=4 noet:
2  *
3  * VIM - Vi IMproved	by Bram Moolenaar
4  *
5  * Do ":help uganda"  in Vim to read copying and usage conditions.
6  * Do ":help credits" in Vim to see a list of people who contributed.
7  * See README.txt for an overview of the Vim source code.
8  */
9 
10 /*
11  * time.c: functions related to time and timers
12  */
13 
14 #include "vim.h"
15 
16 /*
17  * Cache of the current timezone name as retrieved from TZ, or an empty string
18  * where unset, up to 64 octets long including trailing null byte.
19  */
20 #if defined(HAVE_LOCALTIME_R) && defined(HAVE_TZSET)
21 static char	tz_cache[64];
22 #endif
23 
24 /*
25  * Call either localtime(3) or localtime_r(3) from POSIX libc time.h, with the
26  * latter version preferred for reentrancy.
27  *
28  * If we use localtime_r(3) and we have tzset(3) available, check to see if the
29  * environment variable TZ has changed since the last run, and call tzset(3) to
30  * update the global timezone variables if it has.  This is because the POSIX
31  * standard doesn't require localtime_r(3) implementations to do that as it
32  * does with localtime(3), and we don't want to call tzset(3) every time.
33  */
34     static struct tm *
35 vim_localtime(
36     const time_t	*timep,		// timestamp for local representation
37     struct tm		*result UNUSED)	// pointer to caller return buffer
38 {
39 #ifdef HAVE_LOCALTIME_R
40 # ifdef HAVE_TZSET
41     char		*tz;		// pointer for TZ environment var
42 
43     tz = (char *)mch_getenv((char_u *)"TZ");
44     if (tz == NULL)
45 	tz = "";
46     if (STRNCMP(tz_cache, tz, sizeof(tz_cache) - 1) != 0)
47     {
48 	tzset();
49 	vim_strncpy((char_u *)tz_cache, (char_u *)tz, sizeof(tz_cache) - 1);
50     }
51 # endif	// HAVE_TZSET
52     return localtime_r(timep, result);
53 #else
54     return localtime(timep);
55 #endif	// HAVE_LOCALTIME_R
56 }
57 
58 /*
59  * Return the current time in seconds.  Calls time(), unless test_settime()
60  * was used.
61  */
62     time_T
63 vim_time(void)
64 {
65 # ifdef FEAT_EVAL
66     return time_for_testing == 0 ? time(NULL) : time_for_testing;
67 # else
68     return time(NULL);
69 # endif
70 }
71 
72 /*
73  * Replacement for ctime(), which is not safe to use.
74  * Requires strftime(), otherwise returns "(unknown)".
75  * If "thetime" is invalid returns "(invalid)".  Never returns NULL.
76  * When "add_newline" is TRUE add a newline like ctime() does.
77  * Uses a static buffer.
78  */
79     char *
80 get_ctime(time_t thetime, int add_newline)
81 {
82     static char buf[50];
83 #ifdef HAVE_STRFTIME
84     struct tm	tmval;
85     struct tm	*curtime;
86 
87     curtime = vim_localtime(&thetime, &tmval);
88     // MSVC returns NULL for an invalid value of seconds.
89     if (curtime == NULL)
90 	vim_strncpy((char_u *)buf, (char_u *)_("(Invalid)"), sizeof(buf) - 1);
91     else
92     {
93 	(void)strftime(buf, sizeof(buf) - 1, _("%a %b %d %H:%M:%S %Y"),
94 								    curtime);
95 # ifdef MSWIN
96 	if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
97 	{
98 	    char_u	*to_free = NULL;
99 	    int		len;
100 
101 	    acp_to_enc((char_u *)buf, (int)strlen(buf), &to_free, &len);
102 	    if (to_free != NULL)
103 	    {
104 		STRCPY(buf, to_free);
105 		vim_free(to_free);
106 	    }
107 	}
108 # endif
109     }
110 #else
111     STRCPY(buf, "(unknown)");
112 #endif
113     if (add_newline)
114 	STRCAT(buf, "\n");
115     return buf;
116 }
117 
118 #if defined(FEAT_EVAL) || defined(PROTO)
119 
120 #if defined(MACOS_X)
121 # include <time.h>	// for time_t
122 #endif
123 
124 /*
125  * "localtime()" function
126  */
127     void
128 f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
129 {
130     rettv->vval.v_number = (varnumber_T)time(NULL);
131 }
132 
133 # if defined(FEAT_RELTIME)
134 /*
135  * Convert a List to proftime_T.
136  * Return FAIL when there is something wrong.
137  */
138     static int
139 list2proftime(typval_T *arg, proftime_T *tm)
140 {
141     long	n1, n2;
142     int	error = FALSE;
143 
144     if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
145 					     || arg->vval.v_list->lv_len != 2)
146 	return FAIL;
147     n1 = list_find_nr(arg->vval.v_list, 0L, &error);
148     n2 = list_find_nr(arg->vval.v_list, 1L, &error);
149 #  ifdef MSWIN
150     tm->HighPart = n1;
151     tm->LowPart = n2;
152 #  else
153     tm->tv_sec = n1;
154     tm->tv_usec = n2;
155 #  endif
156     return error ? FAIL : OK;
157 }
158 # endif // FEAT_RELTIME
159 
160 /*
161  * "reltime()" function
162  */
163     void
164 f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
165 {
166 # ifdef FEAT_RELTIME
167     proftime_T	res;
168     proftime_T	start;
169 
170     if (argvars[0].v_type == VAR_UNKNOWN)
171     {
172 	// No arguments: get current time.
173 	profile_start(&res);
174     }
175     else if (argvars[1].v_type == VAR_UNKNOWN)
176     {
177 	if (list2proftime(&argvars[0], &res) == FAIL)
178 	    return;
179 	profile_end(&res);
180     }
181     else
182     {
183 	// Two arguments: compute the difference.
184 	if (list2proftime(&argvars[0], &start) == FAIL
185 		|| list2proftime(&argvars[1], &res) == FAIL)
186 	    return;
187 	profile_sub(&res, &start);
188     }
189 
190     if (rettv_list_alloc(rettv) == OK)
191     {
192 	long	n1, n2;
193 
194 #  ifdef MSWIN
195 	n1 = res.HighPart;
196 	n2 = res.LowPart;
197 #  else
198 	n1 = res.tv_sec;
199 	n2 = res.tv_usec;
200 #  endif
201 	list_append_number(rettv->vval.v_list, (varnumber_T)n1);
202 	list_append_number(rettv->vval.v_list, (varnumber_T)n2);
203     }
204 # endif
205 }
206 
207 # ifdef FEAT_FLOAT
208 /*
209  * "reltimefloat()" function
210  */
211     void
212 f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
213 {
214 #  ifdef FEAT_RELTIME
215     proftime_T	tm;
216 #  endif
217 
218     rettv->v_type = VAR_FLOAT;
219     rettv->vval.v_float = 0;
220 #  ifdef FEAT_RELTIME
221     if (list2proftime(&argvars[0], &tm) == OK)
222 	rettv->vval.v_float = profile_float(&tm);
223 #  endif
224 }
225 # endif
226 
227 /*
228  * "reltimestr()" function
229  */
230     void
231 f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
232 {
233 # ifdef FEAT_RELTIME
234     proftime_T	tm;
235 # endif
236 
237     rettv->v_type = VAR_STRING;
238     rettv->vval.v_string = NULL;
239 # ifdef FEAT_RELTIME
240     if (list2proftime(&argvars[0], &tm) == OK)
241 	rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
242 # endif
243 }
244 
245 # if defined(HAVE_STRFTIME) || defined(PROTO)
246 /*
247  * "strftime({format}[, {time}])" function
248  */
249     void
250 f_strftime(typval_T *argvars, typval_T *rettv)
251 {
252     char_u	result_buf[256];
253     struct tm	tmval;
254     struct tm	*curtime;
255     time_t	seconds;
256     char_u	*p;
257 
258     rettv->v_type = VAR_STRING;
259 
260     p = tv_get_string(&argvars[0]);
261     if (argvars[1].v_type == VAR_UNKNOWN)
262 	seconds = time(NULL);
263     else
264 	seconds = (time_t)tv_get_number(&argvars[1]);
265     curtime = vim_localtime(&seconds, &tmval);
266     // MSVC returns NULL for an invalid value of seconds.
267     if (curtime == NULL)
268 	rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
269     else
270     {
271 	vimconv_T   conv;
272 	char_u	    *enc;
273 
274 	conv.vc_type = CONV_NONE;
275 	enc = enc_locale();
276 	convert_setup(&conv, p_enc, enc);
277 	if (conv.vc_type != CONV_NONE)
278 	    p = string_convert(&conv, p, NULL);
279 	if (p != NULL)
280 	    (void)strftime((char *)result_buf, sizeof(result_buf),
281 							  (char *)p, curtime);
282 	else
283 	    result_buf[0] = NUL;
284 
285 	if (conv.vc_type != CONV_NONE)
286 	    vim_free(p);
287 	convert_setup(&conv, enc, p_enc);
288 	if (conv.vc_type != CONV_NONE)
289 	    rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
290 	else
291 	    rettv->vval.v_string = vim_strsave(result_buf);
292 
293 	// Release conversion descriptors
294 	convert_setup(&conv, NULL, NULL);
295 	vim_free(enc);
296     }
297 }
298 # endif
299 
300 # if defined(HAVE_STRPTIME) || defined(PROTO)
301 /*
302  * "strptime({format}, {timestring})" function
303  */
304     void
305 f_strptime(typval_T *argvars, typval_T *rettv)
306 {
307     struct tm	tmval;
308     char_u	*fmt;
309     char_u	*str;
310     vimconv_T   conv;
311     char_u	*enc;
312 
313     vim_memset(&tmval, NUL, sizeof(tmval));
314     fmt = tv_get_string(&argvars[0]);
315     str = tv_get_string(&argvars[1]);
316 
317     conv.vc_type = CONV_NONE;
318     enc = enc_locale();
319     convert_setup(&conv, p_enc, enc);
320     if (conv.vc_type != CONV_NONE)
321 	fmt = string_convert(&conv, fmt, NULL);
322     if (fmt == NULL
323 	    || strptime((char *)str, (char *)fmt, &tmval) == NULL
324 	    || (rettv->vval.v_number = mktime(&tmval)) == -1)
325 	rettv->vval.v_number = 0;
326 
327     if (conv.vc_type != CONV_NONE)
328 	vim_free(fmt);
329     convert_setup(&conv, NULL, NULL);
330     vim_free(enc);
331 }
332 # endif
333 
334 # if defined(FEAT_TIMERS) || defined(PROTO)
335 static timer_T	*first_timer = NULL;
336 static long	last_timer_id = 0;
337 
338 /*
339  * Return time left until "due".  Negative if past "due".
340  */
341     long
342 proftime_time_left(proftime_T *due, proftime_T *now)
343 {
344 #  ifdef MSWIN
345     LARGE_INTEGER fr;
346 
347     if (now->QuadPart > due->QuadPart)
348 	return 0;
349     QueryPerformanceFrequency(&fr);
350     return (long)(((double)(due->QuadPart - now->QuadPart)
351 		   / (double)fr.QuadPart) * 1000);
352 #  else
353     if (now->tv_sec > due->tv_sec)
354 	return 0;
355     return (due->tv_sec - now->tv_sec) * 1000
356 	+ (due->tv_usec - now->tv_usec) / 1000;
357 #  endif
358 }
359 
360 /*
361  * Insert a timer in the list of timers.
362  */
363     static void
364 insert_timer(timer_T *timer)
365 {
366     timer->tr_next = first_timer;
367     timer->tr_prev = NULL;
368     if (first_timer != NULL)
369 	first_timer->tr_prev = timer;
370     first_timer = timer;
371     did_add_timer = TRUE;
372 }
373 
374 /*
375  * Take a timer out of the list of timers.
376  */
377     static void
378 remove_timer(timer_T *timer)
379 {
380     if (timer->tr_prev == NULL)
381 	first_timer = timer->tr_next;
382     else
383 	timer->tr_prev->tr_next = timer->tr_next;
384     if (timer->tr_next != NULL)
385 	timer->tr_next->tr_prev = timer->tr_prev;
386 }
387 
388     static void
389 free_timer(timer_T *timer)
390 {
391     free_callback(&timer->tr_callback);
392     vim_free(timer);
393 }
394 
395 /*
396  * Create a timer and return it.  NULL if out of memory.
397  * Caller should set the callback.
398  */
399     timer_T *
400 create_timer(long msec, int repeat)
401 {
402     timer_T	*timer = ALLOC_CLEAR_ONE(timer_T);
403     long	prev_id = last_timer_id;
404 
405     if (timer == NULL)
406 	return NULL;
407     if (++last_timer_id <= prev_id)
408 	// Overflow!  Might cause duplicates...
409 	last_timer_id = 0;
410     timer->tr_id = last_timer_id;
411     insert_timer(timer);
412     if (repeat != 0)
413 	timer->tr_repeat = repeat - 1;
414     timer->tr_interval = msec;
415 
416     profile_setlimit(msec, &timer->tr_due);
417     return timer;
418 }
419 
420 /*
421  * Invoke the callback of "timer".
422  */
423     static void
424 timer_callback(timer_T *timer)
425 {
426     typval_T	rettv;
427     typval_T	argv[2];
428 
429     argv[0].v_type = VAR_NUMBER;
430     argv[0].vval.v_number = (varnumber_T)timer->tr_id;
431     argv[1].v_type = VAR_UNKNOWN;
432 
433     call_callback(&timer->tr_callback, -1, &rettv, 1, argv);
434     clear_tv(&rettv);
435 }
436 
437 /*
438  * Call timers that are due.
439  * Return the time in msec until the next timer is due.
440  * Returns -1 if there are no pending timers.
441  */
442     long
443 check_due_timer(void)
444 {
445     timer_T	*timer;
446     timer_T	*timer_next;
447     long	this_due;
448     long	next_due = -1;
449     proftime_T	now;
450     int		did_one = FALSE;
451     int		need_update_screen = FALSE;
452     long	current_id = last_timer_id;
453 
454     // Don't run any timers while exiting or dealing with an error.
455     if (exiting || aborting())
456 	return next_due;
457 
458     profile_start(&now);
459     for (timer = first_timer; timer != NULL && !got_int; timer = timer_next)
460     {
461 	timer_next = timer->tr_next;
462 
463 	if (timer->tr_id == -1 || timer->tr_firing || timer->tr_paused)
464 	    continue;
465 	this_due = proftime_time_left(&timer->tr_due, &now);
466 	if (this_due <= 1)
467 	{
468 	    // Save and restore a lot of flags, because the timer fires while
469 	    // waiting for a character, which might be halfway a command.
470 	    int save_timer_busy = timer_busy;
471 	    int save_vgetc_busy = vgetc_busy;
472 	    int save_did_emsg = did_emsg;
473 	    int save_called_emsg = called_emsg;
474 	    int save_must_redraw = must_redraw;
475 	    int save_trylevel = trylevel;
476 	    int save_did_throw = did_throw;
477 	    int save_ex_pressedreturn = get_pressedreturn();
478 	    int save_may_garbage_collect = may_garbage_collect;
479 	    except_T *save_current_exception = current_exception;
480 	    vimvars_save_T vvsave;
481 
482 	    // Create a scope for running the timer callback, ignoring most of
483 	    // the current scope, such as being inside a try/catch.
484 	    timer_busy = timer_busy > 0 || vgetc_busy > 0;
485 	    vgetc_busy = 0;
486 	    called_emsg = 0;
487 	    did_emsg = FALSE;
488 	    did_uncaught_emsg = FALSE;
489 	    must_redraw = 0;
490 	    trylevel = 0;
491 	    did_throw = FALSE;
492 	    current_exception = NULL;
493 	    may_garbage_collect = FALSE;
494 	    save_vimvars(&vvsave);
495 
496 	    timer->tr_firing = TRUE;
497 	    timer_callback(timer);
498 	    timer->tr_firing = FALSE;
499 
500 	    timer_next = timer->tr_next;
501 	    did_one = TRUE;
502 	    timer_busy = save_timer_busy;
503 	    vgetc_busy = save_vgetc_busy;
504 	    if (did_uncaught_emsg)
505 		++timer->tr_emsg_count;
506 	    did_emsg = save_did_emsg;
507 	    called_emsg = save_called_emsg;
508 	    trylevel = save_trylevel;
509 	    did_throw = save_did_throw;
510 	    current_exception = save_current_exception;
511 	    restore_vimvars(&vvsave);
512 	    if (must_redraw != 0)
513 		need_update_screen = TRUE;
514 	    must_redraw = must_redraw > save_must_redraw
515 					      ? must_redraw : save_must_redraw;
516 	    set_pressedreturn(save_ex_pressedreturn);
517 	    may_garbage_collect = save_may_garbage_collect;
518 
519 	    // Only fire the timer again if it repeats and stop_timer() wasn't
520 	    // called while inside the callback (tr_id == -1).
521 	    if (timer->tr_repeat != 0 && timer->tr_id != -1
522 		    && timer->tr_emsg_count < 3)
523 	    {
524 		profile_setlimit(timer->tr_interval, &timer->tr_due);
525 		this_due = proftime_time_left(&timer->tr_due, &now);
526 		if (this_due < 1)
527 		    this_due = 1;
528 		if (timer->tr_repeat > 0)
529 		    --timer->tr_repeat;
530 	    }
531 	    else
532 	    {
533 		this_due = -1;
534 		remove_timer(timer);
535 		free_timer(timer);
536 	    }
537 	}
538 	if (this_due > 0 && (next_due == -1 || next_due > this_due))
539 	    next_due = this_due;
540     }
541 
542     if (did_one)
543 	redraw_after_callback(need_update_screen);
544 
545 #ifdef FEAT_BEVAL_TERM
546     if (bevalexpr_due_set)
547     {
548 	this_due = proftime_time_left(&bevalexpr_due, &now);
549 	if (this_due <= 1)
550 	{
551 	    bevalexpr_due_set = FALSE;
552 	    if (balloonEval == NULL)
553 	    {
554 		balloonEval = ALLOC_CLEAR_ONE(BalloonEval);
555 		balloonEvalForTerm = TRUE;
556 	    }
557 	    if (balloonEval != NULL)
558 	    {
559 		general_beval_cb(balloonEval, 0);
560 		setcursor();
561 		out_flush();
562 	    }
563 	}
564 	else if (next_due == -1 || next_due > this_due)
565 	    next_due = this_due;
566     }
567 #endif
568 #ifdef FEAT_TERMINAL
569     // Some terminal windows may need their buffer updated.
570     next_due = term_check_timers(next_due, &now);
571 #endif
572 
573     return current_id != last_timer_id ? 1 : next_due;
574 }
575 
576 /*
577  * Find a timer by ID.  Returns NULL if not found;
578  */
579     static timer_T *
580 find_timer(long id)
581 {
582     timer_T *timer;
583 
584     if (id >= 0)
585     {
586 	for (timer = first_timer; timer != NULL; timer = timer->tr_next)
587 	    if (timer->tr_id == id)
588 		return timer;
589     }
590     return NULL;
591 }
592 
593 
594 /*
595  * Stop a timer and delete it.
596  */
597     void
598 stop_timer(timer_T *timer)
599 {
600     if (timer->tr_firing)
601 	// Free the timer after the callback returns.
602 	timer->tr_id = -1;
603     else
604     {
605 	remove_timer(timer);
606 	free_timer(timer);
607     }
608 }
609 
610     static void
611 stop_all_timers(void)
612 {
613     timer_T *timer;
614     timer_T *timer_next;
615 
616     for (timer = first_timer; timer != NULL; timer = timer_next)
617     {
618 	timer_next = timer->tr_next;
619 	stop_timer(timer);
620     }
621 }
622 
623     static void
624 add_timer_info(typval_T *rettv, timer_T *timer)
625 {
626     list_T	*list = rettv->vval.v_list;
627     dict_T	*dict = dict_alloc();
628     dictitem_T	*di;
629     long	remaining;
630     proftime_T	now;
631 
632     if (dict == NULL)
633 	return;
634     list_append_dict(list, dict);
635 
636     dict_add_number(dict, "id", timer->tr_id);
637     dict_add_number(dict, "time", (long)timer->tr_interval);
638 
639     profile_start(&now);
640     remaining = proftime_time_left(&timer->tr_due, &now);
641     dict_add_number(dict, "remaining", (long)remaining);
642 
643     dict_add_number(dict, "repeat",
644 		    (long)(timer->tr_repeat < 0 ? -1 : timer->tr_repeat + 1));
645     dict_add_number(dict, "paused", (long)(timer->tr_paused));
646 
647     di = dictitem_alloc((char_u *)"callback");
648     if (di != NULL)
649     {
650 	if (dict_add(dict, di) == FAIL)
651 	    vim_free(di);
652 	else
653 	    put_callback(&timer->tr_callback, &di->di_tv);
654     }
655 }
656 
657     static void
658 add_timer_info_all(typval_T *rettv)
659 {
660     timer_T *timer;
661 
662     for (timer = first_timer; timer != NULL; timer = timer->tr_next)
663 	if (timer->tr_id != -1)
664 	    add_timer_info(rettv, timer);
665 }
666 
667 /*
668  * Mark references in partials of timers.
669  */
670     int
671 set_ref_in_timer(int copyID)
672 {
673     int		abort = FALSE;
674     timer_T	*timer;
675     typval_T	tv;
676 
677     for (timer = first_timer; !abort && timer != NULL; timer = timer->tr_next)
678     {
679 	if (timer->tr_callback.cb_partial != NULL)
680 	{
681 	    tv.v_type = VAR_PARTIAL;
682 	    tv.vval.v_partial = timer->tr_callback.cb_partial;
683 	}
684 	else
685 	{
686 	    tv.v_type = VAR_FUNC;
687 	    tv.vval.v_string = timer->tr_callback.cb_name;
688 	}
689 	abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
690     }
691     return abort;
692 }
693 
694 # if defined(EXITFREE) || defined(PROTO)
695     void
696 timer_free_all()
697 {
698     timer_T *timer;
699 
700     while (first_timer != NULL)
701     {
702 	timer = first_timer;
703 	remove_timer(timer);
704 	free_timer(timer);
705     }
706 }
707 # endif
708 
709 /*
710  * "timer_info([timer])" function
711  */
712     void
713 f_timer_info(typval_T *argvars, typval_T *rettv)
714 {
715     timer_T *timer = NULL;
716 
717     if (rettv_list_alloc(rettv) != OK)
718 	return;
719     if (argvars[0].v_type != VAR_UNKNOWN)
720     {
721 	if (argvars[0].v_type != VAR_NUMBER)
722 	    emsg(_(e_number_exp));
723 	else
724 	{
725 	    timer = find_timer((int)tv_get_number(&argvars[0]));
726 	    if (timer != NULL)
727 		add_timer_info(rettv, timer);
728 	}
729     }
730     else
731 	add_timer_info_all(rettv);
732 }
733 
734 /*
735  * "timer_pause(timer, paused)" function
736  */
737     void
738 f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
739 {
740     timer_T	*timer = NULL;
741     int		paused = (int)tv_get_number(&argvars[1]);
742 
743     if (argvars[0].v_type != VAR_NUMBER)
744 	emsg(_(e_number_exp));
745     else
746     {
747 	timer = find_timer((int)tv_get_number(&argvars[0]));
748 	if (timer != NULL)
749 	    timer->tr_paused = paused;
750     }
751 }
752 
753 /*
754  * "timer_start(time, callback [, options])" function
755  */
756     void
757 f_timer_start(typval_T *argvars, typval_T *rettv)
758 {
759     long	msec = (long)tv_get_number(&argvars[0]);
760     timer_T	*timer;
761     int		repeat = 0;
762     callback_T	callback;
763     dict_T	*dict;
764 
765     rettv->vval.v_number = -1;
766     if (check_secure())
767 	return;
768     if (argvars[2].v_type != VAR_UNKNOWN)
769     {
770 	if (argvars[2].v_type != VAR_DICT
771 				   || (dict = argvars[2].vval.v_dict) == NULL)
772 	{
773 	    semsg(_(e_invarg2), tv_get_string(&argvars[2]));
774 	    return;
775 	}
776 	if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
777 	    repeat = dict_get_number(dict, (char_u *)"repeat");
778     }
779 
780     callback = get_callback(&argvars[1]);
781     if (callback.cb_name == NULL)
782 	return;
783 
784     timer = create_timer(msec, repeat);
785     if (timer == NULL)
786 	free_callback(&callback);
787     else
788     {
789 	set_callback(&timer->tr_callback, &callback);
790 	rettv->vval.v_number = (varnumber_T)timer->tr_id;
791     }
792 }
793 
794 /*
795  * "timer_stop(timer)" function
796  */
797     void
798 f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
799 {
800     timer_T *timer;
801 
802     if (argvars[0].v_type != VAR_NUMBER)
803     {
804 	emsg(_(e_number_exp));
805 	return;
806     }
807     timer = find_timer((int)tv_get_number(&argvars[0]));
808     if (timer != NULL)
809 	stop_timer(timer);
810 }
811 
812 /*
813  * "timer_stopall()" function
814  */
815     void
816 f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
817 {
818     stop_all_timers();
819 }
820 
821 # endif // FEAT_TIMERS
822 
823 # if defined(STARTUPTIME) || defined(PROTO)
824 static struct timeval	prev_timeval;
825 
826 #  ifdef MSWIN
827 /*
828  * Windows doesn't have gettimeofday(), although it does have struct timeval.
829  */
830     static int
831 gettimeofday(struct timeval *tv, char *dummy UNUSED)
832 {
833     long t = clock();
834     tv->tv_sec = t / CLOCKS_PER_SEC;
835     tv->tv_usec = (t - tv->tv_sec * CLOCKS_PER_SEC) * 1000000 / CLOCKS_PER_SEC;
836     return 0;
837 }
838 #  endif
839 
840 /*
841  * Save the previous time before doing something that could nest.
842  * set "*tv_rel" to the time elapsed so far.
843  */
844     void
845 time_push(void *tv_rel, void *tv_start)
846 {
847     *((struct timeval *)tv_rel) = prev_timeval;
848     gettimeofday(&prev_timeval, NULL);
849     ((struct timeval *)tv_rel)->tv_usec = prev_timeval.tv_usec
850 					- ((struct timeval *)tv_rel)->tv_usec;
851     ((struct timeval *)tv_rel)->tv_sec = prev_timeval.tv_sec
852 					 - ((struct timeval *)tv_rel)->tv_sec;
853     if (((struct timeval *)tv_rel)->tv_usec < 0)
854     {
855 	((struct timeval *)tv_rel)->tv_usec += 1000000;
856 	--((struct timeval *)tv_rel)->tv_sec;
857     }
858     *(struct timeval *)tv_start = prev_timeval;
859 }
860 
861 /*
862  * Compute the previous time after doing something that could nest.
863  * Subtract "*tp" from prev_timeval;
864  * Note: The arguments are (void *) to avoid trouble with systems that don't
865  * have struct timeval.
866  */
867     void
868 time_pop(
869     void	*tp)	// actually (struct timeval *)
870 {
871     prev_timeval.tv_usec -= ((struct timeval *)tp)->tv_usec;
872     prev_timeval.tv_sec -= ((struct timeval *)tp)->tv_sec;
873     if (prev_timeval.tv_usec < 0)
874     {
875 	prev_timeval.tv_usec += 1000000;
876 	--prev_timeval.tv_sec;
877     }
878 }
879 
880     static void
881 time_diff(struct timeval *then, struct timeval *now)
882 {
883     long	usec;
884     long	msec;
885 
886     usec = now->tv_usec - then->tv_usec;
887     msec = (now->tv_sec - then->tv_sec) * 1000L + usec / 1000L,
888     usec = usec % 1000L;
889     fprintf(time_fd, "%03ld.%03ld", msec, usec >= 0 ? usec : usec + 1000L);
890 }
891 
892     void
893 time_msg(
894     char	*mesg,
895     void	*tv_start)  // only for do_source: start time; actually
896 			    // (struct timeval *)
897 {
898     static struct timeval	start;
899     struct timeval		now;
900 
901     if (time_fd != NULL)
902     {
903 	if (strstr(mesg, "STARTING") != NULL)
904 	{
905 	    gettimeofday(&start, NULL);
906 	    prev_timeval = start;
907 	    fprintf(time_fd, "\n\ntimes in msec\n");
908 	    fprintf(time_fd, " clock   self+sourced   self:  sourced script\n");
909 	    fprintf(time_fd, " clock   elapsed:              other lines\n\n");
910 	}
911 	gettimeofday(&now, NULL);
912 	time_diff(&start, &now);
913 	if (((struct timeval *)tv_start) != NULL)
914 	{
915 	    fprintf(time_fd, "  ");
916 	    time_diff(((struct timeval *)tv_start), &now);
917 	}
918 	fprintf(time_fd, "  ");
919 	time_diff(&prev_timeval, &now);
920 	prev_timeval = now;
921 	fprintf(time_fd, ": %s\n", mesg);
922     }
923 }
924 # endif	// STARTUPTIME
925 #endif // FEAT_EVAL
926 
927 #if defined(FEAT_SPELL) || defined(FEAT_PERSISTENT_UNDO) || defined(PROTO)
928 /*
929  * Read 8 bytes from "fd" and turn them into a time_T, MSB first.
930  * Returns -1 when encountering EOF.
931  */
932     time_T
933 get8ctime(FILE *fd)
934 {
935     int		c;
936     time_T	n = 0;
937     int		i;
938 
939     for (i = 0; i < 8; ++i)
940     {
941 	c = getc(fd);
942 	if (c == EOF) return -1;
943 	n = (n << 8) + c;
944     }
945     return n;
946 }
947 
948 #ifdef _MSC_VER
949 # if (_MSC_VER <= 1200)
950 // This line is required for VC6 without the service pack.  Also see the
951 // matching #pragma below.
952  #  pragma optimize("", off)
953 # endif
954 #endif
955 
956 /*
957  * Write time_T to file "fd" in 8 bytes.
958  * Returns FAIL when the write failed.
959  */
960     int
961 put_time(FILE *fd, time_T the_time)
962 {
963     char_u	buf[8];
964 
965     time_to_bytes(the_time, buf);
966     return fwrite(buf, (size_t)8, (size_t)1, fd) == 1 ? OK : FAIL;
967 }
968 
969 /*
970  * Write time_T to "buf[8]".
971  */
972     void
973 time_to_bytes(time_T the_time, char_u *buf)
974 {
975     int		c;
976     int		i;
977     int		bi = 0;
978     time_T	wtime = the_time;
979 
980     // time_T can be up to 8 bytes in size, more than long_u, thus we
981     // can't use put_bytes() here.
982     // Another problem is that ">>" may do an arithmetic shift that keeps the
983     // sign.  This happens for large values of wtime.  A cast to long_u may
984     // truncate if time_T is 8 bytes.  So only use a cast when it is 4 bytes,
985     // it's safe to assume that long_u is 4 bytes or more and when using 8
986     // bytes the top bit won't be set.
987     for (i = 7; i >= 0; --i)
988     {
989 	if (i + 1 > (int)sizeof(time_T))
990 	    // ">>" doesn't work well when shifting more bits than avail
991 	    buf[bi++] = 0;
992 	else
993 	{
994 #if defined(SIZEOF_TIME_T) && SIZEOF_TIME_T > 4
995 	    c = (int)(wtime >> (i * 8));
996 #else
997 	    c = (int)((long_u)wtime >> (i * 8));
998 #endif
999 	    buf[bi++] = c;
1000 	}
1001     }
1002 }
1003 
1004 #ifdef _MSC_VER
1005 # if (_MSC_VER <= 1200)
1006  #  pragma optimize("", on)
1007 # endif
1008 #endif
1009 
1010 #endif
1011 
1012 /*
1013  * Put timestamp "tt" in "buf[buflen]" in a nice format.
1014  */
1015     void
1016 add_time(char_u *buf, size_t buflen, time_t tt)
1017 {
1018 #ifdef HAVE_STRFTIME
1019     struct tm	tmval;
1020     struct tm	*curtime;
1021 
1022     if (vim_time() - tt >= 100)
1023     {
1024 	curtime = vim_localtime(&tt, &tmval);
1025 	if (vim_time() - tt < (60L * 60L * 12L))
1026 	    // within 12 hours
1027 	    (void)strftime((char *)buf, buflen, "%H:%M:%S", curtime);
1028 	else
1029 	    // longer ago
1030 	    (void)strftime((char *)buf, buflen, "%Y/%m/%d %H:%M:%S", curtime);
1031     }
1032     else
1033 #endif
1034     {
1035 	long seconds = (long)(vim_time() - tt);
1036 
1037 	vim_snprintf((char *)buf, buflen,
1038 		NGETTEXT("%ld second ago", "%ld seconds ago", seconds),
1039 		seconds);
1040     }
1041 }
1042