~darkmuggle-deactivatedaccount/ubuntu/quantal/grub2/fix-872244

« back to all changes in this revision

Viewing changes to grub-core/normal/cmdline.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Evan Broder, Mario Limonciello
  • Date: 2010-11-24 13:59:55 UTC
  • mfrom: (1.17.6 upstream) (17.6.15 experimental)
  • Revision ID: james.westby@ubuntu.com-20101124135955-r6ii5sepayr7jt53
Tags: 1.99~20101124-1ubuntu1
[ Colin Watson ]
* Resynchronise with Debian experimental.  Remaining changes:
  - Adjust for default Ubuntu boot options ("quiet splash").
  - Default to hiding the menu; holding down Shift at boot will show it.
  - Set a monochromatic theme for Ubuntu.
  - Apply Ubuntu GRUB Legacy changes to legacy update-grub script: title,
    recovery mode, quiet option, tweak how memtest86+ is displayed, and
    use UUIDs where appropriate.
  - Fix backslash-escaping in merge_debconf_into_conf.
  - Remove "GNU/Linux" from default distributor string.
  - Add crashkernel= options if kdump and makedumpfile are available.
  - If other operating systems are installed, then automatically unhide
    the menu.  Otherwise, if GRUB_HIDDEN_TIMEOUT is 0, then use keystatus
    if available to check whether Shift is pressed.  If it is, show the
    menu, otherwise boot immediately.  If keystatus is not available, then
    fall back to a short delay interruptible with Escape.
  - Allow Shift to interrupt 'sleep --interruptible'.
  - Don't display introductory message about line editing unless we're
    actually offering a shell prompt.  Don't clear the screen just before
    booting if we never drew the menu in the first place.
  - Remove some verbose messages printed before reading the configuration
    file.
  - Suppress progress messages as the kernel and initrd load for
    non-recovery kernel menu entries.
  - Change prepare_grub_to_access_device to handle filesystems
    loop-mounted on file images.
  - Ignore devices loop-mounted from files in 10_linux.
  - Show the boot menu if the previous boot failed, that is if it failed
    to get to the end of one of the normal runlevels.
  - Don't generate /boot/grub/device.map during grub-install or
    grub-mkconfig by default.
  - Adjust upgrade version checks for Ubuntu.
  - Don't display "GRUB loading" unless Shift is held down.
  - Adjust versions of grub-doc and grub-legacy-doc conflicts to tolerate
    our backport of the grub-doc split.
  - Fix LVM/RAID probing in the absence of /boot/grub/device.map.
  - Look for .mo files in /usr/share/locale-langpack as well, in
    preference.
  - Make sure GRUB_TIMEOUT isn't quoted unnecessarily.
  - Probe all devices in 'grub-probe --target=drive' if
    /boot/grub/device.map is missing.
  - Build-depend on qemu-kvm rather than qemu-system for grub-pc tests.
  - Use qemu rather than qemu-system-i386.
  - Program vesafb on BIOS systems rather than efifb.
  - Add a grub-rescue-efi-amd64 package containing a rescue CD-ROM image
    for EFI-AMD64.
  - On Wubi, don't ask for an install device, but just update wubildr
    using the diverted grub-install.
  - When embedding the core image in a post-MBR gap, check for and avoid
    sectors matching any of a list of known signatures.
  - Disable video_bochs and video_cirrus on PC BIOS systems, as probing
    PCI space seems to break on some systems.
* Downgrade "ACPI shutdown failed" error to a debug message, since it can
  cause spurious test failures.

[ Evan Broder ]
* Enable lua from grub-extras.
* Incorporate the bitop library into lua.
* Add enum_pci function to grub module in lua.
* Switch back to gfxpayload=keep by default, unless the video hardware
  is known to not support it.

