enter.c 15.4 KB
Newer Older
Thomas Roessler's avatar
Thomas Roessler committed
1
/*
2
 * Copyright (C) 1996-2000 Michael R. Elkins <[email protected]>
3
 * Copyright (C) 2000 Edmund Grimley Evans <[email protected]>
Thomas Roessler's avatar
Thomas Roessler committed
4 5 6 7 8 9 10 11 12 13 14 15 16
 * 
 *     This program is free software; you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation; either version 2 of the License, or
 *     (at your option) any later version.
 * 
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 * 
 *     You should have received a copy of the GNU General Public License
 *     along with this program; if not, write to the Free Software
17
 *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
Thomas Roessler's avatar
Thomas Roessler committed
18 19 20 21 22 23
 */ 

#include "mutt.h"
#include "mutt_menu.h"
#include "mutt_curses.h"
#include "keymap.h"
Thomas Roessler's avatar
Thomas Roessler committed
24
#include "history.h"
Thomas Roessler's avatar
Thomas Roessler committed
25 26 27 28 29 30

#include <string.h>

/* redraw flags for mutt_enter_string() */
enum
{
31 32
  M_REDRAW_INIT = 1,	/* go to end of line and redraw */
  M_REDRAW_LINE		/* redraw entire line */
Thomas Roessler's avatar
Thomas Roessler committed
33 34
};

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
/* FIXME: these functions should deal with unprintable characters */

static int my_wcwidth (wchar_t wc)
{
  return wcwidth (wc);
}

static int my_wcswidth (const wchar_t *s, size_t n)
{
  int w = 0;
  while (n--)
    w += my_wcwidth (*s++);
  return w;
}

static int my_addwch (wchar_t wc)
{
  return mutt_addwch (wc);
}

static size_t width_ceiling (const wchar_t *s, size_t n, int w1)
{
  const wchar_t *s0 = s;
  int w = 0;
  for (; n; s++, n--)
    if ((w += my_wcwidth (*s)) > w1)
      break;
  return s - s0;  
}

void my_wcstombs(char *dest, size_t dlen, const wchar_t *src, size_t slen)
{
  mbstate_t st;
  size_t  k;

  memset (&st, 0, sizeof (st));
  for (; slen && dlen >= 2 * MB_LEN_MAX; dest += k, dlen -= k, src++, slen--)
    if ((k = wcrtomb (dest, *src, &st)) == (size_t)(-1))
      break;
  wcrtomb (dest, 0, &st); /* FIXME */
}

size_t my_mbstowcs (wchar_t **pwbuf, size_t *pwbuflen, size_t i, char *buf)
{
  wchar_t wc;
  mbstate_t st;
  size_t k;
  wchar_t *wbuf;
  size_t wbuflen;

  wbuf = *pwbuf, wbuflen = *pwbuflen;
  memset (&st, 0, sizeof (st));
  for (; (k = mbrtowc (&wc, buf, MB_LEN_MAX, &st)) &&
	 k != (size_t)(-1) && k != (size_t)(-2); buf += k)
  {
    if (i >= wbuflen)
    {
      wbuflen = i + 20;
      safe_realloc ((void **) &wbuf, wbuflen * sizeof (*wbuf));
    }
    wbuf[i++] = wc;
  }
  *pwbuf = wbuf, *pwbuflen = wbuflen;
  return i;
}

/*
102
 * Replace part of the wchar_t buffer, from FROM to CURPOS, by BUF.
103 104
 */

