mutt stable branch with some hacks
at jcs 847 lines 21 kB view raw
1/* 2 * Copyright (C) 1996-2000,2007,2011,2013 Michael R. Elkins <me@mutt.org> 3 * Copyright (C) 2000-2001 Edmund Grimley Evans <edmundo@rano.org> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 */ 19 20#if HAVE_CONFIG_H 21# include "config.h" 22#endif 23 24#include "mutt.h" 25#include "mutt_menu.h" 26#include "mutt_curses.h" 27#include "keymap.h" 28#include "history.h" 29#include "buffy.h" 30 31#include <string.h> 32 33/* redraw flags for mutt_enter_string() */ 34enum 35{ 36 MUTT_REDRAW_INIT = 1, /* go to end of line and redraw */ 37 MUTT_REDRAW_LINE /* redraw entire line */ 38}; 39 40static int my_wcwidth (wchar_t wc) 41{ 42 int n = wcwidth (wc); 43 if (IsWPrint (wc) && n > 0) 44 return n; 45 if (!(wc & ~0x7f)) 46 return 2; 47 if (!(wc & ~0xffff)) 48 return 6; 49 return 10; 50} 51 52/* combining mark / non-spacing character */ 53#define COMB_CHAR(wc) (IsWPrint (wc) && !wcwidth (wc)) 54 55static int my_wcswidth (const wchar_t *s, size_t n) 56{ 57 int w = 0; 58 while (n--) 59 w += my_wcwidth (*s++); 60 return w; 61} 62 63static int my_addwch (wchar_t wc) 64{ 65 int n = wcwidth (wc); 66 if (IsWPrint (wc) && n > 0) 67 return mutt_addwch (wc); 68 if (!(wc & ~0x7f)) 69 return printw ("^%c", ((int)wc + 0x40) & 0x7f); 70 if (!(wc & ~0xffff)) 71 return printw ("\\u%04x", (int)wc); 72 return printw ("\\u%08x", (int)wc); 73} 74 75static size_t width_ceiling (const wchar_t *s, size_t n, int w1) 76{ 77 const wchar_t *s0 = s; 78 int w = 0; 79 for (; n; s++, n--) 80 if ((w += my_wcwidth (*s)) > w1) 81 break; 82 return s - s0; 83} 84 85static void my_wcstombs (char *dest, size_t dlen, const wchar_t *src, size_t slen) 86{ 87 mbstate_t st; 88 size_t k; 89 90 /* First convert directly into the destination buffer */ 91 memset (&st, 0, sizeof (st)); 92 for (; slen && dlen >= MB_LEN_MAX; dest += k, dlen -= k, src++, slen--) 93 if ((k = wcrtomb (dest, *src, &st)) == (size_t)(-1)) 94 break; 95 96 /* If this works, we can stop now */ 97 if (dlen >= MB_LEN_MAX) 98 { 99 /* We don't need to update dest - this just appeases -Wunused-result */ 100 dest += wcrtomb (dest, 0, &st); 101 return; 102 } 103 104 /* Otherwise convert any remaining data into a local buffer */ 105 { 106 char buf[3 * MB_LEN_MAX]; 107 char *p = buf; 108 109 for (; slen && p - buf < dlen; p += k, src++, slen--) 110 if ((k = wcrtomb (p, *src, &st)) == (size_t)(-1)) 111 break; 112 p += wcrtomb (p, 0, &st); 113 114 /* If it fits into the destination buffer, we can stop now */ 115 if (p - buf <= dlen) 116 { 117 memcpy (dest, buf, p - buf); 118 return; 119 } 120 121 /* Otherwise we truncate the string in an ugly fashion */ 122 memcpy (dest, buf, dlen); 123 dest[dlen - 1] = '\0'; /* assume original dlen > 0 */ 124 } 125} 126 127static size_t my_mbstowcs (wchar_t **pwbuf, size_t *pwbuflen, size_t i, char *buf) 128{ 129 wchar_t wc; 130 mbstate_t st; 131 size_t k; 132 wchar_t *wbuf; 133 size_t wbuflen; 134 135 wbuf = *pwbuf, wbuflen = *pwbuflen; 136 137 while (*buf) 138 { 139 memset (&st, 0, sizeof (st)); 140 for (; (k = mbrtowc (&wc, buf, MB_LEN_MAX, &st)) && 141 k != (size_t)(-1) && k != (size_t)(-2); buf += k) 142 { 143 if (i >= wbuflen) 144 { 145 wbuflen = i + 20; 146 safe_realloc (&wbuf, wbuflen * sizeof (*wbuf)); 147 } 148 wbuf[i++] = wc; 149 } 150 if (*buf && (k == (size_t) -1 || k == (size_t) -2)) 151 { 152 if (i >= wbuflen) 153 { 154 wbuflen = i + 20; 155 safe_realloc (&wbuf, wbuflen * sizeof (*wbuf)); 156 } 157 wbuf[i++] = replacement_char(); 158 buf++; 159 } 160 } 161 *pwbuf = wbuf, *pwbuflen = wbuflen; 162 return i; 163} 164 165/* 166 * Replace part of the wchar_t buffer, from FROM to CURPOS, by BUF. 167 */ 168 169static void replace_part (ENTER_STATE *state, size_t from, char *buf) 170{ 171 /* Save the suffix */ 172 size_t savelen = state->lastchar - state->curpos; 173 wchar_t *savebuf = NULL; 174 175 if (savelen) 176 { 177 savebuf = safe_calloc (savelen, sizeof (wchar_t)); 178 memcpy (savebuf, state->wbuf + state->curpos, savelen * sizeof (wchar_t)); 179 } 180 181 /* Convert to wide characters */ 182 state->curpos = my_mbstowcs (&state->wbuf, &state->wbuflen, from, buf); 183 184 if (savelen) 185 { 186 /* Make space for suffix */ 187 if (state->curpos + savelen > state->wbuflen) 188 { 189 state->wbuflen = state->curpos + savelen; 190 safe_realloc (&state->wbuf, state->wbuflen * sizeof (wchar_t)); 191 } 192 193 /* Restore suffix */ 194 memcpy (state->wbuf + state->curpos, savebuf, savelen * sizeof (wchar_t)); 195 FREE (&savebuf); 196 } 197 198 state->lastchar = state->curpos + savelen; 199} 200 201/* 202 * Return 1 if the character is not typically part of a pathname 203 */ 204static inline int is_shell_char(wchar_t ch) 205{ 206 static const wchar_t shell_chars[] = L"<>&()$?*;{}| "; /* ! not included because it can be part of a pathname in Mutt */ 207 return wcschr(shell_chars, ch) != NULL; 208} 209 210/* This function is for very basic input, currently used only by the 211 * built-in editor. It does not handle screen redrawing on resizes 212 * well, because there is no active menu for the built-in editor. 213 * Most callers should prefer mutt_get_field() instead. 214 * 215 * Returns: 216 * 0 if input was given 217 * -1 if abort. 218 */ 219int mutt_enter_string(char *buf, size_t buflen, int col, int flags) 220{ 221 int rv; 222 ENTER_STATE *es = mutt_new_enter_state (); 223 do 224 { 225#if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM) 226 if (SigWinch) 227 { 228 SigWinch = 0; 229 mutt_resize_screen (); 230 clearok(stdscr, TRUE); 231 } 232#endif 233 rv = _mutt_enter_string (buf, buflen, col, flags, 0, NULL, NULL, es); 234 } 235 while (rv == 1); 236 mutt_free_enter_state (&es); 237 return rv; 238} 239 240/* 241 * Returns: 242 * 1 need to redraw the screen and call me again 243 * 0 if input was given 244 * -1 if abort. 245 */ 246int _mutt_enter_string (char *buf, size_t buflen, int col, 247 int flags, int multiple, char ***files, int *numfiles, 248 ENTER_STATE *state) 249{ 250 int width = MuttMessageWindow->cols - col - 1; 251 int redraw; 252 int pass = (flags & MUTT_PASS); 253 int first = 1; 254 int ch, w, r; 255 size_t i; 256 wchar_t *tempbuf = 0; 257 size_t templen = 0; 258 history_class_t hclass; 259 wchar_t wc; 260 mbstate_t mbstate; 261 262 int rv = 0; 263 memset (&mbstate, 0, sizeof (mbstate)); 264 265 if (state->wbuf) 266 { 267 /* Coming back after return 1 */ 268 redraw = MUTT_REDRAW_LINE; 269 first = 0; 270 } 271 else 272 { 273 /* Initialise wbuf from buf */ 274 state->wbuflen = 0; 275 state->lastchar = my_mbstowcs (&state->wbuf, &state->wbuflen, 0, buf); 276 redraw = MUTT_REDRAW_INIT; 277 } 278 279 if (flags & MUTT_FILE) 280 hclass = HC_FILE; 281 else if (flags & MUTT_EFILE) 282 hclass = HC_MBOX; 283 else if (flags & MUTT_CMD) 284 hclass = HC_CMD; 285 else if (flags & MUTT_ALIAS) 286 hclass = HC_ALIAS; 287 else if (flags & MUTT_COMMAND) 288 hclass = HC_COMMAND; 289 else if (flags & MUTT_PATTERN) 290 hclass = HC_PATTERN; 291 else 292 hclass = HC_OTHER; 293 294 for (;;) 295 { 296 if (redraw && !pass) 297 { 298 if (redraw == MUTT_REDRAW_INIT) 299 { 300 /* Go to end of line */ 301 state->curpos = state->lastchar; 302 state->begin = width_ceiling (state->wbuf, state->lastchar, my_wcswidth (state->wbuf, state->lastchar) - width + 1); 303 } 304 if (state->curpos < state->begin || 305 my_wcswidth (state->wbuf + state->begin, state->curpos - state->begin) >= width) 306 state->begin = width_ceiling (state->wbuf, state->lastchar, my_wcswidth (state->wbuf, state->curpos) - width / 2); 307 mutt_window_move (MuttMessageWindow, 0, col); 308 w = 0; 309 for (i = state->begin; i < state->lastchar; i++) 310 { 311 w += my_wcwidth (state->wbuf[i]); 312 if (w > width) 313 break; 314 my_addwch (state->wbuf[i]); 315 } 316 mutt_window_clrtoeol (MuttMessageWindow); 317 mutt_window_move (MuttMessageWindow, 0, 318 col + my_wcswidth (state->wbuf + state->begin, state->curpos - state->begin)); 319 } 320 mutt_refresh (); 321 322 if ((ch = km_dokey (MENU_EDITOR)) < 0) 323 { 324 rv = (SigWinch && ch == -2) ? 1 : -1; 325 goto bye; 326 } 327 328 if (ch != OP_NULL) 329 { 330 first = 0; 331 if (ch != OP_EDITOR_COMPLETE && ch != OP_EDITOR_COMPLETE_QUERY) 332 state->tabs = 0; 333 redraw = MUTT_REDRAW_LINE; 334 switch (ch) 335 { 336 case OP_EDITOR_HISTORY_UP: 337 state->curpos = state->lastchar; 338 if (mutt_history_at_scratch (hclass)) 339 { 340 my_wcstombs (buf, buflen, state->wbuf, state->curpos); 341 mutt_history_save_scratch (hclass, buf); 342 } 343 replace_part (state, 0, mutt_history_prev (hclass)); 344 redraw = MUTT_REDRAW_INIT; 345 break; 346 347 case OP_EDITOR_HISTORY_DOWN: 348 state->curpos = state->lastchar; 349 if (mutt_history_at_scratch (hclass)) 350 { 351 my_wcstombs (buf, buflen, state->wbuf, state->curpos); 352 mutt_history_save_scratch (hclass, buf); 353 } 354 replace_part (state, 0, mutt_history_next (hclass)); 355 redraw = MUTT_REDRAW_INIT; 356 break; 357 358 case OP_EDITOR_HISTORY_SEARCH: 359 state->curpos = state->lastchar; 360 my_wcstombs (buf, buflen, state->wbuf, state->curpos); 361 mutt_history_complete (buf, buflen, hclass); 362 replace_part (state, 0, buf); 363 rv = 1; 364 goto bye; 365 break; 366 367 case OP_EDITOR_BACKSPACE: 368 if (state->curpos == 0) 369 BEEP (); 370 else 371 { 372 i = state->curpos; 373 while (i && COMB_CHAR (state->wbuf[i - 1])) 374 --i; 375 if (i) 376 --i; 377 memmove (state->wbuf + i, state->wbuf + state->curpos, (state->lastchar - state->curpos) * sizeof (wchar_t)); 378 state->lastchar -= state->curpos - i; 379 state->curpos = i; 380 } 381 break; 382 383 case OP_EDITOR_BOL: 384 state->curpos = 0; 385 break; 386 387 case OP_EDITOR_EOL: 388 redraw= MUTT_REDRAW_INIT; 389 break; 390 391 case OP_EDITOR_KILL_LINE: 392 state->curpos = state->lastchar = 0; 393 break; 394 395 case OP_EDITOR_KILL_EOL: 396 state->lastchar = state->curpos; 397 break; 398 399 case OP_EDITOR_BACKWARD_CHAR: 400 if (state->curpos == 0) 401 BEEP (); 402 else 403 { 404 while (state->curpos && COMB_CHAR (state->wbuf[state->curpos - 1])) 405 state->curpos--; 406 if (state->curpos) 407 state->curpos--; 408 } 409 break; 410 411 case OP_EDITOR_FORWARD_CHAR: 412 if (state->curpos == state->lastchar) 413 BEEP (); 414 else 415 { 416 ++state->curpos; 417 while (state->curpos < state->lastchar && COMB_CHAR (state->wbuf[state->curpos])) 418 ++state->curpos; 419 } 420 break; 421 422 case OP_EDITOR_BACKWARD_WORD: 423 if (state->curpos == 0) 424 BEEP (); 425 else 426 { 427 while (state->curpos && iswspace (state->wbuf[state->curpos - 1])) 428 --state->curpos; 429 while (state->curpos && !iswspace (state->wbuf[state->curpos - 1])) 430 --state->curpos; 431 } 432 break; 433 434 case OP_EDITOR_FORWARD_WORD: 435 if (state->curpos == state->lastchar) 436 BEEP (); 437 else 438 { 439 while (state->curpos < state->lastchar && iswspace (state->wbuf[state->curpos])) 440 ++state->curpos; 441 while (state->curpos < state->lastchar && !iswspace (state->wbuf[state->curpos])) 442 ++state->curpos; 443 } 444 break; 445 446 case OP_EDITOR_CAPITALIZE_WORD: 447 case OP_EDITOR_UPCASE_WORD: 448 case OP_EDITOR_DOWNCASE_WORD: 449 if (state->curpos == state->lastchar) 450 { 451 BEEP (); 452 break; 453 } 454 while (state->curpos && !iswspace (state->wbuf[state->curpos])) 455 --state->curpos; 456 while (state->curpos < state->lastchar && iswspace (state->wbuf[state->curpos])) 457 ++state->curpos; 458 while (state->curpos < state->lastchar && !iswspace (state->wbuf[state->curpos])) 459 { 460 if (ch == OP_EDITOR_DOWNCASE_WORD) 461 state->wbuf[state->curpos] = towlower (state->wbuf[state->curpos]); 462 else 463 { 464 state->wbuf[state->curpos] = towupper (state->wbuf[state->curpos]); 465 if (ch == OP_EDITOR_CAPITALIZE_WORD) 466 ch = OP_EDITOR_DOWNCASE_WORD; 467 } 468 state->curpos++; 469 } 470 break; 471 472 case OP_EDITOR_DELETE_CHAR: 473 if (state->curpos == state->lastchar) 474 BEEP (); 475 else 476 { 477 i = state->curpos; 478 while (i < state->lastchar && COMB_CHAR (state->wbuf[i])) 479 ++i; 480 if (i < state->lastchar) 481 ++i; 482 while (i < state->lastchar && COMB_CHAR (state->wbuf[i])) 483 ++i; 484 memmove (state->wbuf + state->curpos, state->wbuf + i, (state->lastchar - i) * sizeof (wchar_t)); 485 state->lastchar -= i - state->curpos; 486 } 487 break; 488 489 case OP_EDITOR_KILL_WORD: 490 /* delete to beginning of word */ 491 if (state->curpos != 0) 492 { 493 i = state->curpos; 494 while (i && iswspace (state->wbuf[i - 1])) 495 --i; 496 if (i) 497 { 498 if (iswalnum (state->wbuf[i - 1])) 499 { 500 for (--i; i && iswalnum (state->wbuf[i - 1]); i--) 501 ; 502 } 503 else 504 --i; 505 } 506 memmove (state->wbuf + i, state->wbuf + state->curpos, 507 (state->lastchar - state->curpos) * sizeof (wchar_t)); 508 state->lastchar += i - state->curpos; 509 state->curpos = i; 510 } 511 break; 512 513 case OP_EDITOR_KILL_EOW: 514 /* delete to end of word */ 515 516 /* first skip over whitespace */ 517 for (i = state->curpos; 518 i < state->lastchar && iswspace (state->wbuf[i]); i++) 519 ; 520 521 /* if there are any characters left.. */ 522 if (i < state->lastchar) 523 { 524 /* if the current character is alphanumeric.. */ 525 if (iswalnum (state->wbuf[i])) 526 { 527 /* skip over the rest of the word consistent of only alphanumerics */ 528 for (; i < state->lastchar && iswalnum (state->wbuf[i]); i++) 529 ; 530 } 531 else 532 { 533 /* skip over one non-alphanumeric character */ 534 ++i; 535 } 536 } 537 538 memmove (state->wbuf + state->curpos, state->wbuf + i, 539 (state->lastchar - i) * sizeof (wchar_t)); 540 state->lastchar += state->curpos - i; 541 break; 542 543 case OP_EDITOR_BUFFY_CYCLE: 544 if (flags & MUTT_EFILE) 545 { 546 first = 1; /* clear input if user types a real key later */ 547 my_wcstombs (buf, buflen, state->wbuf, state->curpos); 548 mutt_buffy (buf, buflen); 549 state->curpos = state->lastchar = my_mbstowcs (&state->wbuf, &state->wbuflen, 0, buf); 550 break; 551 } 552 else if (!(flags & MUTT_FILE)) 553 goto self_insert; 554 /* else fall through */ 555 556 case OP_EDITOR_COMPLETE: 557 case OP_EDITOR_COMPLETE_QUERY: 558 state->tabs++; 559 if (flags & MUTT_CMD) 560 { 561 for (i = state->curpos; i && !is_shell_char(state->wbuf[i-1]); i--) 562 ; 563 my_wcstombs (buf, buflen, state->wbuf + i, state->curpos - i); 564 if (tempbuf && templen == state->lastchar - i && 565 !memcmp (tempbuf, state->wbuf + i, (state->lastchar - i) * sizeof (wchar_t))) 566 { 567 mutt_select_file (buf, buflen, (flags & MUTT_EFILE) ? MUTT_SEL_FOLDER : 0); 568 if (*buf) 569 replace_part (state, i, buf); 570 rv = 1; 571 goto bye; 572 } 573 if (!mutt_complete (buf, buflen)) 574 { 575 templen = state->lastchar - i; 576 safe_realloc (&tempbuf, templen * sizeof (wchar_t)); 577 } 578 else 579 BEEP (); 580 581 replace_part (state, i, buf); 582 } 583 else if (flags & MUTT_ALIAS && ch == OP_EDITOR_COMPLETE) 584 { 585 /* invoke the alias-menu to get more addresses */ 586 for (i = state->curpos; 587 i && state->wbuf[i-1] != ',' && state->wbuf[i-1] != ':'; 588 i--) 589 ; 590 for (; i < state->lastchar && state->wbuf[i] == ' '; i++) 591 ; 592 my_wcstombs (buf, buflen, state->wbuf + i, state->curpos - i); 593 r = mutt_alias_complete (buf, buflen); 594 replace_part (state, i, buf); 595 if (!r) 596 { 597 rv = 1; 598 goto bye; 599 } 600 break; 601 } 602 else if (flags & MUTT_LABEL && ch == OP_EDITOR_COMPLETE) 603 { 604 for (i = state->curpos; 605 i && state->wbuf[i-1] != ',' && state->wbuf[i-1] != ':'; 606 i--) 607 ; 608 for (; i < state->lastchar && state->wbuf[i] == ' '; i++) 609 ; 610 my_wcstombs (buf, buflen, state->wbuf + i, state->curpos - i); 611 r = mutt_label_complete (buf, buflen, state->tabs); 612 replace_part (state, i, buf); 613 if (!r) 614 { 615 rv = 1; 616 goto bye; 617 } 618 break; 619 } 620 else if (flags & MUTT_PATTERN && ch == OP_EDITOR_COMPLETE) 621 { 622 for (i = state->curpos; i && state->wbuf[i-1] != '~'; i--) 623 ; 624 if (i && i < state->curpos && state->wbuf[i-1] == '~' && state->wbuf[i] == 'y') 625 { 626 i++; 627 my_wcstombs (buf, buflen, state->wbuf + i, state->curpos - i); 628 r = mutt_label_complete (buf, buflen, state->tabs); 629 replace_part (state, i, buf); 630 if (!r) 631 { 632 rv = 1; 633 goto bye; 634 } 635 } 636 else 637 goto self_insert; 638 break; 639 } 640 else if (flags & MUTT_ALIAS && ch == OP_EDITOR_COMPLETE_QUERY) 641 { 642 /* invoke the query-menu to get more addresses */ 643 if ((i = state->curpos)) 644 { 645 for (; i && state->wbuf[i - 1] != ','; i--) 646 ; 647 for (; i < state->curpos && state->wbuf[i] == ' '; i++) 648 ; 649 } 650 651 my_wcstombs (buf, buflen, state->wbuf + i, state->curpos - i); 652 mutt_query_complete (buf, buflen); 653 replace_part (state, i, buf); 654 655 rv = 1; 656 goto bye; 657 } 658 else if (flags & MUTT_COMMAND) 659 { 660 my_wcstombs (buf, buflen, state->wbuf, state->curpos); 661 i = strlen (buf); 662 if (i && buf[i - 1] == '=' && 663 mutt_var_value_complete (buf, buflen, i)) 664 state->tabs = 0; 665 else if (!mutt_command_complete (buf, buflen, i, state->tabs)) 666 BEEP (); 667 replace_part (state, 0, buf); 668 } 669 else if (flags & (MUTT_FILE | MUTT_EFILE)) 670 { 671 my_wcstombs (buf, buflen, state->wbuf, state->curpos); 672 673 /* see if the path has changed from the last time */ 674 if ((!tempbuf && !state->lastchar) || 675 (tempbuf && templen == state->lastchar && 676 !memcmp (tempbuf, state->wbuf, state->lastchar * sizeof (wchar_t)))) 677 { 678 _mutt_select_file (buf, buflen, 679 ((flags & MUTT_EFILE) ? MUTT_SEL_FOLDER : 0) | (multiple ? MUTT_SEL_MULTI : 0), 680 files, numfiles); 681 if (*buf) 682 { 683 mutt_pretty_mailbox (buf, buflen); 684 if (!pass) 685 mutt_history_add (hclass, buf, 1); 686 rv = 0; 687 goto bye; 688 } 689 690 /* file selection cancelled */ 691 rv = 1; 692 goto bye; 693 } 694 695 if (!mutt_complete (buf, buflen)) 696 { 697 templen = state->lastchar; 698 safe_realloc (&tempbuf, templen * sizeof (wchar_t)); 699 memcpy (tempbuf, state->wbuf, templen * sizeof (wchar_t)); 700 } 701 else 702 BEEP (); /* let the user know that nothing matched */ 703 replace_part (state, 0, buf); 704 } 705 else 706 goto self_insert; 707 break; 708 709 case OP_EDITOR_QUOTE_CHAR: 710 { 711 event_t event; 712 /*ADDCH (LastKey);*/ 713 do 714 { 715 event = mutt_getch (); 716 } while (event.ch == -2); 717 if (event.ch >= 0) 718 { 719 LastKey = event.ch; 720 goto self_insert; 721 } 722 break; 723 } 724 725 case OP_EDITOR_TRANSPOSE_CHARS: 726 if (state->lastchar < 2) 727 BEEP (); 728 else 729 { 730 wchar_t t; 731 732 if (state->curpos == 0) 733 state->curpos = 2; 734 else if (state->curpos < state->lastchar) 735 ++state->curpos; 736 737 t = state->wbuf[state->curpos - 2]; 738 state->wbuf[state->curpos - 2] = state->wbuf[state->curpos - 1]; 739 state->wbuf[state->curpos - 1] = t; 740 } 741 break; 742 743 default: 744 BEEP (); 745 } 746 } 747 else 748 { 749 750self_insert: 751 752 state->tabs = 0; 753 /* use the raw keypress */ 754 ch = LastKey; 755 756#ifdef KEY_ENTER 757 /* treat ENTER the same as RETURN */ 758 if (ch == KEY_ENTER) 759 ch = '\r'; 760#endif 761 762 /* quietly ignore all other function keys */ 763 if (ch & ~0xff) 764 continue; 765 766 /* gather the octets into a wide character */ 767 { 768 char c; 769 size_t k; 770 771 c = ch; 772 k = mbrtowc (&wc, &c, 1, &mbstate); 773 if (k == (size_t)(-2)) 774 continue; 775 else if (k && k != 1) 776 { 777 memset (&mbstate, 0, sizeof (mbstate)); 778 continue; 779 } 780 } 781 782 if (first && (flags & MUTT_CLEAR)) 783 { 784 first = 0; 785 if (IsWPrint (wc)) /* why? */ 786 state->curpos = state->lastchar = 0; 787 } 788 789 if (wc == '\r' || wc == '\n') 790 { 791 /* Convert from wide characters */ 792 my_wcstombs (buf, buflen, state->wbuf, state->lastchar); 793 if (!pass) 794 mutt_history_add (hclass, buf, 1); 795 796 if (multiple) 797 { 798 char **tfiles; 799 *numfiles = 1; 800 tfiles = safe_calloc (*numfiles, sizeof (char *)); 801 mutt_expand_path (buf, buflen); 802 tfiles[0] = safe_strdup (buf); 803 *files = tfiles; 804 } 805 rv = 0; 806 goto bye; 807 } 808 else if (wc && (wc < ' ' || IsWPrint (wc))) /* why? */ 809 { 810 if (state->lastchar >= state->wbuflen) 811 { 812 state->wbuflen = state->lastchar + 20; 813 safe_realloc (&state->wbuf, state->wbuflen * sizeof (wchar_t)); 814 } 815 memmove (state->wbuf + state->curpos + 1, state->wbuf + state->curpos, (state->lastchar - state->curpos) * sizeof (wchar_t)); 816 state->wbuf[state->curpos++] = wc; 817 state->lastchar++; 818 } 819 else 820 { 821 mutt_flushinp (); 822 BEEP (); 823 } 824 } 825 } 826 827bye: 828 829 mutt_reset_history_state (hclass); 830 FREE (&tempbuf); 831 return rv; 832} 833 834void mutt_free_enter_state (ENTER_STATE **esp) 835{ 836 if (!esp) return; 837 838 FREE (&(*esp)->wbuf); 839 FREE (esp); /* __FREE_CHECKED__ */ 840} 841 842/* 843 * TODO: 844 * very narrow screen might crash it 845 * sort out the input side 846 * unprintable chars 847 */