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.

Raspunde prin e-mail lui