105
static void replace_part (ENTER_STATE *state, size_t from, char *buf)
106 107
{
  /* Save the suffix */
108
  size_t savelen = state->lastchar - state->curpos;
109
  wchar_t *savebuf = safe_malloc (savelen * sizeof (wchar_t));
110
  memcpy (savebuf, state->wbuf + state->curpos, savelen * sizeof (wchar_t));
111 112

  /* Convert to wide characters */
113
  state->curpos = my_mbstowcs (&state->wbuf, &state->wbuflen, from, buf);
114 115

  /* Make space for suffix */
116
  if (state->curpos + savelen > state->wbuflen)
117
  {
118 119
    state->wbuflen = state->curpos + savelen;
    safe_realloc ((void **) state->wbuf, state->wbuflen * sizeof (wchar_t));
120 121 122
  }

  /* Restore suffix */
123 124
  memcpy (state->wbuf + state->curpos, savebuf, savelen * sizeof (wchar_t));
  state->lastchar = state->curpos + savelen;
125 126 127 128 129 130

  free (savebuf);
}

/*
 * Returns:
Thomas Roessler's avatar
Thomas Roessler committed
131 132 133 134
 *	1 need to redraw the screen and call me again
 *	0 if input was given
 * 	-1 if abort.
 */
135

136 137 138 139 140 141 142 143 144
int  mutt_enter_string(char *buf, size_t buflen, int y, int x, int flags)
{
  int rv;
  ENTER_STATE *es = mutt_new_enter_state ();
  rv = _mutt_enter_string (buf, buflen, y, x, flags, 0, NULL, NULL, es);
  mutt_free_enter_state (&es);
  return rv;
}

145
int _mutt_enter_string (char *buf, size_t buflen, int y, int x,
146 147
			int flags, int multiple, char ***files, int *numfiles,
			ENTER_STATE *state)
