To: vim_dev@googlegroups.com Subject: Patch 8.2.0256 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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 #endif - #if defined(MACOS_X) - # include // 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(). * resulting * ^? ^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 // 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 -- Bram@Moolenaar.net -- 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 ///