Patch 8.2.0256
Problem: Time and timer related code is spread out.
Solution: Move time and timer related code to a new file. (Yegappan
Lakshmanan, closes #5604)
Files: Filelist, src/Make_cyg_ming.mak, src/Make_morph.mak,
src/Make_mvc.mak, src/Make_vms.mms, src/Makefile, src/README.md,
src/evalfunc.c, src/ex_cmds.c, src/ex_cmds2.c, src/main.c,
src/memline.c, src/misc1.c, src/misc2.c, src/proto.h,
src/proto/ex_cmds.pro, src/proto/ex_cmds2.pro, src/proto/main.pro,
src/proto/memline.pro, src/proto/misc1.pro, src/proto/misc2.pro,
src/proto/time.pro, src/time.c
*** ../vim-8.2.0255/Filelist 2020-02-12 21:15:37.543497435 +0100
--- Filelist 2020-02-14 13:12:33.919898084 +0100
***************
*** 127,132 ****
--- 127,133 ----
src/termlib.c \
src/testing.c \
src/textprop.c \
+ src/time.c \
src/ui.c \
src/undo.c \
src/usercmd.c \
***************
*** 275,280 ****
--- 276,282 ----
src/proto/termlib.pro \
src/proto/testing.pro \
src/proto/textprop.pro \
+ src/proto/time.pro \
src/proto/ui.pro \
src/proto/undo.pro \
src/proto/usercmd.pro \
*** ../vim-8.2.0255/src/Make_cyg_ming.mak 2020-01-26 15:52:33.011833294
+0100
--- src/Make_cyg_ming.mak 2020-02-14 13:12:33.919898084 +0100
***************
*** 783,788 ****
--- 783,789 ----
$(OUTDIR)/term.o \
$(OUTDIR)/testing.o \
$(OUTDIR)/textprop.o \
+ $(OUTDIR)/time.o \
$(OUTDIR)/ui.o \
$(OUTDIR)/undo.o \
$(OUTDIR)/usercmd.o \
*** ../vim-8.2.0255/src/Make_morph.mak 2019-10-09 22:10:04.000000000 +0200
--- src/Make_morph.mak 2020-02-14 13:12:33.919898084 +0100
***************
*** 102,107 ****
--- 102,108 ----
term.c \
testing.c \
textprop.c \
+ time.c \
ui.c \
undo.c \
usercmd.c \
*** ../vim-8.2.0255/src/Make_mvc.mak 2020-02-12 21:52:29.271749459 +0100
--- src/Make_mvc.mak 2020-02-14 13:12:33.919898084 +0100
***************
*** 799,804 ****
--- 799,805 ----
$(OUTDIR)\term.obj \
$(OUTDIR)\testing.obj \
$(OUTDIR)\textprop.obj \
+ $(OUTDIR)\time.obj \
$(OUTDIR)\ui.obj \
$(OUTDIR)\undo.obj \
$(OUTDIR)\usercmd.obj \
***************
*** 1733,1738 ****
--- 1734,1741 ----
$(OUTDIR)/textprop.obj: $(OUTDIR) textprop.c $(INCL)
+ $(OUTDIR)/time.obj: $(OUTDIR) time.c $(INCL)
+
$(OUTDIR)/ui.obj: $(OUTDIR) ui.c $(INCL)
$(OUTDIR)/undo.obj: $(OUTDIR) undo.c $(INCL)
***************
*** 1926,1931 ****
--- 1929,1935 ----
proto/term.pro \
proto/testing.pro \
proto/textprop.pro \
+ proto/time.pro \
proto/ui.pro \
proto/undo.pro \
proto/usercmd.pro \
*** ../vim-8.2.0255/src/Make_vms.mms 2020-02-13 21:59:22.642962684 +0100
--- src/Make_vms.mms 2020-02-14 13:12:33.923898059 +0100
***************
*** 381,386 ****
--- 381,387 ----
termlib.c \
testing.c \
textprop.c \
+ time.c \
ui.c \
undo.c \
usercmd.c \
***************
*** 487,492 ****
--- 488,494 ----
termlib.obj \
testing.obj \
textprop.obj \
+ time.obj \
ui.obj \
undo.obj \
usercmd.obj \
***************
*** 978,983 ****
--- 980,988 ----
textprop.obj : textprop.c vim.h [.auto]config.h feature.h os_unix.h \
ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
[.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h
+ time.obj : time.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h
ui.obj : ui.c vim.h [.auto]config.h feature.h os_unix.h \
ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
[.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h
*** ../vim-8.2.0255/src/Makefile 2020-01-26 15:52:33.015833276 +0100
--- src/Makefile 2020-02-14 13:12:33.923898059 +0100
***************
*** 1661,1666 ****
--- 1661,1667 ----
terminal.c \
testing.c \
textprop.c \
+ time.c \
ui.c \
undo.c \
usercmd.c \
***************
*** 1800,1805 ****
--- 1801,1807 ----
objects/terminal.o \
objects/testing.o \
objects/textprop.o \
+ objects/time.o \
objects/ui.o \
objects/undo.o \
objects/usercmd.o \
***************
*** 1971,1976 ****
--- 1973,1979 ----
termlib.pro \
testing.pro \
textprop.pro \
+ time.pro \
ui.pro \
undo.pro \
usercmd.pro \
***************
*** 3433,3438 ****
--- 3436,3444 ----
objects/textprop.o: textprop.c
$(CCC) -o $@ textprop.c
+ objects/time.o: time.c
+ $(CCC) -o $@ time.c
+
objects/ui.o: ui.c
$(CCC) -o $@ ui.c
***************
*** 3959,3964 ****
--- 3965,3974 ----
auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
proto.h globals.h
+ objects/time.o: time.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h
objects/ui.o: ui.c vim.h protodef.h auto/config.h feature.h os_unix.h \
auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
*** ../vim-8.2.0255/src/README.md 2019-12-12 12:42:50.000000000 +0100
--- src/README.md 2020-02-14 13:12:33.923898059 +0100
***************
*** 79,84 ****
--- 79,85 ----
term.c | terminal handling, termcap codes
testing.c | testing: assert and test functions
textprop.c | text properties
+ time.c | time and timer functions
undo.c | undo and redo
usercmd.c | user defined commands
userfunc.c | user defined functions
*** ../vim-8.2.0255/src/evalfunc.c 2020-02-12 22:25:22.205551057 +0100
--- src/evalfunc.c 2020-02-14 13:12:33.927898029 +0100
***************
*** 20,29 ****
# include <float.h>
#endif
- #if defined(MACOS_X)
- # include <time.h> // for time_t
- #endif
-
#ifdef FEAT_FLOAT
static void f_abs(typval_T *argvars, typval_T *rettv);
static void f_acos(typval_T *argvars, typval_T *rettv);
--- 20,25 ----
***************
*** 126,132 ****
static void f_libcallnr(typval_T *argvars, typval_T *rettv);
static void f_line(typval_T *argvars, typval_T *rettv);
static void f_line2byte(typval_T *argvars, typval_T *rettv);
- static void f_localtime(typval_T *argvars, typval_T *rettv);
#ifdef FEAT_FLOAT
static void f_log(typval_T *argvars, typval_T *rettv);
static void f_log10(typval_T *argvars, typval_T *rettv);
--- 122,127 ----
***************
*** 173,183 ****
static void f_range(typval_T *argvars, typval_T *rettv);
static void f_reg_executing(typval_T *argvars, typval_T *rettv);
static void f_reg_recording(typval_T *argvars, typval_T *rettv);
- static void f_reltime(typval_T *argvars, typval_T *rettv);
- #ifdef FEAT_FLOAT
- static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
- #endif
- static void f_reltimestr(typval_T *argvars, typval_T *rettv);
static void f_remote_expr(typval_T *argvars, typval_T *rettv);
static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
static void f_remote_peek(typval_T *argvars, typval_T *rettv);
--- 168,173 ----
***************
*** 234,250 ****
static void f_str2list(typval_T *argvars, typval_T *rettv);
static void f_str2nr(typval_T *argvars, typval_T *rettv);
static void f_strchars(typval_T *argvars, typval_T *rettv);
- #ifdef HAVE_STRFTIME
- static void f_strftime(typval_T *argvars, typval_T *rettv);
- #endif
static void f_strgetchar(typval_T *argvars, typval_T *rettv);
static void f_stridx(typval_T *argvars, typval_T *rettv);
static void f_strlen(typval_T *argvars, typval_T *rettv);
static void f_strcharpart(typval_T *argvars, typval_T *rettv);
static void f_strpart(typval_T *argvars, typval_T *rettv);
- #ifdef HAVE_STRPTIME
- static void f_strptime(typval_T *argvars, typval_T *rettv);
- #endif
static void f_strridx(typval_T *argvars, typval_T *rettv);
static void f_strtrans(typval_T *argvars, typval_T *rettv);
static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
--- 224,234 ----
***************
*** 4512,4526 ****
#endif
}
- /*
- * "localtime()" function
- */
- static void
- f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
- {
- rettv->vval.v_number = (varnumber_T)time(NULL);
- }
-
#ifdef FEAT_FLOAT
/*
* "log()" function
--- 4496,4501 ----
***************
*** 5500,5617 ****
return_register(reg_recording, rettv);
}
- #if defined(FEAT_RELTIME)
- /*
- * Convert a List to proftime_T.
- * Return FAIL when there is something wrong.
- */
- static int
- list2proftime(typval_T *arg, proftime_T *tm)
- {
- long n1, n2;
- int error = FALSE;
-
- if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
- || arg->vval.v_list->lv_len != 2)
- return FAIL;
- n1 = list_find_nr(arg->vval.v_list, 0L, &error);
- n2 = list_find_nr(arg->vval.v_list, 1L, &error);
- # ifdef MSWIN
- tm->HighPart = n1;
- tm->LowPart = n2;
- # else
- tm->tv_sec = n1;
- tm->tv_usec = n2;
- # endif
- return error ? FAIL : OK;
- }
- #endif // FEAT_RELTIME
-
- /*
- * "reltime()" function
- */
- static void
- f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
- {
- #ifdef FEAT_RELTIME
- proftime_T res;
- proftime_T start;
-
- if (argvars[0].v_type == VAR_UNKNOWN)
- {
- // No arguments: get current time.
- profile_start(&res);
- }
- else if (argvars[1].v_type == VAR_UNKNOWN)
- {
- if (list2proftime(&argvars[0], &res) == FAIL)
- return;
- profile_end(&res);
- }
- else
- {
- // Two arguments: compute the difference.
- if (list2proftime(&argvars[0], &start) == FAIL
- || list2proftime(&argvars[1], &res) == FAIL)
- return;
- profile_sub(&res, &start);
- }
-
- if (rettv_list_alloc(rettv) == OK)
- {
- long n1, n2;
-
- # ifdef MSWIN
- n1 = res.HighPart;
- n2 = res.LowPart;
- # else
- n1 = res.tv_sec;
- n2 = res.tv_usec;
- # endif
- list_append_number(rettv->vval.v_list, (varnumber_T)n1);
- list_append_number(rettv->vval.v_list, (varnumber_T)n2);
- }
- #endif
- }
-
- #ifdef FEAT_FLOAT
- /*
- * "reltimefloat()" function
- */
- static void
- f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
- {
- # ifdef FEAT_RELTIME
- proftime_T tm;
- # endif
-
- rettv->v_type = VAR_FLOAT;
- rettv->vval.v_float = 0;
- # ifdef FEAT_RELTIME
- if (list2proftime(&argvars[0], &tm) == OK)
- rettv->vval.v_float = profile_float(&tm);
- # endif
- }
- #endif
-
- /*
- * "reltimestr()" function
- */
- static void
- f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
- {
- #ifdef FEAT_RELTIME
- proftime_T tm;
- #endif
-
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = NULL;
- #ifdef FEAT_RELTIME
- if (list2proftime(&argvars[0], &tm) == OK)
- rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
- #endif
- }
-
#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
static void
make_connection(void)
--- 5475,5480 ----
***************
*** 7422,7482 ****
}
- #ifdef HAVE_STRFTIME
- /*
- * "strftime({format}[, {time}])" function
- */
- static void
- f_strftime(typval_T *argvars, typval_T *rettv)
- {
- char_u result_buf[256];
- struct tm tmval;
- struct tm *curtime;
- time_t seconds;
- char_u *p;
-
- rettv->v_type = VAR_STRING;
-
- p = tv_get_string(&argvars[0]);
- if (argvars[1].v_type == VAR_UNKNOWN)
- seconds = time(NULL);
- else
- seconds = (time_t)tv_get_number(&argvars[1]);
- curtime = vim_localtime(&seconds, &tmval);
- // MSVC returns NULL for an invalid value of seconds.
- if (curtime == NULL)
- rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
- else
- {
- vimconv_T conv;
- char_u *enc;
-
- conv.vc_type = CONV_NONE;
- enc = enc_locale();
- convert_setup(&conv, p_enc, enc);
- if (conv.vc_type != CONV_NONE)
- p = string_convert(&conv, p, NULL);
- if (p != NULL)
- (void)strftime((char *)result_buf, sizeof(result_buf),
- (char *)p, curtime);
- else
- result_buf[0] = NUL;
-
- if (conv.vc_type != CONV_NONE)
- vim_free(p);
- convert_setup(&conv, enc, p_enc);
- if (conv.vc_type != CONV_NONE)
- rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
- else
- rettv->vval.v_string = vim_strsave(result_buf);
-
- // Release conversion descriptors
- convert_setup(&conv, NULL, NULL);
- vim_free(enc);
- }
- }
- #endif
-
/*
* "strgetchar()" function
*/
--- 7285,7290 ----
***************
*** 7734,7773 ****
rettv->vval.v_string = vim_strnsave(p + n, len);
}
- #ifdef HAVE_STRPTIME
- /*
- * "strptime({format}, {timestring})" function
- */
- static void
- f_strptime(typval_T *argvars, typval_T *rettv)
- {
- struct tm tmval;
- char_u *fmt;
- char_u *str;
- vimconv_T conv;
- char_u *enc;
-
- vim_memset(&tmval, NUL, sizeof(tmval));
- fmt = tv_get_string(&argvars[0]);
- str = tv_get_string(&argvars[1]);
-
- conv.vc_type = CONV_NONE;
- enc = enc_locale();
- convert_setup(&conv, p_enc, enc);
- if (conv.vc_type != CONV_NONE)
- fmt = string_convert(&conv, fmt, NULL);
- if (fmt == NULL
- || strptime((char *)str, (char *)fmt, &tmval) == NULL
- || (rettv->vval.v_number = mktime(&tmval)) == -1)
- rettv->vval.v_number = 0;
-
- if (conv.vc_type != CONV_NONE)
- vim_free(fmt);
- convert_setup(&conv, NULL, NULL);
- vim_free(enc);
- }
- #endif
-
/*
* "strridx()" function
*/
--- 7542,7547 ----
*** ../vim-8.2.0255/src/ex_cmds.c 2020-01-26 21:59:25.620718163 +0100
--- src/ex_cmds.c 2020-02-14 13:12:33.927898029 +0100
***************
*** 1679,1698 ****
}
/*
- * Return the current time in seconds. Calls time(), unless test_settime()
- * was used.
- */
- time_T
- vim_time(void)
- {
- # ifdef FEAT_EVAL
- return time_for_testing == 0 ? time(NULL) : time_for_testing;
- # else
- return time(NULL);
- # endif
- }
-
- /*
* Implementation of ":fixdel", also used by get_stty().
* <BS> resulting <Del>
* ^? ^H
--- 1679,1684 ----
*** ../vim-8.2.0255/src/ex_cmds2.c 2019-12-23 22:59:14.260820709 +0100
--- src/ex_cmds2.c 2020-02-14 13:12:33.931898004 +0100
***************
*** 14,511 ****
#include "vim.h"
#include "version.h"
- #if defined(FEAT_EVAL) || defined(PROTO)
- # if defined(FEAT_TIMERS) || defined(PROTO)
- static timer_T *first_timer = NULL;
- static long last_timer_id = 0;
-
- /*
- * Return time left until "due". Negative if past "due".
- */
- long
- proftime_time_left(proftime_T *due, proftime_T *now)
- {
- # ifdef MSWIN
- LARGE_INTEGER fr;
-
- if (now->QuadPart > due->QuadPart)
- return 0;
- QueryPerformanceFrequency(&fr);
- return (long)(((double)(due->QuadPart - now->QuadPart)
- / (double)fr.QuadPart) * 1000);
- # else
- if (now->tv_sec > due->tv_sec)
- return 0;
- return (due->tv_sec - now->tv_sec) * 1000
- + (due->tv_usec - now->tv_usec) / 1000;
- # endif
- }
-
- /*
- * Insert a timer in the list of timers.
- */
- static void
- insert_timer(timer_T *timer)
- {
- timer->tr_next = first_timer;
- timer->tr_prev = NULL;
- if (first_timer != NULL)
- first_timer->tr_prev = timer;
- first_timer = timer;
- did_add_timer = TRUE;
- }
-
- /*
- * Take a timer out of the list of timers.
- */
- static void
- remove_timer(timer_T *timer)
- {
- if (timer->tr_prev == NULL)
- first_timer = timer->tr_next;
- else
- timer->tr_prev->tr_next = timer->tr_next;
- if (timer->tr_next != NULL)
- timer->tr_next->tr_prev = timer->tr_prev;
- }
-
- static void
- free_timer(timer_T *timer)
- {
- free_callback(&timer->tr_callback);
- vim_free(timer);
- }
-
- /*
- * Create a timer and return it. NULL if out of memory.
- * Caller should set the callback.
- */
- timer_T *
- create_timer(long msec, int repeat)
- {
- timer_T *timer = ALLOC_CLEAR_ONE(timer_T);
- long prev_id = last_timer_id;
-
- if (timer == NULL)
- return NULL;
- if (++last_timer_id <= prev_id)
- // Overflow! Might cause duplicates...
- last_timer_id = 0;
- timer->tr_id = last_timer_id;
- insert_timer(timer);
- if (repeat != 0)
- timer->tr_repeat = repeat - 1;
- timer->tr_interval = msec;
-
- profile_setlimit(msec, &timer->tr_due);
- return timer;
- }
-
- /*
- * Invoke the callback of "timer".
- */
- static void
- timer_callback(timer_T *timer)
- {
- typval_T rettv;
- typval_T argv[2];
-
- argv[0].v_type = VAR_NUMBER;
- argv[0].vval.v_number = (varnumber_T)timer->tr_id;
- argv[1].v_type = VAR_UNKNOWN;
-
- call_callback(&timer->tr_callback, -1, &rettv, 1, argv);
- clear_tv(&rettv);
- }
-
- /*
- * Call timers that are due.
- * Return the time in msec until the next timer is due.
- * Returns -1 if there are no pending timers.
- */
- long
- check_due_timer(void)
- {
- timer_T *timer;
- timer_T *timer_next;
- long this_due;
- long next_due = -1;
- proftime_T now;
- int did_one = FALSE;
- int need_update_screen = FALSE;
- long current_id = last_timer_id;
-
- // Don't run any timers while exiting or dealing with an error.
- if (exiting || aborting())
- return next_due;
-
- profile_start(&now);
- for (timer = first_timer; timer != NULL && !got_int; timer = timer_next)
- {
- timer_next = timer->tr_next;
-
- if (timer->tr_id == -1 || timer->tr_firing || timer->tr_paused)
- continue;
- this_due = proftime_time_left(&timer->tr_due, &now);
- if (this_due <= 1)
- {
- // Save and restore a lot of flags, because the timer fires while
- // waiting for a character, which might be halfway a command.
- int save_timer_busy = timer_busy;
- int save_vgetc_busy = vgetc_busy;
- int save_did_emsg = did_emsg;
- int save_called_emsg = called_emsg;
- int save_must_redraw = must_redraw;
- int save_trylevel = trylevel;
- int save_did_throw = did_throw;
- int save_ex_pressedreturn = get_pressedreturn();
- int save_may_garbage_collect = may_garbage_collect;
- except_T *save_current_exception = current_exception;
- vimvars_save_T vvsave;
-
- // Create a scope for running the timer callback, ignoring most of
- // the current scope, such as being inside a try/catch.
- timer_busy = timer_busy > 0 || vgetc_busy > 0;
- vgetc_busy = 0;
- called_emsg = 0;
- did_emsg = FALSE;
- did_uncaught_emsg = FALSE;
- must_redraw = 0;
- trylevel = 0;
- did_throw = FALSE;
- current_exception = NULL;
- may_garbage_collect = FALSE;
- save_vimvars(&vvsave);
-
- timer->tr_firing = TRUE;
- timer_callback(timer);
- timer->tr_firing = FALSE;
-
- timer_next = timer->tr_next;
- did_one = TRUE;
- timer_busy = save_timer_busy;
- vgetc_busy = save_vgetc_busy;
- if (did_uncaught_emsg)
- ++timer->tr_emsg_count;
- did_emsg = save_did_emsg;
- called_emsg = save_called_emsg;
- trylevel = save_trylevel;
- did_throw = save_did_throw;
- current_exception = save_current_exception;
- restore_vimvars(&vvsave);
- if (must_redraw != 0)
- need_update_screen = TRUE;
- must_redraw = must_redraw > save_must_redraw
- ? must_redraw : save_must_redraw;
- set_pressedreturn(save_ex_pressedreturn);
- may_garbage_collect = save_may_garbage_collect;
-
- // Only fire the timer again if it repeats and stop_timer() wasn't
- // called while inside the callback (tr_id == -1).
- if (timer->tr_repeat != 0 && timer->tr_id != -1
- && timer->tr_emsg_count < 3)
- {
- profile_setlimit(timer->tr_interval, &timer->tr_due);
- this_due = proftime_time_left(&timer->tr_due, &now);
- if (this_due < 1)
- this_due = 1;
- if (timer->tr_repeat > 0)
- --timer->tr_repeat;
- }
- else
- {
- this_due = -1;
- remove_timer(timer);
- free_timer(timer);
- }
- }
- if (this_due > 0 && (next_due == -1 || next_due > this_due))
- next_due = this_due;
- }
-
- if (did_one)
- redraw_after_callback(need_update_screen);
-
- #ifdef FEAT_BEVAL_TERM
- if (bevalexpr_due_set)
- {
- this_due = proftime_time_left(&bevalexpr_due, &now);
- if (this_due <= 1)
- {
- bevalexpr_due_set = FALSE;
- if (balloonEval == NULL)
- {
- balloonEval = ALLOC_CLEAR_ONE(BalloonEval);
- balloonEvalForTerm = TRUE;
- }
- if (balloonEval != NULL)
- {
- general_beval_cb(balloonEval, 0);
- setcursor();
- out_flush();
- }
- }
- else if (next_due == -1 || next_due > this_due)
- next_due = this_due;
- }
- #endif
- #ifdef FEAT_TERMINAL
- // Some terminal windows may need their buffer updated.
- next_due = term_check_timers(next_due, &now);
- #endif
-
- return current_id != last_timer_id ? 1 : next_due;
- }
-
- /*
- * Find a timer by ID. Returns NULL if not found;
- */
- static timer_T *
- find_timer(long id)
- {
- timer_T *timer;
-
- if (id >= 0)
- {
- for (timer = first_timer; timer != NULL; timer = timer->tr_next)
- if (timer->tr_id == id)
- return timer;
- }
- return NULL;
- }
-
-
- /*
- * Stop a timer and delete it.
- */
- void
- stop_timer(timer_T *timer)
- {
- if (timer->tr_firing)
- // Free the timer after the callback returns.
- timer->tr_id = -1;
- else
- {
- remove_timer(timer);
- free_timer(timer);
- }
- }
-
- static void
- stop_all_timers(void)
- {
- timer_T *timer;
- timer_T *timer_next;
-
- for (timer = first_timer; timer != NULL; timer = timer_next)
- {
- timer_next = timer->tr_next;
- stop_timer(timer);
- }
- }
-
- static void
- add_timer_info(typval_T *rettv, timer_T *timer)
- {
- list_T *list = rettv->vval.v_list;
- dict_T *dict = dict_alloc();
- dictitem_T *di;
- long remaining;
- proftime_T now;
-
- if (dict == NULL)
- return;
- list_append_dict(list, dict);
-
- dict_add_number(dict, "id", timer->tr_id);
- dict_add_number(dict, "time", (long)timer->tr_interval);
-
- profile_start(&now);
- remaining = proftime_time_left(&timer->tr_due, &now);
- dict_add_number(dict, "remaining", (long)remaining);
-
- dict_add_number(dict, "repeat",
- (long)(timer->tr_repeat < 0 ? -1 : timer->tr_repeat + 1));
- dict_add_number(dict, "paused", (long)(timer->tr_paused));
-
- di = dictitem_alloc((char_u *)"callback");
- if (di != NULL)
- {
- if (dict_add(dict, di) == FAIL)
- vim_free(di);
- else
- put_callback(&timer->tr_callback, &di->di_tv);
- }
- }
-
- static void
- add_timer_info_all(typval_T *rettv)
- {
- timer_T *timer;
-
- for (timer = first_timer; timer != NULL; timer = timer->tr_next)
- if (timer->tr_id != -1)
- add_timer_info(rettv, timer);
- }
-
- /*
- * Mark references in partials of timers.
- */
- int
- set_ref_in_timer(int copyID)
- {
- int abort = FALSE;
- timer_T *timer;
- typval_T tv;
-
- for (timer = first_timer; !abort && timer != NULL; timer = timer->tr_next)
- {
- if (timer->tr_callback.cb_partial != NULL)
- {
- tv.v_type = VAR_PARTIAL;
- tv.vval.v_partial = timer->tr_callback.cb_partial;
- }
- else
- {
- tv.v_type = VAR_FUNC;
- tv.vval.v_string = timer->tr_callback.cb_name;
- }
- abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
- }
- return abort;
- }
-
- # if defined(EXITFREE) || defined(PROTO)
- void
- timer_free_all()
- {
- timer_T *timer;
-
- while (first_timer != NULL)
- {
- timer = first_timer;
- remove_timer(timer);
- free_timer(timer);
- }
- }
- # endif
-
- /*
- * "timer_info([timer])" function
- */
- void
- f_timer_info(typval_T *argvars, typval_T *rettv)
- {
- timer_T *timer = NULL;
-
- if (rettv_list_alloc(rettv) != OK)
- return;
- if (argvars[0].v_type != VAR_UNKNOWN)
- {
- if (argvars[0].v_type != VAR_NUMBER)
- emsg(_(e_number_exp));
- else
- {
- timer = find_timer((int)tv_get_number(&argvars[0]));
- if (timer != NULL)
- add_timer_info(rettv, timer);
- }
- }
- else
- add_timer_info_all(rettv);
- }
-
- /*
- * "timer_pause(timer, paused)" function
- */
- void
- f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
- {
- timer_T *timer = NULL;
- int paused = (int)tv_get_number(&argvars[1]);
-
- if (argvars[0].v_type != VAR_NUMBER)
- emsg(_(e_number_exp));
- else
- {
- timer = find_timer((int)tv_get_number(&argvars[0]));
- if (timer != NULL)
- timer->tr_paused = paused;
- }
- }
-
- /*
- * "timer_start(time, callback [, options])" function
- */
- void
- f_timer_start(typval_T *argvars, typval_T *rettv)
- {
- long msec = (long)tv_get_number(&argvars[0]);
- timer_T *timer;
- int repeat = 0;
- callback_T callback;
- dict_T *dict;
-
- rettv->vval.v_number = -1;
- if (check_secure())
- return;
- if (argvars[2].v_type != VAR_UNKNOWN)
- {
- if (argvars[2].v_type != VAR_DICT
- || (dict = argvars[2].vval.v_dict) == NULL)
- {
- semsg(_(e_invarg2), tv_get_string(&argvars[2]));
- return;
- }
- if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
- repeat = dict_get_number(dict, (char_u *)"repeat");
- }
-
- callback = get_callback(&argvars[1]);
- if (callback.cb_name == NULL)
- return;
-
- timer = create_timer(msec, repeat);
- if (timer == NULL)
- free_callback(&callback);
- else
- {
- set_callback(&timer->tr_callback, &callback);
- rettv->vval.v_number = (varnumber_T)timer->tr_id;
- }
- }
-
- /*
- * "timer_stop(timer)" function
- */
- void
- f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
- {
- timer_T *timer;
-
- if (argvars[0].v_type != VAR_NUMBER)
- {
- emsg(_(e_number_exp));
- return;
- }
- timer = find_timer((int)tv_get_number(&argvars[0]));
- if (timer != NULL)
- stop_timer(timer);
- }
-
- /*
- * "timer_stopall()" function
- */
- void
- f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
- {
- stop_all_timers();
- }
-
- # endif // FEAT_TIMERS
-
- #endif // FEAT_EVAL
-
/*
* If 'autowrite' option set, try to write the file.
* Careful: autocommands may make "buf" invalid!
--- 14,19 ----
*** ../vim-8.2.0255/src/main.c 2020-02-03 21:29:27.631654305 +0100
--- src/main.c 2020-02-14 13:12:33.931898004 +0100
***************
*** 3669,3778 ****
#endif // NO_VIM_MAIN
- #if defined(STARTUPTIME) || defined(PROTO)
- static struct timeval prev_timeval;
-
- # ifdef MSWIN
- /*
- * Windows doesn't have gettimeofday(), although it does have struct timeval.
- */
- static int
- gettimeofday(struct timeval *tv, char *dummy UNUSED)
- {
- long t = clock();
- tv->tv_sec = t / CLOCKS_PER_SEC;
- tv->tv_usec = (t - tv->tv_sec * CLOCKS_PER_SEC) * 1000000 /
CLOCKS_PER_SEC;
- return 0;
- }
- # endif
-
- /*
- * Save the previous time before doing something that could nest.
- * set "*tv_rel" to the time elapsed so far.
- */
- void
- time_push(void *tv_rel, void *tv_start)
- {
- *((struct timeval *)tv_rel) = prev_timeval;
- gettimeofday(&prev_timeval, NULL);
- ((struct timeval *)tv_rel)->tv_usec = prev_timeval.tv_usec
- - ((struct timeval *)tv_rel)->tv_usec;
- ((struct timeval *)tv_rel)->tv_sec = prev_timeval.tv_sec
- - ((struct timeval *)tv_rel)->tv_sec;
- if (((struct timeval *)tv_rel)->tv_usec < 0)
- {
- ((struct timeval *)tv_rel)->tv_usec += 1000000;
- --((struct timeval *)tv_rel)->tv_sec;
- }
- *(struct timeval *)tv_start = prev_timeval;
- }
-
- /*
- * Compute the previous time after doing something that could nest.
- * Subtract "*tp" from prev_timeval;
- * Note: The arguments are (void *) to avoid trouble with systems that don't
- * have struct timeval.
- */
- void
- time_pop(
- void *tp) // actually (struct timeval *)
- {
- prev_timeval.tv_usec -= ((struct timeval *)tp)->tv_usec;
- prev_timeval.tv_sec -= ((struct timeval *)tp)->tv_sec;
- if (prev_timeval.tv_usec < 0)
- {
- prev_timeval.tv_usec += 1000000;
- --prev_timeval.tv_sec;
- }
- }
-
- static void
- time_diff(struct timeval *then, struct timeval *now)
- {
- long usec;
- long msec;
-
- usec = now->tv_usec - then->tv_usec;
- msec = (now->tv_sec - then->tv_sec) * 1000L + usec / 1000L,
- usec = usec % 1000L;
- fprintf(time_fd, "%03ld.%03ld", msec, usec >= 0 ? usec : usec + 1000L);
- }
-
- void
- time_msg(
- char *mesg,
- void *tv_start) // only for do_source: start time; actually
- // (struct timeval *)
- {
- static struct timeval start;
- struct timeval now;
-
- if (time_fd != NULL)
- {
- if (strstr(mesg, "STARTING") != NULL)
- {
- gettimeofday(&start, NULL);
- prev_timeval = start;
- fprintf(time_fd, "\n\ntimes in msec\n");
- fprintf(time_fd, " clock self+sourced self: sourced script\n");
- fprintf(time_fd, " clock elapsed: other lines\n\n");
- }
- gettimeofday(&now, NULL);
- time_diff(&start, &now);
- if (((struct timeval *)tv_start) != NULL)
- {
- fprintf(time_fd, " ");
- time_diff(((struct timeval *)tv_start), &now);
- }
- fprintf(time_fd, " ");
- time_diff(&prev_timeval, &now);
- prev_timeval = now;
- fprintf(time_fd, ": %s\n", mesg);
- }
- }
-
- #endif
-
#if !defined(NO_VIM_MAIN) && defined(FEAT_EVAL)
static void
set_progpath(char_u *argv0)
--- 3669,3674 ----
*** ../vim-8.2.0255/src/memline.c 2020-01-26 21:59:25.624718145 +0100
--- src/memline.c 2020-02-14 13:12:33.935897975 +0100
***************
*** 2081,2174 ****
#endif
/*
- * Cache of the current timezone name as retrieved from TZ, or an empty string
- * where unset, up to 64 octets long including trailing null byte.
- */
- #if defined(HAVE_LOCALTIME_R) && defined(HAVE_TZSET)
- static char tz_cache[64];
- #endif
-
- /*
- * Call either localtime(3) or localtime_r(3) from POSIX libc time.h, with the
- * latter version preferred for reentrancy.
- *
- * If we use localtime_r(3) and we have tzset(3) available, check to see if
the
- * environment variable TZ has changed since the last run, and call tzset(3)
to
- * update the global timezone variables if it has. This is because the POSIX
- * standard doesn't require localtime_r(3) implementations to do that as it
- * does with localtime(3), and we don't want to call tzset(3) every time.
- */
- struct tm *
- vim_localtime(
- const time_t *timep, // timestamp for local representation
- struct tm *result UNUSED) // pointer to caller return buffer
- {
- #ifdef HAVE_LOCALTIME_R
- # ifdef HAVE_TZSET
- char *tz; // pointer for TZ environment var
-
- tz = (char *)mch_getenv((char_u *)"TZ");
- if (tz == NULL)
- tz = "";
- if (STRNCMP(tz_cache, tz, sizeof(tz_cache) - 1) != 0)
- {
- tzset();
- vim_strncpy((char_u *)tz_cache, (char_u *)tz, sizeof(tz_cache) - 1);
- }
- # endif // HAVE_TZSET
- return localtime_r(timep, result);
- #else
- return localtime(timep);
- #endif // HAVE_LOCALTIME_R
- }
-
- /*
- * Replacement for ctime(), which is not safe to use.
- * Requires strftime(), otherwise returns "(unknown)".
- * If "thetime" is invalid returns "(invalid)". Never returns NULL.
- * When "add_newline" is TRUE add a newline like ctime() does.
- * Uses a static buffer.
- */
- char *
- get_ctime(time_t thetime, int add_newline)
- {
- static char buf[50];
- #ifdef HAVE_STRFTIME
- struct tm tmval;
- struct tm *curtime;
-
- curtime = vim_localtime(&thetime, &tmval);
- // MSVC returns NULL for an invalid value of seconds.
- if (curtime == NULL)
- vim_strncpy((char_u *)buf, (char_u *)_("(Invalid)"), sizeof(buf) - 1);
- else
- {
- (void)strftime(buf, sizeof(buf) - 1, _("%a %b %d %H:%M:%S %Y"),
- curtime);
- # ifdef MSWIN
- if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
- {
- char_u *to_free = NULL;
- int len;
-
- acp_to_enc((char_u *)buf, (int)strlen(buf), &to_free, &len);
- if (to_free != NULL)
- {
- STRCPY(buf, to_free);
- vim_free(to_free);
- }
- }
- # endif
- }
- #else
- STRCPY(buf, "(unknown)");
- #endif
- if (add_newline)
- STRCAT(buf, "\n");
- return buf;
- }
-
- /*
* Give information about an existing swap file.
* Returns timestamp (0 when unknown).
*/
--- 2081,2086 ----
*** ../vim-8.2.0255/src/misc1.c 2020-02-02 22:24:00.628827172 +0100
--- src/misc1.c 2020-02-14 13:12:33.935897975 +0100
***************
*** 2597,2630 ****
;
return path_is_url(p);
}
-
- /*
- * Put timestamp "tt" in "buf[buflen]" in a nice format.
- */
- void
- add_time(char_u *buf, size_t buflen, time_t tt)
- {
- #ifdef HAVE_STRFTIME
- struct tm tmval;
- struct tm *curtime;
-
- if (vim_time() - tt >= 100)
- {
- curtime = vim_localtime(&tt, &tmval);
- if (vim_time() - tt < (60L * 60L * 12L))
- // within 12 hours
- (void)strftime((char *)buf, buflen, "%H:%M:%S", curtime);
- else
- // longer ago
- (void)strftime((char *)buf, buflen, "%Y/%m/%d %H:%M:%S", curtime);
- }
- else
- #endif
- {
- long seconds = (long)(vim_time() - tt);
-
- vim_snprintf((char *)buf, buflen,
- NGETTEXT("%ld second ago", "%ld seconds ago", seconds),
- seconds);
- }
- }
--- 2597,2599 ----
*** ../vim-8.2.0255/src/misc2.c 2019-12-21 18:25:50.453560468 +0100
--- src/misc2.c 2020-02-14 13:12:33.935897975 +0100
***************
*** 4127,4152 ****
}
/*
- * Read 8 bytes from "fd" and turn them into a time_T, MSB first.
- * Returns -1 when encountering EOF.
- */
- time_T
- get8ctime(FILE *fd)
- {
- int c;
- time_T n = 0;
- int i;
-
- for (i = 0; i < 8; ++i)
- {
- c = getc(fd);
- if (c == EOF) return -1;
- n = (n << 8) + c;
- }
- return n;
- }
-
- /*
* Read a string of length "cnt" from "fd" into allocated memory.
* Returns NULL when out of memory or unable to read that many bytes.
*/
--- 4127,4132 ----
***************
*** 4191,4258 ****
return OK;
}
- #ifdef _MSC_VER
- # if (_MSC_VER <= 1200)
- // This line is required for VC6 without the service pack. Also see the
- // matching #pragma below.
- # pragma optimize("", off)
- # endif
- #endif
-
- /*
- * Write time_T to file "fd" in 8 bytes.
- * Returns FAIL when the write failed.
- */
- int
- put_time(FILE *fd, time_T the_time)
- {
- char_u buf[8];
-
- time_to_bytes(the_time, buf);
- return fwrite(buf, (size_t)8, (size_t)1, fd) == 1 ? OK : FAIL;
- }
-
- /*
- * Write time_T to "buf[8]".
- */
- void
- time_to_bytes(time_T the_time, char_u *buf)
- {
- int c;
- int i;
- int bi = 0;
- time_T wtime = the_time;
-
- // time_T can be up to 8 bytes in size, more than long_u, thus we
- // can't use put_bytes() here.
- // Another problem is that ">>" may do an arithmetic shift that keeps the
- // sign. This happens for large values of wtime. A cast to long_u may
- // truncate if time_T is 8 bytes. So only use a cast when it is 4 bytes,
- // it's safe to assume that long_u is 4 bytes or more and when using 8
- // bytes the top bit won't be set.
- for (i = 7; i >= 0; --i)
- {
- if (i + 1 > (int)sizeof(time_T))
- // ">>" doesn't work well when shifting more bits than avail
- buf[bi++] = 0;
- else
- {
- #if defined(SIZEOF_TIME_T) && SIZEOF_TIME_T > 4
- c = (int)(wtime >> (i * 8));
- #else
- c = (int)((long_u)wtime >> (i * 8));
- #endif
- buf[bi++] = c;
- }
- }
- }
-
- #ifdef _MSC_VER
- # if (_MSC_VER <= 1200)
- # pragma optimize("", on)
- # endif
- #endif
-
#endif
#if defined(FEAT_QUICKFIX) || defined(FEAT_SPELL) || defined(PROTO)
--- 4171,4176 ----
*** ../vim-8.2.0255/src/proto.h 2020-01-26 15:52:33.023833239 +0100
--- src/proto.h 2020-02-14 13:12:33.935897975 +0100
***************
*** 221,226 ****
--- 221,227 ----
# include "textprop.pro"
# endif
# include "testing.pro"
+ # include "time.pro"
# include "ui.pro"
# include "undo.pro"
# include "usercmd.pro"
*** ../vim-8.2.0255/src/proto/ex_cmds.pro 2019-12-12 12:55:20.000000000
+0100
--- src/proto/ex_cmds.pro 2020-02-14 13:12:33.939897950 +0100
***************
*** 9,15 ****
void do_shell(char_u *cmd, int flags);
char_u *make_filter_cmd(char_u *cmd, char_u *itmp, char_u *otmp);
void append_redir(char_u *buf, int buflen, char_u *opt, char_u *fname);
- time_T vim_time(void);
void do_fixdel(exarg_T *eap);
void print_line_no_prefix(linenr_T lnum, int use_number, int list);
void print_line(linenr_T lnum, int use_number, int list);
--- 9,14 ----
*** ../vim-8.2.0255/src/proto/ex_cmds2.pro 2019-12-12 12:55:20.000000000
+0100
--- src/proto/ex_cmds2.pro 2020-02-14 13:12:33.939897950 +0100
***************
*** 1,15 ****
/* ex_cmds2.c */
- long proftime_time_left(proftime_T *due, proftime_T *now);
- timer_T *create_timer(long msec, int repeat);
- long check_due_timer(void);
- void stop_timer(timer_T *timer);
- int set_ref_in_timer(int copyID);
- void timer_free_all(void);
- void f_timer_info(typval_T *argvars, typval_T *rettv);
- void f_timer_pause(typval_T *argvars, typval_T *rettv);
- void f_timer_start(typval_T *argvars, typval_T *rettv);
- void f_timer_stop(typval_T *argvars, typval_T *rettv);
- void f_timer_stopall(typval_T *argvars, typval_T *rettv);
int autowrite(buf_T *buf, int forceit);
void autowrite_all(void);
int check_changed(buf_T *buf, int flags);
--- 1,4 ----
*** ../vim-8.2.0255/src/proto/main.pro 2019-12-12 12:55:26.000000000 +0100
--- src/proto/main.pro 2020-02-14 13:12:33.939897950 +0100
***************
*** 12,20 ****
void getout(int exitval);
int process_env(char_u *env, int is_viminit);
void mainerr_arg_missing(char_u *str);
- void time_push(void *tv_rel, void *tv_start);
- void time_pop(void *tp);
- void time_msg(char *mesg, void *tv_start);
void server_to_input_buf(char_u *str);
char_u *eval_client_expr_to_string(char_u *expr);
int sendToLocalVim(char_u *cmd, int asExpr, char_u **result);
--- 12,17 ----
*** ../vim-8.2.0255/src/proto/memline.pro 2019-12-12 12:55:27.000000000
+0100
--- src/proto/memline.pro 2020-02-14 13:12:33.939897950 +0100
***************
*** 13,20 ****
int recover_names(char_u *fname, int list, int nr, char_u **fname_out);
char_u *make_percent_swname(char_u *dir, char_u *name);
void get_b0_dict(char_u *fname, dict_T *d);
- struct tm *vim_localtime(const time_t *timep, struct tm *result);
- char *get_ctime(time_t thetime, int add_newline);
void ml_sync_all(int check_file, int check_char);
void ml_preserve(buf_T *buf, int message);
char_u *ml_get(linenr_T lnum);
--- 13,18 ----
*** ../vim-8.2.0255/src/proto/misc1.pro 2020-02-02 22:24:00.628827172 +0100
--- src/proto/misc1.pro 2020-02-14 13:12:33.939897950 +0100
***************
*** 47,51 ****
char_u *get_isolated_shell_name(void);
int path_is_url(char_u *p);
int path_with_url(char_u *fname);
- void add_time(char_u *buf, size_t buflen, time_t tt);
/* vim: set ft=c : */
--- 47,50 ----
*** ../vim-8.2.0255/src/proto/misc2.pro 2019-12-12 12:55:28.000000000 +0100
--- src/proto/misc2.pro 2020-02-14 13:12:33.939897950 +0100
***************
*** 94,104 ****
int get2c(FILE *fd);
int get3c(FILE *fd);
int get4c(FILE *fd);
- time_T get8ctime(FILE *fd);
char_u *read_string(FILE *fd, int cnt);
int put_bytes(FILE *fd, long_u nr, int len);
- int put_time(FILE *fd, time_T the_time);
- void time_to_bytes(time_T the_time, char_u *buf);
int has_non_ascii(char_u *s);
int mch_parse_cmd(char_u *cmd, int use_shcf, char ***argv, int *argc);
int build_argv_from_string(char_u *cmd, char ***argv, int *argc);
--- 94,101 ----
*** ../vim-8.2.0255/src/proto/time.pro 2020-02-14 13:19:01.674366860 +0100
--- src/proto/time.pro 2020-02-14 13:12:33.939897950 +0100
***************
*** 0 ****
--- 1,28 ----
+ /* time.c */
+ char *get_ctime(time_t thetime, int add_newline);
+ time_T vim_time(void);
+ void f_localtime(typval_T *argvars, typval_T *rettv);
+ void f_reltime(typval_T *argvars, typval_T *rettv);
+ void f_reltimefloat(typval_T *argvars, typval_T *rettv);
+ void f_reltimestr(typval_T *argvars, typval_T *rettv);
+ void f_strftime(typval_T *argvars, typval_T *rettv);
+ void f_strptime(typval_T *argvars, typval_T *rettv);
+ long proftime_time_left(proftime_T *due, proftime_T *now);
+ timer_T *create_timer(long msec, int repeat);
+ long check_due_timer(void);
+ void stop_timer(timer_T *timer);
+ int set_ref_in_timer(int copyID);
+ void timer_free_all(void);
+ void f_timer_info(typval_T *argvars, typval_T *rettv);
+ void f_timer_pause(typval_T *argvars, typval_T *rettv);
+ void f_timer_start(typval_T *argvars, typval_T *rettv);
+ void f_timer_stop(typval_T *argvars, typval_T *rettv);
+ void f_timer_stopall(typval_T *argvars, typval_T *rettv);
+ void time_push(void *tv_rel, void *tv_start);
+ void time_pop(void *tp);
+ void time_msg(char *mesg, void *tv_start);
+ time_T get8ctime(FILE *fd);
+ int put_time(FILE *fd, time_T the_time);
+ void time_to_bytes(time_T the_time, char_u *buf);
+ void add_time(char_u *buf, size_t buflen, time_t tt);
+ /* vim: set ft=c : */
*** ../vim-8.2.0255/src/time.c 2020-02-14 13:19:01.682366848 +0100
--- src/time.c 2020-02-14 13:12:33.943897920 +0100
***************
*** 0 ****
--- 1,1041 ----
+ /* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved by Bram Moolenaar
+ *
+ * Do ":help uganda" in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ * See README.txt for an overview of the Vim source code.
+ */
+
+ /*
+ * time.c: functions related to time and timers
+ */
+
+ #include "vim.h"
+
+ /*
+ * Cache of the current timezone name as retrieved from TZ, or an empty string
+ * where unset, up to 64 octets long including trailing null byte.
+ */
+ #if defined(HAVE_LOCALTIME_R) && defined(HAVE_TZSET)
+ static char tz_cache[64];
+ #endif
+
+ /*
+ * Call either localtime(3) or localtime_r(3) from POSIX libc time.h, with the
+ * latter version preferred for reentrancy.
+ *
+ * If we use localtime_r(3) and we have tzset(3) available, check to see if
the
+ * environment variable TZ has changed since the last run, and call tzset(3)
to
+ * update the global timezone variables if it has. This is because the POSIX
+ * standard doesn't require localtime_r(3) implementations to do that as it
+ * does with localtime(3), and we don't want to call tzset(3) every time.
+ */
+ static struct tm *
+ vim_localtime(
+ const time_t *timep, // timestamp for local representation
+ struct tm *result UNUSED) // pointer to caller return buffer
+ {
+ #ifdef HAVE_LOCALTIME_R
+ # ifdef HAVE_TZSET
+ char *tz; // pointer for TZ environment var
+
+ tz = (char *)mch_getenv((char_u *)"TZ");
+ if (tz == NULL)
+ tz = "";
+ if (STRNCMP(tz_cache, tz, sizeof(tz_cache) - 1) != 0)
+ {
+ tzset();
+ vim_strncpy((char_u *)tz_cache, (char_u *)tz, sizeof(tz_cache) - 1);
+ }
+ # endif // HAVE_TZSET
+ return localtime_r(timep, result);
+ #else
+ return localtime(timep);
+ #endif // HAVE_LOCALTIME_R
+ }
+
+ /*
+ * Return the current time in seconds. Calls time(), unless test_settime()
+ * was used.
+ */
+ time_T
+ vim_time(void)
+ {
+ # ifdef FEAT_EVAL
+ return time_for_testing == 0 ? time(NULL) : time_for_testing;
+ # else
+ return time(NULL);
+ # endif
+ }
+
+ /*
+ * Replacement for ctime(), which is not safe to use.
+ * Requires strftime(), otherwise returns "(unknown)".
+ * If "thetime" is invalid returns "(invalid)". Never returns NULL.
+ * When "add_newline" is TRUE add a newline like ctime() does.
+ * Uses a static buffer.
+ */
+ char *
+ get_ctime(time_t thetime, int add_newline)
+ {
+ static char buf[50];
+ #ifdef HAVE_STRFTIME
+ struct tm tmval;
+ struct tm *curtime;
+
+ curtime = vim_localtime(&thetime, &tmval);
+ // MSVC returns NULL for an invalid value of seconds.
+ if (curtime == NULL)
+ vim_strncpy((char_u *)buf, (char_u *)_("(Invalid)"), sizeof(buf) - 1);
+ else
+ {
+ (void)strftime(buf, sizeof(buf) - 1, _("%a %b %d %H:%M:%S %Y"),
+ curtime);
+ # ifdef MSWIN
+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+ {
+ char_u *to_free = NULL;
+ int len;
+
+ acp_to_enc((char_u *)buf, (int)strlen(buf), &to_free, &len);
+ if (to_free != NULL)
+ {
+ STRCPY(buf, to_free);
+ vim_free(to_free);
+ }
+ }
+ # endif
+ }
+ #else
+ STRCPY(buf, "(unknown)");
+ #endif
+ if (add_newline)
+ STRCAT(buf, "\n");
+ return buf;
+ }
+
+ #if defined(FEAT_EVAL) || defined(PROTO)
+
+ #if defined(MACOS_X)
+ # include <time.h> // for time_t
+ #endif
+
+ /*
+ * "localtime()" function
+ */
+ void
+ f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
+ {
+ rettv->vval.v_number = (varnumber_T)time(NULL);
+ }
+
+ # if defined(FEAT_RELTIME)
+ /*
+ * Convert a List to proftime_T.
+ * Return FAIL when there is something wrong.
+ */
+ static int
+ list2proftime(typval_T *arg, proftime_T *tm)
+ {
+ long n1, n2;
+ int error = FALSE;
+
+ if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
+ || arg->vval.v_list->lv_len != 2)
+ return FAIL;
+ n1 = list_find_nr(arg->vval.v_list, 0L, &error);
+ n2 = list_find_nr(arg->vval.v_list, 1L, &error);
+ # ifdef MSWIN
+ tm->HighPart = n1;
+ tm->LowPart = n2;
+ # else
+ tm->tv_sec = n1;
+ tm->tv_usec = n2;
+ # endif
+ return error ? FAIL : OK;
+ }
+ # endif // FEAT_RELTIME
+
+ /*
+ * "reltime()" function
+ */
+ void
+ f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+ {
+ # ifdef FEAT_RELTIME
+ proftime_T res;
+ proftime_T start;
+
+ if (argvars[0].v_type == VAR_UNKNOWN)
+ {
+ // No arguments: get current time.
+ profile_start(&res);
+ }
+ else if (argvars[1].v_type == VAR_UNKNOWN)
+ {
+ if (list2proftime(&argvars[0], &res) == FAIL)
+ return;
+ profile_end(&res);
+ }
+ else
+ {
+ // Two arguments: compute the difference.
+ if (list2proftime(&argvars[0], &start) == FAIL
+ || list2proftime(&argvars[1], &res) == FAIL)
+ return;
+ profile_sub(&res, &start);
+ }
+
+ if (rettv_list_alloc(rettv) == OK)
+ {
+ long n1, n2;
+
+ # ifdef MSWIN
+ n1 = res.HighPart;
+ n2 = res.LowPart;
+ # else
+ n1 = res.tv_sec;
+ n2 = res.tv_usec;
+ # endif
+ list_append_number(rettv->vval.v_list, (varnumber_T)n1);
+ list_append_number(rettv->vval.v_list, (varnumber_T)n2);
+ }
+ # endif
+ }
+
+ # ifdef FEAT_FLOAT
+ /*
+ * "reltimefloat()" function
+ */
+ void
+ f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
+ {
+ # ifdef FEAT_RELTIME
+ proftime_T tm;
+ # endif
+
+ rettv->v_type = VAR_FLOAT;
+ rettv->vval.v_float = 0;
+ # ifdef FEAT_RELTIME
+ if (list2proftime(&argvars[0], &tm) == OK)
+ rettv->vval.v_float = profile_float(&tm);
+ # endif
+ }
+ # endif
+
+ /*
+ * "reltimestr()" function
+ */
+ void
+ f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
+ {
+ # ifdef FEAT_RELTIME
+ proftime_T tm;
+ # endif
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+ # ifdef FEAT_RELTIME
+ if (list2proftime(&argvars[0], &tm) == OK)
+ rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
+ # endif
+ }
+
+ # if defined(HAVE_STRFTIME) || defined(PROTO)
+ /*
+ * "strftime({format}[, {time}])" function
+ */
+ void
+ f_strftime(typval_T *argvars, typval_T *rettv)
+ {
+ char_u result_buf[256];
+ struct tm tmval;
+ struct tm *curtime;
+ time_t seconds;
+ char_u *p;
+
+ rettv->v_type = VAR_STRING;
+
+ p = tv_get_string(&argvars[0]);
+ if (argvars[1].v_type == VAR_UNKNOWN)
+ seconds = time(NULL);
+ else
+ seconds = (time_t)tv_get_number(&argvars[1]);
+ curtime = vim_localtime(&seconds, &tmval);
+ // MSVC returns NULL for an invalid value of seconds.
+ if (curtime == NULL)
+ rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
+ else
+ {
+ vimconv_T conv;
+ char_u *enc;
+
+ conv.vc_type = CONV_NONE;
+ enc = enc_locale();
+ convert_setup(&conv, p_enc, enc);
+ if (conv.vc_type != CONV_NONE)
+ p = string_convert(&conv, p, NULL);
+ if (p != NULL)
+ (void)strftime((char *)result_buf, sizeof(result_buf),
+ (char *)p, curtime);
+ else
+ result_buf[0] = NUL;
+
+ if (conv.vc_type != CONV_NONE)
+ vim_free(p);
+ convert_setup(&conv, enc, p_enc);
+ if (conv.vc_type != CONV_NONE)
+ rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
+ else
+ rettv->vval.v_string = vim_strsave(result_buf);
+
+ // Release conversion descriptors
+ convert_setup(&conv, NULL, NULL);
+ vim_free(enc);
+ }
+ }
+ # endif
+
+ # if defined(HAVE_STRPTIME) || defined(PROTO)
+ /*
+ * "strptime({format}, {timestring})" function
+ */
+ void
+ f_strptime(typval_T *argvars, typval_T *rettv)
+ {
+ struct tm tmval;
+ char_u *fmt;
+ char_u *str;
+ vimconv_T conv;
+ char_u *enc;
+
+ vim_memset(&tmval, NUL, sizeof(tmval));
+ fmt = tv_get_string(&argvars[0]);
+ str = tv_get_string(&argvars[1]);
+
+ conv.vc_type = CONV_NONE;
+ enc = enc_locale();
+ convert_setup(&conv, p_enc, enc);
+ if (conv.vc_type != CONV_NONE)
+ fmt = string_convert(&conv, fmt, NULL);
+ if (fmt == NULL
+ || strptime((char *)str, (char *)fmt, &tmval) == NULL
+ || (rettv->vval.v_number = mktime(&tmval)) == -1)
+ rettv->vval.v_number = 0;
+
+ if (conv.vc_type != CONV_NONE)
+ vim_free(fmt);
+ convert_setup(&conv, NULL, NULL);
+ vim_free(enc);
+ }
+ # endif
+
+ # if defined(FEAT_TIMERS) || defined(PROTO)
+ static timer_T *first_timer = NULL;
+ static long last_timer_id = 0;
+
+ /*
+ * Return time left until "due". Negative if past "due".
+ */
+ long
+ proftime_time_left(proftime_T *due, proftime_T *now)
+ {
+ # ifdef MSWIN
+ LARGE_INTEGER fr;
+
+ if (now->QuadPart > due->QuadPart)
+ return 0;
+ QueryPerformanceFrequency(&fr);
+ return (long)(((double)(due->QuadPart - now->QuadPart)
+ / (double)fr.QuadPart) * 1000);
+ # else
+ if (now->tv_sec > due->tv_sec)
+ return 0;
+ return (due->tv_sec - now->tv_sec) * 1000
+ + (due->tv_usec - now->tv_usec) / 1000;
+ # endif
+ }
+
+ /*
+ * Insert a timer in the list of timers.
+ */
+ static void
+ insert_timer(timer_T *timer)
+ {
+ timer->tr_next = first_timer;
+ timer->tr_prev = NULL;
+ if (first_timer != NULL)
+ first_timer->tr_prev = timer;
+ first_timer = timer;
+ did_add_timer = TRUE;
+ }
+
+ /*
+ * Take a timer out of the list of timers.
+ */
+ static void
+ remove_timer(timer_T *timer)
+ {
+ if (timer->tr_prev == NULL)
+ first_timer = timer->tr_next;
+ else
+ timer->tr_prev->tr_next = timer->tr_next;
+ if (timer->tr_next != NULL)
+ timer->tr_next->tr_prev = timer->tr_prev;
+ }
+
+ static void
+ free_timer(timer_T *timer)
+ {
+ free_callback(&timer->tr_callback);
+ vim_free(timer);
+ }
+
+ /*
+ * Create a timer and return it. NULL if out of memory.
+ * Caller should set the callback.
+ */
+ timer_T *
+ create_timer(long msec, int repeat)
+ {
+ timer_T *timer = ALLOC_CLEAR_ONE(timer_T);
+ long prev_id = last_timer_id;
+
+ if (timer == NULL)
+ return NULL;
+ if (++last_timer_id <= prev_id)
+ // Overflow! Might cause duplicates...
+ last_timer_id = 0;
+ timer->tr_id = last_timer_id;
+ insert_timer(timer);
+ if (repeat != 0)
+ timer->tr_repeat = repeat - 1;
+ timer->tr_interval = msec;
+
+ profile_setlimit(msec, &timer->tr_due);
+ return timer;
+ }
+
+ /*
+ * Invoke the callback of "timer".
+ */
+ static void
+ timer_callback(timer_T *timer)
+ {
+ typval_T rettv;
+ typval_T argv[2];
+
+ argv[0].v_type = VAR_NUMBER;
+ argv[0].vval.v_number = (varnumber_T)timer->tr_id;
+ argv[1].v_type = VAR_UNKNOWN;
+
+ call_callback(&timer->tr_callback, -1, &rettv, 1, argv);
+ clear_tv(&rettv);
+ }
+
+ /*
+ * Call timers that are due.
+ * Return the time in msec until the next timer is due.
+ * Returns -1 if there are no pending timers.
+ */
+ long
+ check_due_timer(void)
+ {
+ timer_T *timer;
+ timer_T *timer_next;
+ long this_due;
+ long next_due = -1;
+ proftime_T now;
+ int did_one = FALSE;
+ int need_update_screen = FALSE;
+ long current_id = last_timer_id;
+
+ // Don't run any timers while exiting or dealing with an error.
+ if (exiting || aborting())
+ return next_due;
+
+ profile_start(&now);
+ for (timer = first_timer; timer != NULL && !got_int; timer = timer_next)
+ {
+ timer_next = timer->tr_next;
+
+ if (timer->tr_id == -1 || timer->tr_firing || timer->tr_paused)
+ continue;
+ this_due = proftime_time_left(&timer->tr_due, &now);
+ if (this_due <= 1)
+ {
+ // Save and restore a lot of flags, because the timer fires while
+ // waiting for a character, which might be halfway a command.
+ int save_timer_busy = timer_busy;
+ int save_vgetc_busy = vgetc_busy;
+ int save_did_emsg = did_emsg;
+ int save_called_emsg = called_emsg;
+ int save_must_redraw = must_redraw;
+ int save_trylevel = trylevel;
+ int save_did_throw = did_throw;
+ int save_ex_pressedreturn = get_pressedreturn();
+ int save_may_garbage_collect = may_garbage_collect;
+ except_T *save_current_exception = current_exception;
+ vimvars_save_T vvsave;
+
+ // Create a scope for running the timer callback, ignoring most of
+ // the current scope, such as being inside a try/catch.
+ timer_busy = timer_busy > 0 || vgetc_busy > 0;
+ vgetc_busy = 0;
+ called_emsg = 0;
+ did_emsg = FALSE;
+ did_uncaught_emsg = FALSE;
+ must_redraw = 0;
+ trylevel = 0;
+ did_throw = FALSE;
+ current_exception = NULL;
+ may_garbage_collect = FALSE;
+ save_vimvars(&vvsave);
+
+ timer->tr_firing = TRUE;
+ timer_callback(timer);
+ timer->tr_firing = FALSE;
+
+ timer_next = timer->tr_next;
+ did_one = TRUE;
+ timer_busy = save_timer_busy;
+ vgetc_busy = save_vgetc_busy;
+ if (did_uncaught_emsg)
+ ++timer->tr_emsg_count;
+ did_emsg = save_did_emsg;
+ called_emsg = save_called_emsg;
+ trylevel = save_trylevel;
+ did_throw = save_did_throw;
+ current_exception = save_current_exception;
+ restore_vimvars(&vvsave);
+ if (must_redraw != 0)
+ need_update_screen = TRUE;
+ must_redraw = must_redraw > save_must_redraw
+ ? must_redraw : save_must_redraw;
+ set_pressedreturn(save_ex_pressedreturn);
+ may_garbage_collect = save_may_garbage_collect;
+
+ // Only fire the timer again if it repeats and stop_timer() wasn't
+ // called while inside the callback (tr_id == -1).
+ if (timer->tr_repeat != 0 && timer->tr_id != -1
+ && timer->tr_emsg_count < 3)
+ {
+ profile_setlimit(timer->tr_interval, &timer->tr_due);
+ this_due = proftime_time_left(&timer->tr_due, &now);
+ if (this_due < 1)
+ this_due = 1;
+ if (timer->tr_repeat > 0)
+ --timer->tr_repeat;
+ }
+ else
+ {
+ this_due = -1;
+ remove_timer(timer);
+ free_timer(timer);
+ }
+ }
+ if (this_due > 0 && (next_due == -1 || next_due > this_due))
+ next_due = this_due;
+ }
+
+ if (did_one)
+ redraw_after_callback(need_update_screen);
+
+ #ifdef FEAT_BEVAL_TERM
+ if (bevalexpr_due_set)
+ {
+ this_due = proftime_time_left(&bevalexpr_due, &now);
+ if (this_due <= 1)
+ {
+ bevalexpr_due_set = FALSE;
+ if (balloonEval == NULL)
+ {
+ balloonEval = ALLOC_CLEAR_ONE(BalloonEval);
+ balloonEvalForTerm = TRUE;
+ }
+ if (balloonEval != NULL)
+ {
+ general_beval_cb(balloonEval, 0);
+ setcursor();
+ out_flush();
+ }
+ }
+ else if (next_due == -1 || next_due > this_due)
+ next_due = this_due;
+ }
+ #endif
+ #ifdef FEAT_TERMINAL
+ // Some terminal windows may need their buffer updated.
+ next_due = term_check_timers(next_due, &now);
+ #endif
+
+ return current_id != last_timer_id ? 1 : next_due;
+ }
+
+ /*
+ * Find a timer by ID. Returns NULL if not found;
+ */
+ static timer_T *
+ find_timer(long id)
+ {
+ timer_T *timer;
+
+ if (id >= 0)
+ {
+ for (timer = first_timer; timer != NULL; timer = timer->tr_next)
+ if (timer->tr_id == id)
+ return timer;
+ }
+ return NULL;
+ }
+
+
+ /*
+ * Stop a timer and delete it.
+ */
+ void
+ stop_timer(timer_T *timer)
+ {
+ if (timer->tr_firing)
+ // Free the timer after the callback returns.
+ timer->tr_id = -1;
+ else
+ {
+ remove_timer(timer);
+ free_timer(timer);
+ }
+ }
+
+ static void
+ stop_all_timers(void)
+ {
+ timer_T *timer;
+ timer_T *timer_next;
+
+ for (timer = first_timer; timer != NULL; timer = timer_next)
+ {
+ timer_next = timer->tr_next;
+ stop_timer(timer);
+ }
+ }
+
+ static void
+ add_timer_info(typval_T *rettv, timer_T *timer)
+ {
+ list_T *list = rettv->vval.v_list;
+ dict_T *dict = dict_alloc();
+ dictitem_T *di;
+ long remaining;
+ proftime_T now;
+
+ if (dict == NULL)
+ return;
+ list_append_dict(list, dict);
+
+ dict_add_number(dict, "id", timer->tr_id);
+ dict_add_number(dict, "time", (long)timer->tr_interval);
+
+ profile_start(&now);
+ remaining = proftime_time_left(&timer->tr_due, &now);
+ dict_add_number(dict, "remaining", (long)remaining);
+
+ dict_add_number(dict, "repeat",
+ (long)(timer->tr_repeat < 0 ? -1 : timer->tr_repeat + 1));
+ dict_add_number(dict, "paused", (long)(timer->tr_paused));
+
+ di = dictitem_alloc((char_u *)"callback");
+ if (di != NULL)
+ {
+ if (dict_add(dict, di) == FAIL)
+ vim_free(di);
+ else
+ put_callback(&timer->tr_callback, &di->di_tv);
+ }
+ }
+
+ static void
+ add_timer_info_all(typval_T *rettv)
+ {
+ timer_T *timer;
+
+ for (timer = first_timer; timer != NULL; timer = timer->tr_next)
+ if (timer->tr_id != -1)
+ add_timer_info(rettv, timer);
+ }
+
+ /*
+ * Mark references in partials of timers.
+ */
+ int
+ set_ref_in_timer(int copyID)
+ {
+ int abort = FALSE;
+ timer_T *timer;
+ typval_T tv;
+
+ for (timer = first_timer; !abort && timer != NULL; timer = timer->tr_next)
+ {
+ if (timer->tr_callback.cb_partial != NULL)
+ {
+ tv.v_type = VAR_PARTIAL;
+ tv.vval.v_partial = timer->tr_callback.cb_partial;
+ }
+ else
+ {
+ tv.v_type = VAR_FUNC;
+ tv.vval.v_string = timer->tr_callback.cb_name;
+ }
+ abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
+ }
+ return abort;
+ }
+
+ # if defined(EXITFREE) || defined(PROTO)
+ void
+ timer_free_all()
+ {
+ timer_T *timer;
+
+ while (first_timer != NULL)
+ {
+ timer = first_timer;
+ remove_timer(timer);
+ free_timer(timer);
+ }
+ }
+ # endif
+
+ /*
+ * "timer_info([timer])" function
+ */
+ void
+ f_timer_info(typval_T *argvars, typval_T *rettv)
+ {
+ timer_T *timer = NULL;
+
+ if (rettv_list_alloc(rettv) != OK)
+ return;
+ if (argvars[0].v_type != VAR_UNKNOWN)
+ {
+ if (argvars[0].v_type != VAR_NUMBER)
+ emsg(_(e_number_exp));
+ else
+ {
+ timer = find_timer((int)tv_get_number(&argvars[0]));
+ if (timer != NULL)
+ add_timer_info(rettv, timer);
+ }
+ }
+ else
+ add_timer_info_all(rettv);
+ }
+
+ /*
+ * "timer_pause(timer, paused)" function
+ */
+ void
+ f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
+ {
+ timer_T *timer = NULL;
+ int paused = (int)tv_get_number(&argvars[1]);
+
+ if (argvars[0].v_type != VAR_NUMBER)
+ emsg(_(e_number_exp));
+ else
+ {
+ timer = find_timer((int)tv_get_number(&argvars[0]));
+ if (timer != NULL)
+ timer->tr_paused = paused;
+ }
+ }
+
+ /*
+ * "timer_start(time, callback [, options])" function
+ */
+ void
+ f_timer_start(typval_T *argvars, typval_T *rettv)
+ {
+ long msec = (long)tv_get_number(&argvars[0]);
+ timer_T *timer;
+ int repeat = 0;
+ callback_T callback;
+ dict_T *dict;
+
+ rettv->vval.v_number = -1;
+ if (check_secure())
+ return;
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ if (argvars[2].v_type != VAR_DICT
+ || (dict = argvars[2].vval.v_dict) == NULL)
+ {
+ semsg(_(e_invarg2), tv_get_string(&argvars[2]));
+ return;
+ }
+ if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
+ repeat = dict_get_number(dict, (char_u *)"repeat");
+ }
+
+ callback = get_callback(&argvars[1]);
+ if (callback.cb_name == NULL)
+ return;
+
+ timer = create_timer(msec, repeat);
+ if (timer == NULL)
+ free_callback(&callback);
+ else
+ {
+ set_callback(&timer->tr_callback, &callback);
+ rettv->vval.v_number = (varnumber_T)timer->tr_id;
+ }
+ }
+
+ /*
+ * "timer_stop(timer)" function
+ */
+ void
+ f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
+ {
+ timer_T *timer;
+
+ if (argvars[0].v_type != VAR_NUMBER)
+ {
+ emsg(_(e_number_exp));
+ return;
+ }
+ timer = find_timer((int)tv_get_number(&argvars[0]));
+ if (timer != NULL)
+ stop_timer(timer);
+ }
+
+ /*
+ * "timer_stopall()" function
+ */
+ void
+ f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+ {
+ stop_all_timers();
+ }
+
+ # endif // FEAT_TIMERS
+
+ # if defined(STARTUPTIME) || defined(PROTO)
+ static struct timeval prev_timeval;
+
+ # ifdef MSWIN
+ /*
+ * Windows doesn't have gettimeofday(), although it does have struct timeval.
+ */
+ static int
+ gettimeofday(struct timeval *tv, char *dummy UNUSED)
+ {
+ long t = clock();
+ tv->tv_sec = t / CLOCKS_PER_SEC;
+ tv->tv_usec = (t - tv->tv_sec * CLOCKS_PER_SEC) * 1000000 /
CLOCKS_PER_SEC;
+ return 0;
+ }
+ # endif
+
+ /*
+ * Save the previous time before doing something that could nest.
+ * set "*tv_rel" to the time elapsed so far.
+ */
+ void
+ time_push(void *tv_rel, void *tv_start)
+ {
+ *((struct timeval *)tv_rel) = prev_timeval;
+ gettimeofday(&prev_timeval, NULL);
+ ((struct timeval *)tv_rel)->tv_usec = prev_timeval.tv_usec
+ - ((struct timeval *)tv_rel)->tv_usec;
+ ((struct timeval *)tv_rel)->tv_sec = prev_timeval.tv_sec
+ - ((struct timeval *)tv_rel)->tv_sec;
+ if (((struct timeval *)tv_rel)->tv_usec < 0)
+ {
+ ((struct timeval *)tv_rel)->tv_usec += 1000000;
+ --((struct timeval *)tv_rel)->tv_sec;
+ }
+ *(struct timeval *)tv_start = prev_timeval;
+ }
+
+ /*
+ * Compute the previous time after doing something that could nest.
+ * Subtract "*tp" from prev_timeval;
+ * Note: The arguments are (void *) to avoid trouble with systems that don't
+ * have struct timeval.
+ */
+ void
+ time_pop(
+ void *tp) // actually (struct timeval *)
+ {
+ prev_timeval.tv_usec -= ((struct timeval *)tp)->tv_usec;
+ prev_timeval.tv_sec -= ((struct timeval *)tp)->tv_sec;
+ if (prev_timeval.tv_usec < 0)
+ {
+ prev_timeval.tv_usec += 1000000;
+ --prev_timeval.tv_sec;
+ }
+ }
+
+ static void
+ time_diff(struct timeval *then, struct timeval *now)
+ {
+ long usec;
+ long msec;
+
+ usec = now->tv_usec - then->tv_usec;
+ msec = (now->tv_sec - then->tv_sec) * 1000L + usec / 1000L,
+ usec = usec % 1000L;
+ fprintf(time_fd, "%03ld.%03ld", msec, usec >= 0 ? usec : usec + 1000L);
+ }
+
+ void
+ time_msg(
+ char *mesg,
+ void *tv_start) // only for do_source: start time; actually
+ // (struct timeval *)
+ {
+ static struct timeval start;
+ struct timeval now;
+
+ if (time_fd != NULL)
+ {
+ if (strstr(mesg, "STARTING") != NULL)
+ {
+ gettimeofday(&start, NULL);
+ prev_timeval = start;
+ fprintf(time_fd, "\n\ntimes in msec\n");
+ fprintf(time_fd, " clock self+sourced self: sourced script\n");
+ fprintf(time_fd, " clock elapsed: other lines\n\n");
+ }
+ gettimeofday(&now, NULL);
+ time_diff(&start, &now);
+ if (((struct timeval *)tv_start) != NULL)
+ {
+ fprintf(time_fd, " ");
+ time_diff(((struct timeval *)tv_start), &now);
+ }
+ fprintf(time_fd, " ");
+ time_diff(&prev_timeval, &now);
+ prev_timeval = now;
+ fprintf(time_fd, ": %s\n", mesg);
+ }
+ }
+ # endif // STARTUPTIME
+ #endif // FEAT_EVAL
+
+ #if defined(FEAT_SPELL) || defined(FEAT_PERSISTENT_UNDO) || defined(PROTO)
+ /*
+ * Read 8 bytes from "fd" and turn them into a time_T, MSB first.
+ * Returns -1 when encountering EOF.
+ */
+ time_T
+ get8ctime(FILE *fd)
+ {
+ int c;
+ time_T n = 0;
+ int i;
+
+ for (i = 0; i < 8; ++i)
+ {
+ c = getc(fd);
+ if (c == EOF) return -1;
+ n = (n << 8) + c;
+ }
+ return n;
+ }
+
+ #ifdef _MSC_VER
+ # if (_MSC_VER <= 1200)
+ // This line is required for VC6 without the service pack. Also see the
+ // matching #pragma below.
+ # pragma optimize("", off)
+ # endif
+ #endif
+
+ /*
+ * Write time_T to file "fd" in 8 bytes.
+ * Returns FAIL when the write failed.
+ */
+ int
+ put_time(FILE *fd, time_T the_time)
+ {
+ char_u buf[8];
+
+ time_to_bytes(the_time, buf);
+ return fwrite(buf, (size_t)8, (size_t)1, fd) == 1 ? OK : FAIL;
+ }
+
+ /*
+ * Write time_T to "buf[8]".
+ */
+ void
+ time_to_bytes(time_T the_time, char_u *buf)
+ {
+ int c;
+ int i;
+ int bi = 0;
+ time_T wtime = the_time;
+
+ // time_T can be up to 8 bytes in size, more than long_u, thus we
+ // can't use put_bytes() here.
+ // Another problem is that ">>" may do an arithmetic shift that keeps the
+ // sign. This happens for large values of wtime. A cast to long_u may
+ // truncate if time_T is 8 bytes. So only use a cast when it is 4 bytes,
+ // it's safe to assume that long_u is 4 bytes or more and when using 8
+ // bytes the top bit won't be set.
+ for (i = 7; i >= 0; --i)
+ {
+ if (i + 1 > (int)sizeof(time_T))
+ // ">>" doesn't work well when shifting more bits than avail
+ buf[bi++] = 0;
+ else
+ {
+ #if defined(SIZEOF_TIME_T) && SIZEOF_TIME_T > 4
+ c = (int)(wtime >> (i * 8));
+ #else
+ c = (int)((long_u)wtime >> (i * 8));
+ #endif
+ buf[bi++] = c;
+ }
+ }
+ }
+
+ #ifdef _MSC_VER
+ # if (_MSC_VER <= 1200)
+ # pragma optimize("", on)
+ # endif
+ #endif
+
+ #endif
+
+ /*
+ * Put timestamp "tt" in "buf[buflen]" in a nice format.
+ */
+ void
+ add_time(char_u *buf, size_t buflen, time_t tt)
+ {
+ #ifdef HAVE_STRFTIME
+ struct tm tmval;
+ struct tm *curtime;
+
+ if (vim_time() - tt >= 100)
+ {
+ curtime = vim_localtime(&tt, &tmval);
+ if (vim_time() - tt < (60L * 60L * 12L))
+ // within 12 hours
+ (void)strftime((char *)buf, buflen, "%H:%M:%S", curtime);
+ else
+ // longer ago
+ (void)strftime((char *)buf, buflen, "%Y/%m/%d %H:%M:%S", curtime);
+ }
+ else
+ #endif
+ {
+ long seconds = (long)(vim_time() - tt);
+
+ vim_snprintf((char *)buf, buflen,
+ NGETTEXT("%ld second ago", "%ld seconds ago", seconds),
+ seconds);
+ }
+ }
*** ../vim-8.2.0255/src/version.c 2020-02-13 21:59:22.642962684 +0100
--- src/version.c 2020-02-14 13:13:29.951541817 +0100
***************
*** 744,745 ****
--- 744,747 ----
{ /* Add new patch number below this line */
+ /**/
+ 256,
/**/
--
ASCII stupid question, get a stupid ANSI.
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/vim_dev/202002141222.01ECMt4w032425%40masaka.moolenaar.net.