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