[ Mario Limonciello ]
* Built part_msdos and vfat into bootx64.efi (LP: #677758)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  GRUB  --  GRand Unified Bootloader
 
3
 *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2009  Free Software Foundation, Inc.
 
4
 *
 
5
 *  GRUB 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 3 of the License, or
 
8
 *  (at your option) any later version.
 
9
 *
 
10
 *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
 
17
 */
 
18
 
 
19
#include <grub/normal.h>
 
20
#include <grub/misc.h>
 
21
#include <grub/term.h>
 
22
#include <grub/err.h>
 
23
#include <grub/types.h>
 
24
#include <grub/mm.h>
 
25
#include <grub/partition.h>
 
26
#include <grub/disk.h>
 
27
#include <grub/file.h>
 
28
#include <grub/env.h>
 
29
#include <grub/i18n.h>
 
30
#include <grub/charset.h>
 
31
 
 
32
static grub_uint32_t *kill_buf;
 
33
 
 
34
static int hist_size;
 
35
static grub_uint32_t **hist_lines = 0;
 
36
static int hist_pos = 0;
 
37
static int hist_end = 0;
 
38
static int hist_used = 0;
 
39
 
 
40
grub_err_t
 
41
grub_set_history (int newsize)
 
42
{
 
43
  grub_uint32_t **old_hist_lines = hist_lines;
 
44
  hist_lines = grub_malloc (sizeof (grub_uint32_t *) * newsize);
 
45
 
 
46
  /* Copy the old lines into the new buffer.  */
 
47
  if (old_hist_lines)
 
48
    {
 
49
      /* Remove the lines that don't fit in the new buffer.  */
 
50
      if (newsize < hist_used)
 
51
        {
 
52
          int i;
 
53
          int delsize = hist_used - newsize;
 
54
          hist_used = newsize;
 
55
 
 
56
          for (i = 1; i <= delsize; i++)
 
57
            {
 
58
              int pos = hist_end - i;
 
59
              if (pos < 0)
 
60
                pos += hist_size;
 
61
              grub_free (old_hist_lines[pos]);
 
62
            }
 
63
 
 
64
          hist_end -= delsize;
 
65
          if (hist_end < 0)
 
66
            hist_end += hist_size;
 
67
        }
 
68
 
 
69
      if (hist_pos < hist_end)
 
70
        grub_memmove (hist_lines, old_hist_lines + hist_pos,
 
71
                      (hist_end - hist_pos) * sizeof (grub_uint32_t *));
 
72
      else if (hist_used)
 
73
        {
 
74
          /* Copy the older part.  */
 
75
          grub_memmove (hist_lines, old_hist_lines + hist_pos,
 
76
                        (hist_size - hist_pos) * sizeof (grub_uint32_t *));
 
77
 
 
78
          /* Copy the newer part. */
 
79
          grub_memmove (hist_lines + hist_size - hist_pos, old_hist_lines,
 
80
                        hist_end * sizeof (grub_uint32_t *));
 
81
        }
 
82
    }
 
83
 
 
84
  grub_free (old_hist_lines);
 
85
 
 
86
  hist_size = newsize;
 
87
  hist_pos = 0;
 
88
  hist_end = hist_used;
 
89
  return 0;
 
90
}
 
91
 
 
92
/* Get the entry POS from the history where `0' is the newest
 
93
   entry.  */
 
94
static grub_uint32_t *
 
95
grub_history_get (int pos)
 
96
{
 
97
  pos = (hist_pos + pos) % hist_size;
 
98
  return hist_lines[pos];
 
99
}
 
100
 
 
101
static grub_size_t
 
102
strlen_ucs4 (const grub_uint32_t *s)
 
103
{
 
104
  const grub_uint32_t *p = s;
 
105
 
 
106
  while (*p)
 
107
    p++;
 
108
 
 
109
  return p - s;
 
110
}
 
111
 
 
112
/* Replace the history entry on position POS with the string S.  */
 
113
static void
 
114
grub_history_set (int pos, grub_uint32_t *s, grub_size_t len)
 
115
{
 
116
  grub_free (hist_lines[pos]);
 
117
  hist_lines[pos] = grub_malloc ((len + 1) * sizeof (grub_uint32_t));
 
118
  if (!hist_lines[pos])
 
119
    {
 
120
      grub_print_error ();
 
121
      grub_errno = GRUB_ERR_NONE;
 
122
      return ;
 
123
    }
 
124
  grub_memcpy (hist_lines[pos], s, len * sizeof (grub_uint32_t));
 
125
  hist_lines[pos][len] = 0;
 
126
}
 
127
 
 
128
/* Insert a new history line S on the top of the history.  */
 
129
static void
 
130
grub_history_add (grub_uint32_t *s, grub_size_t len)
 
131
{
 
132
  /* Remove the oldest entry in the history to make room for a new
 
133
     entry.  */
 
134
  if (hist_used + 1 > hist_size)
 
135
    {
 
136
      hist_end--;
 
137
      if (hist_end < 0)
 
138
        hist_end = hist_size + hist_end;
 
139
 
 
140
      grub_free (hist_lines[hist_end]);
 
141
    }
 
142
  else
 
143
    hist_used++;
 
144
 
 
145
  /* Move to the next position.  */
 
146
  hist_pos--;
 
147
  if (hist_pos < 0)
 
148
    hist_pos = hist_size + hist_pos;
 
149
 
 
150
  /* Insert into history.  */
 
151
  hist_lines[hist_pos] = NULL;
 
152
  grub_history_set (hist_pos, s, len);
 
153
}
 
154
 
 
155
/* Replace the history entry on position POS with the string S.  */
 
156
static void
 
157
grub_history_replace (int pos, grub_uint32_t *s, grub_size_t len)
 
158
{
 
159
  grub_history_set ((hist_pos + pos) % hist_size, s, len);
 
160
}
 
161
 
 
162
/* A completion hook to print items.  */
 
163
static void
 
164
print_completion (const char *item, grub_completion_type_t type, int count)
 
165
{
 
166
  if (count == 0)
 
167
    {
 
168
      /* If this is the first time, print a label.  */
 
169
      
 
170
      grub_puts ("");
 
171
      switch (type)
 
172
        {
 
173
        case GRUB_COMPLETION_TYPE_COMMAND:
 
174
          grub_puts_ (N_("Possible commands are:"));
 
175
          break;
 
176
        case GRUB_COMPLETION_TYPE_DEVICE:
 
177
          grub_puts_ (N_("Possible devices are:"));
 
178
          break;
 
179
        case GRUB_COMPLETION_TYPE_FILE:
 
180
          grub_puts_ (N_("Possible files are:"));
 
181
          break;
 
182
        case GRUB_COMPLETION_TYPE_PARTITION:
 
183
          grub_puts_ (N_("Possible partitions are:"));
 
184
          break;
 
185
        case GRUB_COMPLETION_TYPE_ARGUMENT:
 
186
          grub_puts_ (N_("Possible arguments are:"));
 
187
          break;
 
188
        default:
 
189
          grub_puts_ (N_("Possible things are:"));
 
190
          break;
 
191
        }
 
192
      grub_puts ("");
 
193
    }
 
194
 
 
195
  if (type == GRUB_COMPLETION_TYPE_PARTITION)
 
196
    {
 
197
      grub_normal_print_device_info (item);
 
198
      grub_errno = GRUB_ERR_NONE;
 
199
    }
 
200
  else
 
201
    grub_printf (" %s", item);
 
202
}
 
203
 
 
204
struct cmdline_term
 
205
{
 
206
  unsigned xpos, ypos, ystart, width, height;
 
207
  struct grub_term_output *term;
 
208
};
 
209
 
 
210
/* Get a command-line. If ESC is pushed, return zero,
 
211
   otherwise return command line.  */
 
212
/* FIXME: The dumb interface is not supported yet.  */
 
213
char *
 
214
grub_cmdline_get (const char *prompt)
 
215
{
 
216
  grub_size_t lpos, llen;
 
217
  grub_size_t plen;
 
218
  grub_uint32_t *buf;
 
219
  grub_size_t max_len = 256;
 
220
  int key;
 
221
  int histpos = 0;
 
222
  auto void cl_insert (const grub_uint32_t *str);
 
223
  auto void cl_delete (unsigned len);
 
224
  auto inline void __attribute__ ((always_inline)) cl_print (struct cmdline_term *cl_term, int pos,
 
225
                        grub_uint32_t c);
 
226
  auto void cl_set_pos (struct cmdline_term *cl_term);
 
227
  auto void cl_print_all (int pos, grub_uint32_t c);
 
228
  auto void cl_set_pos_all (void);
 
229
  auto void init_clterm (struct cmdline_term *cl_term_cur);
 
230
  auto void init_clterm_all (void);
 
231
  const char *prompt_translated = _(prompt);
 
232
  struct cmdline_term *cl_terms;
 
233
  char *ret;
 
234
  unsigned nterms;
 
235
 
 
236
  void cl_set_pos (struct cmdline_term *cl_term)
 
237
  {
 
238
    cl_term->xpos = (plen + lpos) % (cl_term->width - 1);
 
239
    cl_term->ypos = cl_term->ystart + (plen + lpos) / (cl_term->width - 1);
 
240
    grub_term_gotoxy (cl_term->term, cl_term->xpos, cl_term->ypos);
 
241
  }
 
242
 
 
243
  void cl_set_pos_all ()
 
244
  {
 
245
    unsigned i;
 
246
    for (i = 0; i < nterms; i++)
 
247
      cl_set_pos (&cl_terms[i]);
 
248
  }
 
249
 
 
250
  inline void __attribute__ ((always_inline)) cl_print (struct cmdline_term *cl_term, int pos, grub_uint32_t c)
 
251
    {
 
252
      grub_uint32_t *p;
 
253
 
 
254
      for (p = buf + pos; p < buf + llen; p++)
 
255
        {
 
256
          if (c)
 
257
            grub_putcode (c, cl_term->term);
 
258
          else
 
259
            grub_putcode (*p, cl_term->term);
 
260
          cl_term->xpos++;
 
261
          if (cl_term->xpos >= cl_term->width - 1)
 
262
            {
 
263
              cl_term->xpos = 0;
 
264
              if (cl_term->ypos >= (unsigned) (cl_term->height - 1))
 
265
                cl_term->ystart--;
 
266
              else
 
267
                cl_term->ypos++;
 
268
              grub_putcode ('\n', cl_term->term);
 
269
            }
 
270
        }
 
271
    }
 
272
 
 
273
  void cl_print_all (int pos, grub_uint32_t c)
 
274
  {
 
275
    unsigned i;
 
276
    for (i = 0; i < nterms; i++)
 
277
      cl_print (&cl_terms[i], pos, c);
 
278
  }
 
279
 
 
280
  void cl_insert (const grub_uint32_t *str)
 
281
    {
 
282
      grub_size_t len = strlen_ucs4 (str);
 
283
 
 
284
      if (len + llen >= max_len)
 
285
        {
 
286
          grub_uint32_t *nbuf;
 
287
          max_len *= 2;
 
288
          nbuf = grub_realloc (buf, sizeof (grub_uint32_t) * max_len);
 
289
          if (nbuf)
 
290
            buf = nbuf;
 
291
          else
 
292
            {
 
293
              grub_print_error ();
 
294
              grub_errno = GRUB_ERR_NONE;
 
295
              max_len /= 2;
 
296
            }
 
297
        }
 
298
 
 
299
      if (len + llen < max_len)
 
300
        {
 
301
          grub_memmove (buf + lpos + len, buf + lpos,
 
302
                        (llen - lpos + 1) * sizeof (grub_uint32_t));
 
303
          grub_memmove (buf + lpos, str, len * sizeof (grub_uint32_t));
 
304
 
 
305
          llen += len;
 
306
          cl_set_pos_all ();
 
307
          cl_print_all (lpos, 0);
 
308
          lpos += len;
 
309
          cl_set_pos_all ();
 
310
        }
 
311
    }
 
312
 
 
313
  void cl_delete (unsigned len)
 
314
    {
 
315
      if (lpos + len <= llen)
 
316
        {
 
317
          grub_size_t saved_lpos = lpos;
 
318
 
 
319
          lpos = llen - len;
 
320
          cl_set_pos_all ();
 
321
          cl_print_all (lpos, ' ');
 
322
          lpos = saved_lpos;
 
323
          cl_set_pos_all ();
 
324
 
 
325
          grub_memmove (buf + lpos, buf + lpos + len,
 
326
                        sizeof (grub_uint32_t) * (llen - lpos + 1));
 
327
          llen -= len;
 
328
          cl_print_all (lpos, 0);
 
329
          cl_set_pos_all ();
 
330
        }
 
331
    }
 
332
 
 
333
  void init_clterm (struct cmdline_term *cl_term_cur)
 
334
  {
 
335
    cl_term_cur->xpos = plen;
 
336
    cl_term_cur->ypos = (grub_term_getxy (cl_term_cur->term) & 0xFF);
 
337
    cl_term_cur->ystart = cl_term_cur->ypos;
 
338
    cl_term_cur->width = grub_term_width (cl_term_cur->term);
 
339
    cl_term_cur->height = grub_term_height (cl_term_cur->term);
 
340
  }
 
341
 
 
342
  void init_clterm_all (void)
 
343
  {
 
344
    unsigned i;
 
345
    for (i = 0; i < nterms; i++)
 
346
      init_clterm (&cl_terms[i]);
 
347
  }
 
348
 
 
349
  buf = grub_malloc (max_len * sizeof (grub_uint32_t));
 
350
  if (!buf)
 
351
    return 0;
 
352
 
 
353
  plen = grub_strlen (prompt_translated) + sizeof (" ") - 1;
 
354
  lpos = llen = 0;
 
355
  buf[0] = '\0';
 
356
 
 
357
  {
 
358
    grub_term_output_t term;
 
359
 
 
360
    FOR_ACTIVE_TERM_OUTPUTS(term)
 
361
      if ((grub_term_getxy (term) >> 8) != 0)
 
362
        grub_putcode ('\n', term);
 
363
  }
 
364
  grub_printf ("%s ", prompt_translated);
 
365
  grub_normal_reset_more ();
 
366
 
 
367
  {
 
368
    struct cmdline_term *cl_term_cur;
 
369
    struct grub_term_output *cur;
 
370
    nterms = 0;
 
371
    FOR_ACTIVE_TERM_OUTPUTS(cur)
 
372
      nterms++;
 
373
 
 
374
    cl_terms = grub_malloc (sizeof (cl_terms[0]) * nterms);
 
375
    if (!cl_terms)
 
376
      return 0;
 
377
    cl_term_cur = cl_terms;
 
378
    FOR_ACTIVE_TERM_OUTPUTS(cur)
 
379
    {
 
380
      cl_term_cur->term = cur;
 
381
      init_clterm (cl_term_cur);
 
382
      cl_term_cur++;
 
383
    }
 
384
  }
 
385
 
 
386
  if (hist_used == 0)
 
387
    grub_history_add (buf, llen);
 
388
 
 
389
  grub_refresh ();
 
390
 
 
391
  while ((key = grub_getkey ()) != '\n' && key != '\r')
 
392
    {
 
393
      switch (key)
 
394
        {
 
395
        case GRUB_TERM_CTRL | 'a':
 
396
        case GRUB_TERM_KEY_HOME:
 
397
          lpos = 0;
 
398
          cl_set_pos_all ();
 
399
          break;
 
400
 
 
401
        case GRUB_TERM_CTRL | 'b':
 
402
        case GRUB_TERM_KEY_LEFT:
 
403
          if (lpos > 0)
 
404
            {
 
405
              lpos--;
 
406
              cl_set_pos_all ();
 
407
            }
 
408
          break;
 
409
 
 
410
        case GRUB_TERM_CTRL | 'e':
 
411
        case GRUB_TERM_KEY_END:
 
412
          lpos = llen;
 
413
          cl_set_pos_all ();
 
414
          break;
 
415
 
 
416
        case GRUB_TERM_CTRL | 'f':
 
417
        case GRUB_TERM_KEY_RIGHT:
 
418
          if (lpos < llen)
 
419
            {
 
420
              lpos++;
 
421
              cl_set_pos_all ();
 
422
            }
 
423
          break;
 
424
 
 
425
        case GRUB_TERM_CTRL | 'i':
 
426
        case '\t':
 
427
          {
 
428
            int restore;
 
429
            char *insertu8;
 
430
            char *bufu8;
 
431
            grub_uint32_t c;
 
432
 
 
433
            c = buf[lpos];
 
434
            buf[lpos] = '\0';
 
435
 
 
436
            bufu8 = grub_ucs4_to_utf8_alloc (buf, lpos);
 
437
            buf[lpos] = c;
 
438
            if (!bufu8)
 
439
              {
 
440
                grub_print_error ();
 
441
                grub_errno = GRUB_ERR_NONE;
 
442
                break;
 
443
              }
 
444
 
 
445
            insertu8 = grub_normal_do_completion (bufu8, &restore,
 
446
                                                  print_completion);
 
447
            grub_free (bufu8);
 
448
 
 
449
            grub_normal_reset_more ();
 
450
 
 
451
            if (restore)
 
452
              {
 
453
                /* Restore the prompt.  */
 
454
                grub_printf ("\n%s ", prompt_translated);
 
455
                init_clterm_all ();
 
456
                cl_print_all (0, 0);
 
457
              }
 
458
 
 
459
            if (insertu8)
 
460
              {
 
461
                grub_size_t insertlen;
 
462
                grub_ssize_t t;
 
463
                grub_uint32_t *insert;
 
464
 
 
465
                insertlen = grub_strlen (insertu8);
 
466
                insert = grub_malloc ((insertlen + 1) * sizeof (grub_uint32_t));
 
467
                if (!insert)
 
468
                  {
 
469
                    grub_free (insertu8);
 
470
                    grub_print_error ();
 
471
                    grub_errno = GRUB_ERR_NONE;
 
472
                    break;
 
473
                  }
 
474
                t = grub_utf8_to_ucs4 (insert, insertlen,
 
475
                                       (grub_uint8_t *) insertu8,
 
476
                                       insertlen, 0);
 
477
                if (t > 0)
 
478
                  {
 
479
                    if (insert[t-1] == ' ' && buf[lpos] == ' ')
 
480
                      {
 
481
                        insert[t-1] = 0;
 
482
                        if (t != 1)
 
483
                          cl_insert (insert);
 
484
                        lpos++;
 
485
                      }
 
486
                    else
 
487
                      {
 
488
                        insert[t] = 0;
 
489
                        cl_insert (insert);
 
490
                      }
 
491
                  }
 
492
 
 
493
                grub_free (insertu8);
 
494
                grub_free (insert);
 
495
              }
 
496
            cl_set_pos_all ();
 
497
          }
 
498
          break;
 
499
 
 
500
        case GRUB_TERM_CTRL | 'k':
 
501
          if (lpos < llen)
 
502
            {
 
503
              if (kill_buf)
 
504
                grub_free (kill_buf);
 
505
 
 
506
              kill_buf = grub_malloc ((llen - lpos + 1)
 
507
                                      * sizeof (grub_uint32_t));
 
508
              if (grub_errno)
 
509
                {
 
510
                  grub_print_error ();
 
511
                  grub_errno = GRUB_ERR_NONE;
 
512
                }
 
513
              else
 
514
                {
 
515
                  grub_memcpy (kill_buf, buf + lpos,
 
516
                               (llen - lpos + 1) * sizeof (grub_uint32_t));
 
517
                  kill_buf[llen - lpos] = 0;
 
518
                }
 
519
 
 
520
              cl_delete (llen - lpos);
 
521
            }
 
522
          break;
 
523
 
 
524
        case GRUB_TERM_CTRL | 'n':
 
525
        case GRUB_TERM_KEY_DOWN:
 
526
          {
 
527
            grub_uint32_t *hist;
 
528
 
 
529
            lpos = 0;
 
530
 
 
531
            if (histpos > 0)
 
532
              {
 
533
                grub_history_replace (histpos, buf, llen);
 
534
                histpos--;
 
535
              }
 
536
 
 
537
            cl_delete (llen);
 
538
            hist = grub_history_get (histpos);
 
539
            cl_insert (hist);
 
540
 
 
541
            break;
 
542
          }
 
543
 
 
544
        case GRUB_TERM_KEY_UP:
 
545
        case GRUB_TERM_CTRL | 'p':
 
546
          {
 
547
            grub_uint32_t *hist;
 
548
 
 
549
            lpos = 0;
 
550
 
 
551
            if (histpos < hist_used - 1)
 
552
              {
 
553
                grub_history_replace (histpos, buf, llen);
 
554
                histpos++;
 
555
              }
 
556
 
 
557
            cl_delete (llen);
 
558
            hist = grub_history_get (histpos);
 
559
 
 
560
            cl_insert (hist);
 
561
          }
 
562
          break;
 
563
 
 
564
        case GRUB_TERM_CTRL | 'u':
 
565
          if (lpos > 0)
 
566
            {
 
567
              grub_size_t n = lpos;
 
568
 
 
569
              if (kill_buf)
 
570
                grub_free (kill_buf);
 
571
 
 
572
              kill_buf = grub_malloc (n + 1);
 
573
              if (grub_errno)
 
574
                {
 
575
                  grub_print_error ();
 
576
                  grub_errno = GRUB_ERR_NONE;
 
577
                }
 
578
              if (kill_buf)
 
579
                {
 
580
                  grub_memcpy (kill_buf, buf, n);
 
581
                  kill_buf[n] = '\0';
 
582
                }
 
583
 
 
584
              lpos = 0;
 
585
              cl_set_pos_all ();
 
586
              cl_delete (n);
 
587
            }
 
588
          break;
 
589
 
 
590
        case GRUB_TERM_CTRL | 'y':
 
591
          if (kill_buf)
 
592
            cl_insert (kill_buf);
 
593
          break;
 
594
 
 
595
        case '\e':
 
596
          grub_free (cl_terms);
 
597
          return 0;
 
598
 
 
599
        case '\b':
 
600
          if (lpos > 0)
 
601
            {
 
602
              lpos--;
 
603
              cl_set_pos_all ();
 
604
            }
 
605
          else
 
606
            break;
 
607
          /* fall through */
 
608
 
 
609
        case GRUB_TERM_CTRL | 'd':
 
610
        case GRUB_TERM_KEY_DC:
 
611
          if (lpos < llen)
 
612
            cl_delete (1);
 
613
          break;
 
614
 
 
615
        default:
 
616
          if (grub_isprint (key))
 
617
            {
 
618
              grub_uint32_t str[2];
 
619
 
 
620
              str[0] = key;
 
621
              str[1] = '\0';
 
622
              cl_insert (str);
 
623
            }
 
624
          break;
 
625
        }
 
626
 
 
627
      grub_refresh ();
 
628
    }
 
629
 
 
630
  grub_xputs ("\n");
 
631
  grub_refresh ();
 
632
 
 
633
  /* Remove leading spaces.  */
 
634
  lpos = 0;
 
635
  while (buf[lpos] == ' ')
 
636
    lpos++;
 
637
 
 
638
  histpos = 0;
 
639
  if (strlen_ucs4 (buf) > 0)
 
640
    {
 
641
      grub_uint32_t empty[] = { 0 };
 
642
      grub_history_replace (histpos, buf, llen);
 
643
      grub_history_add (empty, 0);
 
644
    }
 
645
 
 
646
  ret = grub_ucs4_to_utf8_alloc (buf + lpos, llen - lpos + 1);
 
647
  grub_free (buf);
 
648
  grub_free (cl_terms);
 
649
  return ret;
 
650
}