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 * message.c: functions for displaying messages on the command line 12 */ 13 14 #define MESSAGE_FILE // don't include prototype for smsg() 15 #define USING_FLOAT_STUFF 16 17 #include "vim.h" 18 19 static void add_msg_hist(char_u *s, int len, int attr); 20 static void hit_return_msg(void); 21 static void msg_home_replace_attr(char_u *fname, int attr); 22 static void msg_puts_attr_len(char *str, int maxlen, int attr); 23 static void msg_puts_display(char_u *str, int maxlen, int attr, int recurse); 24 static void msg_scroll_up(void); 25 static void inc_msg_scrolled(void); 26 static void store_sb_text(char_u **sb_str, char_u *s, int attr, int *sb_col, int finish); 27 static void t_puts(int *t_col, char_u *t_s, char_u *s, int attr); 28 static void msg_puts_printf(char_u *str, int maxlen); 29 static int do_more_prompt(int typed_char); 30 static void msg_screen_putchar(int c, int attr); 31 static void msg_moremsg(int full); 32 static int msg_check_screen(void); 33 static void redir_write(char_u *s, int maxlen); 34 #ifdef FEAT_CON_DIALOG 35 static char_u *msg_show_console_dialog(char_u *message, char_u *buttons, int dfltbutton); 36 static int confirm_msg_used = FALSE; // displaying confirm_msg 37 static char_u *confirm_msg = NULL; // ":confirm" message 38 static char_u *confirm_msg_tail; // tail of confirm_msg 39 static void display_confirm_msg(void); 40 #endif 41 #ifdef FEAT_JOB_CHANNEL 42 static int emsg_to_channel_log = FALSE; 43 #endif 44 45 struct msg_hist 46 { 47 struct msg_hist *next; 48 char_u *msg; 49 int attr; 50 }; 51 52 static struct msg_hist *first_msg_hist = NULL; 53 static struct msg_hist *last_msg_hist = NULL; 54 static int msg_hist_len = 0; 55 56 static FILE *verbose_fd = NULL; 57 static int verbose_did_open = FALSE; 58 59 /* 60 * When writing messages to the screen, there are many different situations. 61 * A number of variables is used to remember the current state: 62 * msg_didany TRUE when messages were written since the last time the 63 * user reacted to a prompt. 64 * Reset: After hitting a key for the hit-return prompt, 65 * hitting <CR> for the command line or input(). 66 * Set: When any message is written to the screen. 67 * msg_didout TRUE when something was written to the current line. 68 * Reset: When advancing to the next line, when the current 69 * text can be overwritten. 70 * Set: When any message is written to the screen. 71 * msg_nowait No extra delay for the last drawn message. 72 * Used in normal_cmd() before the mode message is drawn. 73 * emsg_on_display There was an error message recently. Indicates that there 74 * should be a delay before redrawing. 75 * msg_scroll The next message should not overwrite the current one. 76 * msg_scrolled How many lines the screen has been scrolled (because of 77 * messages). Used in update_screen() to scroll the screen 78 * back. Incremented each time the screen scrolls a line. 79 * msg_scrolled_ign TRUE when msg_scrolled is non-zero and msg_puts_attr() 80 * writes something without scrolling should not make 81 * need_wait_return to be set. This is a hack to make ":ts" 82 * work without an extra prompt. 83 * lines_left Number of lines available for messages before the 84 * more-prompt is to be given. -1 when not set. 85 * need_wait_return TRUE when the hit-return prompt is needed. 86 * Reset: After giving the hit-return prompt, when the user 87 * has answered some other prompt. 88 * Set: When the ruler or typeahead display is overwritten, 89 * scrolling the screen for some message. 90 * keep_msg Message to be displayed after redrawing the screen, in 91 * main_loop(). 92 * This is an allocated string or NULL when not used. 93 */ 94 95 /* 96 * msg(s) - displays the string 's' on the status line 97 * When terminal not initialized (yet) mch_errmsg(..) is used. 98 * return TRUE if wait_return not called 99 */ 100 int 101 msg(char *s) 102 { 103 return msg_attr_keep(s, 0, FALSE); 104 } 105 106 /* 107 * Like msg() but keep it silent when 'verbosefile' is set. 108 */ 109 int 110 verb_msg(char *s) 111 { 112 int n; 113 114 verbose_enter(); 115 n = msg_attr_keep(s, 0, FALSE); 116 verbose_leave(); 117 118 return n; 119 } 120 121 int 122 msg_attr(char *s, int attr) 123 { 124 return msg_attr_keep(s, attr, FALSE); 125 } 126 127 int 128 msg_attr_keep( 129 char *s, 130 int attr, 131 int keep) // TRUE: set keep_msg if it doesn't scroll 132 { 133 static int entered = 0; 134 int retval; 135 char_u *buf = NULL; 136 137 // Skip messages not matching ":filter pattern". 138 // Don't filter when there is an error. 139 if (!emsg_on_display && message_filtered((char_u *)s)) 140 return TRUE; 141 142 #ifdef FEAT_EVAL 143 if (attr == 0) 144 set_vim_var_string(VV_STATUSMSG, (char_u *)s, -1); 145 #endif 146 147 /* 148 * It is possible that displaying a messages causes a problem (e.g., 149 * when redrawing the window), which causes another message, etc.. To 150 * break this loop, limit the recursiveness to 3 levels. 151 */ 152 if (entered >= 3) 153 return TRUE; 154 ++entered; 155 156 // Add message to history (unless it's a repeated kept message or a 157 // truncated message) 158 if ((char_u *)s != keep_msg 159 || (*s != '<' 160 && last_msg_hist != NULL 161 && last_msg_hist->msg != NULL 162 && STRCMP(s, last_msg_hist->msg))) 163 add_msg_hist((char_u *)s, -1, attr); 164 165 #ifdef FEAT_JOB_CHANNEL 166 if (emsg_to_channel_log) 167 // Write message in the channel log. 168 ch_log(NULL, "ERROR: %s", (char *)s); 169 #endif 170 171 // Truncate the message if needed. 172 msg_start(); 173 buf = msg_strtrunc((char_u *)s, FALSE); 174 if (buf != NULL) 175 s = (char *)buf; 176 177 msg_outtrans_attr((char_u *)s, attr); 178 msg_clr_eos(); 179 retval = msg_end(); 180 181 if (keep && retval && vim_strsize((char_u *)s) 182 < (int)(Rows - cmdline_row - 1) * Columns + sc_col) 183 set_keep_msg((char_u *)s, 0); 184 185 vim_free(buf); 186 --entered; 187 return retval; 188 } 189 190 /* 191 * Truncate a string such that it can be printed without causing a scroll. 192 * Returns an allocated string or NULL when no truncating is done. 193 */ 194 char_u * 195 msg_strtrunc( 196 char_u *s, 197 int force) // always truncate 198 { 199 char_u *buf = NULL; 200 int len; 201 int room; 202 203 // May truncate message to avoid a hit-return prompt 204 if ((!msg_scroll && !need_wait_return && shortmess(SHM_TRUNCALL) 205 && !exmode_active && msg_silent == 0) || force) 206 { 207 len = vim_strsize(s); 208 if (msg_scrolled != 0) 209 // Use all the columns. 210 room = (int)(Rows - msg_row) * Columns - 1; 211 else 212 // Use up to 'showcmd' column. 213 room = (int)(Rows - msg_row - 1) * Columns + sc_col - 1; 214 if (len > room && room > 0) 215 { 216 if (enc_utf8) 217 // may have up to 18 bytes per cell (6 per char, up to two 218 // composing chars) 219 len = (room + 2) * 18; 220 else if (enc_dbcs == DBCS_JPNU) 221 // may have up to 2 bytes per cell for euc-jp 222 len = (room + 2) * 2; 223 else 224 len = room + 2; 225 buf = alloc(len); 226 if (buf != NULL) 227 trunc_string(s, buf, room, len); 228 } 229 } 230 return buf; 231 } 232 233 /* 234 * Truncate a string "s" to "buf" with cell width "room". 235 * "s" and "buf" may be equal. 236 */ 237 void 238 trunc_string( 239 char_u *s, 240 char_u *buf, 241 int room_in, 242 int buflen) 243 { 244 size_t room = room_in - 3; // "..." takes 3 chars 245 size_t half; 246 size_t len = 0; 247 int e; 248 int i; 249 int n; 250 251 if (room_in < 3) 252 room = 0; 253 half = room / 2; 254 255 // First part: Start of the string. 256 for (e = 0; len < half && e < buflen; ++e) 257 { 258 if (s[e] == NUL) 259 { 260 // text fits without truncating! 261 buf[e] = NUL; 262 return; 263 } 264 n = ptr2cells(s + e); 265 if (len + n > half) 266 break; 267 len += n; 268 buf[e] = s[e]; 269 if (has_mbyte) 270 for (n = (*mb_ptr2len)(s + e); --n > 0; ) 271 { 272 if (++e == buflen) 273 break; 274 buf[e] = s[e]; 275 } 276 } 277 278 // Last part: End of the string. 279 i = e; 280 if (enc_dbcs != 0) 281 { 282 // For DBCS going backwards in a string is slow, but 283 // computing the cell width isn't too slow: go forward 284 // until the rest fits. 285 n = vim_strsize(s + i); 286 while (len + n > room) 287 { 288 n -= ptr2cells(s + i); 289 i += (*mb_ptr2len)(s + i); 290 } 291 } 292 else if (enc_utf8) 293 { 294 // For UTF-8 we can go backwards easily. 295 half = i = (int)STRLEN(s); 296 for (;;) 297 { 298 do 299 half = half - utf_head_off(s, s + half - 1) - 1; 300 while (half > 0 && utf_iscomposing(utf_ptr2char(s + half))); 301 n = ptr2cells(s + half); 302 if (len + n > room || half == 0) 303 break; 304 len += n; 305 i = (int)half; 306 } 307 } 308 else 309 { 310 for (i = (int)STRLEN(s); 311 i - 1 >= 0 && len + (n = ptr2cells(s + i - 1)) <= room; --i) 312 len += n; 313 } 314 315 316 if (i <= e + 3) 317 { 318 // text fits without truncating 319 if (s != buf) 320 { 321 len = STRLEN(s); 322 if (len >= (size_t)buflen) 323 len = buflen - 1; 324 len = len - e + 1; 325 if (len < 1) 326 buf[e - 1] = NUL; 327 else 328 mch_memmove(buf + e, s + e, len); 329 } 330 } 331 else if (e + 3 < buflen) 332 { 333 // set the middle and copy the last part 334 mch_memmove(buf + e, "...", (size_t)3); 335 len = STRLEN(s + i) + 1; 336 if (len >= (size_t)buflen - e - 3) 337 len = buflen - e - 3 - 1; 338 mch_memmove(buf + e + 3, s + i, len); 339 buf[e + 3 + len - 1] = NUL; 340 } 341 else 342 { 343 // can't fit in the "...", just truncate it 344 buf[e - 1] = NUL; 345 } 346 } 347 348 /* 349 * Automatic prototype generation does not understand this function. 350 * Note: Caller of smsg() and smsg_attr() must check the resulting string is 351 * shorter than IOSIZE!!! 352 */ 353 #ifndef PROTO 354 355 int vim_snprintf(char *str, size_t str_m, const char *fmt, ...); 356 357 int 358 smsg(const char *s, ...) 359 { 360 if (IObuff == NULL) 361 { 362 // Very early in initialisation and already something wrong, just 363 // give the raw message so the user at least gets a hint. 364 return msg((char *)s); 365 } 366 else 367 { 368 va_list arglist; 369 370 va_start(arglist, s); 371 vim_vsnprintf((char *)IObuff, IOSIZE, s, arglist); 372 va_end(arglist); 373 return msg((char *)IObuff); 374 } 375 } 376 377 int 378 smsg_attr(int attr, const char *s, ...) 379 { 380 if (IObuff == NULL) 381 { 382 // Very early in initialisation and already something wrong, just 383 // give the raw message so the user at least gets a hint. 384 return msg_attr((char *)s, attr); 385 } 386 else 387 { 388 va_list arglist; 389 390 va_start(arglist, s); 391 vim_vsnprintf((char *)IObuff, IOSIZE, s, arglist); 392 va_end(arglist); 393 return msg_attr((char *)IObuff, attr); 394 } 395 } 396 397 int 398 smsg_attr_keep(int attr, const char *s, ...) 399 { 400 if (IObuff == NULL) 401 { 402 // Very early in initialisation and already something wrong, just 403 // give the raw message so the user at least gets a hint. 404 return msg_attr_keep((char *)s, attr, TRUE); 405 } 406 else 407 { 408 va_list arglist; 409 410 va_start(arglist, s); 411 vim_vsnprintf((char *)IObuff, IOSIZE, s, arglist); 412 va_end(arglist); 413 return msg_attr_keep((char *)IObuff, attr, TRUE); 414 } 415 } 416 417 #endif 418 419 /* 420 * Remember the last sourcing name/lnum used in an error message, so that it 421 * isn't printed each time when it didn't change. 422 */ 423 static int last_sourcing_lnum = 0; 424 static char_u *last_sourcing_name = NULL; 425 426 /* 427 * Reset the last used sourcing name/lnum. Makes sure it is displayed again 428 * for the next error message; 429 */ 430 void 431 reset_last_sourcing(void) 432 { 433 VIM_CLEAR(last_sourcing_name); 434 last_sourcing_lnum = 0; 435 } 436 437 /* 438 * Return TRUE if "SOURCING_NAME" differs from "last_sourcing_name". 439 */ 440 static int 441 other_sourcing_name(void) 442 { 443 if (SOURCING_NAME != NULL) 444 { 445 if (last_sourcing_name != NULL) 446 return STRCMP(SOURCING_NAME, last_sourcing_name) != 0; 447 return TRUE; 448 } 449 return FALSE; 450 } 451 452 /* 453 * Get the message about the source, as used for an error message. 454 * Returns an allocated string with room for one more character. 455 * Returns NULL when no message is to be given. 456 */ 457 static char_u * 458 get_emsg_source(void) 459 { 460 char_u *Buf, *p; 461 462 if (SOURCING_NAME != NULL && other_sourcing_name()) 463 { 464 char_u *sname = estack_sfile(); 465 char_u *tofree = sname; 466 467 if (sname == NULL) 468 sname = SOURCING_NAME; 469 470 p = (char_u *)_("Error detected while processing %s:"); 471 Buf = alloc(STRLEN(sname) + STRLEN(p)); 472 if (Buf != NULL) 473 sprintf((char *)Buf, (char *)p, sname); 474 vim_free(tofree); 475 return Buf; 476 } 477 return NULL; 478 } 479 480 /* 481 * Get the message about the source lnum, as used for an error message. 482 * Returns an allocated string with room for one more character. 483 * Returns NULL when no message is to be given. 484 */ 485 static char_u * 486 get_emsg_lnum(void) 487 { 488 char_u *Buf, *p; 489 490 // lnum is 0 when executing a command from the command line 491 // argument, we don't want a line number then 492 if (SOURCING_NAME != NULL 493 && (other_sourcing_name() || SOURCING_LNUM != last_sourcing_lnum) 494 && SOURCING_LNUM != 0) 495 { 496 p = (char_u *)_("line %4ld:"); 497 Buf = alloc(STRLEN(p) + 20); 498 if (Buf != NULL) 499 sprintf((char *)Buf, (char *)p, (long)SOURCING_LNUM); 500 return Buf; 501 } 502 return NULL; 503 } 504 505 /* 506 * Display name and line number for the source of an error. 507 * Remember the file name and line number, so that for the next error the info 508 * is only displayed if it changed. 509 */ 510 void 511 msg_source(int attr) 512 { 513 char_u *p; 514 515 ++no_wait_return; 516 p = get_emsg_source(); 517 if (p != NULL) 518 { 519 msg_attr((char *)p, attr); 520 vim_free(p); 521 } 522 p = get_emsg_lnum(); 523 if (p != NULL) 524 { 525 msg_attr((char *)p, HL_ATTR(HLF_N)); 526 vim_free(p); 527 last_sourcing_lnum = SOURCING_LNUM; // only once for each line 528 } 529 530 // remember the last sourcing name printed, also when it's empty 531 if (SOURCING_NAME == NULL || other_sourcing_name()) 532 { 533 vim_free(last_sourcing_name); 534 if (SOURCING_NAME == NULL) 535 last_sourcing_name = NULL; 536 else 537 last_sourcing_name = vim_strsave(SOURCING_NAME); 538 } 539 --no_wait_return; 540 } 541 542 /* 543 * Return TRUE if not giving error messages right now: 544 * If "emsg_off" is set: no error messages at the moment. 545 * If "msg" is in 'debug': do error message but without side effects. 546 * If "emsg_skip" is set: never do error messages. 547 */ 548 static int 549 emsg_not_now(void) 550 { 551 if ((emsg_off > 0 && vim_strchr(p_debug, 'm') == NULL 552 && vim_strchr(p_debug, 't') == NULL) 553 #ifdef FEAT_EVAL 554 || emsg_skip > 0 555 #endif 556 ) 557 return TRUE; 558 return FALSE; 559 } 560 561 #if defined(FEAT_EVAL) || defined(PROTO) 562 static garray_T ignore_error_list = GA_EMPTY; 563 564 void 565 ignore_error_for_testing(char_u *error) 566 { 567 if (ignore_error_list.ga_itemsize == 0) 568 ga_init2(&ignore_error_list, sizeof(char_u *), 1); 569 570 if (STRCMP("RESET", error) == 0) 571 ga_clear_strings(&ignore_error_list); 572 else 573 ga_add_string(&ignore_error_list, error); 574 } 575 576 static int 577 ignore_error(char_u *msg) 578 { 579 int i; 580 581 for (i = 0; i < ignore_error_list.ga_len; ++i) 582 if (strstr((char *)msg, 583 (char *)((char_u **)(ignore_error_list.ga_data))[i]) != NULL) 584 return TRUE; 585 return FALSE; 586 } 587 #endif 588 589 #if !defined(HAVE_STRERROR) || defined(PROTO) 590 /* 591 * Replacement for perror() that behaves more or less like emsg() was called. 592 * v:errmsg will be set and called_emsg will be incremented. 593 */ 594 void 595 do_perror(char *msg) 596 { 597 perror(msg); 598 ++emsg_silent; 599 emsg(msg); 600 --emsg_silent; 601 } 602 #endif 603 604 /* 605 * emsg_core() - display an error message 606 * 607 * Rings the bell, if appropriate, and calls message() to do the real work 608 * When terminal not initialized (yet) mch_errmsg(..) is used. 609 * 610 * Return TRUE if wait_return not called. 611 * Note: caller must check 'emsg_not_now()' before calling this. 612 */ 613 static int 614 emsg_core(char_u *s) 615 { 616 int attr; 617 char_u *p; 618 int r; 619 #ifdef FEAT_EVAL 620 int ignore = FALSE; 621 int severe; 622 #endif 623 624 #ifdef FEAT_EVAL 625 // When testing some errors are turned into a normal message. 626 if (ignore_error(s)) 627 // don't call msg() if it results in a dialog 628 return msg_use_printf() ? FALSE : msg((char *)s); 629 #endif 630 631 ++called_emsg; 632 633 #ifdef FEAT_EVAL 634 // If "emsg_severe" is TRUE: When an error exception is to be thrown, 635 // prefer this message over previous messages for the same command. 636 severe = emsg_severe; 637 emsg_severe = FALSE; 638 #endif 639 640 if (!emsg_off || vim_strchr(p_debug, 't') != NULL) 641 { 642 #ifdef FEAT_EVAL 643 /* 644 * Cause a throw of an error exception if appropriate. Don't display 645 * the error message in this case. (If no matching catch clause will 646 * be found, the message will be displayed later on.) "ignore" is set 647 * when the message should be ignored completely (used for the 648 * interrupt message). 649 */ 650 if (cause_errthrow(s, severe, &ignore) == TRUE) 651 { 652 if (!ignore) 653 ++did_emsg; 654 return TRUE; 655 } 656 657 // set "v:errmsg", also when using ":silent! cmd" 658 set_vim_var_string(VV_ERRMSG, s, -1); 659 #endif 660 661 /* 662 * When using ":silent! cmd" ignore error messages. 663 * But do write it to the redirection file. 664 */ 665 if (emsg_silent != 0) 666 { 667 if (emsg_noredir == 0) 668 { 669 msg_start(); 670 p = get_emsg_source(); 671 if (p != NULL) 672 { 673 STRCAT(p, "\n"); 674 redir_write(p, -1); 675 vim_free(p); 676 } 677 p = get_emsg_lnum(); 678 if (p != NULL) 679 { 680 STRCAT(p, "\n"); 681 redir_write(p, -1); 682 vim_free(p); 683 } 684 redir_write(s, -1); 685 } 686 #ifdef FEAT_JOB_CHANNEL 687 ch_log(NULL, "ERROR silent: %s", (char *)s); 688 #endif 689 return TRUE; 690 } 691 692 ex_exitval = 1; 693 694 // Reset msg_silent, an error causes messages to be switched back on. 695 msg_silent = 0; 696 cmd_silent = FALSE; 697 698 if (global_busy) // break :global command 699 ++global_busy; 700 701 if (p_eb) 702 beep_flush(); // also includes flush_buffers() 703 else 704 flush_buffers(FLUSH_MINIMAL); // flush internal buffers 705 ++did_emsg; // flag for DoOneCmd() 706 #ifdef FEAT_EVAL 707 did_uncaught_emsg = TRUE; 708 #endif 709 } 710 711 emsg_on_display = TRUE; // remember there is an error message 712 ++msg_scroll; // don't overwrite a previous message 713 attr = HL_ATTR(HLF_E); // set highlight mode for error messages 714 if (msg_scrolled != 0) 715 need_wait_return = TRUE; // needed in case emsg() is called after 716 // wait_return has reset need_wait_return 717 // and a redraw is expected because 718 // msg_scrolled is non-zero 719 720 #ifdef FEAT_JOB_CHANNEL 721 emsg_to_channel_log = TRUE; 722 #endif 723 /* 724 * Display name and line number for the source of the error. 725 */ 726 msg_source(attr); 727 728 /* 729 * Display the error message itself. 730 */ 731 msg_nowait = FALSE; // wait for this msg 732 r = msg_attr((char *)s, attr); 733 734 #ifdef FEAT_JOB_CHANNEL 735 emsg_to_channel_log = FALSE; 736 #endif 737 return r; 738 } 739 740 /* 741 * Print an error message. 742 */ 743 int 744 emsg(char *s) 745 { 746 // Skip this if not giving error messages at the moment. 747 if (!emsg_not_now()) 748 return emsg_core((char_u *)s); 749 return TRUE; // no error messages at the moment 750 } 751 752 #ifndef PROTO // manual proto with __attribute__ 753 /* 754 * Print an error message with format string and variable arguments. 755 * Note: caller must not pass 'IObuff' as 1st argument. 756 */ 757 int 758 semsg(const char *s, ...) 759 { 760 // Skip this if not giving error messages at the moment. 761 if (!emsg_not_now()) 762 { 763 if (IObuff == NULL) 764 { 765 // Very early in initialisation and already something wrong, just 766 // give the raw message so the user at least gets a hint. 767 return emsg_core((char_u *)s); 768 } 769 else 770 { 771 va_list ap; 772 773 va_start(ap, s); 774 vim_vsnprintf((char *)IObuff, IOSIZE, s, ap); 775 va_end(ap); 776 return emsg_core(IObuff); 777 } 778 } 779 return TRUE; // no error messages at the moment 780 } 781 #endif 782 783 /* 784 * Same as emsg(...), but abort on error when ABORT_ON_INTERNAL_ERROR is 785 * defined. It is used for internal errors only, so that they can be 786 * detected when fuzzing vim. 787 */ 788 void 789 iemsg(char *s) 790 { 791 if (!emsg_not_now()) 792 emsg_core((char_u *)s); 793 #ifdef ABORT_ON_INTERNAL_ERROR 794 abort(); 795 #endif 796 } 797 798 #ifndef PROTO // manual proto with __attribute__ 799 /* 800 * Same as semsg(...) but abort on error when ABORT_ON_INTERNAL_ERROR is 801 * defined. It is used for internal errors only, so that they can be 802 * detected when fuzzing vim. 803 * Note: caller must not pass 'IObuff' as 1st argument. 804 */ 805 void 806 siemsg(const char *s, ...) 807 { 808 if (!emsg_not_now()) 809 { 810 if (IObuff == NULL) 811 { 812 // Very early in initialisation and already something wrong, just 813 // give the raw message so the user at least gets a hint. 814 emsg_core((char_u *)s); 815 } 816 else 817 { 818 va_list ap; 819 820 va_start(ap, s); 821 vim_vsnprintf((char *)IObuff, IOSIZE, s, ap); 822 va_end(ap); 823 emsg_core(IObuff); 824 } 825 } 826 # ifdef ABORT_ON_INTERNAL_ERROR 827 abort(); 828 # endif 829 } 830 #endif 831 832 /* 833 * Give an "Internal error" message. 834 */ 835 void 836 internal_error(char *where) 837 { 838 siemsg(_(e_intern2), where); 839 } 840 841 // emsg3() and emsgn() are in misc2.c to avoid warnings for the prototypes. 842 843 void 844 emsg_invreg(int name) 845 { 846 semsg(_("E354: Invalid register name: '%s'"), transchar(name)); 847 } 848 849 /* 850 * Give an error message which contains %s for "name[len]". 851 */ 852 void 853 emsg_namelen(char *msg, char_u *name, int len) 854 { 855 char_u *copy = vim_strnsave((char_u *)name, len); 856 857 semsg(msg, copy == NULL ? "NULL" : (char *)copy); 858 } 859 860 /* 861 * Like msg(), but truncate to a single line if p_shm contains 't', or when 862 * "force" is TRUE. This truncates in another way as for normal messages. 863 * Careful: The string may be changed by msg_may_trunc()! 864 * Returns a pointer to the printed message, if wait_return() not called. 865 */ 866 char * 867 msg_trunc_attr(char *s, int force, int attr) 868 { 869 int n; 870 char *ts; 871 872 // Add message to history before truncating 873 add_msg_hist((char_u *)s, -1, attr); 874 875 ts = (char *)msg_may_trunc(force, (char_u *)s); 876 877 msg_hist_off = TRUE; 878 n = msg_attr(ts, attr); 879 msg_hist_off = FALSE; 880 881 if (n) 882 return ts; 883 return NULL; 884 } 885 886 /* 887 * Check if message "s" should be truncated at the start (for filenames). 888 * Return a pointer to where the truncated message starts. 889 * Note: May change the message by replacing a character with '<'. 890 */ 891 char_u * 892 msg_may_trunc(int force, char_u *s) 893 { 894 int n; 895 int room; 896 897 room = (int)(Rows - cmdline_row - 1) * Columns + sc_col - 1; 898 if ((force || (shortmess(SHM_TRUNC) && !exmode_active)) 899 && (n = (int)STRLEN(s) - room) > 0) 900 { 901 if (has_mbyte) 902 { 903 int size = vim_strsize(s); 904 905 // There may be room anyway when there are multibyte chars. 906 if (size <= room) 907 return s; 908 909 for (n = 0; size >= room; ) 910 { 911 size -= (*mb_ptr2cells)(s + n); 912 n += (*mb_ptr2len)(s + n); 913 } 914 --n; 915 } 916 s += n; 917 *s = '<'; 918 } 919 return s; 920 } 921 922 static void 923 add_msg_hist( 924 char_u *s, 925 int len, // -1 for undetermined length 926 int attr) 927 { 928 struct msg_hist *p; 929 930 if (msg_hist_off || msg_silent != 0) 931 return; 932 933 // Don't let the message history get too big 934 while (msg_hist_len > MAX_MSG_HIST_LEN) 935 (void)delete_first_msg(); 936 937 // allocate an entry and add the message at the end of the history 938 p = ALLOC_ONE(struct msg_hist); 939 if (p != NULL) 940 { 941 if (len < 0) 942 len = (int)STRLEN(s); 943 // remove leading and trailing newlines 944 while (len > 0 && *s == '\n') 945 { 946 ++s; 947 --len; 948 } 949 while (len > 0 && s[len - 1] == '\n') 950 --len; 951 p->msg = vim_strnsave(s, len); 952 p->next = NULL; 953 p->attr = attr; 954 if (last_msg_hist != NULL) 955 last_msg_hist->next = p; 956 last_msg_hist = p; 957 if (first_msg_hist == NULL) 958 first_msg_hist = last_msg_hist; 959 ++msg_hist_len; 960 } 961 } 962 963 /* 964 * Delete the first (oldest) message from the history. 965 * Returns FAIL if there are no messages. 966 */ 967 int 968 delete_first_msg(void) 969 { 970 struct msg_hist *p; 971 972 if (msg_hist_len <= 0) 973 return FAIL; 974 p = first_msg_hist; 975 first_msg_hist = p->next; 976 if (first_msg_hist == NULL) 977 last_msg_hist = NULL; // history is empty 978 vim_free(p->msg); 979 vim_free(p); 980 --msg_hist_len; 981 return OK; 982 } 983 984 /* 985 * ":messages" command. 986 */ 987 void 988 ex_messages(exarg_T *eap) 989 { 990 struct msg_hist *p; 991 char_u *s; 992 int c = 0; 993 994 if (STRCMP(eap->arg, "clear") == 0) 995 { 996 int keep = eap->addr_count == 0 ? 0 : eap->line2; 997 998 while (msg_hist_len > keep) 999 (void)delete_first_msg(); 1000 return; 1001 } 1002 1003 if (*eap->arg != NUL) 1004 { 1005 emsg(_(e_invarg)); 1006 return; 1007 } 1008 1009 msg_hist_off = TRUE; 1010 1011 p = first_msg_hist; 1012 if (eap->addr_count != 0) 1013 { 1014 // Count total messages 1015 for (; p != NULL && !got_int; p = p->next) 1016 c++; 1017 1018 c -= eap->line2; 1019 1020 // Skip without number of messages specified 1021 for (p = first_msg_hist; p != NULL && !got_int && c > 0; 1022 p = p->next, c--); 1023 } 1024 1025 if (p == first_msg_hist) 1026 { 1027 s = mch_getenv((char_u *)"LANG"); 1028 if (s != NULL && *s != NUL) 1029 // The next comment is extracted by xgettext and put in po file for 1030 // translators to read. 1031 msg_attr( 1032 // Translator: Please replace the name and email address 1033 // with the appropriate text for your translation. 1034 _("Messages maintainer: Bram Moolenaar <[email protected]>"), 1035 HL_ATTR(HLF_T)); 1036 } 1037 1038 // Display what was not skipped. 1039 for (; p != NULL && !got_int; p = p->next) 1040 if (p->msg != NULL) 1041 msg_attr((char *)p->msg, p->attr); 1042 1043 msg_hist_off = FALSE; 1044 } 1045 1046 #if defined(FEAT_CON_DIALOG) || defined(FIND_REPLACE_DIALOG) || defined(PROTO) 1047 /* 1048 * Call this after prompting the user. This will avoid a hit-return message 1049 * and a delay. 1050 */ 1051 void 1052 msg_end_prompt(void) 1053 { 1054 need_wait_return = FALSE; 1055 emsg_on_display = FALSE; 1056 cmdline_row = msg_row; 1057 msg_col = 0; 1058 msg_clr_eos(); 1059 lines_left = -1; 1060 } 1061 #endif 1062 1063 /* 1064 * Wait for the user to hit a key (normally Enter). 1065 * If "redraw" is TRUE, clear and redraw the screen. 1066 * If "redraw" is FALSE, just redraw the screen. 1067 * If "redraw" is -1, don't redraw at all. 1068 */ 1069 void 1070 wait_return(int redraw) 1071 { 1072 int c; 1073 int oldState; 1074 int tmpState; 1075 int had_got_int; 1076 int save_reg_recording; 1077 FILE *save_scriptout; 1078 1079 if (redraw == TRUE) 1080 must_redraw = CLEAR; 1081 1082 // If using ":silent cmd", don't wait for a return. Also don't set 1083 // need_wait_return to do it later. 1084 if (msg_silent != 0) 1085 return; 1086 1087 /* 1088 * When inside vgetc(), we can't wait for a typed character at all. 1089 * With the global command (and some others) we only need one return at 1090 * the end. Adjust cmdline_row to avoid the next message overwriting the 1091 * last one. 1092 */ 1093 if (vgetc_busy > 0) 1094 return; 1095 need_wait_return = TRUE; 1096 if (no_wait_return) 1097 { 1098 if (!exmode_active) 1099 cmdline_row = msg_row; 1100 return; 1101 } 1102 1103 redir_off = TRUE; // don't redirect this message 1104 oldState = State; 1105 if (quit_more) 1106 { 1107 c = CAR; // just pretend CR was hit 1108 quit_more = FALSE; 1109 got_int = FALSE; 1110 } 1111 else if (exmode_active) 1112 { 1113 msg_puts(" "); // make sure the cursor is on the right line 1114 c = CAR; // no need for a return in ex mode 1115 got_int = FALSE; 1116 } 1117 else 1118 { 1119 // Make sure the hit-return prompt is on screen when 'guioptions' was 1120 // just changed. 1121 screenalloc(FALSE); 1122 1123 State = HITRETURN; 1124 setmouse(); 1125 #ifdef USE_ON_FLY_SCROLL 1126 dont_scroll = TRUE; // disallow scrolling here 1127 #endif 1128 cmdline_row = msg_row; 1129 1130 // Avoid the sequence that the user types ":" at the hit-return prompt 1131 // to start an Ex command, but the file-changed dialog gets in the 1132 // way. 1133 if (need_check_timestamps) 1134 check_timestamps(FALSE); 1135 1136 hit_return_msg(); 1137 1138 do 1139 { 1140 // Remember "got_int", if it is set vgetc() probably returns a 1141 // CTRL-C, but we need to loop then. 1142 had_got_int = got_int; 1143 1144 // Don't do mappings here, we put the character back in the 1145 // typeahead buffer. 1146 ++no_mapping; 1147 ++allow_keys; 1148 1149 // Temporarily disable Recording. If Recording is active, the 1150 // character will be recorded later, since it will be added to the 1151 // typebuf after the loop 1152 save_reg_recording = reg_recording; 1153 save_scriptout = scriptout; 1154 reg_recording = 0; 1155 scriptout = NULL; 1156 c = safe_vgetc(); 1157 if (had_got_int && !global_busy) 1158 got_int = FALSE; 1159 --no_mapping; 1160 --allow_keys; 1161 reg_recording = save_reg_recording; 1162 scriptout = save_scriptout; 1163 1164 #ifdef FEAT_CLIPBOARD 1165 // Strange way to allow copying (yanking) a modeless selection at 1166 // the hit-enter prompt. Use CTRL-Y, because the same is used in 1167 // Cmdline-mode and it's harmless when there is no selection. 1168 if (c == Ctrl_Y && clip_star.state == SELECT_DONE) 1169 { 1170 clip_copy_modeless_selection(TRUE); 1171 c = K_IGNORE; 1172 } 1173 #endif 1174 1175 /* 1176 * Allow scrolling back in the messages. 1177 * Also accept scroll-down commands when messages fill the screen, 1178 * to avoid that typing one 'j' too many makes the messages 1179 * disappear. 1180 */ 1181 if (p_more && !p_cp) 1182 { 1183 if (c == 'b' || c == 'k' || c == 'u' || c == 'g' 1184 || c == K_UP || c == K_PAGEUP) 1185 { 1186 if (msg_scrolled > Rows) 1187 // scroll back to show older messages 1188 do_more_prompt(c); 1189 else 1190 { 1191 msg_didout = FALSE; 1192 c = K_IGNORE; 1193 msg_col = 1194 #ifdef FEAT_RIGHTLEFT 1195 cmdmsg_rl ? Columns - 1 : 1196 #endif 1197 0; 1198 } 1199 if (quit_more) 1200 { 1201 c = CAR; // just pretend CR was hit 1202 quit_more = FALSE; 1203 got_int = FALSE; 1204 } 1205 else if (c != K_IGNORE) 1206 { 1207 c = K_IGNORE; 1208 hit_return_msg(); 1209 } 1210 } 1211 else if (msg_scrolled > Rows - 2 1212 && (c == 'j' || c == 'd' || c == 'f' 1213 || c == K_DOWN || c == K_PAGEDOWN)) 1214 c = K_IGNORE; 1215 } 1216 } while ((had_got_int && c == Ctrl_C) 1217 || c == K_IGNORE 1218 #ifdef FEAT_GUI 1219 || c == K_VER_SCROLLBAR || c == K_HOR_SCROLLBAR 1220 #endif 1221 || c == K_LEFTDRAG || c == K_LEFTRELEASE 1222 || c == K_MIDDLEDRAG || c == K_MIDDLERELEASE 1223 || c == K_RIGHTDRAG || c == K_RIGHTRELEASE 1224 || c == K_MOUSELEFT || c == K_MOUSERIGHT 1225 || c == K_MOUSEDOWN || c == K_MOUSEUP 1226 || c == K_MOUSEMOVE 1227 || (!mouse_has(MOUSE_RETURN) 1228 && mouse_row < msg_row 1229 && (c == K_LEFTMOUSE 1230 || c == K_MIDDLEMOUSE 1231 || c == K_RIGHTMOUSE 1232 || c == K_X1MOUSE 1233 || c == K_X2MOUSE)) 1234 ); 1235 ui_breakcheck(); 1236 /* 1237 * Avoid that the mouse-up event causes visual mode to start. 1238 */ 1239 if (c == K_LEFTMOUSE || c == K_MIDDLEMOUSE || c == K_RIGHTMOUSE 1240 || c == K_X1MOUSE || c == K_X2MOUSE) 1241 (void)jump_to_mouse(MOUSE_SETPOS, NULL, 0); 1242 else if (vim_strchr((char_u *)"\r\n ", c) == NULL && c != Ctrl_C) 1243 { 1244 // Put the character back in the typeahead buffer. Don't use the 1245 // stuff buffer, because lmaps wouldn't work. 1246 ins_char_typebuf(c); 1247 do_redraw = TRUE; // need a redraw even though there is 1248 // typeahead 1249 } 1250 } 1251 redir_off = FALSE; 1252 1253 /* 1254 * If the user hits ':', '?' or '/' we get a command line from the next 1255 * line. 1256 */ 1257 if (c == ':' || c == '?' || c == '/') 1258 { 1259 if (!exmode_active) 1260 cmdline_row = msg_row; 1261 skip_redraw = TRUE; // skip redraw once 1262 do_redraw = FALSE; 1263 #ifdef FEAT_TERMINAL 1264 skip_term_loop = TRUE; 1265 #endif 1266 } 1267 1268 /* 1269 * If the window size changed set_shellsize() will redraw the screen. 1270 * Otherwise the screen is only redrawn if 'redraw' is set and no ':' 1271 * typed. 1272 */ 1273 tmpState = State; 1274 State = oldState; // restore State before set_shellsize 1275 setmouse(); 1276 msg_check(); 1277 1278 #if defined(UNIX) || defined(VMS) 1279 /* 1280 * When switching screens, we need to output an extra newline on exit. 1281 */ 1282 if (swapping_screen() && !termcap_active) 1283 newline_on_exit = TRUE; 1284 #endif 1285 1286 need_wait_return = FALSE; 1287 did_wait_return = TRUE; 1288 emsg_on_display = FALSE; // can delete error message now 1289 lines_left = -1; // reset lines_left at next msg_start() 1290 reset_last_sourcing(); 1291 if (keep_msg != NULL && vim_strsize(keep_msg) >= 1292 (Rows - cmdline_row - 1) * Columns + sc_col) 1293 VIM_CLEAR(keep_msg); // don't redisplay message, it's too long 1294 1295 if (tmpState == SETWSIZE) // got resize event while in vgetc() 1296 { 1297 starttermcap(); // start termcap before redrawing 1298 shell_resized(); 1299 } 1300 else if (!skip_redraw 1301 && (redraw == TRUE || (msg_scrolled != 0 && redraw != -1))) 1302 { 1303 starttermcap(); // start termcap before redrawing 1304 redraw_later(VALID); 1305 } 1306 } 1307 1308 /* 1309 * Write the hit-return prompt. 1310 */ 1311 static void 1312 hit_return_msg(void) 1313 { 1314 int save_p_more = p_more; 1315 1316 p_more = FALSE; // don't want see this message when scrolling back 1317 if (msg_didout) // start on a new line 1318 msg_putchar('\n'); 1319 if (got_int) 1320 msg_puts(_("Interrupt: ")); 1321 1322 msg_puts_attr(_("Press ENTER or type command to continue"), HL_ATTR(HLF_R)); 1323 if (!msg_use_printf()) 1324 msg_clr_eos(); 1325 p_more = save_p_more; 1326 } 1327 1328 /* 1329 * Set "keep_msg" to "s". Free the old value and check for NULL pointer. 1330 */ 1331 void 1332 set_keep_msg(char_u *s, int attr) 1333 { 1334 vim_free(keep_msg); 1335 if (s != NULL && msg_silent == 0) 1336 keep_msg = vim_strsave(s); 1337 else 1338 keep_msg = NULL; 1339 keep_msg_more = FALSE; 1340 keep_msg_attr = attr; 1341 } 1342 1343 #if defined(FEAT_TERMRESPONSE) || defined(PROTO) 1344 /* 1345 * If there currently is a message being displayed, set "keep_msg" to it, so 1346 * that it will be displayed again after redraw. 1347 */ 1348 void 1349 set_keep_msg_from_hist(void) 1350 { 1351 if (keep_msg == NULL && last_msg_hist != NULL && msg_scrolled == 0 1352 && (State & NORMAL)) 1353 set_keep_msg(last_msg_hist->msg, last_msg_hist->attr); 1354 } 1355 #endif 1356 1357 /* 1358 * Prepare for outputting characters in the command line. 1359 */ 1360 void 1361 msg_start(void) 1362 { 1363 int did_return = FALSE; 1364 1365 if (!msg_silent) 1366 VIM_CLEAR(keep_msg); 1367 1368 #ifdef FEAT_EVAL 1369 if (need_clr_eos) 1370 { 1371 // Halfway an ":echo" command and getting an (error) message: clear 1372 // any text from the command. 1373 need_clr_eos = FALSE; 1374 msg_clr_eos(); 1375 } 1376 #endif 1377 1378 if (!msg_scroll && full_screen) // overwrite last message 1379 { 1380 msg_row = cmdline_row; 1381 msg_col = 1382 #ifdef FEAT_RIGHTLEFT 1383 cmdmsg_rl ? Columns - 1 : 1384 #endif 1385 0; 1386 } 1387 else if (msg_didout) // start message on next line 1388 { 1389 msg_putchar('\n'); 1390 did_return = TRUE; 1391 if (exmode_active != EXMODE_NORMAL) 1392 cmdline_row = msg_row; 1393 } 1394 if (!msg_didany || lines_left < 0) 1395 msg_starthere(); 1396 if (msg_silent == 0) 1397 { 1398 msg_didout = FALSE; // no output on current line yet 1399 cursor_off(); 1400 } 1401 1402 // when redirecting, may need to start a new line. 1403 if (!did_return) 1404 redir_write((char_u *)"\n", -1); 1405 } 1406 1407 /* 1408 * Note that the current msg position is where messages start. 1409 */ 1410 void 1411 msg_starthere(void) 1412 { 1413 lines_left = cmdline_row; 1414 msg_didany = FALSE; 1415 } 1416 1417 void 1418 msg_putchar(int c) 1419 { 1420 msg_putchar_attr(c, 0); 1421 } 1422 1423 void 1424 msg_putchar_attr(int c, int attr) 1425 { 1426 char_u buf[MB_MAXBYTES + 1]; 1427 1428 if (IS_SPECIAL(c)) 1429 { 1430 buf[0] = K_SPECIAL; 1431 buf[1] = K_SECOND(c); 1432 buf[2] = K_THIRD(c); 1433 buf[3] = NUL; 1434 } 1435 else 1436 buf[(*mb_char2bytes)(c, buf)] = NUL; 1437 msg_puts_attr((char *)buf, attr); 1438 } 1439 1440 void 1441 msg_outnum(long n) 1442 { 1443 char buf[20]; 1444 1445 sprintf(buf, "%ld", n); 1446 msg_puts(buf); 1447 } 1448 1449 void 1450 msg_home_replace(char_u *fname) 1451 { 1452 msg_home_replace_attr(fname, 0); 1453 } 1454 1455 #if defined(FEAT_FIND_ID) || defined(PROTO) 1456 void 1457 msg_home_replace_hl(char_u *fname) 1458 { 1459 msg_home_replace_attr(fname, HL_ATTR(HLF_D)); 1460 } 1461 #endif 1462 1463 static void 1464 msg_home_replace_attr(char_u *fname, int attr) 1465 { 1466 char_u *name; 1467 1468 name = home_replace_save(NULL, fname); 1469 if (name != NULL) 1470 msg_outtrans_attr(name, attr); 1471 vim_free(name); 1472 } 1473 1474 /* 1475 * Output 'len' characters in 'str' (including NULs) with translation 1476 * if 'len' is -1, output up to a NUL character. 1477 * Use attributes 'attr'. 1478 * Return the number of characters it takes on the screen. 1479 */ 1480 int 1481 msg_outtrans(char_u *str) 1482 { 1483 return msg_outtrans_attr(str, 0); 1484 } 1485 1486 int 1487 msg_outtrans_attr(char_u *str, int attr) 1488 { 1489 return msg_outtrans_len_attr(str, (int)STRLEN(str), attr); 1490 } 1491 1492 int 1493 msg_outtrans_len(char_u *str, int len) 1494 { 1495 return msg_outtrans_len_attr(str, len, 0); 1496 } 1497 1498 /* 1499 * Output one character at "p". Return pointer to the next character. 1500 * Handles multi-byte characters. 1501 */ 1502 char_u * 1503 msg_outtrans_one(char_u *p, int attr) 1504 { 1505 int l; 1506 1507 if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1) 1508 { 1509 msg_outtrans_len_attr(p, l, attr); 1510 return p + l; 1511 } 1512 msg_puts_attr((char *)transchar_byte(*p), attr); 1513 return p + 1; 1514 } 1515 1516 int 1517 msg_outtrans_len_attr(char_u *msgstr, int len, int attr) 1518 { 1519 int retval = 0; 1520 char_u *str = msgstr; 1521 char_u *plain_start = msgstr; 1522 char_u *s; 1523 int mb_l; 1524 int c; 1525 1526 // if MSG_HIST flag set, add message to history 1527 if (attr & MSG_HIST) 1528 { 1529 add_msg_hist(str, len, attr); 1530 attr &= ~MSG_HIST; 1531 } 1532 1533 // If the string starts with a composing character first draw a space on 1534 // which the composing char can be drawn. 1535 if (enc_utf8 && utf_iscomposing(utf_ptr2char(msgstr))) 1536 msg_puts_attr(" ", attr); 1537 1538 /* 1539 * Go over the string. Special characters are translated and printed. 1540 * Normal characters are printed several at a time. 1541 */ 1542 while (--len >= 0) 1543 { 1544 if (enc_utf8) 1545 // Don't include composing chars after the end. 1546 mb_l = utfc_ptr2len_len(str, len + 1); 1547 else if (has_mbyte) 1548 mb_l = (*mb_ptr2len)(str); 1549 else 1550 mb_l = 1; 1551 if (has_mbyte && mb_l > 1) 1552 { 1553 c = (*mb_ptr2char)(str); 1554 if (vim_isprintc(c)) 1555 // printable multi-byte char: count the cells. 1556 retval += (*mb_ptr2cells)(str); 1557 else 1558 { 1559 // unprintable multi-byte char: print the printable chars so 1560 // far and the translation of the unprintable char. 1561 if (str > plain_start) 1562 msg_puts_attr_len((char *)plain_start, 1563 (int)(str - plain_start), attr); 1564 plain_start = str + mb_l; 1565 msg_puts_attr((char *)transchar(c), 1566 attr == 0 ? HL_ATTR(HLF_8) : attr); 1567 retval += char2cells(c); 1568 } 1569 len -= mb_l - 1; 1570 str += mb_l; 1571 } 1572 else 1573 { 1574 s = transchar_byte(*str); 1575 if (s[1] != NUL) 1576 { 1577 // unprintable char: print the printable chars so far and the 1578 // translation of the unprintable char. 1579 if (str > plain_start) 1580 msg_puts_attr_len((char *)plain_start, 1581 (int)(str - plain_start), attr); 1582 plain_start = str + 1; 1583 msg_puts_attr((char *)s, attr == 0 ? HL_ATTR(HLF_8) : attr); 1584 retval += (int)STRLEN(s); 1585 } 1586 else 1587 ++retval; 1588 ++str; 1589 } 1590 } 1591 1592 if (str > plain_start) 1593 // print the printable chars at the end 1594 msg_puts_attr_len((char *)plain_start, (int)(str - plain_start), attr); 1595 1596 return retval; 1597 } 1598 1599 #if defined(FEAT_QUICKFIX) || defined(PROTO) 1600 void 1601 msg_make(char_u *arg) 1602 { 1603 int i; 1604 static char_u *str = (char_u *)"eeffoc", *rs = (char_u *)"Plon#dqg#vxjduB"; 1605 1606 arg = skipwhite(arg); 1607 for (i = 5; *arg && i >= 0; --i) 1608 if (*arg++ != str[i]) 1609 break; 1610 if (i < 0) 1611 { 1612 msg_putchar('\n'); 1613 for (i = 0; rs[i]; ++i) 1614 msg_putchar(rs[i] - 3); 1615 } 1616 } 1617 #endif 1618 1619 /* 1620 * Output the string 'str' up to a NUL character. 1621 * Return the number of characters it takes on the screen. 1622 * 1623 * If K_SPECIAL is encountered, then it is taken in conjunction with the 1624 * following character and shown as <F1>, <S-Up> etc. Any other character 1625 * which is not printable shown in <> form. 1626 * If 'from' is TRUE (lhs of a mapping), a space is shown as <Space>. 1627 * If a character is displayed in one of these special ways, is also 1628 * highlighted (its highlight name is '8' in the p_hl variable). 1629 * Otherwise characters are not highlighted. 1630 * This function is used to show mappings, where we want to see how to type 1631 * the character/string -- webb 1632 */ 1633 int 1634 msg_outtrans_special( 1635 char_u *strstart, 1636 int from, // TRUE for lhs of a mapping 1637 int maxlen) // screen columns, 0 for unlimited 1638 { 1639 char_u *str = strstart; 1640 int retval = 0; 1641 char *text; 1642 int attr; 1643 int len; 1644 1645 attr = HL_ATTR(HLF_8); 1646 while (*str != NUL) 1647 { 1648 // Leading and trailing spaces need to be displayed in <> form. 1649 if ((str == strstart || str[1] == NUL) && *str == ' ') 1650 { 1651 text = "<Space>"; 1652 ++str; 1653 } 1654 else 1655 text = (char *)str2special(&str, from); 1656 len = vim_strsize((char_u *)text); 1657 if (maxlen > 0 && retval + len >= maxlen) 1658 break; 1659 // Highlight special keys 1660 msg_puts_attr(text, len > 1 1661 && (*mb_ptr2len)((char_u *)text) <= 1 ? attr : 0); 1662 retval += len; 1663 } 1664 return retval; 1665 } 1666 1667 #if defined(FEAT_EVAL) || defined(PROTO) 1668 /* 1669 * Return the lhs or rhs of a mapping, with the key codes turned into printable 1670 * strings, in an allocated string. 1671 */ 1672 char_u * 1673 str2special_save( 1674 char_u *str, 1675 int is_lhs) // TRUE for lhs, FALSE for rhs 1676 { 1677 garray_T ga; 1678 char_u *p = str; 1679 1680 ga_init2(&ga, 1, 40); 1681 while (*p != NUL) 1682 ga_concat(&ga, str2special(&p, is_lhs)); 1683 ga_append(&ga, NUL); 1684 return (char_u *)ga.ga_data; 1685 } 1686 #endif 1687 1688 /* 1689 * Return the printable string for the key codes at "*sp". 1690 * Used for translating the lhs or rhs of a mapping to printable chars. 1691 * Advances "sp" to the next code. 1692 */ 1693 char_u * 1694 str2special( 1695 char_u **sp, 1696 int from) // TRUE for lhs of mapping 1697 { 1698 int c; 1699 static char_u buf[7]; 1700 char_u *str = *sp; 1701 int modifiers = 0; 1702 int special = FALSE; 1703 1704 if (has_mbyte) 1705 { 1706 char_u *p; 1707 1708 // Try to un-escape a multi-byte character. Return the un-escaped 1709 // string if it is a multi-byte character. 1710 p = mb_unescape(sp); 1711 if (p != NULL) 1712 return p; 1713 } 1714 1715 c = *str; 1716 if (c == K_SPECIAL && str[1] != NUL && str[2] != NUL) 1717 { 1718 if (str[1] == KS_MODIFIER) 1719 { 1720 modifiers = str[2]; 1721 str += 3; 1722 c = *str; 1723 } 1724 if (c == K_SPECIAL && str[1] != NUL && str[2] != NUL) 1725 { 1726 c = TO_SPECIAL(str[1], str[2]); 1727 str += 2; 1728 } 1729 if (IS_SPECIAL(c) || modifiers) // special key 1730 special = TRUE; 1731 } 1732 1733 if (has_mbyte && !IS_SPECIAL(c)) 1734 { 1735 int len = (*mb_ptr2len)(str); 1736 1737 // For multi-byte characters check for an illegal byte. 1738 if (has_mbyte && MB_BYTE2LEN(*str) > len) 1739 { 1740 transchar_nonprint(buf, c); 1741 *sp = str + 1; 1742 return buf; 1743 } 1744 // Since 'special' is TRUE the multi-byte character 'c' will be 1745 // processed by get_special_key_name() 1746 c = (*mb_ptr2char)(str); 1747 *sp = str + len; 1748 } 1749 else 1750 *sp = str + 1; 1751 1752 // Make unprintable characters in <> form, also <M-Space> and <Tab>. 1753 // Use <Space> only for lhs of a mapping. 1754 if (special || char2cells(c) > 1 || (from && c == ' ')) 1755 return get_special_key_name(c, modifiers); 1756 buf[0] = c; 1757 buf[1] = NUL; 1758 return buf; 1759 } 1760 1761 /* 1762 * Translate a key sequence into special key names. 1763 */ 1764 void 1765 str2specialbuf(char_u *sp, char_u *buf, int len) 1766 { 1767 char_u *s; 1768 1769 *buf = NUL; 1770 while (*sp) 1771 { 1772 s = str2special(&sp, FALSE); 1773 if ((int)(STRLEN(s) + STRLEN(buf)) < len) 1774 STRCAT(buf, s); 1775 } 1776 } 1777 1778 /* 1779 * print line for :print or :list command 1780 */ 1781 void 1782 msg_prt_line(char_u *s, int list) 1783 { 1784 int c; 1785 int col = 0; 1786 int n_extra = 0; 1787 int c_extra = 0; 1788 int c_final = 0; 1789 char_u *p_extra = NULL; // init to make SASC shut up 1790 int n; 1791 int attr = 0; 1792 char_u *trail = NULL; 1793 int l; 1794 char_u buf[MB_MAXBYTES + 1]; 1795 1796 if (curwin->w_p_list) 1797 list = TRUE; 1798 1799 // find start of trailing whitespace 1800 if (list && lcs_trail) 1801 { 1802 trail = s + STRLEN(s); 1803 while (trail > s && VIM_ISWHITE(trail[-1])) 1804 --trail; 1805 } 1806 1807 // output a space for an empty line, otherwise the line will be 1808 // overwritten 1809 if (*s == NUL && !(list && lcs_eol != NUL)) 1810 msg_putchar(' '); 1811 1812 while (!got_int) 1813 { 1814 if (n_extra > 0) 1815 { 1816 --n_extra; 1817 if (n_extra == 0 && c_final) 1818 c = c_final; 1819 else if (c_extra) 1820 c = c_extra; 1821 else 1822 c = *p_extra++; 1823 } 1824 else if (has_mbyte && (l = (*mb_ptr2len)(s)) > 1) 1825 { 1826 col += (*mb_ptr2cells)(s); 1827 if (lcs_nbsp != NUL && list 1828 && (mb_ptr2char(s) == 160 1829 || mb_ptr2char(s) == 0x202f)) 1830 { 1831 mb_char2bytes(lcs_nbsp, buf); 1832 buf[(*mb_ptr2len)(buf)] = NUL; 1833 } 1834 else 1835 { 1836 mch_memmove(buf, s, (size_t)l); 1837 buf[l] = NUL; 1838 } 1839 msg_puts((char *)buf); 1840 s += l; 1841 continue; 1842 } 1843 else 1844 { 1845 attr = 0; 1846 c = *s++; 1847 if (c == TAB && (!list || lcs_tab1)) 1848 { 1849 // tab amount depends on current column 1850 #ifdef FEAT_VARTABS 1851 n_extra = tabstop_padding(col, curbuf->b_p_ts, 1852 curbuf->b_p_vts_array) - 1; 1853 #else 1854 n_extra = curbuf->b_p_ts - col % curbuf->b_p_ts - 1; 1855 #endif 1856 if (!list) 1857 { 1858 c = ' '; 1859 c_extra = ' '; 1860 c_final = NUL; 1861 } 1862 else 1863 { 1864 c = (n_extra == 0 && lcs_tab3) ? lcs_tab3 : lcs_tab1; 1865 c_extra = lcs_tab2; 1866 c_final = lcs_tab3; 1867 attr = HL_ATTR(HLF_8); 1868 } 1869 } 1870 else if (c == 160 && list && lcs_nbsp != NUL) 1871 { 1872 c = lcs_nbsp; 1873 attr = HL_ATTR(HLF_8); 1874 } 1875 else if (c == NUL && list && lcs_eol != NUL) 1876 { 1877 p_extra = (char_u *)""; 1878 c_extra = NUL; 1879 c_final = NUL; 1880 n_extra = 1; 1881 c = lcs_eol; 1882 attr = HL_ATTR(HLF_AT); 1883 --s; 1884 } 1885 else if (c != NUL && (n = byte2cells(c)) > 1) 1886 { 1887 n_extra = n - 1; 1888 p_extra = transchar_byte(c); 1889 c_extra = NUL; 1890 c_final = NUL; 1891 c = *p_extra++; 1892 // Use special coloring to be able to distinguish <hex> from 1893 // the same in plain text. 1894 attr = HL_ATTR(HLF_8); 1895 } 1896 else if (c == ' ' && trail != NULL && s > trail) 1897 { 1898 c = lcs_trail; 1899 attr = HL_ATTR(HLF_8); 1900 } 1901 else if (c == ' ' && list && lcs_space != NUL) 1902 { 1903 c = lcs_space; 1904 attr = HL_ATTR(HLF_8); 1905 } 1906 } 1907 1908 if (c == NUL) 1909 break; 1910 1911 msg_putchar_attr(c, attr); 1912 col++; 1913 } 1914 msg_clr_eos(); 1915 } 1916 1917 /* 1918 * Use screen_puts() to output one multi-byte character. 1919 * Return the pointer "s" advanced to the next character. 1920 */ 1921 static char_u * 1922 screen_puts_mbyte(char_u *s, int l, int attr) 1923 { 1924 int cw; 1925 1926 msg_didout = TRUE; // remember that line is not empty 1927 cw = (*mb_ptr2cells)(s); 1928 if (cw > 1 && ( 1929 #ifdef FEAT_RIGHTLEFT 1930 cmdmsg_rl ? msg_col <= 1 : 1931 #endif 1932 msg_col == Columns - 1)) 1933 { 1934 // Doesn't fit, print a highlighted '>' to fill it up. 1935 msg_screen_putchar('>', HL_ATTR(HLF_AT)); 1936 return s; 1937 } 1938 1939 screen_puts_len(s, l, msg_row, msg_col, attr); 1940 #ifdef FEAT_RIGHTLEFT 1941 if (cmdmsg_rl) 1942 { 1943 msg_col -= cw; 1944 if (msg_col == 0) 1945 { 1946 msg_col = Columns; 1947 ++msg_row; 1948 } 1949 } 1950 else 1951 #endif 1952 { 1953 msg_col += cw; 1954 if (msg_col >= Columns) 1955 { 1956 msg_col = 0; 1957 ++msg_row; 1958 } 1959 } 1960 return s + l; 1961 } 1962 1963 /* 1964 * Output a string to the screen at position msg_row, msg_col. 1965 * Update msg_row and msg_col for the next message. 1966 */ 1967 void 1968 msg_puts(char *s) 1969 { 1970 msg_puts_attr(s, 0); 1971 } 1972 1973 void 1974 msg_puts_title(char *s) 1975 { 1976 msg_puts_attr(s, HL_ATTR(HLF_T)); 1977 } 1978 1979 /* 1980 * Show a message in such a way that it always fits in the line. Cut out a 1981 * part in the middle and replace it with "..." when necessary. 1982 * Does not handle multi-byte characters! 1983 */ 1984 static void 1985 msg_outtrans_long_len_attr(char_u *longstr, int len, int attr) 1986 { 1987 int slen = len; 1988 int room; 1989 1990 room = Columns - msg_col; 1991 if (len > room && room >= 20) 1992 { 1993 slen = (room - 3) / 2; 1994 msg_outtrans_len_attr(longstr, slen, attr); 1995 msg_puts_attr("...", HL_ATTR(HLF_8)); 1996 } 1997 msg_outtrans_len_attr(longstr + len - slen, slen, attr); 1998 } 1999 2000 void 2001 msg_outtrans_long_attr(char_u *longstr, int attr) 2002 { 2003 msg_outtrans_long_len_attr(longstr, (int)STRLEN(longstr), attr); 2004 } 2005 2006 /* 2007 * Basic function for writing a message with highlight attributes. 2008 */ 2009 void 2010 msg_puts_attr(char *s, int attr) 2011 { 2012 msg_puts_attr_len(s, -1, attr); 2013 } 2014 2015 /* 2016 * Like msg_puts_attr(), but with a maximum length "maxlen" (in bytes). 2017 * When "maxlen" is -1 there is no maximum length. 2018 * When "maxlen" is >= 0 the message is not put in the history. 2019 */ 2020 static void 2021 msg_puts_attr_len(char *str, int maxlen, int attr) 2022 { 2023 /* 2024 * If redirection is on, also write to the redirection file. 2025 */ 2026 redir_write((char_u *)str, maxlen); 2027 2028 /* 2029 * Don't print anything when using ":silent cmd". 2030 */ 2031 if (msg_silent != 0) 2032 return; 2033 2034 // if MSG_HIST flag set, add message to history 2035 if ((attr & MSG_HIST) && maxlen < 0) 2036 { 2037 add_msg_hist((char_u *)str, -1, attr); 2038 attr &= ~MSG_HIST; 2039 } 2040 2041 // When writing something to the screen after it has scrolled, requires a 2042 // wait-return prompt later. Needed when scrolling, resetting 2043 // need_wait_return after some prompt, and then outputting something 2044 // without scrolling 2045 // Not needed when only using CR to move the cursor. 2046 if (msg_scrolled != 0 && !msg_scrolled_ign && STRCMP(str, "\r") != 0) 2047 need_wait_return = TRUE; 2048 msg_didany = TRUE; // remember that something was outputted 2049 2050 /* 2051 * If there is no valid screen, use fprintf so we can see error messages. 2052 * If termcap is not active, we may be writing in an alternate console 2053 * window, cursor positioning may not work correctly (window size may be 2054 * different, e.g. for Win32 console) or we just don't know where the 2055 * cursor is. 2056 */ 2057 if (msg_use_printf()) 2058 msg_puts_printf((char_u *)str, maxlen); 2059 else 2060 msg_puts_display((char_u *)str, maxlen, attr, FALSE); 2061 } 2062 2063 /* 2064 * The display part of msg_puts_attr_len(). 2065 * May be called recursively to display scroll-back text. 2066 */ 2067 static void 2068 msg_puts_display( 2069 char_u *str, 2070 int maxlen, 2071 int attr, 2072 int recurse) 2073 { 2074 char_u *s = str; 2075 char_u *t_s = str; // string from "t_s" to "s" is still todo 2076 int t_col = 0; // screen cells todo, 0 when "t_s" not used 2077 int l; 2078 int cw; 2079 char_u *sb_str = str; 2080 int sb_col = msg_col; 2081 int wrap; 2082 int did_last_char; 2083 2084 did_wait_return = FALSE; 2085 while ((maxlen < 0 || (int)(s - str) < maxlen) && *s != NUL) 2086 { 2087 /* 2088 * We are at the end of the screen line when: 2089 * - When outputting a newline. 2090 * - When outputting a character in the last column. 2091 */ 2092 if (!recurse && msg_row >= Rows - 1 && (*s == '\n' || ( 2093 #ifdef FEAT_RIGHTLEFT 2094 cmdmsg_rl 2095 ? ( 2096 msg_col <= 1 2097 || (*s == TAB && msg_col <= 7) 2098 || (has_mbyte && (*mb_ptr2cells)(s) > 1 && msg_col <= 2)) 2099 : 2100 #endif 2101 ((*s != '\r' && msg_col + t_col >= Columns - 1) 2102 || (*s == TAB && msg_col + t_col >= ((Columns - 1) & ~7)) 2103 || (has_mbyte && (*mb_ptr2cells)(s) > 1 2104 && msg_col + t_col >= Columns - 2))))) 2105 { 2106 /* 2107 * The screen is scrolled up when at the last row (some terminals 2108 * scroll automatically, some don't. To avoid problems we scroll 2109 * ourselves). 2110 */ 2111 if (t_col > 0) 2112 // output postponed text 2113 t_puts(&t_col, t_s, s, attr); 2114 2115 // When no more prompt and no more room, truncate here 2116 if (msg_no_more && lines_left == 0) 2117 break; 2118 2119 // Scroll the screen up one line. 2120 msg_scroll_up(); 2121 2122 msg_row = Rows - 2; 2123 if (msg_col >= Columns) // can happen after screen resize 2124 msg_col = Columns - 1; 2125 2126 // Display char in last column before showing more-prompt. 2127 if (*s >= ' ' 2128 #ifdef FEAT_RIGHTLEFT 2129 && !cmdmsg_rl 2130 #endif 2131 ) 2132 { 2133 if (has_mbyte) 2134 { 2135 if (enc_utf8 && maxlen >= 0) 2136 // avoid including composing chars after the end 2137 l = utfc_ptr2len_len(s, (int)((str + maxlen) - s)); 2138 else 2139 l = (*mb_ptr2len)(s); 2140 s = screen_puts_mbyte(s, l, attr); 2141 } 2142 else 2143 msg_screen_putchar(*s++, attr); 2144 did_last_char = TRUE; 2145 } 2146 else 2147 did_last_char = FALSE; 2148 2149 if (p_more) 2150 // store text for scrolling back 2151 store_sb_text(&sb_str, s, attr, &sb_col, TRUE); 2152 2153 inc_msg_scrolled(); 2154 need_wait_return = TRUE; // may need wait_return in main() 2155 redraw_cmdline = TRUE; 2156 if (cmdline_row > 0 && !exmode_active) 2157 --cmdline_row; 2158 2159 /* 2160 * If screen is completely filled and 'more' is set then wait 2161 * for a character. 2162 */ 2163 if (lines_left > 0) 2164 --lines_left; 2165 if (p_more && lines_left == 0 && State != HITRETURN 2166 && !msg_no_more && !exmode_active) 2167 { 2168 #ifdef FEAT_CON_DIALOG 2169 if (do_more_prompt(NUL)) 2170 s = confirm_msg_tail; 2171 #else 2172 (void)do_more_prompt(NUL); 2173 #endif 2174 if (quit_more) 2175 return; 2176 } 2177 2178 // When we displayed a char in last column need to check if there 2179 // is still more. 2180 if (did_last_char) 2181 continue; 2182 } 2183 2184 wrap = *s == '\n' 2185 || msg_col + t_col >= Columns 2186 || (has_mbyte && (*mb_ptr2cells)(s) > 1 2187 && msg_col + t_col >= Columns - 1); 2188 if (t_col > 0 && (wrap || *s == '\r' || *s == '\b' 2189 || *s == '\t' || *s == BELL)) 2190 // output any postponed text 2191 t_puts(&t_col, t_s, s, attr); 2192 2193 if (wrap && p_more && !recurse) 2194 // store text for scrolling back 2195 store_sb_text(&sb_str, s, attr, &sb_col, TRUE); 2196 2197 if (*s == '\n') // go to next line 2198 { 2199 msg_didout = FALSE; // remember that line is empty 2200 #ifdef FEAT_RIGHTLEFT 2201 if (cmdmsg_rl) 2202 msg_col = Columns - 1; 2203 else 2204 #endif 2205 msg_col = 0; 2206 if (++msg_row >= Rows) // safety check 2207 msg_row = Rows - 1; 2208 } 2209 else if (*s == '\r') // go to column 0 2210 { 2211 msg_col = 0; 2212 } 2213 else if (*s == '\b') // go to previous char 2214 { 2215 if (msg_col) 2216 --msg_col; 2217 } 2218 else if (*s == TAB) // translate Tab into spaces 2219 { 2220 do 2221 msg_screen_putchar(' ', attr); 2222 while (msg_col & 7); 2223 } 2224 else if (*s == BELL) // beep (from ":sh") 2225 vim_beep(BO_SH); 2226 else 2227 { 2228 if (has_mbyte) 2229 { 2230 cw = (*mb_ptr2cells)(s); 2231 if (enc_utf8 && maxlen >= 0) 2232 // avoid including composing chars after the end 2233 l = utfc_ptr2len_len(s, (int)((str + maxlen) - s)); 2234 else 2235 l = (*mb_ptr2len)(s); 2236 } 2237 else 2238 { 2239 cw = 1; 2240 l = 1; 2241 } 2242 2243 // When drawing from right to left or when a double-wide character 2244 // doesn't fit, draw a single character here. Otherwise collect 2245 // characters and draw them all at once later. 2246 if ( 2247 # ifdef FEAT_RIGHTLEFT 2248 cmdmsg_rl || 2249 # endif 2250 (cw > 1 && msg_col + t_col >= Columns - 1)) 2251 { 2252 if (l > 1) 2253 s = screen_puts_mbyte(s, l, attr) - 1; 2254 else 2255 msg_screen_putchar(*s, attr); 2256 } 2257 else 2258 { 2259 // postpone this character until later 2260 if (t_col == 0) 2261 t_s = s; 2262 t_col += cw; 2263 s += l - 1; 2264 } 2265 } 2266 ++s; 2267 } 2268 2269 // output any postponed text 2270 if (t_col > 0) 2271 t_puts(&t_col, t_s, s, attr); 2272 if (p_more && !recurse) 2273 store_sb_text(&sb_str, s, attr, &sb_col, FALSE); 2274 2275 msg_check(); 2276 } 2277 2278 /* 2279 * Return TRUE when ":filter pattern" was used and "msg" does not match 2280 * "pattern". 2281 */ 2282 int 2283 message_filtered(char_u *msg) 2284 { 2285 int match; 2286 2287 if (cmdmod.filter_regmatch.regprog == NULL) 2288 return FALSE; 2289 match = vim_regexec(&cmdmod.filter_regmatch, msg, (colnr_T)0); 2290 return cmdmod.filter_force ? match : !match; 2291 } 2292 2293 /* 2294 * Scroll the screen up one line for displaying the next message line. 2295 */ 2296 static void 2297 msg_scroll_up(void) 2298 { 2299 #ifdef FEAT_GUI 2300 // Remove the cursor before scrolling, ScreenLines[] is going 2301 // to become invalid. 2302 if (gui.in_use) 2303 gui_undraw_cursor(); 2304 #endif 2305 // scrolling up always works 2306 mch_disable_flush(); 2307 screen_del_lines(0, 0, 1, (int)Rows, TRUE, 0, NULL); 2308 mch_enable_flush(); 2309 2310 if (!can_clear((char_u *)" ")) 2311 { 2312 // Scrolling up doesn't result in the right background. Set the 2313 // background here. It's not efficient, but avoids that we have to do 2314 // it all over the code. 2315 screen_fill((int)Rows - 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0); 2316 2317 // Also clear the last char of the last but one line if it was not 2318 // cleared before to avoid a scroll-up. 2319 if (ScreenAttrs[LineOffset[Rows - 2] + Columns - 1] == (sattr_T)-1) 2320 screen_fill((int)Rows - 2, (int)Rows - 1, 2321 (int)Columns - 1, (int)Columns, ' ', ' ', 0); 2322 } 2323 } 2324 2325 /* 2326 * Increment "msg_scrolled". 2327 */ 2328 static void 2329 inc_msg_scrolled(void) 2330 { 2331 #ifdef FEAT_EVAL 2332 if (*get_vim_var_str(VV_SCROLLSTART) == NUL) 2333 { 2334 char_u *p = SOURCING_NAME; 2335 char_u *tofree = NULL; 2336 int len; 2337 2338 // v:scrollstart is empty, set it to the script/function name and line 2339 // number 2340 if (p == NULL) 2341 p = (char_u *)_("Unknown"); 2342 else 2343 { 2344 len = (int)STRLEN(p) + 40; 2345 tofree = alloc(len); 2346 if (tofree != NULL) 2347 { 2348 vim_snprintf((char *)tofree, len, _("%s line %ld"), 2349 p, (long)SOURCING_LNUM); 2350 p = tofree; 2351 } 2352 } 2353 set_vim_var_string(VV_SCROLLSTART, p, -1); 2354 vim_free(tofree); 2355 } 2356 #endif 2357 ++msg_scrolled; 2358 if (must_redraw < VALID) 2359 must_redraw = VALID; 2360 } 2361 2362 /* 2363 * To be able to scroll back at the "more" and "hit-enter" prompts we need to 2364 * store the displayed text and remember where screen lines start. 2365 */ 2366 typedef struct msgchunk_S msgchunk_T; 2367 struct msgchunk_S 2368 { 2369 msgchunk_T *sb_next; 2370 msgchunk_T *sb_prev; 2371 char sb_eol; // TRUE when line ends after this text 2372 int sb_msg_col; // column in which text starts 2373 int sb_attr; // text attributes 2374 char_u sb_text[1]; // text to be displayed, actually longer 2375 }; 2376 2377 static msgchunk_T *last_msgchunk = NULL; // last displayed text 2378 2379 static msgchunk_T *msg_sb_start(msgchunk_T *mps); 2380 2381 typedef enum { 2382 SB_CLEAR_NONE = 0, 2383 SB_CLEAR_ALL, 2384 SB_CLEAR_CMDLINE_BUSY, 2385 SB_CLEAR_CMDLINE_DONE 2386 } sb_clear_T; 2387 2388 // When to clear text on next msg. 2389 static sb_clear_T do_clear_sb_text = SB_CLEAR_NONE; 2390 2391 /* 2392 * Store part of a printed message for displaying when scrolling back. 2393 */ 2394 static void 2395 store_sb_text( 2396 char_u **sb_str, // start of string 2397 char_u *s, // just after string 2398 int attr, 2399 int *sb_col, 2400 int finish) // line ends 2401 { 2402 msgchunk_T *mp; 2403 2404 if (do_clear_sb_text == SB_CLEAR_ALL 2405 || do_clear_sb_text == SB_CLEAR_CMDLINE_DONE) 2406 { 2407 clear_sb_text(do_clear_sb_text == SB_CLEAR_ALL); 2408 do_clear_sb_text = SB_CLEAR_NONE; 2409 } 2410 2411 if (s > *sb_str) 2412 { 2413 mp = alloc(sizeof(msgchunk_T) + (s - *sb_str)); 2414 if (mp != NULL) 2415 { 2416 mp->sb_eol = finish; 2417 mp->sb_msg_col = *sb_col; 2418 mp->sb_attr = attr; 2419 vim_strncpy(mp->sb_text, *sb_str, s - *sb_str); 2420 2421 if (last_msgchunk == NULL) 2422 { 2423 last_msgchunk = mp; 2424 mp->sb_prev = NULL; 2425 } 2426 else 2427 { 2428 mp->sb_prev = last_msgchunk; 2429 last_msgchunk->sb_next = mp; 2430 last_msgchunk = mp; 2431 } 2432 mp->sb_next = NULL; 2433 } 2434 } 2435 else if (finish && last_msgchunk != NULL) 2436 last_msgchunk->sb_eol = TRUE; 2437 2438 *sb_str = s; 2439 *sb_col = 0; 2440 } 2441 2442 /* 2443 * Finished showing messages, clear the scroll-back text on the next message. 2444 */ 2445 void 2446 may_clear_sb_text(void) 2447 { 2448 do_clear_sb_text = SB_CLEAR_ALL; 2449 } 2450 2451 /* 2452 * Starting to edit the command line, do not clear messages now. 2453 */ 2454 void 2455 sb_text_start_cmdline(void) 2456 { 2457 do_clear_sb_text = SB_CLEAR_CMDLINE_BUSY; 2458 msg_sb_eol(); 2459 } 2460 2461 /* 2462 * Ending to edit the command line. Clear old lines but the last one later. 2463 */ 2464 void 2465 sb_text_end_cmdline(void) 2466 { 2467 do_clear_sb_text = SB_CLEAR_CMDLINE_DONE; 2468 } 2469 2470 /* 2471 * Clear any text remembered for scrolling back. 2472 * When "all" is FALSE keep the last line. 2473 * Called when redrawing the screen. 2474 */ 2475 void 2476 clear_sb_text(int all) 2477 { 2478 msgchunk_T *mp; 2479 msgchunk_T **lastp; 2480 2481 if (all) 2482 lastp = &last_msgchunk; 2483 else 2484 { 2485 if (last_msgchunk == NULL) 2486 return; 2487 lastp = &last_msgchunk->sb_prev; 2488 } 2489 2490 while (*lastp != NULL) 2491 { 2492 mp = (*lastp)->sb_prev; 2493 vim_free(*lastp); 2494 *lastp = mp; 2495 } 2496 } 2497 2498 /* 2499 * "g<" command. 2500 */ 2501 void 2502 show_sb_text(void) 2503 { 2504 msgchunk_T *mp; 2505 2506 // Only show something if there is more than one line, otherwise it looks 2507 // weird, typing a command without output results in one line. 2508 mp = msg_sb_start(last_msgchunk); 2509 if (mp == NULL || mp->sb_prev == NULL) 2510 vim_beep(BO_MESS); 2511 else 2512 { 2513 do_more_prompt('G'); 2514 wait_return(FALSE); 2515 } 2516 } 2517 2518 /* 2519 * Move to the start of screen line in already displayed text. 2520 */ 2521 static msgchunk_T * 2522 msg_sb_start(msgchunk_T *mps) 2523 { 2524 msgchunk_T *mp = mps; 2525 2526 while (mp != NULL && mp->sb_prev != NULL && !mp->sb_prev->sb_eol) 2527 mp = mp->sb_prev; 2528 return mp; 2529 } 2530 2531 /* 2532 * Mark the last message chunk as finishing the line. 2533 */ 2534 void 2535 msg_sb_eol(void) 2536 { 2537 if (last_msgchunk != NULL) 2538 last_msgchunk->sb_eol = TRUE; 2539 } 2540 2541 /* 2542 * Display a screen line from previously displayed text at row "row". 2543 * Returns a pointer to the text for the next line (can be NULL). 2544 */ 2545 static msgchunk_T * 2546 disp_sb_line(int row, msgchunk_T *smp) 2547 { 2548 msgchunk_T *mp = smp; 2549 char_u *p; 2550 2551 for (;;) 2552 { 2553 msg_row = row; 2554 msg_col = mp->sb_msg_col; 2555 p = mp->sb_text; 2556 if (*p == '\n') // don't display the line break 2557 ++p; 2558 msg_puts_display(p, -1, mp->sb_attr, TRUE); 2559 if (mp->sb_eol || mp->sb_next == NULL) 2560 break; 2561 mp = mp->sb_next; 2562 } 2563 return mp->sb_next; 2564 } 2565 2566 /* 2567 * Output any postponed text for msg_puts_attr_len(). 2568 */ 2569 static void 2570 t_puts( 2571 int *t_col, 2572 char_u *t_s, 2573 char_u *s, 2574 int attr) 2575 { 2576 // output postponed text 2577 msg_didout = TRUE; // remember that line is not empty 2578 screen_puts_len(t_s, (int)(s - t_s), msg_row, msg_col, attr); 2579 msg_col += *t_col; 2580 *t_col = 0; 2581 // If the string starts with a composing character don't increment the 2582 // column position for it. 2583 if (enc_utf8 && utf_iscomposing(utf_ptr2char(t_s))) 2584 --msg_col; 2585 if (msg_col >= Columns) 2586 { 2587 msg_col = 0; 2588 ++msg_row; 2589 } 2590 } 2591 2592 /* 2593 * Returns TRUE when messages should be printed with mch_errmsg(). 2594 * This is used when there is no valid screen, so we can see error messages. 2595 * If termcap is not active, we may be writing in an alternate console 2596 * window, cursor positioning may not work correctly (window size may be 2597 * different, e.g. for Win32 console) or we just don't know where the 2598 * cursor is. 2599 */ 2600 int 2601 msg_use_printf(void) 2602 { 2603 return (!msg_check_screen() 2604 #if defined(MSWIN) && (!defined(FEAT_GUI_MSWIN) || defined(VIMDLL)) 2605 # ifdef VIMDLL 2606 || (!gui.in_use && !termcap_active) 2607 # else 2608 || !termcap_active 2609 # endif 2610 #endif 2611 || (swapping_screen() && !termcap_active) 2612 ); 2613 } 2614 2615 /* 2616 * Print a message when there is no valid screen. 2617 */ 2618 static void 2619 msg_puts_printf(char_u *str, int maxlen) 2620 { 2621 char_u *s = str; 2622 char_u *buf = NULL; 2623 char_u *p = s; 2624 2625 #ifdef MSWIN 2626 if (!(silent_mode && p_verbose == 0)) 2627 mch_settmode(TMODE_COOK); // handle CR and NL correctly 2628 #endif 2629 while ((maxlen < 0 || (int)(s - str) < maxlen) && *s != NUL) 2630 { 2631 if (!(silent_mode && p_verbose == 0)) 2632 { 2633 // NL --> CR NL translation (for Unix, not for "--version") 2634 if (*s == NL) 2635 { 2636 int n = (int)(s - p); 2637 2638 buf = alloc(n + 3); 2639 if (buf != NULL) 2640 { 2641 memcpy(buf, p, n); 2642 if (!info_message) 2643 buf[n++] = CAR; 2644 buf[n++] = NL; 2645 buf[n++] = NUL; 2646 if (info_message) // informative message, not an error 2647 mch_msg((char *)buf); 2648 else 2649 mch_errmsg((char *)buf); 2650 vim_free(buf); 2651 } 2652 p = s + 1; 2653 } 2654 } 2655 2656 // primitive way to compute the current column 2657 #ifdef FEAT_RIGHTLEFT 2658 if (cmdmsg_rl) 2659 { 2660 if (*s == CAR || *s == NL) 2661 msg_col = Columns - 1; 2662 else 2663 --msg_col; 2664 } 2665 else 2666 #endif 2667 { 2668 if (*s == CAR || *s == NL) 2669 msg_col = 0; 2670 else 2671 ++msg_col; 2672 } 2673 ++s; 2674 } 2675 2676 if (*p != NUL && !(silent_mode && p_verbose == 0)) 2677 { 2678 int c = -1; 2679 2680 if (maxlen > 0 && STRLEN(p) > (size_t)maxlen) 2681 { 2682 c = p[maxlen]; 2683 p[maxlen] = 0; 2684 } 2685 if (info_message) 2686 mch_msg((char *)p); 2687 else 2688 mch_errmsg((char *)p); 2689 if (c != -1) 2690 p[maxlen] = c; 2691 } 2692 2693 msg_didout = TRUE; // assume that line is not empty 2694 2695 #ifdef MSWIN 2696 if (!(silent_mode && p_verbose == 0)) 2697 mch_settmode(TMODE_RAW); 2698 #endif 2699 } 2700 2701 /* 2702 * Show the more-prompt and handle the user response. 2703 * This takes care of scrolling back and displaying previously displayed text. 2704 * When at hit-enter prompt "typed_char" is the already typed character, 2705 * otherwise it's NUL. 2706 * Returns TRUE when jumping ahead to "confirm_msg_tail". 2707 */ 2708 static int 2709 do_more_prompt(int typed_char) 2710 { 2711 static int entered = FALSE; 2712 int used_typed_char = typed_char; 2713 int oldState = State; 2714 int c; 2715 #ifdef FEAT_CON_DIALOG 2716 int retval = FALSE; 2717 #endif 2718 int toscroll; 2719 msgchunk_T *mp_last = NULL; 2720 msgchunk_T *mp; 2721 int i; 2722 2723 // We get called recursively when a timer callback outputs a message. In 2724 // that case don't show another prompt. Also when at the hit-Enter prompt 2725 // and nothing was typed. 2726 if (entered || (State == HITRETURN && typed_char == 0)) 2727 return FALSE; 2728 entered = TRUE; 2729 2730 if (typed_char == 'G') 2731 { 2732 // "g<": Find first line on the last page. 2733 mp_last = msg_sb_start(last_msgchunk); 2734 for (i = 0; i < Rows - 2 && mp_last != NULL 2735 && mp_last->sb_prev != NULL; ++i) 2736 mp_last = msg_sb_start(mp_last->sb_prev); 2737 } 2738 2739 State = ASKMORE; 2740 setmouse(); 2741 if (typed_char == NUL) 2742 msg_moremsg(FALSE); 2743 for (;;) 2744 { 2745 /* 2746 * Get a typed character directly from the user. 2747 */ 2748 if (used_typed_char != NUL) 2749 { 2750 c = used_typed_char; // was typed at hit-enter prompt 2751 used_typed_char = NUL; 2752 } 2753 else 2754 c = get_keystroke(); 2755 2756 #if defined(FEAT_MENU) && defined(FEAT_GUI) 2757 if (c == K_MENU) 2758 { 2759 int idx = get_menu_index(current_menu, ASKMORE); 2760 2761 // Used a menu. If it starts with CTRL-Y, it must 2762 // be a "Copy" for the clipboard. Otherwise 2763 // assume that we end 2764 if (idx == MENU_INDEX_INVALID) 2765 continue; 2766 c = *current_menu->strings[idx]; 2767 if (c != NUL && current_menu->strings[idx][1] != NUL) 2768 ins_typebuf(current_menu->strings[idx] + 1, 2769 current_menu->noremap[idx], 0, TRUE, 2770 current_menu->silent[idx]); 2771 } 2772 #endif 2773 2774 toscroll = 0; 2775 switch (c) 2776 { 2777 case BS: // scroll one line back 2778 case K_BS: 2779 case 'k': 2780 case K_UP: 2781 toscroll = -1; 2782 break; 2783 2784 case CAR: // one extra line 2785 case NL: 2786 case 'j': 2787 case K_DOWN: 2788 toscroll = 1; 2789 break; 2790 2791 case 'u': // Up half a page 2792 toscroll = -(Rows / 2); 2793 break; 2794 2795 case 'd': // Down half a page 2796 toscroll = Rows / 2; 2797 break; 2798 2799 case 'b': // one page back 2800 case K_PAGEUP: 2801 toscroll = -(Rows - 1); 2802 break; 2803 2804 case ' ': // one extra page 2805 case 'f': 2806 case K_PAGEDOWN: 2807 case K_LEFTMOUSE: 2808 toscroll = Rows - 1; 2809 break; 2810 2811 case 'g': // all the way back to the start 2812 toscroll = -999999; 2813 break; 2814 2815 case 'G': // all the way to the end 2816 toscroll = 999999; 2817 lines_left = 999999; 2818 break; 2819 2820 case ':': // start new command line 2821 #ifdef FEAT_CON_DIALOG 2822 if (!confirm_msg_used) 2823 #endif 2824 { 2825 // Since got_int is set all typeahead will be flushed, but we 2826 // want to keep this ':', remember that in a special way. 2827 typeahead_noflush(':'); 2828 #ifdef FEAT_TERMINAL 2829 skip_term_loop = TRUE; 2830 #endif 2831 cmdline_row = Rows - 1; // put ':' on this line 2832 skip_redraw = TRUE; // skip redraw once 2833 need_wait_return = FALSE; // don't wait in main() 2834 } 2835 // FALLTHROUGH 2836 case 'q': // quit 2837 case Ctrl_C: 2838 case ESC: 2839 #ifdef FEAT_CON_DIALOG 2840 if (confirm_msg_used) 2841 { 2842 // Jump to the choices of the dialog. 2843 retval = TRUE; 2844 } 2845 else 2846 #endif 2847 { 2848 got_int = TRUE; 2849 quit_more = TRUE; 2850 } 2851 // When there is some more output (wrapping line) display that 2852 // without another prompt. 2853 lines_left = Rows - 1; 2854 break; 2855 2856 #ifdef FEAT_CLIPBOARD 2857 case Ctrl_Y: 2858 // Strange way to allow copying (yanking) a modeless 2859 // selection at the more prompt. Use CTRL-Y, 2860 // because the same is used in Cmdline-mode and at the 2861 // hit-enter prompt. However, scrolling one line up 2862 // might be expected... 2863 if (clip_star.state == SELECT_DONE) 2864 clip_copy_modeless_selection(TRUE); 2865 continue; 2866 #endif 2867 default: // no valid response 2868 msg_moremsg(TRUE); 2869 continue; 2870 } 2871 2872 if (toscroll != 0) 2873 { 2874 if (toscroll < 0) 2875 { 2876 // go to start of last line 2877 if (mp_last == NULL) 2878 mp = msg_sb_start(last_msgchunk); 2879 else if (mp_last->sb_prev != NULL) 2880 mp = msg_sb_start(mp_last->sb_prev); 2881 else 2882 mp = NULL; 2883 2884 // go to start of line at top of the screen 2885 for (i = 0; i < Rows - 2 && mp != NULL && mp->sb_prev != NULL; 2886 ++i) 2887 mp = msg_sb_start(mp->sb_prev); 2888 2889 if (mp != NULL && mp->sb_prev != NULL) 2890 { 2891 // Find line to be displayed at top. 2892 for (i = 0; i > toscroll; --i) 2893 { 2894 if (mp == NULL || mp->sb_prev == NULL) 2895 break; 2896 mp = msg_sb_start(mp->sb_prev); 2897 if (mp_last == NULL) 2898 mp_last = msg_sb_start(last_msgchunk); 2899 else 2900 mp_last = msg_sb_start(mp_last->sb_prev); 2901 } 2902 2903 if (toscroll == -1 && screen_ins_lines(0, 0, 1, 2904 (int)Rows, 0, NULL) == OK) 2905 { 2906 // display line at top 2907 (void)disp_sb_line(0, mp); 2908 } 2909 else 2910 { 2911 // redisplay all lines 2912 screenclear(); 2913 for (i = 0; mp != NULL && i < Rows - 1; ++i) 2914 { 2915 mp = disp_sb_line(i, mp); 2916 ++msg_scrolled; 2917 } 2918 } 2919 toscroll = 0; 2920 } 2921 } 2922 else 2923 { 2924 // First display any text that we scrolled back. 2925 while (toscroll > 0 && mp_last != NULL) 2926 { 2927 // scroll up, display line at bottom 2928 msg_scroll_up(); 2929 inc_msg_scrolled(); 2930 screen_fill((int)Rows - 2, (int)Rows - 1, 0, 2931 (int)Columns, ' ', ' ', 0); 2932 mp_last = disp_sb_line((int)Rows - 2, mp_last); 2933 --toscroll; 2934 } 2935 } 2936 2937 if (toscroll <= 0) 2938 { 2939 // displayed the requested text, more prompt again 2940 screen_fill((int)Rows - 1, (int)Rows, 0, 2941 (int)Columns, ' ', ' ', 0); 2942 msg_moremsg(FALSE); 2943 continue; 2944 } 2945 2946 // display more text, return to caller 2947 lines_left = toscroll; 2948 } 2949 2950 break; 2951 } 2952 2953 // clear the --more-- message 2954 screen_fill((int)Rows - 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0); 2955 State = oldState; 2956 setmouse(); 2957 if (quit_more) 2958 { 2959 msg_row = Rows - 1; 2960 msg_col = 0; 2961 } 2962 #ifdef FEAT_RIGHTLEFT 2963 else if (cmdmsg_rl) 2964 msg_col = Columns - 1; 2965 #endif 2966 2967 entered = FALSE; 2968 #ifdef FEAT_CON_DIALOG 2969 return retval; 2970 #else 2971 return FALSE; 2972 #endif 2973 } 2974 2975 #if defined(USE_MCH_ERRMSG) || defined(PROTO) 2976 2977 #ifdef mch_errmsg 2978 # undef mch_errmsg 2979 #endif 2980 #ifdef mch_msg 2981 # undef mch_msg 2982 #endif 2983 2984 #if defined(MSWIN) && (!defined(FEAT_GUI_MSWIN) || defined(VIMDLL)) 2985 static void 2986 mch_errmsg_c(char *str) 2987 { 2988 int len = (int)STRLEN(str); 2989 DWORD nwrite = 0; 2990 DWORD mode = 0; 2991 HANDLE h = GetStdHandle(STD_ERROR_HANDLE); 2992 2993 if (GetConsoleMode(h, &mode) && enc_codepage >= 0 2994 && (int)GetConsoleCP() != enc_codepage) 2995 { 2996 WCHAR *w = enc_to_utf16((char_u *)str, &len); 2997 2998 WriteConsoleW(h, w, len, &nwrite, NULL); 2999 vim_free(w); 3000 } 3001 else 3002 { 3003 fprintf(stderr, "%s", str); 3004 } 3005 } 3006 #endif 3007 3008 /* 3009 * Give an error message. To be used when the screen hasn't been initialized 3010 * yet. When stderr can't be used, collect error messages until the GUI has 3011 * started and they can be displayed in a message box. 3012 */ 3013 void 3014 mch_errmsg(char *str) 3015 { 3016 #if !defined(MSWIN) || defined(FEAT_GUI_MSWIN) 3017 int len; 3018 #endif 3019 3020 #if (defined(UNIX) || defined(FEAT_GUI)) && !defined(ALWAYS_USE_GUI) && !defined(VIMDLL) 3021 // On Unix use stderr if it's a tty. 3022 // When not going to start the GUI also use stderr. 3023 // On Mac, when started from Finder, stderr is the console. 3024 if ( 3025 # ifdef UNIX 3026 # ifdef MACOS_X 3027 (isatty(2) && strcmp("/dev/console", ttyname(2)) != 0) 3028 # else 3029 isatty(2) 3030 # endif 3031 # ifdef FEAT_GUI 3032 || 3033 # endif 3034 # endif 3035 # ifdef FEAT_GUI 3036 !(gui.in_use || gui.starting) 3037 # endif 3038 ) 3039 { 3040 fprintf(stderr, "%s", str); 3041 return; 3042 } 3043 #endif 3044 3045 #if defined(MSWIN) && (!defined(FEAT_GUI_MSWIN) || defined(VIMDLL)) 3046 # ifdef VIMDLL 3047 if (!(gui.in_use || gui.starting)) 3048 # endif 3049 { 3050 mch_errmsg_c(str); 3051 return; 3052 } 3053 #endif 3054 3055 #if !defined(MSWIN) || defined(FEAT_GUI_MSWIN) 3056 // avoid a delay for a message that isn't there 3057 emsg_on_display = FALSE; 3058 3059 len = (int)STRLEN(str) + 1; 3060 if (error_ga.ga_growsize == 0) 3061 { 3062 error_ga.ga_growsize = 80; 3063 error_ga.ga_itemsize = 1; 3064 } 3065 if (ga_grow(&error_ga, len) == OK) 3066 { 3067 mch_memmove((char_u *)error_ga.ga_data + error_ga.ga_len, 3068 (char_u *)str, len); 3069 # ifdef UNIX 3070 // remove CR characters, they are displayed 3071 { 3072 char_u *p; 3073 3074 p = (char_u *)error_ga.ga_data + error_ga.ga_len; 3075 for (;;) 3076 { 3077 p = vim_strchr(p, '\r'); 3078 if (p == NULL) 3079 break; 3080 *p = ' '; 3081 } 3082 } 3083 # endif 3084 --len; // don't count the NUL at the end 3085 error_ga.ga_len += len; 3086 } 3087 #endif 3088 } 3089 3090 #if defined(MSWIN) && (!defined(FEAT_GUI_MSWIN) || defined(VIMDLL)) 3091 static void 3092 mch_msg_c(char *str) 3093 { 3094 int len = (int)STRLEN(str); 3095 DWORD nwrite = 0; 3096 DWORD mode; 3097 HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); 3098 3099 3100 if (GetConsoleMode(h, &mode) && enc_codepage >= 0 3101 && (int)GetConsoleCP() != enc_codepage) 3102 { 3103 WCHAR *w = enc_to_utf16((char_u *)str, &len); 3104 3105 WriteConsoleW(h, w, len, &nwrite, NULL); 3106 vim_free(w); 3107 } 3108 else 3109 { 3110 printf("%s", str); 3111 } 3112 } 3113 #endif 3114 3115 /* 3116 * Give a message. To be used when the screen hasn't been initialized yet. 3117 * When there is no tty, collect messages until the GUI has started and they 3118 * can be displayed in a message box. 3119 */ 3120 void 3121 mch_msg(char *str) 3122 { 3123 #if (defined(UNIX) || defined(FEAT_GUI)) && !defined(ALWAYS_USE_GUI) && !defined(VIMDLL) 3124 // On Unix use stdout if we have a tty. This allows "vim -h | more" and 3125 // uses mch_errmsg() when started from the desktop. 3126 // When not going to start the GUI also use stdout. 3127 // On Mac, when started from Finder, stderr is the console. 3128 if ( 3129 # ifdef UNIX 3130 # ifdef MACOS_X 3131 (isatty(2) && strcmp("/dev/console", ttyname(2)) != 0) 3132 # else 3133 isatty(2) 3134 # endif 3135 # ifdef FEAT_GUI 3136 || 3137 # endif 3138 # endif 3139 # ifdef FEAT_GUI 3140 !(gui.in_use || gui.starting) 3141 # endif 3142 ) 3143 { 3144 printf("%s", str); 3145 return; 3146 } 3147 #endif 3148 3149 #if defined(MSWIN) && (!defined(FEAT_GUI_MSWIN) || defined(VIMDLL)) 3150 # ifdef VIMDLL 3151 if (!(gui.in_use || gui.starting)) 3152 # endif 3153 { 3154 mch_msg_c(str); 3155 return; 3156 } 3157 #endif 3158 #if !defined(MSWIN) || defined(FEAT_GUI_MSWIN) 3159 mch_errmsg(str); 3160 #endif 3161 } 3162 #endif // USE_MCH_ERRMSG 3163 3164 /* 3165 * Put a character on the screen at the current message position and advance 3166 * to the next position. Only for printable ASCII! 3167 */ 3168 static void 3169 msg_screen_putchar(int c, int attr) 3170 { 3171 msg_didout = TRUE; // remember that line is not empty 3172 screen_putchar(c, msg_row, msg_col, attr); 3173 #ifdef FEAT_RIGHTLEFT 3174 if (cmdmsg_rl) 3175 { 3176 if (--msg_col == 0) 3177 { 3178 msg_col = Columns; 3179 ++msg_row; 3180 } 3181 } 3182 else 3183 #endif 3184 { 3185 if (++msg_col >= Columns) 3186 { 3187 msg_col = 0; 3188 ++msg_row; 3189 } 3190 } 3191 } 3192 3193 static void 3194 msg_moremsg(int full) 3195 { 3196 int attr; 3197 char_u *s = (char_u *)_("-- More --"); 3198 3199 attr = HL_ATTR(HLF_M); 3200 screen_puts(s, (int)Rows - 1, 0, attr); 3201 if (full) 3202 screen_puts((char_u *) 3203 _(" SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "), 3204 (int)Rows - 1, vim_strsize(s), attr); 3205 } 3206 3207 /* 3208 * Repeat the message for the current mode: ASKMORE, EXTERNCMD, CONFIRM or 3209 * exmode_active. 3210 */ 3211 void 3212 repeat_message(void) 3213 { 3214 if (State == ASKMORE) 3215 { 3216 msg_moremsg(TRUE); // display --more-- message again 3217 msg_row = Rows - 1; 3218 } 3219 #ifdef FEAT_CON_DIALOG 3220 else if (State == CONFIRM) 3221 { 3222 display_confirm_msg(); // display ":confirm" message again 3223 msg_row = Rows - 1; 3224 } 3225 #endif 3226 else if (State == EXTERNCMD) 3227 { 3228 windgoto(msg_row, msg_col); // put cursor back 3229 } 3230 else if (State == HITRETURN || State == SETWSIZE) 3231 { 3232 if (msg_row == Rows - 1) 3233 { 3234 // Avoid drawing the "hit-enter" prompt below the previous one, 3235 // overwrite it. Esp. useful when regaining focus and a 3236 // FocusGained autocmd exists but didn't draw anything. 3237 msg_didout = FALSE; 3238 msg_col = 0; 3239 msg_clr_eos(); 3240 } 3241 hit_return_msg(); 3242 msg_row = Rows - 1; 3243 } 3244 } 3245 3246 /* 3247 * msg_check_screen - check if the screen is initialized. 3248 * Also check msg_row and msg_col, if they are too big it may cause a crash. 3249 * While starting the GUI the terminal codes will be set for the GUI, but the 3250 * output goes to the terminal. Don't use the terminal codes then. 3251 */ 3252 static int 3253 msg_check_screen(void) 3254 { 3255 if (!full_screen || !screen_valid(FALSE)) 3256 return FALSE; 3257 3258 if (msg_row >= Rows) 3259 msg_row = Rows - 1; 3260 if (msg_col >= Columns) 3261 msg_col = Columns - 1; 3262 return TRUE; 3263 } 3264 3265 /* 3266 * Clear from current message position to end of screen. 3267 * Skip this when ":silent" was used, no need to clear for redirection. 3268 */ 3269 void 3270 msg_clr_eos(void) 3271 { 3272 if (msg_silent == 0) 3273 msg_clr_eos_force(); 3274 } 3275 3276 /* 3277 * Clear from current message position to end of screen. 3278 * Note: msg_col is not updated, so we remember the end of the message 3279 * for msg_check(). 3280 */ 3281 void 3282 msg_clr_eos_force(void) 3283 { 3284 if (msg_use_printf()) 3285 { 3286 if (full_screen) // only when termcap codes are valid 3287 { 3288 if (*T_CD) 3289 out_str(T_CD); // clear to end of display 3290 else if (*T_CE) 3291 out_str(T_CE); // clear to end of line 3292 } 3293 } 3294 else 3295 { 3296 #ifdef FEAT_RIGHTLEFT 3297 if (cmdmsg_rl) 3298 { 3299 screen_fill(msg_row, msg_row + 1, 0, msg_col + 1, ' ', ' ', 0); 3300 screen_fill(msg_row + 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0); 3301 } 3302 else 3303 #endif 3304 { 3305 screen_fill(msg_row, msg_row + 1, msg_col, (int)Columns, 3306 ' ', ' ', 0); 3307 screen_fill(msg_row + 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0); 3308 } 3309 } 3310 } 3311 3312 /* 3313 * Clear the command line. 3314 */ 3315 void 3316 msg_clr_cmdline(void) 3317 { 3318 msg_row = cmdline_row; 3319 msg_col = 0; 3320 msg_clr_eos_force(); 3321 } 3322 3323 /* 3324 * end putting a message on the screen 3325 * call wait_return if the message does not fit in the available space 3326 * return TRUE if wait_return not called. 3327 */ 3328 int 3329 msg_end(void) 3330 { 3331 /* 3332 * If the string is larger than the window, 3333 * or the ruler option is set and we run into it, 3334 * we have to redraw the window. 3335 * Do not do this if we are abandoning the file or editing the command line. 3336 */ 3337 if (!exiting && need_wait_return && !(State & CMDLINE)) 3338 { 3339 wait_return(FALSE); 3340 return FALSE; 3341 } 3342 out_flush(); 3343 return TRUE; 3344 } 3345 3346 /* 3347 * If the written message runs into the shown command or ruler, we have to 3348 * wait for hit-return and redraw the window later. 3349 */ 3350 void 3351 msg_check(void) 3352 { 3353 if (msg_row == Rows - 1 && msg_col >= sc_col) 3354 { 3355 need_wait_return = TRUE; 3356 redraw_cmdline = TRUE; 3357 } 3358 } 3359 3360 /* 3361 * May write a string to the redirection file. 3362 * When "maxlen" is -1 write the whole string, otherwise up to "maxlen" bytes. 3363 */ 3364 static void 3365 redir_write(char_u *str, int maxlen) 3366 { 3367 char_u *s = str; 3368 static int cur_col = 0; 3369 3370 // Don't do anything for displaying prompts and the like. 3371 if (redir_off) 3372 return; 3373 3374 // If 'verbosefile' is set prepare for writing in that file. 3375 if (*p_vfile != NUL && verbose_fd == NULL) 3376 verbose_open(); 3377 3378 if (redirecting()) 3379 { 3380 // If the string doesn't start with CR or NL, go to msg_col 3381 if (*s != '\n' && *s != '\r') 3382 { 3383 while (cur_col < msg_col) 3384 { 3385 #ifdef FEAT_EVAL 3386 if (redir_execute) 3387 execute_redir_str((char_u *)" ", -1); 3388 else if (redir_reg) 3389 write_reg_contents(redir_reg, (char_u *)" ", -1, TRUE); 3390 else if (redir_vname) 3391 var_redir_str((char_u *)" ", -1); 3392 else 3393 #endif 3394 if (redir_fd != NULL) 3395 fputs(" ", redir_fd); 3396 if (verbose_fd != NULL) 3397 fputs(" ", verbose_fd); 3398 ++cur_col; 3399 } 3400 } 3401 3402 #ifdef FEAT_EVAL 3403 if (redir_execute) 3404 execute_redir_str(s, maxlen); 3405 else if (redir_reg) 3406 write_reg_contents(redir_reg, s, maxlen, TRUE); 3407 else if (redir_vname) 3408 var_redir_str(s, maxlen); 3409 #endif 3410 3411 // Write and adjust the current column. 3412 while (*s != NUL && (maxlen < 0 || (int)(s - str) < maxlen)) 3413 { 3414 #ifdef FEAT_EVAL 3415 if (!redir_reg && !redir_vname && !redir_execute) 3416 #endif 3417 if (redir_fd != NULL) 3418 putc(*s, redir_fd); 3419 if (verbose_fd != NULL) 3420 putc(*s, verbose_fd); 3421 if (*s == '\r' || *s == '\n') 3422 cur_col = 0; 3423 else if (*s == '\t') 3424 cur_col += (8 - cur_col % 8); 3425 else 3426 ++cur_col; 3427 ++s; 3428 } 3429 3430 if (msg_silent != 0) // should update msg_col 3431 msg_col = cur_col; 3432 } 3433 } 3434 3435 int 3436 redirecting(void) 3437 { 3438 return redir_fd != NULL || *p_vfile != NUL 3439 #ifdef FEAT_EVAL 3440 || redir_reg || redir_vname || redir_execute 3441 #endif 3442 ; 3443 } 3444 3445 /* 3446 * Before giving verbose message. 3447 * Must always be called paired with verbose_leave()! 3448 */ 3449 void 3450 verbose_enter(void) 3451 { 3452 if (*p_vfile != NUL) 3453 ++msg_silent; 3454 } 3455 3456 /* 3457 * After giving verbose message. 3458 * Must always be called paired with verbose_enter()! 3459 */ 3460 void 3461 verbose_leave(void) 3462 { 3463 if (*p_vfile != NUL) 3464 if (--msg_silent < 0) 3465 msg_silent = 0; 3466 } 3467 3468 /* 3469 * Like verbose_enter() and set msg_scroll when displaying the message. 3470 */ 3471 void 3472 verbose_enter_scroll(void) 3473 { 3474 if (*p_vfile != NUL) 3475 ++msg_silent; 3476 else 3477 // always scroll up, don't overwrite 3478 msg_scroll = TRUE; 3479 } 3480 3481 /* 3482 * Like verbose_leave() and set cmdline_row when displaying the message. 3483 */ 3484 void 3485 verbose_leave_scroll(void) 3486 { 3487 if (*p_vfile != NUL) 3488 { 3489 if (--msg_silent < 0) 3490 msg_silent = 0; 3491 } 3492 else 3493 cmdline_row = msg_row; 3494 } 3495 3496 /* 3497 * Called when 'verbosefile' is set: stop writing to the file. 3498 */ 3499 void 3500 verbose_stop(void) 3501 { 3502 if (verbose_fd != NULL) 3503 { 3504 fclose(verbose_fd); 3505 verbose_fd = NULL; 3506 } 3507 verbose_did_open = FALSE; 3508 } 3509 3510 /* 3511 * Open the file 'verbosefile'. 3512 * Return FAIL or OK. 3513 */ 3514 int 3515 verbose_open(void) 3516 { 3517 if (verbose_fd == NULL && !verbose_did_open) 3518 { 3519 // Only give the error message once. 3520 verbose_did_open = TRUE; 3521 3522 verbose_fd = mch_fopen((char *)p_vfile, "a"); 3523 if (verbose_fd == NULL) 3524 { 3525 semsg(_(e_notopen), p_vfile); 3526 return FAIL; 3527 } 3528 } 3529 return OK; 3530 } 3531 3532 /* 3533 * Give a warning message (for searching). 3534 * Use 'w' highlighting and may repeat the message after redrawing 3535 */ 3536 void 3537 give_warning(char_u *message, int hl) 3538 { 3539 // Don't do this for ":silent". 3540 if (msg_silent != 0) 3541 return; 3542 3543 // Don't want a hit-enter prompt here. 3544 ++no_wait_return; 3545 3546 #ifdef FEAT_EVAL 3547 set_vim_var_string(VV_WARNINGMSG, message, -1); 3548 #endif 3549 VIM_CLEAR(keep_msg); 3550 if (hl) 3551 keep_msg_attr = HL_ATTR(HLF_W); 3552 else 3553 keep_msg_attr = 0; 3554 if (msg_attr((char *)message, keep_msg_attr) && msg_scrolled == 0) 3555 set_keep_msg(message, keep_msg_attr); 3556 msg_didout = FALSE; // overwrite this message 3557 msg_nowait = TRUE; // don't wait for this message 3558 msg_col = 0; 3559 3560 --no_wait_return; 3561 } 3562 3563 #if defined(FEAT_EVAL) || defined(PROTO) 3564 void 3565 give_warning2(char_u *message, char_u *a1, int hl) 3566 { 3567 if (IObuff == NULL) 3568 { 3569 // Very early in initialisation and already something wrong, just give 3570 // the raw message so the user at least gets a hint. 3571 give_warning((char_u *)message, hl); 3572 } 3573 else 3574 { 3575 vim_snprintf((char *)IObuff, IOSIZE, (char *)message, a1); 3576 give_warning(IObuff, hl); 3577 } 3578 } 3579 #endif 3580 3581 /* 3582 * Advance msg cursor to column "col". 3583 */ 3584 void 3585 msg_advance(int col) 3586 { 3587 if (msg_silent != 0) // nothing to advance to 3588 { 3589 msg_col = col; // for redirection, may fill it up later 3590 return; 3591 } 3592 if (col >= Columns) // not enough room 3593 col = Columns - 1; 3594 #ifdef FEAT_RIGHTLEFT 3595 if (cmdmsg_rl) 3596 while (msg_col > Columns - col) 3597 msg_putchar(' '); 3598 else 3599 #endif 3600 while (msg_col < col) 3601 msg_putchar(' '); 3602 } 3603 3604 #if defined(FEAT_CON_DIALOG) || defined(PROTO) 3605 /* 3606 * Used for "confirm()" function, and the :confirm command prefix. 3607 * Versions which haven't got flexible dialogs yet, and console 3608 * versions, get this generic handler which uses the command line. 3609 * 3610 * type = one of: 3611 * VIM_QUESTION, VIM_INFO, VIM_WARNING, VIM_ERROR or VIM_GENERIC 3612 * title = title string (can be NULL for default) 3613 * (neither used in console dialogs at the moment) 3614 * 3615 * Format of the "buttons" string: 3616 * "Button1Name\nButton2Name\nButton3Name" 3617 * The first button should normally be the default/accept 3618 * The second button should be the 'Cancel' button 3619 * Other buttons- use your imagination! 3620 * A '&' in a button name becomes a shortcut, so each '&' should be before a 3621 * different letter. 3622 */ 3623 int 3624 do_dialog( 3625 int type UNUSED, 3626 char_u *title UNUSED, 3627 char_u *message, 3628 char_u *buttons, 3629 int dfltbutton, 3630 char_u *textfield UNUSED, // IObuff for inputdialog(), NULL 3631 // otherwise 3632 int ex_cmd) // when TRUE pressing : accepts default and starts 3633 // Ex command 3634 { 3635 int oldState; 3636 int retval = 0; 3637 char_u *hotkeys; 3638 int c; 3639 int i; 3640 3641 #ifndef NO_CONSOLE 3642 // Don't output anything in silent mode ("ex -s") 3643 if (silent_mode) 3644 return dfltbutton; // return default option 3645 #endif 3646 3647 #ifdef FEAT_GUI_DIALOG 3648 // When GUI is running and 'c' not in 'guioptions', use the GUI dialog 3649 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL) 3650 { 3651 c = gui_mch_dialog(type, title, message, buttons, dfltbutton, 3652 textfield, ex_cmd); 3653 // avoid a hit-enter prompt without clearing the cmdline 3654 need_wait_return = FALSE; 3655 emsg_on_display = FALSE; 3656 cmdline_row = msg_row; 3657 3658 // Flush output to avoid that further messages and redrawing is done 3659 // in the wrong order. 3660 out_flush(); 3661 gui_mch_update(); 3662 3663 return c; 3664 } 3665 #endif 3666 3667 oldState = State; 3668 State = CONFIRM; 3669 setmouse(); 3670 3671 /* 3672 * Since we wait for a keypress, don't make the 3673 * user press RETURN as well afterwards. 3674 */ 3675 ++no_wait_return; 3676 hotkeys = msg_show_console_dialog(message, buttons, dfltbutton); 3677 3678 if (hotkeys != NULL) 3679 { 3680 for (;;) 3681 { 3682 // Get a typed character directly from the user. 3683 c = get_keystroke(); 3684 switch (c) 3685 { 3686 case CAR: // User accepts default option 3687 case NL: 3688 retval = dfltbutton; 3689 break; 3690 case Ctrl_C: // User aborts/cancels 3691 case ESC: 3692 retval = 0; 3693 break; 3694 default: // Could be a hotkey? 3695 if (c < 0) // special keys are ignored here 3696 continue; 3697 if (c == ':' && ex_cmd) 3698 { 3699 retval = dfltbutton; 3700 ins_char_typebuf(':'); 3701 break; 3702 } 3703 3704 // Make the character lowercase, as chars in "hotkeys" are. 3705 c = MB_TOLOWER(c); 3706 retval = 1; 3707 for (i = 0; hotkeys[i]; ++i) 3708 { 3709 if (has_mbyte) 3710 { 3711 if ((*mb_ptr2char)(hotkeys + i) == c) 3712 break; 3713 i += (*mb_ptr2len)(hotkeys + i) - 1; 3714 } 3715 else 3716 if (hotkeys[i] == c) 3717 break; 3718 ++retval; 3719 } 3720 if (hotkeys[i]) 3721 break; 3722 // No hotkey match, so keep waiting 3723 continue; 3724 } 3725 break; 3726 } 3727 3728 vim_free(hotkeys); 3729 } 3730 3731 State = oldState; 3732 setmouse(); 3733 --no_wait_return; 3734 msg_end_prompt(); 3735 3736 return retval; 3737 } 3738 3739 /* 3740 * Copy one character from "*from" to "*to", taking care of multi-byte 3741 * characters. Return the length of the character in bytes. 3742 */ 3743 static int 3744 copy_char( 3745 char_u *from, 3746 char_u *to, 3747 int lowercase) // make character lower case 3748 { 3749 int len; 3750 int c; 3751 3752 if (has_mbyte) 3753 { 3754 if (lowercase) 3755 { 3756 c = MB_TOLOWER((*mb_ptr2char)(from)); 3757 return (*mb_char2bytes)(c, to); 3758 } 3759 else 3760 { 3761 len = (*mb_ptr2len)(from); 3762 mch_memmove(to, from, (size_t)len); 3763 return len; 3764 } 3765 } 3766 else 3767 { 3768 if (lowercase) 3769 *to = (char_u)TOLOWER_LOC(*from); 3770 else 3771 *to = *from; 3772 return 1; 3773 } 3774 } 3775 3776 /* 3777 * Format the dialog string, and display it at the bottom of 3778 * the screen. Return a string of hotkey chars (if defined) for 3779 * each 'button'. If a button has no hotkey defined, the first character of 3780 * the button is used. 3781 * The hotkeys can be multi-byte characters, but without combining chars. 3782 * 3783 * Returns an allocated string with hotkeys, or NULL for error. 3784 */ 3785 static char_u * 3786 msg_show_console_dialog( 3787 char_u *message, 3788 char_u *buttons, 3789 int dfltbutton) 3790 { 3791 int len = 0; 3792 #define HOTK_LEN (has_mbyte ? MB_MAXBYTES : 1) 3793 int lenhotkey = HOTK_LEN; // count first button 3794 char_u *hotk = NULL; 3795 char_u *msgp = NULL; 3796 char_u *hotkp = NULL; 3797 char_u *r; 3798 int copy; 3799 #define HAS_HOTKEY_LEN 30 3800 char_u has_hotkey[HAS_HOTKEY_LEN]; 3801 int first_hotkey = FALSE; // first char of button is hotkey 3802 int idx; 3803 3804 has_hotkey[0] = FALSE; 3805 3806 /* 3807 * First loop: compute the size of memory to allocate. 3808 * Second loop: copy to the allocated memory. 3809 */ 3810 for (copy = 0; copy <= 1; ++copy) 3811 { 3812 r = buttons; 3813 idx = 0; 3814 while (*r) 3815 { 3816 if (*r == DLG_BUTTON_SEP) 3817 { 3818 if (copy) 3819 { 3820 *msgp++ = ','; 3821 *msgp++ = ' '; // '\n' -> ', ' 3822 3823 // advance to next hotkey and set default hotkey 3824 if (has_mbyte) 3825 hotkp += STRLEN(hotkp); 3826 else 3827 ++hotkp; 3828 hotkp[copy_char(r + 1, hotkp, TRUE)] = NUL; 3829 if (dfltbutton) 3830 --dfltbutton; 3831 3832 // If no hotkey is specified first char is used. 3833 if (idx < HAS_HOTKEY_LEN - 1 && !has_hotkey[++idx]) 3834 first_hotkey = TRUE; 3835 } 3836 else 3837 { 3838 len += 3; // '\n' -> ', '; 'x' -> '(x)' 3839 lenhotkey += HOTK_LEN; // each button needs a hotkey 3840 if (idx < HAS_HOTKEY_LEN - 1) 3841 has_hotkey[++idx] = FALSE; 3842 } 3843 } 3844 else if (*r == DLG_HOTKEY_CHAR || first_hotkey) 3845 { 3846 if (*r == DLG_HOTKEY_CHAR) 3847 ++r; 3848 first_hotkey = FALSE; 3849 if (copy) 3850 { 3851 if (*r == DLG_HOTKEY_CHAR) // '&&a' -> '&a' 3852 *msgp++ = *r; 3853 else 3854 { 3855 // '&a' -> '[a]' 3856 *msgp++ = (dfltbutton == 1) ? '[' : '('; 3857 msgp += copy_char(r, msgp, FALSE); 3858 *msgp++ = (dfltbutton == 1) ? ']' : ')'; 3859 3860 // redefine hotkey 3861 hotkp[copy_char(r, hotkp, TRUE)] = NUL; 3862 } 3863 } 3864 else 3865 { 3866 ++len; // '&a' -> '[a]' 3867 if (idx < HAS_HOTKEY_LEN - 1) 3868 has_hotkey[idx] = TRUE; 3869 } 3870 } 3871 else 3872 { 3873 // everything else copy literally 3874 if (copy) 3875 msgp += copy_char(r, msgp, FALSE); 3876 } 3877 3878 // advance to the next character 3879 MB_PTR_ADV(r); 3880 } 3881 3882 if (copy) 3883 { 3884 *msgp++ = ':'; 3885 *msgp++ = ' '; 3886 *msgp = NUL; 3887 } 3888 else 3889 { 3890 len += (int)(STRLEN(message) 3891 + 2 // for the NL's 3892 + STRLEN(buttons) 3893 + 3); // for the ": " and NUL 3894 lenhotkey++; // for the NUL 3895 3896 // If no hotkey is specified first char is used. 3897 if (!has_hotkey[0]) 3898 { 3899 first_hotkey = TRUE; 3900 len += 2; // "x" -> "[x]" 3901 } 3902 3903 /* 3904 * Now allocate and load the strings 3905 */ 3906 vim_free(confirm_msg); 3907 confirm_msg = alloc(len); 3908 if (confirm_msg == NULL) 3909 return NULL; 3910 *confirm_msg = NUL; 3911 hotk = alloc(lenhotkey); 3912 if (hotk == NULL) 3913 return NULL; 3914 3915 *confirm_msg = '\n'; 3916 STRCPY(confirm_msg + 1, message); 3917 3918 msgp = confirm_msg + 1 + STRLEN(message); 3919 hotkp = hotk; 3920 3921 // Define first default hotkey. Keep the hotkey string NUL 3922 // terminated to avoid reading past the end. 3923 hotkp[copy_char(buttons, hotkp, TRUE)] = NUL; 3924 3925 // Remember where the choices start, displaying starts here when 3926 // "hotkp" typed at the more prompt. 3927 confirm_msg_tail = msgp; 3928 *msgp++ = '\n'; 3929 } 3930 } 3931 3932 display_confirm_msg(); 3933 return hotk; 3934 } 3935 3936 /* 3937 * Display the ":confirm" message. Also called when screen resized. 3938 */ 3939 static void 3940 display_confirm_msg(void) 3941 { 3942 // avoid that 'q' at the more prompt truncates the message here 3943 ++confirm_msg_used; 3944 if (confirm_msg != NULL) 3945 msg_puts_attr((char *)confirm_msg, HL_ATTR(HLF_M)); 3946 --confirm_msg_used; 3947 } 3948 3949 #endif // FEAT_CON_DIALOG 3950 3951 #if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG) 3952 3953 int 3954 vim_dialog_yesno( 3955 int type, 3956 char_u *title, 3957 char_u *message, 3958 int dflt) 3959 { 3960 if (do_dialog(type, 3961 title == NULL ? (char_u *)_("Question") : title, 3962 message, 3963 (char_u *)_("&Yes\n&No"), dflt, NULL, FALSE) == 1) 3964 return VIM_YES; 3965 return VIM_NO; 3966 } 3967 3968 int 3969 vim_dialog_yesnocancel( 3970 int type, 3971 char_u *title, 3972 char_u *message, 3973 int dflt) 3974 { 3975 switch (do_dialog(type, 3976 title == NULL ? (char_u *)_("Question") : title, 3977 message, 3978 (char_u *)_("&Yes\n&No\n&Cancel"), dflt, NULL, FALSE)) 3979 { 3980 case 1: return VIM_YES; 3981 case 2: return VIM_NO; 3982 } 3983 return VIM_CANCEL; 3984 } 3985 3986 int 3987 vim_dialog_yesnoallcancel( 3988 int type, 3989 char_u *title, 3990 char_u *message, 3991 int dflt) 3992 { 3993 switch (do_dialog(type, 3994 title == NULL ? (char_u *)"Question" : title, 3995 message, 3996 (char_u *)_("&Yes\n&No\nSave &All\n&Discard All\n&Cancel"), 3997 dflt, NULL, FALSE)) 3998 { 3999 case 1: return VIM_YES; 4000 case 2: return VIM_NO; 4001 case 3: return VIM_ALL; 4002 case 4: return VIM_DISCARDALL; 4003 } 4004 return VIM_CANCEL; 4005 } 4006 4007 #endif // FEAT_GUI_DIALOG || FEAT_CON_DIALOG 4008 4009 #if defined(FEAT_EVAL) 4010 static char *e_printf = N_("E766: Insufficient arguments for printf()"); 4011 4012 /* 4013 * Get number argument from "idxp" entry in "tvs". First entry is 1. 4014 */ 4015 static varnumber_T 4016 tv_nr(typval_T *tvs, int *idxp) 4017 { 4018 int idx = *idxp - 1; 4019 varnumber_T n = 0; 4020 int err = FALSE; 4021 4022 if (tvs[idx].v_type == VAR_UNKNOWN) 4023 emsg(_(e_printf)); 4024 else 4025 { 4026 ++*idxp; 4027 n = tv_get_number_chk(&tvs[idx], &err); 4028 if (err) 4029 n = 0; 4030 } 4031 return n; 4032 } 4033 4034 /* 4035 * Get string argument from "idxp" entry in "tvs". First entry is 1. 4036 * If "tofree" is NULL tv_get_string_chk() is used. Some types (e.g. List) 4037 * are not converted to a string. 4038 * If "tofree" is not NULL echo_string() is used. All types are converted to 4039 * a string with the same format as ":echo". The caller must free "*tofree". 4040 * Returns NULL for an error. 4041 */ 4042 static char * 4043 tv_str(typval_T *tvs, int *idxp, char_u **tofree) 4044 { 4045 int idx = *idxp - 1; 4046 char *s = NULL; 4047 static char_u numbuf[NUMBUFLEN]; 4048 4049 if (tvs[idx].v_type == VAR_UNKNOWN) 4050 emsg(_(e_printf)); 4051 else 4052 { 4053 ++*idxp; 4054 if (tofree != NULL) 4055 s = (char *)echo_string(&tvs[idx], tofree, numbuf, get_copyID()); 4056 else 4057 s = (char *)tv_get_string_chk(&tvs[idx]); 4058 } 4059 return s; 4060 } 4061 4062 # ifdef FEAT_FLOAT 4063 /* 4064 * Get float argument from "idxp" entry in "tvs". First entry is 1. 4065 */ 4066 static double 4067 tv_float(typval_T *tvs, int *idxp) 4068 { 4069 int idx = *idxp - 1; 4070 double f = 0; 4071 4072 if (tvs[idx].v_type == VAR_UNKNOWN) 4073 emsg(_(e_printf)); 4074 else 4075 { 4076 ++*idxp; 4077 if (tvs[idx].v_type == VAR_FLOAT) 4078 f = tvs[idx].vval.v_float; 4079 else if (tvs[idx].v_type == VAR_NUMBER) 4080 f = (double)tvs[idx].vval.v_number; 4081 else 4082 emsg(_("E807: Expected Float argument for printf()")); 4083 } 4084 return f; 4085 } 4086 # endif 4087 #endif 4088 4089 #ifdef FEAT_FLOAT 4090 /* 4091 * Return the representation of infinity for printf() function: 4092 * "-inf", "inf", "+inf", " inf", "-INF", "INF", "+INF" or " INF". 4093 */ 4094 static const char * 4095 infinity_str(int positive, 4096 char fmt_spec, 4097 int force_sign, 4098 int space_for_positive) 4099 { 4100 static const char *table[] = 4101 { 4102 "-inf", "inf", "+inf", " inf", 4103 "-INF", "INF", "+INF", " INF" 4104 }; 4105 int idx = positive * (1 + force_sign + force_sign * space_for_positive); 4106 4107 if (ASCII_ISUPPER(fmt_spec)) 4108 idx += 4; 4109 return table[idx]; 4110 } 4111 #endif 4112 4113 /* 4114 * This code was included to provide a portable vsnprintf() and snprintf(). 4115 * Some systems may provide their own, but we always use this one for 4116 * consistency. 4117 * 4118 * This code is based on snprintf.c - a portable implementation of snprintf 4119 * by Mark Martinec <[email protected]>, Version 2.2, 2000-10-06. 4120 * Included with permission. It was heavily modified to fit in Vim. 4121 * The original code, including useful comments, can be found here: 4122 * http://www.ijs.si/software/snprintf/ 4123 * 4124 * This snprintf() only supports the following conversion specifiers: 4125 * s, c, d, u, o, x, X, p (and synonyms: i, D, U, O - see below) 4126 * with flags: '-', '+', ' ', '0' and '#'. 4127 * An asterisk is supported for field width as well as precision. 4128 * 4129 * Limited support for floating point was added: 'f', 'F', 'e', 'E', 'g', 'G'. 4130 * 4131 * Length modifiers 'h' (short int) and 'l' (long int) and 'll' (long long int) 4132 * are supported. 4133 * 4134 * The locale is not used, the string is used as a byte string. This is only 4135 * relevant for double-byte encodings where the second byte may be '%'. 4136 * 4137 * It is permitted for "str_m" to be zero, and it is permitted to specify NULL 4138 * pointer for resulting string argument if "str_m" is zero (as per ISO C99). 4139 * 4140 * The return value is the number of characters which would be generated 4141 * for the given input, excluding the trailing NUL. If this value 4142 * is greater or equal to "str_m", not all characters from the result 4143 * have been stored in str, output bytes beyond the ("str_m"-1) -th character 4144 * are discarded. If "str_m" is greater than zero it is guaranteed 4145 * the resulting string will be NUL-terminated. 4146 */ 4147 4148 /* 4149 * When va_list is not supported we only define vim_snprintf(). 4150 * 4151 * vim_vsnprintf_typval() can be invoked with either "va_list" or a list of 4152 * "typval_T". When the latter is not used it must be NULL. 4153 */ 4154 4155 // When generating prototypes all of this is skipped, cproto doesn't 4156 // understand this. 4157 #ifndef PROTO 4158 4159 // Like vim_vsnprintf() but append to the string. 4160 int 4161 vim_snprintf_add(char *str, size_t str_m, const char *fmt, ...) 4162 { 4163 va_list ap; 4164 int str_l; 4165 size_t len = STRLEN(str); 4166 size_t space; 4167 4168 if (str_m <= len) 4169 space = 0; 4170 else 4171 space = str_m - len; 4172 va_start(ap, fmt); 4173 str_l = vim_vsnprintf(str + len, space, fmt, ap); 4174 va_end(ap); 4175 return str_l; 4176 } 4177 4178 int 4179 vim_snprintf(char *str, size_t str_m, const char *fmt, ...) 4180 { 4181 va_list ap; 4182 int str_l; 4183 4184 va_start(ap, fmt); 4185 str_l = vim_vsnprintf(str, str_m, fmt, ap); 4186 va_end(ap); 4187 return str_l; 4188 } 4189 4190 int 4191 vim_vsnprintf( 4192 char *str, 4193 size_t str_m, 4194 const char *fmt, 4195 va_list ap) 4196 { 4197 return vim_vsnprintf_typval(str, str_m, fmt, ap, NULL); 4198 } 4199 4200 int 4201 vim_vsnprintf_typval( 4202 char *str, 4203 size_t str_m, 4204 const char *fmt, 4205 va_list ap, 4206 typval_T *tvs) 4207 { 4208 size_t str_l = 0; 4209 const char *p = fmt; 4210 int arg_idx = 1; 4211 4212 if (p == NULL) 4213 p = ""; 4214 while (*p != NUL) 4215 { 4216 if (*p != '%') 4217 { 4218 char *q = strchr(p + 1, '%'); 4219 size_t n = (q == NULL) ? STRLEN(p) : (size_t)(q - p); 4220 4221 // Copy up to the next '%' or NUL without any changes. 4222 if (str_l < str_m) 4223 { 4224 size_t avail = str_m - str_l; 4225 4226 mch_memmove(str + str_l, p, n > avail ? avail : n); 4227 } 4228 p += n; 4229 str_l += n; 4230 } 4231 else 4232 { 4233 size_t min_field_width = 0, precision = 0; 4234 int zero_padding = 0, precision_specified = 0, justify_left = 0; 4235 int alternate_form = 0, force_sign = 0; 4236 4237 // If both the ' ' and '+' flags appear, the ' ' flag should be 4238 // ignored. 4239 int space_for_positive = 1; 4240 4241 // allowed values: \0, h, l, L 4242 char length_modifier = '\0'; 4243 4244 // temporary buffer for simple numeric->string conversion 4245 # if defined(FEAT_FLOAT) 4246 # define TMP_LEN 350 // On my system 1e308 is the biggest number possible. 4247 // That sounds reasonable to use as the maximum 4248 // printable. 4249 # elif defined(FEAT_NUM64) 4250 # define TMP_LEN 66 4251 # else 4252 # define TMP_LEN 34 4253 # endif 4254 char tmp[TMP_LEN]; 4255 4256 // string address in case of string argument 4257 const char *str_arg = NULL; 4258 4259 // natural field width of arg without padding and sign 4260 size_t str_arg_l; 4261 4262 // unsigned char argument value - only defined for c conversion. 4263 // N.B. standard explicitly states the char argument for the c 4264 // conversion is unsigned 4265 unsigned char uchar_arg; 4266 4267 // number of zeros to be inserted for numeric conversions as 4268 // required by the precision or minimal field width 4269 size_t number_of_zeros_to_pad = 0; 4270 4271 // index into tmp where zero padding is to be inserted 4272 size_t zero_padding_insertion_ind = 0; 4273 4274 // current conversion specifier character 4275 char fmt_spec = '\0'; 4276 4277 // buffer for 's' and 'S' specs 4278 char_u *tofree = NULL; 4279 4280 4281 p++; // skip '%' 4282 4283 // parse flags 4284 while (*p == '0' || *p == '-' || *p == '+' || *p == ' ' 4285 || *p == '#' || *p == '\'') 4286 { 4287 switch (*p) 4288 { 4289 case '0': zero_padding = 1; break; 4290 case '-': justify_left = 1; break; 4291 case '+': force_sign = 1; space_for_positive = 0; break; 4292 case ' ': force_sign = 1; 4293 // If both the ' ' and '+' flags appear, the ' ' 4294 // flag should be ignored 4295 break; 4296 case '#': alternate_form = 1; break; 4297 case '\'': break; 4298 } 4299 p++; 4300 } 4301 // If the '0' and '-' flags both appear, the '0' flag should be 4302 // ignored. 4303 4304 // parse field width 4305 if (*p == '*') 4306 { 4307 int j; 4308 4309 p++; 4310 j = 4311 # if defined(FEAT_EVAL) 4312 tvs != NULL ? tv_nr(tvs, &arg_idx) : 4313 # endif 4314 va_arg(ap, int); 4315 if (j >= 0) 4316 min_field_width = j; 4317 else 4318 { 4319 min_field_width = -j; 4320 justify_left = 1; 4321 } 4322 } 4323 else if (VIM_ISDIGIT((int)(*p))) 4324 { 4325 // size_t could be wider than unsigned int; make sure we treat 4326 // argument like common implementations do 4327 unsigned int uj = *p++ - '0'; 4328 4329 while (VIM_ISDIGIT((int)(*p))) 4330 uj = 10 * uj + (unsigned int)(*p++ - '0'); 4331 min_field_width = uj; 4332 } 4333 4334 // parse precision 4335 if (*p == '.') 4336 { 4337 p++; 4338 precision_specified = 1; 4339 if (*p == '*') 4340 { 4341 int j; 4342 4343 j = 4344 # if defined(FEAT_EVAL) 4345 tvs != NULL ? tv_nr(tvs, &arg_idx) : 4346 # endif 4347 va_arg(ap, int); 4348 p++; 4349 if (j >= 0) 4350 precision = j; 4351 else 4352 { 4353 precision_specified = 0; 4354 precision = 0; 4355 } 4356 } 4357 else if (VIM_ISDIGIT((int)(*p))) 4358 { 4359 // size_t could be wider than unsigned int; make sure we 4360 // treat argument like common implementations do 4361 unsigned int uj = *p++ - '0'; 4362 4363 while (VIM_ISDIGIT((int)(*p))) 4364 uj = 10 * uj + (unsigned int)(*p++ - '0'); 4365 precision = uj; 4366 } 4367 } 4368 4369 // parse 'h', 'l' and 'll' length modifiers 4370 if (*p == 'h' || *p == 'l') 4371 { 4372 length_modifier = *p; 4373 p++; 4374 if (length_modifier == 'l' && *p == 'l') 4375 { 4376 // double l = long long 4377 # ifdef FEAT_NUM64 4378 length_modifier = 'L'; 4379 # else 4380 length_modifier = 'l'; // treat it as a single 'l' 4381 # endif 4382 p++; 4383 } 4384 } 4385 fmt_spec = *p; 4386 4387 // common synonyms: 4388 switch (fmt_spec) 4389 { 4390 case 'i': fmt_spec = 'd'; break; 4391 case 'D': fmt_spec = 'd'; length_modifier = 'l'; break; 4392 case 'U': fmt_spec = 'u'; length_modifier = 'l'; break; 4393 case 'O': fmt_spec = 'o'; length_modifier = 'l'; break; 4394 default: break; 4395 } 4396 4397 # if defined(FEAT_EVAL) && defined(FEAT_NUM64) 4398 switch (fmt_spec) 4399 { 4400 case 'd': case 'u': case 'o': case 'x': case 'X': 4401 if (tvs != NULL && length_modifier == '\0') 4402 length_modifier = 'L'; 4403 } 4404 # endif 4405 4406 // get parameter value, do initial processing 4407 switch (fmt_spec) 4408 { 4409 // '%' and 'c' behave similar to 's' regarding flags and field 4410 // widths 4411 case '%': 4412 case 'c': 4413 case 's': 4414 case 'S': 4415 str_arg_l = 1; 4416 switch (fmt_spec) 4417 { 4418 case '%': 4419 str_arg = p; 4420 break; 4421 4422 case 'c': 4423 { 4424 int j; 4425 4426 j = 4427 # if defined(FEAT_EVAL) 4428 tvs != NULL ? tv_nr(tvs, &arg_idx) : 4429 # endif 4430 va_arg(ap, int); 4431 // standard demands unsigned char 4432 uchar_arg = (unsigned char)j; 4433 str_arg = (char *)&uchar_arg; 4434 break; 4435 } 4436 4437 case 's': 4438 case 'S': 4439 str_arg = 4440 # if defined(FEAT_EVAL) 4441 tvs != NULL ? tv_str(tvs, &arg_idx, &tofree) : 4442 # endif 4443 va_arg(ap, char *); 4444 if (str_arg == NULL) 4445 { 4446 str_arg = "[NULL]"; 4447 str_arg_l = 6; 4448 } 4449 // make sure not to address string beyond the specified 4450 // precision !!! 4451 else if (!precision_specified) 4452 str_arg_l = strlen(str_arg); 4453 // truncate string if necessary as requested by precision 4454 else if (precision == 0) 4455 str_arg_l = 0; 4456 else 4457 { 4458 // Don't put the #if inside memchr(), it can be a 4459 // macro. 4460 // memchr on HP does not like n > 2^31 !!! 4461 char *q = memchr(str_arg, '\0', 4462 precision <= (size_t)0x7fffffffL ? precision 4463 : (size_t)0x7fffffffL); 4464 str_arg_l = (q == NULL) ? precision 4465 : (size_t)(q - str_arg); 4466 } 4467 if (fmt_spec == 'S') 4468 { 4469 if (min_field_width != 0) 4470 min_field_width += STRLEN(str_arg) 4471 - mb_string2cells((char_u *)str_arg, -1); 4472 if (precision) 4473 { 4474 char_u *p1; 4475 size_t i = 0; 4476 4477 for (p1 = (char_u *)str_arg; *p1; 4478 p1 += mb_ptr2len(p1)) 4479 { 4480 i += (size_t)mb_ptr2cells(p1); 4481 if (i > precision) 4482 break; 4483 } 4484 str_arg_l = precision = p1 - (char_u *)str_arg; 4485 } 4486 } 4487 break; 4488 4489 default: 4490 break; 4491 } 4492 break; 4493 4494 case 'd': case 'u': 4495 case 'b': case 'B': 4496 case 'o': 4497 case 'x': case 'X': 4498 case 'p': 4499 { 4500 // NOTE: the u, b, o, x, X and p conversion specifiers 4501 // imply the value is unsigned; d implies a signed 4502 // value 4503 4504 // 0 if numeric argument is zero (or if pointer is 4505 // NULL for 'p'), +1 if greater than zero (or nonzero 4506 // for unsigned arguments), -1 if negative (unsigned 4507 // argument is never negative) 4508 int arg_sign = 0; 4509 4510 // only defined for length modifier h, or for no 4511 // length modifiers 4512 int int_arg = 0; 4513 unsigned int uint_arg = 0; 4514 4515 // only defined for length modifier l 4516 long int long_arg = 0; 4517 unsigned long int ulong_arg = 0; 4518 4519 # ifdef FEAT_NUM64 4520 // only defined for length modifier ll 4521 varnumber_T llong_arg = 0; 4522 uvarnumber_T ullong_arg = 0; 4523 # endif 4524 4525 // only defined for b conversion 4526 uvarnumber_T bin_arg = 0; 4527 4528 // pointer argument value -only defined for p 4529 // conversion 4530 void *ptr_arg = NULL; 4531 4532 if (fmt_spec == 'p') 4533 { 4534 length_modifier = '\0'; 4535 ptr_arg = 4536 # if defined(FEAT_EVAL) 4537 tvs != NULL ? (void *)tv_str(tvs, &arg_idx, 4538 NULL) : 4539 # endif 4540 va_arg(ap, void *); 4541 if (ptr_arg != NULL) 4542 arg_sign = 1; 4543 } 4544 else if (fmt_spec == 'b' || fmt_spec == 'B') 4545 { 4546 bin_arg = 4547 # if defined(FEAT_EVAL) 4548 tvs != NULL ? 4549 (uvarnumber_T)tv_nr(tvs, &arg_idx) : 4550 # endif 4551 va_arg(ap, uvarnumber_T); 4552 if (bin_arg != 0) 4553 arg_sign = 1; 4554 } 4555 else if (fmt_spec == 'd') 4556 { 4557 // signed 4558 switch (length_modifier) 4559 { 4560 case '\0': 4561 case 'h': 4562 // char and short arguments are passed as int. 4563 int_arg = 4564 # if defined(FEAT_EVAL) 4565 tvs != NULL ? tv_nr(tvs, &arg_idx) : 4566 # endif 4567 va_arg(ap, int); 4568 if (int_arg > 0) 4569 arg_sign = 1; 4570 else if (int_arg < 0) 4571 arg_sign = -1; 4572 break; 4573 case 'l': 4574 long_arg = 4575 # if defined(FEAT_EVAL) 4576 tvs != NULL ? tv_nr(tvs, &arg_idx) : 4577 # endif 4578 va_arg(ap, long int); 4579 if (long_arg > 0) 4580 arg_sign = 1; 4581 else if (long_arg < 0) 4582 arg_sign = -1; 4583 break; 4584 # ifdef FEAT_NUM64 4585 case 'L': 4586 llong_arg = 4587 # if defined(FEAT_EVAL) 4588 tvs != NULL ? tv_nr(tvs, &arg_idx) : 4589 # endif 4590 va_arg(ap, varnumber_T); 4591 if (llong_arg > 0) 4592 arg_sign = 1; 4593 else if (llong_arg < 0) 4594 arg_sign = -1; 4595 break; 4596 # endif 4597 } 4598 } 4599 else 4600 { 4601 // unsigned 4602 switch (length_modifier) 4603 { 4604 case '\0': 4605 case 'h': 4606 uint_arg = 4607 # if defined(FEAT_EVAL) 4608 tvs != NULL ? (unsigned) 4609 tv_nr(tvs, &arg_idx) : 4610 # endif 4611 va_arg(ap, unsigned int); 4612 if (uint_arg != 0) 4613 arg_sign = 1; 4614 break; 4615 case 'l': 4616 ulong_arg = 4617 # if defined(FEAT_EVAL) 4618 tvs != NULL ? (unsigned long) 4619 tv_nr(tvs, &arg_idx) : 4620 # endif 4621 va_arg(ap, unsigned long int); 4622 if (ulong_arg != 0) 4623 arg_sign = 1; 4624 break; 4625 # ifdef FEAT_NUM64 4626 case 'L': 4627 ullong_arg = 4628 # if defined(FEAT_EVAL) 4629 tvs != NULL ? (uvarnumber_T) 4630 tv_nr(tvs, &arg_idx) : 4631 # endif 4632 va_arg(ap, uvarnumber_T); 4633 if (ullong_arg != 0) 4634 arg_sign = 1; 4635 break; 4636 # endif 4637 } 4638 } 4639 4640 str_arg = tmp; 4641 str_arg_l = 0; 4642 4643 // NOTE: 4644 // For d, i, u, o, x, and X conversions, if precision is 4645 // specified, the '0' flag should be ignored. This is so 4646 // with Solaris 2.6, Digital UNIX 4.0, HPUX 10, Linux, 4647 // FreeBSD, NetBSD; but not with Perl. 4648 if (precision_specified) 4649 zero_padding = 0; 4650 if (fmt_spec == 'd') 4651 { 4652 if (force_sign && arg_sign >= 0) 4653 tmp[str_arg_l++] = space_for_positive ? ' ' : '+'; 4654 // leave negative numbers for sprintf to handle, to 4655 // avoid handling tricky cases like (short int)-32768 4656 } 4657 else if (alternate_form) 4658 { 4659 if (arg_sign != 0 4660 && (fmt_spec == 'b' || fmt_spec == 'B' 4661 || fmt_spec == 'x' || fmt_spec == 'X') ) 4662 { 4663 tmp[str_arg_l++] = '0'; 4664 tmp[str_arg_l++] = fmt_spec; 4665 } 4666 // alternate form should have no effect for p 4667 // conversion, but ... 4668 } 4669 4670 zero_padding_insertion_ind = str_arg_l; 4671 if (!precision_specified) 4672 precision = 1; // default precision is 1 4673 if (precision == 0 && arg_sign == 0) 4674 { 4675 // When zero value is formatted with an explicit 4676 // precision 0, the resulting formatted string is 4677 // empty (d, i, u, b, B, o, x, X, p). 4678 } 4679 else 4680 { 4681 char f[6]; 4682 int f_l = 0; 4683 4684 // construct a simple format string for sprintf 4685 f[f_l++] = '%'; 4686 if (!length_modifier) 4687 ; 4688 else if (length_modifier == 'L') 4689 { 4690 # ifdef FEAT_NUM64 4691 # ifdef MSWIN 4692 f[f_l++] = 'I'; 4693 f[f_l++] = '6'; 4694 f[f_l++] = '4'; 4695 # else 4696 f[f_l++] = 'l'; 4697 f[f_l++] = 'l'; 4698 # endif 4699 # else 4700 f[f_l++] = 'l'; 4701 # endif 4702 } 4703 else 4704 f[f_l++] = length_modifier; 4705 f[f_l++] = fmt_spec; 4706 f[f_l++] = '\0'; 4707 4708 if (fmt_spec == 'p') 4709 str_arg_l += sprintf(tmp + str_arg_l, f, ptr_arg); 4710 else if (fmt_spec == 'b' || fmt_spec == 'B') 4711 { 4712 char b[8 * sizeof(uvarnumber_T)]; 4713 size_t b_l = 0; 4714 uvarnumber_T bn = bin_arg; 4715 4716 do 4717 { 4718 b[sizeof(b) - ++b_l] = '0' + (bn & 0x1); 4719 bn >>= 1; 4720 } 4721 while (bn != 0); 4722 4723 memcpy(tmp + str_arg_l, b + sizeof(b) - b_l, b_l); 4724 str_arg_l += b_l; 4725 } 4726 else if (fmt_spec == 'd') 4727 { 4728 // signed 4729 switch (length_modifier) 4730 { 4731 case '\0': 4732 case 'h': str_arg_l += sprintf( 4733 tmp + str_arg_l, f, int_arg); 4734 break; 4735 case 'l': str_arg_l += sprintf( 4736 tmp + str_arg_l, f, long_arg); 4737 break; 4738 # ifdef FEAT_NUM64 4739 case 'L': str_arg_l += sprintf( 4740 tmp + str_arg_l, f, llong_arg); 4741 break; 4742 # endif 4743 } 4744 } 4745 else 4746 { 4747 // unsigned 4748 switch (length_modifier) 4749 { 4750 case '\0': 4751 case 'h': str_arg_l += sprintf( 4752 tmp + str_arg_l, f, uint_arg); 4753 break; 4754 case 'l': str_arg_l += sprintf( 4755 tmp + str_arg_l, f, ulong_arg); 4756 break; 4757 # ifdef FEAT_NUM64 4758 case 'L': str_arg_l += sprintf( 4759 tmp + str_arg_l, f, ullong_arg); 4760 break; 4761 # endif 4762 } 4763 } 4764 4765 // include the optional minus sign and possible 4766 // "0x" in the region before the zero padding 4767 // insertion point 4768 if (zero_padding_insertion_ind < str_arg_l 4769 && tmp[zero_padding_insertion_ind] == '-') 4770 zero_padding_insertion_ind++; 4771 if (zero_padding_insertion_ind + 1 < str_arg_l 4772 && tmp[zero_padding_insertion_ind] == '0' 4773 && (tmp[zero_padding_insertion_ind + 1] == 'x' 4774 || tmp[zero_padding_insertion_ind + 1] == 'X')) 4775 zero_padding_insertion_ind += 2; 4776 } 4777 4778 { 4779 size_t num_of_digits = str_arg_l 4780 - zero_padding_insertion_ind; 4781 4782 if (alternate_form && fmt_spec == 'o' 4783 // unless zero is already the first 4784 // character 4785 && !(zero_padding_insertion_ind < str_arg_l 4786 && tmp[zero_padding_insertion_ind] == '0')) 4787 { 4788 // assure leading zero for alternate-form 4789 // octal numbers 4790 if (!precision_specified 4791 || precision < num_of_digits + 1) 4792 { 4793 // precision is increased to force the 4794 // first character to be zero, except if a 4795 // zero value is formatted with an 4796 // explicit precision of zero 4797 precision = num_of_digits + 1; 4798 } 4799 } 4800 // zero padding to specified precision? 4801 if (num_of_digits < precision) 4802 number_of_zeros_to_pad = precision - num_of_digits; 4803 } 4804 // zero padding to specified minimal field width? 4805 if (!justify_left && zero_padding) 4806 { 4807 int n = (int)(min_field_width - (str_arg_l 4808 + number_of_zeros_to_pad)); 4809 if (n > 0) 4810 number_of_zeros_to_pad += n; 4811 } 4812 break; 4813 } 4814 4815 # ifdef FEAT_FLOAT 4816 case 'f': 4817 case 'F': 4818 case 'e': 4819 case 'E': 4820 case 'g': 4821 case 'G': 4822 { 4823 // Floating point. 4824 double f; 4825 double abs_f; 4826 char format[40]; 4827 int l; 4828 int remove_trailing_zeroes = FALSE; 4829 4830 f = 4831 # if defined(FEAT_EVAL) 4832 tvs != NULL ? tv_float(tvs, &arg_idx) : 4833 # endif 4834 va_arg(ap, double); 4835 abs_f = f < 0 ? -f : f; 4836 4837 if (fmt_spec == 'g' || fmt_spec == 'G') 4838 { 4839 // Would be nice to use %g directly, but it prints 4840 // "1.0" as "1", we don't want that. 4841 if ((abs_f >= 0.001 && abs_f < 10000000.0) 4842 || abs_f == 0.0) 4843 fmt_spec = ASCII_ISUPPER(fmt_spec) ? 'F' : 'f'; 4844 else 4845 fmt_spec = fmt_spec == 'g' ? 'e' : 'E'; 4846 remove_trailing_zeroes = TRUE; 4847 } 4848 4849 if ((fmt_spec == 'f' || fmt_spec == 'F') && 4850 # ifdef VAX 4851 abs_f > 1.0e38 4852 # else 4853 abs_f > 1.0e307 4854 # endif 4855 ) 4856 { 4857 // Avoid a buffer overflow 4858 STRCPY(tmp, infinity_str(f > 0.0, fmt_spec, 4859 force_sign, space_for_positive)); 4860 str_arg_l = STRLEN(tmp); 4861 zero_padding = 0; 4862 } 4863 else 4864 { 4865 if (isnan(f)) 4866 { 4867 // Not a number: nan or NAN 4868 STRCPY(tmp, ASCII_ISUPPER(fmt_spec) ? "NAN" 4869 : "nan"); 4870 str_arg_l = 3; 4871 zero_padding = 0; 4872 } 4873 else if (isinf(f)) 4874 { 4875 STRCPY(tmp, infinity_str(f > 0.0, fmt_spec, 4876 force_sign, space_for_positive)); 4877 str_arg_l = STRLEN(tmp); 4878 zero_padding = 0; 4879 } 4880 else 4881 { 4882 // Regular float number 4883 format[0] = '%'; 4884 l = 1; 4885 if (force_sign) 4886 format[l++] = space_for_positive ? ' ' : '+'; 4887 if (precision_specified) 4888 { 4889 size_t max_prec = TMP_LEN - 10; 4890 4891 // Make sure we don't get more digits than we 4892 // have room for. 4893 if ((fmt_spec == 'f' || fmt_spec == 'F') 4894 && abs_f > 1.0) 4895 max_prec -= (size_t)log10(abs_f); 4896 if (precision > max_prec) 4897 precision = max_prec; 4898 l += sprintf(format + l, ".%d", (int)precision); 4899 } 4900 format[l] = fmt_spec == 'F' ? 'f' : fmt_spec; 4901 format[l + 1] = NUL; 4902 4903 str_arg_l = sprintf(tmp, format, f); 4904 } 4905 4906 if (remove_trailing_zeroes) 4907 { 4908 int i; 4909 char *tp; 4910 4911 // Using %g or %G: remove superfluous zeroes. 4912 if (fmt_spec == 'f' || fmt_spec == 'F') 4913 tp = tmp + str_arg_l - 1; 4914 else 4915 { 4916 tp = (char *)vim_strchr((char_u *)tmp, 4917 fmt_spec == 'e' ? 'e' : 'E'); 4918 if (tp != NULL) 4919 { 4920 // Remove superfluous '+' and leading 4921 // zeroes from the exponent. 4922 if (tp[1] == '+') 4923 { 4924 // Change "1.0e+07" to "1.0e07" 4925 STRMOVE(tp + 1, tp + 2); 4926 --str_arg_l; 4927 } 4928 i = (tp[1] == '-') ? 2 : 1; 4929 while (tp[i] == '0') 4930 { 4931 // Change "1.0e07" to "1.0e7" 4932 STRMOVE(tp + i, tp + i + 1); 4933 --str_arg_l; 4934 } 4935 --tp; 4936 } 4937 } 4938 4939 if (tp != NULL && !precision_specified) 4940 // Remove trailing zeroes, but keep the one 4941 // just after a dot. 4942 while (tp > tmp + 2 && *tp == '0' 4943 && tp[-1] != '.') 4944 { 4945 STRMOVE(tp, tp + 1); 4946 --tp; 4947 --str_arg_l; 4948 } 4949 } 4950 else 4951 { 4952 char *tp; 4953 4954 // Be consistent: some printf("%e") use 1.0e+12 4955 // and some 1.0e+012. Remove one zero in the last 4956 // case. 4957 tp = (char *)vim_strchr((char_u *)tmp, 4958 fmt_spec == 'e' ? 'e' : 'E'); 4959 if (tp != NULL && (tp[1] == '+' || tp[1] == '-') 4960 && tp[2] == '0' 4961 && vim_isdigit(tp[3]) 4962 && vim_isdigit(tp[4])) 4963 { 4964 STRMOVE(tp + 2, tp + 3); 4965 --str_arg_l; 4966 } 4967 } 4968 } 4969 if (zero_padding && min_field_width > str_arg_l 4970 && (tmp[0] == '-' || force_sign)) 4971 { 4972 // padding 0's should be inserted after the sign 4973 number_of_zeros_to_pad = min_field_width - str_arg_l; 4974 zero_padding_insertion_ind = 1; 4975 } 4976 str_arg = tmp; 4977 break; 4978 } 4979 # endif 4980 4981 default: 4982 // unrecognized conversion specifier, keep format string 4983 // as-is 4984 zero_padding = 0; // turn zero padding off for non-numeric 4985 // conversion 4986 justify_left = 1; 4987 min_field_width = 0; // reset flags 4988 4989 // discard the unrecognized conversion, just keep * 4990 // the unrecognized conversion character 4991 str_arg = p; 4992 str_arg_l = 0; 4993 if (*p != NUL) 4994 str_arg_l++; // include invalid conversion specifier 4995 // unchanged if not at end-of-string 4996 break; 4997 } 4998 4999 if (*p != NUL) 5000 p++; // step over the just processed conversion specifier 5001 5002 // insert padding to the left as requested by min_field_width; 5003 // this does not include the zero padding in case of numerical 5004 // conversions 5005 if (!justify_left) 5006 { 5007 // left padding with blank or zero 5008 int pn = (int)(min_field_width - (str_arg_l + number_of_zeros_to_pad)); 5009 5010 if (pn > 0) 5011 { 5012 if (str_l < str_m) 5013 { 5014 size_t avail = str_m - str_l; 5015 5016 vim_memset(str + str_l, zero_padding ? '0' : ' ', 5017 (size_t)pn > avail ? avail 5018 : (size_t)pn); 5019 } 5020 str_l += pn; 5021 } 5022 } 5023 5024 // zero padding as requested by the precision or by the minimal 5025 // field width for numeric conversions required? 5026 if (number_of_zeros_to_pad == 0) 5027 { 5028 // will not copy first part of numeric right now, * 5029 // force it to be copied later in its entirety 5030 zero_padding_insertion_ind = 0; 5031 } 5032 else 5033 { 5034 // insert first part of numerics (sign or '0x') before zero 5035 // padding 5036 int zn = (int)zero_padding_insertion_ind; 5037 5038 if (zn > 0) 5039 { 5040 if (str_l < str_m) 5041 { 5042 size_t avail = str_m - str_l; 5043 5044 mch_memmove(str + str_l, str_arg, 5045 (size_t)zn > avail ? avail 5046 : (size_t)zn); 5047 } 5048 str_l += zn; 5049 } 5050 5051 // insert zero padding as requested by the precision or min 5052 // field width 5053 zn = (int)number_of_zeros_to_pad; 5054 if (zn > 0) 5055 { 5056 if (str_l < str_m) 5057 { 5058 size_t avail = str_m - str_l; 5059 5060 vim_memset(str + str_l, '0', 5061 (size_t)zn > avail ? avail 5062 : (size_t)zn); 5063 } 5064 str_l += zn; 5065 } 5066 } 5067 5068 // insert formatted string 5069 // (or as-is conversion specifier for unknown conversions) 5070 { 5071 int sn = (int)(str_arg_l - zero_padding_insertion_ind); 5072 5073 if (sn > 0) 5074 { 5075 if (str_l < str_m) 5076 { 5077 size_t avail = str_m - str_l; 5078 5079 mch_memmove(str + str_l, 5080 str_arg + zero_padding_insertion_ind, 5081 (size_t)sn > avail ? avail : (size_t)sn); 5082 } 5083 str_l += sn; 5084 } 5085 } 5086 5087 // insert right padding 5088 if (justify_left) 5089 { 5090 // right blank padding to the field width 5091 int pn = (int)(min_field_width 5092 - (str_arg_l + number_of_zeros_to_pad)); 5093 5094 if (pn > 0) 5095 { 5096 if (str_l < str_m) 5097 { 5098 size_t avail = str_m - str_l; 5099 5100 vim_memset(str + str_l, ' ', 5101 (size_t)pn > avail ? avail 5102 : (size_t)pn); 5103 } 5104 str_l += pn; 5105 } 5106 } 5107 vim_free(tofree); 5108 } 5109 } 5110 5111 if (str_m > 0) 5112 { 5113 // make sure the string is nul-terminated even at the expense of 5114 // overwriting the last character (shouldn't happen, but just in case) 5115 // 5116 str[str_l <= str_m - 1 ? str_l : str_m - 1] = '\0'; 5117 } 5118 5119 if (tvs != NULL && tvs[arg_idx - 1].v_type != VAR_UNKNOWN) 5120 emsg(_("E767: Too many arguments to printf()")); 5121 5122 // Return the number of characters formatted (excluding trailing nul 5123 // character), that is, the number of characters that would have been 5124 // written to the buffer if it were large enough. 5125 return (int)str_l; 5126 } 5127 5128 #endif // PROTO 5129