Thomas Roessler's avatar
Thomas Roessler committed
148
{
149 150 151
  int width = COLS - x - 1;
  int redraw;
  int pass = (flags & M_PASS);
Thomas Roessler's avatar
Thomas Roessler committed
152
  int first = 1;
153
  int tabs = 0; /* number of *consecutive* TABs */
154 155 156 157 158
  int ch, w, r;
  size_t i;
  wchar_t *tempbuf = 0;
  size_t templen = 0;
  history_class_t hclass;
159

160 161 162
  int rv = 0;
  
  if (state->wbuf)
163 164 165 166 167
  {
    /* Coming back after return 1 */
    redraw = M_REDRAW_LINE;
  }
  else
168
  {
169
    /* Initialise wbuf from buf */
170
    state->wbuflen = 0;
171
    state->lastchar = my_mbstowcs (&state->wbuf, &state->wbuflen, 0, buf);
172
    redraw = M_REDRAW_INIT;
173 174
  }

175
  if (flags & (M_FILE | M_EFILE))
Thomas Roessler's avatar
Thomas Roessler committed
176
    hclass = HC_FILE;
177
  else if (flags & M_CMD)
Thomas Roessler's avatar
Thomas Roessler committed
178
    hclass = HC_CMD;
179
  else if (flags & M_ALIAS)
Thomas Roessler's avatar
Thomas Roessler committed
180
    hclass = HC_ALIAS;
181
  else if (flags & M_COMMAND)
182
    hclass = HC_COMMAND;
183 184
  else if (flags & M_PATTERN)
    hclass = HC_PATTERN;
Thomas Roessler's avatar
Thomas Roessler committed
185 186
  else 
    hclass = HC_OTHER;
187 188
    
  for (;;)
Thomas Roessler's avatar
Thomas Roessler committed
189
  {
190
    if (redraw && !pass)
Thomas Roessler's avatar
Thomas Roessler committed
191 192 193
    {
      if (redraw == M_REDRAW_INIT)
      {
194
	/* Go to end of line */
195 196
	state->curpos = state->lastchar;
	state->begin = width_ceiling (state->wbuf, state->lastchar, my_wcswidth (state->wbuf, state->lastchar) - width + 1);
197
      } 
198 199
      if (state->curpos < state->begin ||
	  my_wcswidth (state->wbuf + state->begin, state->curpos - state->begin) >= width)
200
	state->begin = width_ceiling (state->wbuf, state->lastchar, my_wcswidth (state->wbuf, state->curpos) - width / 2);
201 202
      move (y, x);
      w = 0;
203
      for (i = state->begin; i < state->lastchar; i++)
Thomas Roessler's avatar
Thomas Roessler committed
204
      {
205
	w += my_wcwidth (state->wbuf[i]);
206
	if (w > width)
Thomas Roessler's avatar
Thomas Roessler committed
207
	  break;
208
	my_addwch (state->wbuf[i]);
209
      }
Thomas Roessler's avatar
Thomas Roessler committed
210
      clrtoeol ();
211
      move (y, x + my_wcswidth (state->wbuf + state->begin, state->curpos - state->begin));
Thomas Roessler's avatar
Thomas Roessler committed
212 213 214 215 216
    }
    mutt_refresh ();

    if ((ch = km_dokey (MENU_EDITOR)) == -1)
    {
217 218
      rv = -1; 
      goto bye;
Thomas Roessler's avatar
Thomas Roessler committed
219 220
    }

221
    if (ch != OP_NULL)
Thomas Roessler's avatar
Thomas Roessler committed
222
    {
223
      first = 0;
224 225
      if (ch != OP_EDITOR_COMPLETE)
	tabs = 0;
226
      redraw = M_REDRAW_LINE;
Thomas Roessler's avatar
Thomas Roessler committed
227 228 229
      switch (ch)
      {
	case OP_EDITOR_HISTORY_UP:
230
	  state->curpos = state->lastchar;
231
	  replace_part (state, 0, mutt_history_prev (hclass));
232
	  redraw = M_REDRAW_INIT;
Thomas Roessler's avatar
Thomas Roessler committed
233
	  break;
234

Thomas Roessler's avatar
Thomas Roessler committed
235
	case OP_EDITOR_HISTORY_DOWN:
236
	  state->curpos = state->lastchar;
237
	  replace_part (state, 0, mutt_history_prev (hclass));
238
	  redraw = M_REDRAW_INIT;
Thomas Roessler's avatar
Thomas Roessler committed
239
	  break;
240

Thomas Roessler's avatar
Thomas Roessler committed
241
	case OP_EDITOR_BACKSPACE:
242
	  if (state->curpos == 0)
Thomas Roessler's avatar
Thomas Roessler committed
243
	    BEEP ();
244
	  else
Thomas Roessler's avatar
Thomas Roessler committed
245
	  {
246 247
	    i = state->curpos;
	    while (i && !wcwidth (state->wbuf[i - 1]))
248 249 250
	      --i;
	    if (i)
	      --i;
251
	    memmove (state->wbuf + i, state->wbuf + state->curpos, (state->lastchar - state->curpos) * sizeof (wchar_t));
252
	    state->lastchar -= state->curpos - i;
253
	    state->curpos = i;
Thomas Roessler's avatar
Thomas Roessler committed
254 255
	  }
	  break;
256

Thomas Roessler's avatar
Thomas Roessler committed
257
	case OP_EDITOR_BOL:
258
	  state->curpos = 0;
Thomas Roessler's avatar
Thomas Roessler committed
259
	  break;
260

Thomas Roessler's avatar
Thomas Roessler committed
261
	case OP_EDITOR_EOL:
262
	  redraw= M_REDRAW_INIT;
Thomas Roessler's avatar
Thomas Roessler committed
263
	  break;
264

Thomas Roessler's avatar
Thomas Roessler committed
265
	case OP_EDITOR_KILL_LINE:
266
	  state->curpos = state->lastchar = 0;
Thomas Roessler's avatar
Thomas Roessler committed
267
	  break;
268

Thomas Roessler's avatar
Thomas Roessler committed
269
	case OP_EDITOR_KILL_EOL:
270
	  state->lastchar = state->curpos;
Thomas Roessler's avatar
Thomas Roessler committed
271
	  break;
272

Thomas Roessler's avatar
Thomas Roessler committed
273
	case OP_EDITOR_BACKWARD_CHAR:
274
	  if (state->curpos == 0)
Thomas Roessler's avatar
Thomas Roessler committed
275 276 277
	    BEEP ();
	  else
	  {
278 279 280 281
	    while (state->curpos && !wcwidth (state->wbuf[state->curpos - 1]))
	      state->curpos--;
	    if (state->curpos)
	      state->curpos--;
Thomas Roessler's avatar
Thomas Roessler committed
282 283
	  }
	  break;
284

Thomas Roessler's avatar
Thomas Roessler committed
285
	case OP_EDITOR_FORWARD_CHAR:
286
	  if (state->curpos == state->lastchar)
Thomas Roessler's avatar
Thomas Roessler committed
287 288 289
	    BEEP ();
	  else
	  {
290
	    ++state->curpos;
291
	    while (state->curpos < state->lastchar && !wcwidth (state->wbuf[state->curpos]))
292
	      ++state->curpos;
Thomas Roessler's avatar
Thomas Roessler committed
293 294
	  }
	  break;
295

296
	case OP_EDITOR_BACKWARD_WORD:
297
	  if (state->curpos == 0)
298 299 300
	    BEEP ();
	  else
	  {
301
	    while (state->curpos && iswspace (state->wbuf[state->curpos - 1]))
302
	      --state->curpos;
303
	    while (state->curpos && !iswspace (state->wbuf[state->curpos - 1]))
304
	      --state->curpos;
305 306 307 308
	  }
	  break;

	case OP_EDITOR_FORWARD_WORD:
309
	  if (state->curpos == state->lastchar)
310 311 312
	    BEEP ();
	  else
	  {
313
	    while (state->curpos < state->lastchar && iswspace (state->wbuf[state->curpos]))
314
	      ++state->curpos;
315
	    while (state->curpos < state->lastchar && !iswspace (state->wbuf[state->curpos]))
316
	      ++state->curpos;
317 318 319
	  }
	  break;

320 321 322
	case OP_EDITOR_CAPITALIZE_WORD:
	case OP_EDITOR_UPCASE_WORD:
	case OP_EDITOR_DOWNCASE_WORD:
323
	  if (state->curpos == state->lastchar)
324
	  {
325
	    BEEP ();
326 327
	    break;
	  }
328
	  while (state->curpos && !iswspace (state->wbuf[state->curpos]))
329
	    --state->curpos;
330
	  while (state->curpos < state->lastchar && iswspace (state->wbuf[state->curpos]))
331
	    ++state->curpos;
332
	  while (state->curpos < state->lastchar && !iswspace (state->wbuf[state->curpos]))
333
	  {
334
	    if (ch == OP_EDITOR_DOWNCASE_WORD)
335
	      state->wbuf[state->curpos] = towlower (state->wbuf[state->curpos]);
336
	    else
337
	    {
338
	      state->wbuf[state->curpos] = towupper (state->wbuf[state->curpos]);
339 340
	      if (ch == OP_EDITOR_CAPITALIZE_WORD)
		ch = OP_EDITOR_DOWNCASE_WORD;
341
	    }
342
	    state->curpos++;
343 344
	  }
	  break;
345

Thomas Roessler's avatar
Thomas Roessler committed
346
	case OP_EDITOR_DELETE_CHAR:
347
	  if (state->curpos == state->lastchar)
Thomas Roessler's avatar
Thomas Roessler committed
348
	    BEEP ();
349
	  else
Thomas Roessler's avatar
Thomas Roessler committed
350
	  {
351
	    i = state->curpos;
352
	    while (i < state->lastchar && !wcwidth (state->wbuf[i]))
353
	      ++i;
354
	    if (i < state->lastchar)
355
	      ++i;
356
	    while (i < state->lastchar && !wcwidth (state->wbuf[i]))
357
	      ++i;
358
	    memmove (state->wbuf + state->curpos, state->wbuf + i, (state->lastchar - i) * sizeof (wchar_t));
359
	    state->lastchar -= i - state->curpos;
Thomas Roessler's avatar
Thomas Roessler committed
360 361
	  }
	  break;
362

363 364 365 366
	case OP_EDITOR_KILL_WORD:
	  /* delete to begining of word */
	  if (state->curpos != 0)
	  {
367 368 369 370
	    i = state->curpos;
	    while (i && iswspace (state->wbuf[i - 1]))
	      --i;
	    if (i)
371
	    {
372
	      if (iswalnum (state->wbuf[i - 1]))
373
	      {
374
		for (--i; i && iswalnum (state->wbuf[i - 1]); i--)
375 376 377
		  ;
	      }
	      else
378
		--i;
379
	    }
380 381 382 383
	    memmove (state->wbuf + i, state->wbuf + state->curpos,
		     (state->lastchar - state->curpos) * sizeof (wchar_t));
	    state->lastchar += i - state->curpos;
	    state->curpos = i;
384 385 386 387 388
	  }
	  break;

	case OP_EDITOR_KILL_EOW:
	  /* delete to end of word */
389 390
	  for (i = state->curpos;
	       i < state->lastchar && iswspace (state->wbuf[i]); i++)
391
	    ;
392
	  for (; i < state->lastchar && !iswspace (state->wbuf[i]); i++)
393
	    ;
394 395 396
	  memmove (state->wbuf + state->curpos, state->wbuf + i,
		   (state->lastchar - i) * sizeof (wchar_t));
	  state->lastchar += state->curpos - i;
397
	  break;
398

Thomas Roessler's avatar
Thomas Roessler committed
399 400 401 402
	case OP_EDITOR_BUFFY_CYCLE:
	  if (flags & M_EFILE)
	  {
	    first = 1; /* clear input if user types a real key later */
403
	    my_wcstombs (buf, buflen, state->wbuf, state->curpos);
404
	    mutt_buffy (buf);
405
	    state->curpos = state->lastchar = my_mbstowcs (&state->wbuf, &state->wbuflen, 0, buf);
Thomas Roessler's avatar
Thomas Roessler committed
406 407 408 409 410 411 412
	    break;
	  }
	  else if (!(flags & M_FILE))
	    goto self_insert;
	  /* fall through to completion routine (M_FILE) */

	case OP_EDITOR_COMPLETE:
413
	  tabs++;
Thomas Roessler's avatar
Thomas Roessler committed
414 415
	  if (flags & M_CMD)
	  {
416
	    for (i = state->curpos; i && state->wbuf[i-1] != ' '; i--)
417
	      ;
418
	    my_wcstombs (buf, buflen, state->wbuf + i, state->curpos - i);
419
	    if (tempbuf && templen == state->lastchar - i &&
420
		!memcmp (tempbuf, state->wbuf + i, (state->lastchar - i) * sizeof (wchar_t)))
Thomas Roessler's avatar
Thomas Roessler committed
421
	    {
422
	      mutt_select_file (buf, buflen, 0);
Thomas Roessler's avatar
Thomas Roessler committed
423
	      set_option (OPTNEEDREDRAW);
424
	      if (*buf)
425
		replace_part (state, i, buf);
426 427
	      rv = 1; 
	      goto bye;
428 429 430
	    }
	    if (!mutt_complete (buf, buflen))
	    {
431
	      templen = state->lastchar - i;
432
	      safe_realloc ((void **) &tempbuf, templen * sizeof (wchar_t));
Thomas Roessler's avatar
Thomas Roessler committed
433 434 435
	    }
	    else
	      BEEP ();
436

437
	    replace_part (state, i, buf);
Thomas Roessler's avatar
Thomas Roessler committed
438 439 440 441
	  }
	  else if (flags & M_ALIAS)
	  {
	    /* invoke the alias-menu to get more addresses */
442
	    for (i = state->curpos; i && state->wbuf[i-1] != ','; i--)
443
	      ;
444
	    for (; i < state->lastchar && state->wbuf[i] == ' '; i++)
445
	      ;
446
	    my_wcstombs (buf, buflen, state->wbuf + i, state->curpos - i);
447
	    r = mutt_alias_complete (buf, buflen);
448
	    replace_part (state, i, buf);
449
	    if (!r)
450 451 452 453
	    {
	      rv = 1;
	      goto bye;
	    }
454
	    break;
Thomas Roessler's avatar
Thomas Roessler committed
455
	  }
Thomas Roessler's avatar
Thomas Roessler committed
456 457
	  else if (flags & M_COMMAND)
	  {
458
	    my_wcstombs (buf, buflen, state->wbuf, state->curpos);
459
	    i = strlen (buf);
460
	    if (i && buf[i - 1] == '=' &&
461
		mutt_var_value_complete (buf, buflen, i))
462
	      tabs = 0;
463
	    else if (!mutt_command_complete (buf, buflen, i, tabs))
464
	      BEEP ();
465
	    replace_part (state, 0, buf);
Thomas Roessler's avatar
Thomas Roessler committed
466
	  }
Thomas Roessler's avatar
Thomas Roessler committed
467 468
	  else if (flags & (M_FILE | M_EFILE))
	  {
469
	    my_wcstombs (buf, buflen, state->wbuf, state->curpos);
Thomas Roessler's avatar
Thomas Roessler committed
470 471

	    /* see if the path has changed from the last time */
472 473
	    if (!tempbuf || (templen == state->lastchar &&
		!memcmp (tempbuf, state->wbuf, state->lastchar * sizeof (wchar_t))))
Thomas Roessler's avatar
Thomas Roessler committed
474
	    {
475
	      _mutt_select_file (buf, buflen, 0, multiple, files, numfiles);
Thomas Roessler's avatar
Thomas Roessler committed
476
	      set_option (OPTNEEDREDRAW);
477
	      if (*buf)
Thomas Roessler's avatar
Thomas Roessler committed
478
	      {
479 480 481
		mutt_pretty_mailbox (buf);
		if (!pass)
		  mutt_history_add (hclass, buf);
482 483
		rv = 0;
		goto bye;
Thomas Roessler's avatar
Thomas Roessler committed
484
	      }
485 486

	      /* file selection cancelled */
487 488
	      rv = 1;
	      goto bye;
Thomas Roessler's avatar
Thomas Roessler committed
489 490
	    }

491 492
	    if (!mutt_complete (buf, buflen))
	    {
493
	      templen = state->lastchar;
494 495
	      safe_realloc ((void **) &tempbuf, templen * sizeof (wchar_t));
	      memcpy (tempbuf, state->wbuf, templen * sizeof (wchar_t));
496
	    }
Thomas Roessler's avatar
Thomas Roessler committed
497 498
	    else
	      BEEP (); /* let the user know that nothing matched */
499
	    replace_part (state, 0, buf);
Thomas Roessler's avatar
Thomas Roessler committed
500 501 502 503 504 505 506 507 508
	  }
	  else
	    goto self_insert;
	  break;

	case OP_EDITOR_COMPLETE_QUERY:
	  if (flags & M_ALIAS)
	  {
	    /* invoke the query-menu to get more addresses */
509
	    if (state->curpos)
Thomas Roessler's avatar
Thomas Roessler committed
510
	    {
511
	      for (i = state->curpos; i && buf[i - 1] != ','; i--)
512
		;
513
	      for (; i < state->curpos && buf[i] == ' '; i++)
514
		;
515
	      my_wcstombs (buf, buflen, state->wbuf + i, state->curpos - i);
516
	      mutt_query_complete (buf, buflen);
517
	      replace_part (state, i, buf);
Thomas Roessler's avatar
Thomas Roessler committed
518 519
	    }
	    else
520
	    {
521
	      my_wcstombs (buf, buflen, state->wbuf, state->curpos);
522
	      mutt_query_menu (buf, buflen);
523
	      replace_part (state, 0, buf);
524
	    }
525 526
	    rv = 1; 
	    goto bye;
Thomas Roessler's avatar
Thomas Roessler committed
527 528 529 530 531
	  }
	  else
	    goto self_insert;

	case OP_EDITOR_QUOTE_CHAR:
532
	  {
533 534 535 536 537 538 539 540
	    event_t event;
	    /*ADDCH (LastKey);*/
	    event = mutt_getch ();
	    if (event.ch != -1)
	    {
	      LastKey = event.ch;
	      goto self_insert;
	    }
541 542
	  }

543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560
	case OP_EDITOR_TRANSPOSE_CHARS:
	  if (state->lastchar < 2)
	    BEEP ();
	  else
	{
	    wchar_t t;

	    if (state->curpos == 0)
	      state->curpos = 2;
	    else if (state->curpos < state->lastchar)
	      ++state->curpos;

	    t = state->wbuf[state->curpos - 2];
	    state->wbuf[state->curpos - 2] = state->wbuf[state->curpos - 1];
	    state->wbuf[state->curpos - 1] = t;
	  }
	  break;

Thomas Roessler's avatar
Thomas Roessler committed
561 562 563 564 565 566
	default:
	  BEEP ();
      }
    }
    else
    {
567
      
Thomas Roessler's avatar
Thomas Roessler committed
568 569
self_insert:

570
      tabs = 0;
Thomas Roessler's avatar
Thomas Roessler committed
571 572 573 574 575 576
      /* use the raw keypress */
      ch = LastKey;

      if (first && (flags & M_CLEAR))
      {
	first = 0;
577
	if (IsWPrint (ch)) /* why? */
578
	  state->curpos = state->lastchar = 0;
Thomas Roessler's avatar
Thomas Roessler committed
579 580 581 582
      }

      if (CI_is_return (ch))
      {
583
	/* Convert from wide characters */
584
	my_wcstombs (buf, buflen, state->wbuf, state->lastchar);
Thomas Roessler's avatar
Thomas Roessler committed
585
	if (!pass)
586 587
	  mutt_history_add (hclass, buf);

588 589 590 591 592
	if (multiple)
	{
	  char **tfiles;
	  *numfiles = 1;
	  tfiles = safe_malloc (*numfiles * sizeof (char *));
593 594
	  mutt_expand_path (buf, buflen);
	  tfiles[0] = safe_strdup (buf);
595 596
	  *files = tfiles;
	}
597 598
	rv = 0; 
	goto bye;
Thomas Roessler's avatar
Thomas Roessler committed
599
      }
600
      else if ((ch < ' ' || IsWPrint (ch))) /* why? */
Thomas Roessler's avatar
Thomas Roessler committed
601
      {
602
	if (state->lastchar >= state->wbuflen)
Thomas Roessler's avatar
Thomas Roessler committed
603
	{
604
	  state->wbuflen = state->lastchar + 20;
605
	  safe_realloc ((void **) &state->wbuf, state->wbuflen * sizeof (wchar_t));
Thomas Roessler's avatar
Thomas Roessler committed
606
	}
607
	memmove (state->wbuf + state->curpos + 1, state->wbuf + state->curpos, (state->lastchar - state->curpos) * sizeof (wchar_t));
608
	state->wbuf[state->curpos++] = ch;
609
	state->lastchar++;
Thomas Roessler's avatar
Thomas Roessler committed
610 611 612 613 614 615 616 617
      }
      else
      {
	mutt_flushinp ();
	BEEP ();
      }
    }
  }
618 619 620 621 622 623 624 625 626 627 628 629 630
  
  bye:
  
  safe_free ((void **) &tempbuf);
  return rv;
}

void mutt_free_enter_state (ENTER_STATE **esp)
{
  if (!esp) return;
  
  safe_free ((void **) &(*esp)->wbuf);
  safe_free ((void **) esp);
Thomas Roessler's avatar
Thomas Roessler committed
631
}
632 633 634 635 636 637 638

/*
 * TODO:
 * very narrow screen might crash it
 * sort out the input side
 * unprintable chars
 */