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