~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

Viewing changes to grub-core/normal/menu_entry.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) 2005,2006,2007,2008,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/term.h>
 
21
#include <grub/misc.h>
 
22
#include <grub/mm.h>
 
23
#include <grub/loader.h>
 
24
#include <grub/command.h>
 
25
#include <grub/parser.h>
 
26
#include <grub/script_sh.h>
 
27
#include <grub/auth.h>
 
28
#include <grub/i18n.h>
 
29
#include <grub/charset.h>
 
30
 
 
31
enum update_mode
 
32
  {
 
33
    NO_LINE,
 
34
    SINGLE_LINE,
 
35
    ALL_LINES
 
36
  };
 
37
 
 
38
struct line
 
39
{
 
40
  /* The line buffer.  */
 
41
  char *buf;
 
42
  /* The length of the line.  */
 
43
  int len;
 
44
  /* The maximum length of the line.  */
 
45
  int max_len;
 
46
};
 
47
 
 
48
struct per_term_screen
 
49
{
 
50
  struct grub_term_output *term;
 
51
  /* The X coordinate.  */
 
52
  int x;
 
53
  /* The Y coordinate.  */
 
54
  int y;
 
55
};
 
56
 
 
57
struct screen
 
58
{
 
59
  /* The array of lines.  */
 
60
  struct line *lines;
 
61
  /* The number of lines.  */
 
62
  int num_lines;
 
63
  /* The current column.  */
 
64
  int column;
 
65
  /* The real column.  */
 
66
  int real_column;
 
67
  /* The current line.  */
 
68
  int line;
 
69
  /* The kill buffer.  */
 
70
  char *killed_text;
 
71
  /* The flag of a completion window.  */
 
72
  int completion_shown;
 
73
 
 
74
  int submenu;
 
75
 
 
76
  struct per_term_screen *terms;
 
77
  unsigned nterms;
 
78
};
 
79
 
 
80
/* Used for storing completion items temporarily.  */
 
81
static struct line completion_buffer;
 
82
static int completion_type;
 
83
 
 
84
/* Initialize a line.  */
 
85
static int
 
86
init_line (struct line *linep)
 
87
{
 
88
  linep->len = 0;
 
89
  linep->max_len = 80; /* XXX */
 
90
  linep->buf = grub_malloc (linep->max_len);
 
91
  if (! linep->buf)
 
92
    return 0;
 
93
 
 
94
  return 1;
 
95
}
 
96
 
 
97
/* Allocate extra space if necessary.  */
 
98
static int
 
99
ensure_space (struct line *linep, int extra)
 
100
{
 
101
  if (linep->max_len < linep->len + extra)
 
102
    {
 
103
      linep->max_len = linep->len + extra + 80; /* XXX */
 
104
      linep->buf = grub_realloc (linep->buf, linep->max_len + 1);
 
105
      if (! linep->buf)
 
106
        return 0;
 
107
    }
 
108
 
 
109
  return 1;
 
110
}
 
111
 
 
112
/* Return the number of lines occupied by this line on the screen.  */
 
113
static int
 
114
get_logical_num_lines (struct line *linep, struct per_term_screen *term_screen)
 
115
{
 
116
  return (linep->len / grub_term_entry_width (term_screen->term)) + 1;
 
117
}
 
118
 
 
119
/* Print a line.  */
 
120
static void
 
121
print_line (struct line *linep, int offset, int start, int y,
 
122
            struct per_term_screen *term_screen)
 
123
{
 
124
  grub_term_gotoxy (term_screen->term, 
 
125
                    GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + start + 1,
 
126
                    y + GRUB_TERM_FIRST_ENTRY_Y);
 
127
 
 
128
  if (linep->len >= offset + grub_term_entry_width (term_screen->term))
 
129
    {
 
130
      char *p, c;
 
131
      p = linep->buf + offset + grub_term_entry_width (term_screen->term);
 
132
      c = *p;
 
133
      *p = 0;
 
134
      grub_puts_terminal (linep->buf + offset + start, term_screen->term);
 
135
      *p = c;
 
136
      grub_putcode ('\\', term_screen->term);
 
137
    }
 
138
  else
 
139
    {
 
140
      int i;
 
141
      char *p, c;
 
142
 
 
143
      p = linep->buf + linep->len;
 
144
      c = *p;
 
145
      *p = 0;
 
146
      grub_puts_terminal (linep->buf + offset + start, term_screen->term);
 
147
      *p = c;
 
148
 
 
149
      for (i = 0;
 
150
           i <= grub_term_entry_width (term_screen->term) - linep->len + offset;
 
151
           i++)
 
152
        grub_putcode (' ', term_screen->term);
 
153
    }
 
154
}
 
155
 
 
156
/* Print an empty line.  */
 
157
static void
 
158
print_empty_line (int y, struct per_term_screen *term_screen)
 
159
{
 
160
  int i;
 
161
 
 
162
  grub_term_gotoxy (term_screen->term,
 
163
                    GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1,
 
164
                    y + GRUB_TERM_FIRST_ENTRY_Y);
 
165
 
 
166
  for (i = 0; i < grub_term_entry_width (term_screen->term) + 1; i++)
 
167
    grub_putcode (' ', term_screen->term);
 
168
}
 
169
 
 
170
/* Print an up arrow.  */
 
171
static void
 
172
print_up (int flag, struct per_term_screen *term_screen)
 
173
{
 
174
  grub_term_gotoxy (term_screen->term, GRUB_TERM_LEFT_BORDER_X 
 
175
                    + grub_term_border_width (term_screen->term),
 
176
                    GRUB_TERM_FIRST_ENTRY_Y);
 
177
 
 
178
  if (flag)
 
179
    grub_putcode (GRUB_UNICODE_UPARROW, term_screen->term);
 
180
  else
 
181
    grub_putcode (' ', term_screen->term);
 
182
}
 
183
 
 
184
/* Print a down arrow.  */
 
185
static void
 
186
print_down (int flag, struct per_term_screen *term_screen)
 
187
{
 
188
  grub_term_gotoxy (term_screen->term, GRUB_TERM_LEFT_BORDER_X
 
189
                    + grub_term_border_width (term_screen->term),
 
190
                    GRUB_TERM_TOP_BORDER_Y 
 
191
                    + grub_term_num_entries (term_screen->term));
 
192
 
 
193
  if (flag)
 
194
    grub_putcode (GRUB_UNICODE_DOWNARROW, term_screen->term);
 
195
  else
 
196
    grub_putcode (' ', term_screen->term);
 
197
}
 
198
 
 
199
/* Draw the lines of the screen SCREEN.  */
 
200
static void
 
201
update_screen (struct screen *screen, struct per_term_screen *term_screen,
 
202
               int region_start, int region_column,
 
203
               int up, int down, enum update_mode mode)
 
204
{
 
205
  int up_flag = 0;
 
206
  int down_flag = 0;
 
207
  int y;
 
208
  int i;
 
209
  struct line *linep;
 
210
 
 
211
  /* Check if scrolling is necessary.  */
 
212
  if (term_screen->y < 0 || term_screen->y
 
213
      >= grub_term_num_entries (term_screen->term))
 
214
    {
 
215
      if (term_screen->y < 0)
 
216
        term_screen->y = 0;
 
217
      else
 
218
        term_screen->y = grub_term_num_entries (term_screen->term) - 1;
 
219
 
 
220
      region_start = 0;
 
221
      region_column = 0;
 
222
      up = 1;
 
223
      down = 1;
 
224
      mode = ALL_LINES;
 
225
    }
 
226
 
 
227
  if (mode != NO_LINE)
 
228
    {
 
229
      /* Draw lines. This code is tricky, because this must calculate logical
 
230
         positions.  */
 
231
      y = term_screen->y - screen->column
 
232
        / grub_term_entry_width (term_screen->term);
 
233
      i = screen->line;
 
234
      linep = screen->lines + i;
 
235
      while (y > 0)
 
236
        {
 
237
           i--;
 
238
           linep--;
 
239
           y -= get_logical_num_lines (linep, term_screen);
 
240
        }
 
241
 
 
242
      if (y < 0 || i > 0)
 
243
        up_flag = 1;
 
244
 
 
245
      do
 
246
        {
 
247
          int column;
 
248
 
 
249
          if (linep >= screen->lines + screen->num_lines)
 
250
            break;
 
251
 
 
252
          for (column = 0;
 
253
               column <= linep->len
 
254
                 && y < grub_term_num_entries (term_screen->term);
 
255
               column += grub_term_entry_width (term_screen->term), y++)
 
256
            {
 
257
              if (y < 0)
 
258
                continue;
 
259
 
 
260
              if (i == region_start)
 
261
                {
 
262
                  if (region_column >= column
 
263
                      && region_column
 
264
                      < (column
 
265
                         + grub_term_entry_width (term_screen->term)))
 
266
                    print_line (linep, column, region_column - column, y,
 
267
                                term_screen);
 
268
                  else if (region_column < column)
 
269
                    print_line (linep, column, 0, y, term_screen);
 
270
                }
 
271
              else if (i > region_start && mode == ALL_LINES)
 
272
                print_line (linep, column, 0, y, term_screen);
 
273
            }
 
274
 
 
275
          if (y == grub_term_num_entries (term_screen->term))
 
276
            {
 
277
              if (column <= linep->len || i + 1 < screen->num_lines)
 
278
                down_flag = 1;
 
279
            }
 
280
 
 
281
          linep++;
 
282
          i++;
 
283
 
 
284
          if (mode == ALL_LINES && i == screen->num_lines)
 
285
            for (; y < grub_term_num_entries (term_screen->term); y++)
 
286
              print_empty_line (y, term_screen);
 
287
 
 
288
        }
 
289
      while (y < grub_term_num_entries (term_screen->term));
 
290
 
 
291
      /* Draw up and down arrows.  */
 
292
      if (up)
 
293
        print_up (up_flag, term_screen);
 
294
      if (down)
 
295
        print_down (down_flag, term_screen);
 
296
    }
 
297
 
 
298
  /* Place the cursor.  */
 
299
  grub_term_gotoxy (term_screen->term, 
 
300
                    GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1
 
301
                    + term_screen->x,
 
302
                    GRUB_TERM_FIRST_ENTRY_Y + term_screen->y);
 
303
 
 
304
  grub_term_refresh (term_screen->term);
 
305
}
 
306
 
 
307
static void
 
308
update_screen_all (struct screen *screen,
 
309
                   int region_start, int region_column,
 
310
                   int up, int down, enum update_mode mode)
 
311
{
 
312
  unsigned i;
 
313
  for (i = 0; i < screen->nterms; i++)
 
314
    update_screen (screen, &screen->terms[i], region_start, region_column,
 
315
                   up, down, mode);
 
316
}
 
317
 
 
318
static int
 
319
insert_string (struct screen *screen, char *s, int update)
 
320
{
 
321
  int region_start = screen->num_lines;
 
322
  int region_column = 0;
 
323
  int down[screen->nterms];
 
324
  enum update_mode mode[screen->nterms];
 
325
  unsigned i;
 
326
 
 
327
  for (i = 0; i < screen->nterms; i++)
 
328
    {
 
329
      down[i] = 0;
 
330
      mode[i] = NO_LINE;
 
331
    }
 
332
 
 
333
  while (*s)
 
334
    {
 
335
      if (*s == '\n')
 
336
        {
 
337
          /* LF is special because it creates a new line.  */
 
338
          struct line *current_linep;
 
339
          struct line *next_linep;
 
340
          int size;
 
341
 
 
342
          /* Make a new line.  */
 
343
          screen->num_lines++;
 
344
          screen->lines = grub_realloc (screen->lines,
 
345
                                        screen->num_lines
 
346
                                        * sizeof (screen->lines[0]));
 
347
          if (! screen->lines)
 
348
            return 0;
 
349
 
 
350
          /* Scroll down. */
 
351
          grub_memmove (screen->lines + screen->line + 2,
 
352
                        screen->lines + screen->line + 1,
 
353
                        ((screen->num_lines - screen->line - 2)
 
354
                         * sizeof (struct line)));
 
355
 
 
356
          if (! init_line (screen->lines + screen->line + 1))
 
357
            return 0;
 
358
 
 
359
          /* Fold the line.  */
 
360
          current_linep = screen->lines + screen->line;
 
361
          next_linep = current_linep + 1;
 
362
          size = current_linep->len - screen->column;
 
363
 
 
364
          if (! ensure_space (next_linep, size))
 
365
            return 0;
 
366
 
 
367
          grub_memmove (next_linep->buf,
 
368
                        current_linep->buf + screen->column,
 
369
                        size);
 
370
          current_linep->len = screen->column;
 
371
          next_linep->len = size;
 
372
 
 
373
          /* Update a dirty region.  */
 
374
          if (region_start > screen->line)
 
375
            {
 
376
              region_start = screen->line;
 
377
              region_column = screen->column;
 
378
            }
 
379
 
 
380
          for (i = 0; i < screen->nterms; i++)
 
381
            {
 
382
              mode[i] = ALL_LINES;
 
383
              down[i] = 1; /* XXX not optimal.  */
 
384
            }
 
385
 
 
386
          /* Move the cursor.  */
 
387
          screen->column = screen->real_column = 0;
 
388
          screen->line++;
 
389
          for (i = 0; i < screen->nterms; i++)
 
390
            {
 
391
              screen->terms[i].x = 0;
 
392
              screen->terms[i].y++;
 
393
            }
 
394
          s++;
 
395
        }
 
396
      else
 
397
        {
 
398
          /* All but LF.  */
 
399
          char *p;
 
400
          struct line *current_linep;
 
401
          int size;
 
402
          int orig_num[screen->nterms], new_num[screen->nterms];
 
403
 
 
404
          /* Find a string delimited by LF.  */
 
405
          p = grub_strchr (s, '\n');
 
406
          if (! p)
 
407
            p = s + grub_strlen (s);
 
408
 
 
409
          /* Insert the string.  */
 
410
          current_linep = screen->lines + screen->line;
 
411
          size = p - s;
 
412
          if (! ensure_space (current_linep, size))
 
413
            return 0;
 
414
 
 
415
          grub_memmove (current_linep->buf + screen->column + size,
 
416
                        current_linep->buf + screen->column,
 
417
                        current_linep->len - screen->column);
 
418
          grub_memmove (current_linep->buf + screen->column,
 
419
                        s,
 
420
                        size);
 
421
          for (i = 0; i < screen->nterms; i++)
 
422
            orig_num[i] = get_logical_num_lines (current_linep,
 
423
                                                 &screen->terms[i]);
 
424
          current_linep->len += size;
 
425
          for (i = 0; i < screen->nterms; i++)
 
426
            new_num[i] = get_logical_num_lines (current_linep,
 
427
                                                &screen->terms[i]);
 
428
 
 
429
          /* Update the dirty region.  */
 
430
          if (region_start > screen->line)
 
431
            {
 
432
              region_start = screen->line;
 
433
              region_column = screen->column;
 
434
            }
 
435
 
 
436
          for (i = 0; i < screen->nterms; i++)
 
437
            if (orig_num[i] != new_num[i])
 
438
              {
 
439
                mode[i] = ALL_LINES;
 
440
                down[i] = 1; /* XXX not optimal.  */
 
441
              }
 
442
            else if (mode[i] != ALL_LINES)
 
443
              mode[i] = SINGLE_LINE;
 
444
 
 
445
          /* Move the cursor.  */
 
446
          screen->column += size;
 
447
          screen->real_column = screen->column;
 
448
          for (i = 0; i < screen->nterms; i++)
 
449
            {
 
450
              screen->terms[i].x += size;
 
451
              screen->terms[i].y += screen->terms[i].x
 
452
                / grub_term_entry_width (screen->terms[i].term);
 
453
              screen->terms[i].x
 
454
                %= grub_term_entry_width (screen->terms[i].term);
 
455
            }
 
456
          s = p;
 
457
        }
 
458
    }
 
459
 
 
460
  if (update)
 
461
    for (i = 0; i < screen->nterms; i++)
 
462
      update_screen (screen, &screen->terms[i],
 
463
                     region_start, region_column, 0, down[i], mode[i]);
 
464
 
 
465
  return 1;
 
466
}
 
467
 
 
468
/* Release the resource allocated for SCREEN.  */
 
469
static void
 
470
destroy_screen (struct screen *screen)
 
471
{
 
472
  int i;
 
473
 
 
474
  if (screen->lines)
 
475
    for (i = 0; i < screen->num_lines; i++)
 
476
      {
 
477
        struct line *linep = screen->lines + i;
 
478
 
 
479
        if (linep)
 
480
          grub_free (linep->buf);
 
481
      }
 
482
 
 
483
  grub_free (screen->killed_text);
 
484
  grub_free (screen->lines);
 
485
  grub_free (screen->terms);
 
486
  grub_free (screen);
 
487
}
 
488
 
 
489
/* Make a new screen.  */
 
490
static struct screen *
 
491
make_screen (grub_menu_entry_t entry)
 
492
{
 
493
  struct screen *screen;
 
494
  unsigned i;
 
495
 
 
496
  /* Initialize the screen.  */
 
497
  screen = grub_zalloc (sizeof (*screen));
 
498
  if (! screen)
 
499
    return 0;
 
500
 
 
501
  screen->submenu = entry->submenu;
 
502
 
 
503
  screen->num_lines = 1;
 
504
  screen->lines = grub_malloc (sizeof (struct line));
 
505
  if (! screen->lines)
 
506
    goto fail;
 
507
 
 
508
  /* Initialize the first line which must be always present.  */
 
509
  if (! init_line (screen->lines))
 
510
    goto fail;
 
511
 
 
512
  insert_string (screen, (char *) entry->sourcecode, 0);
 
513
 
 
514
  /* Reset the cursor position.  */
 
515
  screen->column = 0;
 
516
  screen->real_column = 0;
 
517
  screen->line = 0;
 
518
  for (i = 0; i < screen->nterms; i++)
 
519
    {
 
520
      screen->terms[i].x = 0;
 
521
      screen->terms[i].y = 0;
 
522
    }
 
523
 
 
524
  return screen;
 
525
 
 
526
 fail:
 
527
  destroy_screen (screen);
 
528
  return 0;
 
529
}
 
530
 
 
531
static int
 
532
forward_char (struct screen *screen, int update)
 
533
{
 
534
  struct line *linep;
 
535
  unsigned i;
 
536
 
 
537
  linep = screen->lines + screen->line;
 
538
  if (screen->column < linep->len)
 
539
    {
 
540
      screen->column++;
 
541
      for (i = 0; i < screen->nterms; i++)
 
542
        {
 
543
          screen->terms[i].x++;
 
544
          if (screen->terms[i].x
 
545
              == grub_term_entry_width (screen->terms[i].term))
 
546
            {
 
547
              screen->terms[i].x = 0;
 
548
              screen->terms[i].y++;
 
549
            }
 
550
        }
 
551
    }
 
552
  else if (screen->num_lines > screen->line + 1)
 
553
    {
 
554
      screen->column = 0;
 
555
      screen->line++;
 
556
      for (i = 0; i < screen->nterms; i++)
 
557
        {
 
558
          screen->terms[i].x = 0;
 
559
          screen->terms[i].y++;
 
560
        }
 
561
    }
 
562
 
 
563
  screen->real_column = screen->column;
 
564
 
 
565
  if (update)
 
566
    update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE);
 
567
  return 1;
 
568
}
 
569
 
 
570
static int
 
571
backward_char (struct screen *screen, int update)
 
572
{
 
573
  unsigned i;
 
574
 
 
575
  if (screen->column > 0)
 
576
    {
 
577
      screen->column--;
 
578
      for (i = 0; i < screen->nterms; i++)
 
579
        {
 
580
          screen->terms[i].x--;
 
581
          if (screen->terms[i].x == -1)
 
582
            {
 
583
              screen->terms[i].x
 
584
                = grub_term_entry_width (screen->terms[i].term) - 1;
 
585
              screen->terms[i].y--;
 
586
            }
 
587
        }
 
588
    }
 
589
  else if (screen->line > 0)
 
590
    {
 
591
      struct line *linep;
 
592
 
 
593
      screen->line--;
 
594
      linep = screen->lines + screen->line;
 
595
      screen->column = linep->len;
 
596
      for (i = 0; i < screen->nterms; i++)
 
597
        {
 
598
          screen->terms[i].x = screen->column
 
599
            % grub_term_entry_width (screen->terms[i].term);
 
600
          screen->terms[i].y--;
 
601
        }
 
602
    }
 
603
 
 
604
  screen->real_column = screen->column;
 
605
 
 
606
  if (update)
 
607
    update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE);
 
608
 
 
609
  return 1;
 
610
}
 
611
 
 
612
static int
 
613
previous_line (struct screen *screen, int update)
 
614
{
 
615
  unsigned i;
 
616
 
 
617
  if (screen->line > 0)
 
618
    {
 
619
      struct line *linep;
 
620
      int col;
 
621
 
 
622
      /* How many physical lines from the current position
 
623
         to the first physical line?  */
 
624
      col = screen->column;
 
625
 
 
626
      screen->line--;
 
627
 
 
628
      linep = screen->lines + screen->line;
 
629
      if (linep->len < screen->real_column)
 
630
        screen->column = linep->len;
 
631
      else
 
632
        screen->column = screen->real_column;
 
633
 
 
634
      for (i = 0; i < screen->nterms; i++)
 
635
        {
 
636
          int dy;
 
637
          dy = col / grub_term_entry_width (screen->terms[i].term);
 
638
 
 
639
          /* How many physical lines from the current position
 
640
             to the last physical line?  */
 
641
          dy += (linep->len / grub_term_entry_width (screen->terms[i].term)
 
642
                 - screen->column
 
643
                 / grub_term_entry_width (screen->terms[i].term));
 
644
        
 
645
          screen->terms[i].y -= dy + 1;
 
646
          screen->terms[i].x
 
647
            = screen->column % grub_term_entry_width (screen->terms[i].term);
 
648
      }
 
649
    }
 
650
  else
 
651
    {
 
652
      for (i = 0; i < screen->nterms; i++)
 
653
        {
 
654
          screen->terms[i].y
 
655
            -= screen->column / grub_term_entry_width (screen->terms[i].term);
 
656
          screen->terms[i].x = 0;
 
657
        }
 
658
      screen->column = 0;
 
659
    }
 
660
 
 
661
  if (update)
 
662
    update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE);
 
663
 
 
664
  return 1;
 
665
}
 
666
 
 
667
static int
 
668
next_line (struct screen *screen, int update)
 
669
{
 
670
  unsigned i;
 
671
 
 
672
  if (screen->line < screen->num_lines - 1)
 
673
    {
 
674
      struct line *linep;
 
675
      int l1, c1;
 
676
 
 
677
      /* How many physical lines from the current position
 
678
         to the last physical line?  */
 
679
      linep = screen->lines + screen->line;
 
680
      l1 = linep->len;
 
681
      c1 = screen->column;
 
682
 
 
683
      screen->line++;
 
684
 
 
685
      linep++;
 
686
      if (linep->len < screen->real_column)
 
687
        screen->column = linep->len;
 
688
      else
 
689
        screen->column = screen->real_column;
 
690
 
 
691
      for (i = 0; i < screen->nterms; i++)
 
692
        {
 
693
          int dy;
 
694
          dy = l1 / grub_term_entry_width (screen->terms[i].term)
 
695
            - c1 / grub_term_entry_width (screen->terms[i].term);
 
696
          /* How many physical lines from the current position
 
697
             to the first physical line?  */
 
698
          dy += screen->column / grub_term_entry_width (screen->terms[i].term);
 
699
          screen->terms[i].y += dy + 1;
 
700
          screen->terms[i].x = screen->column
 
701
            % grub_term_entry_width (screen->terms[i].term);
 
702
        }
 
703
    }
 
704
  else
 
705
    {
 
706
      struct line *linep;
 
707
      int l, s;
 
708
      
 
709
      linep = screen->lines + screen->line;
 
710
      l = linep->len;
 
711
      s = screen->column;
 
712
      screen->column = linep->len;
 
713
      for (i = 0; i < screen->nterms; i++)
 
714
        {
 
715
          screen->terms[i].y 
 
716
            += (l / grub_term_entry_width (screen->terms[i].term)
 
717
                -  s / grub_term_entry_width (screen->terms[i].term));
 
718
          screen->terms[i].x
 
719
            = screen->column % grub_term_entry_width (screen->terms[i].term);
 
720
        }
 
721
    }
 
722
 
 
723
  if (update)
 
724
    update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE);
 
725
 
 
726
  return 1;
 
727
}
 
728
 
 
729
static int
 
730
beginning_of_line (struct screen *screen, int update)
 
731
{
 
732
  unsigned i;
 
733
  int col;
 
734
  
 
735
  col = screen->column;
 
736
  screen->column = screen->real_column = 0;
 
737
  for (i = 0; i < screen->nterms; i++)
 
738
    {
 
739
      screen->terms[i].x = 0;
 
740
      screen->terms[i].y -= col / grub_term_entry_width (screen->terms[i].term);
 
741
    }
 
742
 
 
743
  if (update)
 
744
    update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE);
 
745
 
 
746
  return 1;
 
747
}
 
748
 
 
749
static int
 
750
end_of_line (struct screen *screen, int update)
 
751
{
 
752
  struct line *linep;
 
753
  unsigned i;
 
754
  int col;
 
755
 
 
756
  linep = screen->lines + screen->line;
 
757
  col = screen->column;
 
758
  screen->column = screen->real_column = linep->len;
 
759
  for (i = 0; i < screen->nterms; i++)
 
760
    {
 
761
      screen->terms[i].y 
 
762
        += (linep->len / grub_term_entry_width (screen->terms->term)
 
763
            - col / grub_term_entry_width (screen->terms->term));
 
764
      screen->terms[i].x
 
765
        = screen->column % grub_term_entry_width (screen->terms->term);
 
766
    }
 
767
 
 
768
  if (update)
 
769
    update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE);
 
770
 
 
771
  return 1;
 
772
}
 
773
 
 
774
static int
 
775
delete_char (struct screen *screen, int update)
 
776
{
 
777
  struct line *linep;
 
778
  int start = screen->num_lines;
 
779
  int column = 0;
 
780
 
 
781
  linep = screen->lines + screen->line;
 
782
  if (linep->len > screen->column)
 
783
    {
 
784
      int orig_num[screen->nterms], new_num;
 
785
      unsigned i;
 
786
 
 
787
      for (i = 0; i < screen->nterms; i++)
 
788
        orig_num[i] = get_logical_num_lines (linep, &screen->terms[i]);
 
789
 
 
790
      grub_memmove (linep->buf + screen->column,
 
791
                    linep->buf + screen->column + 1,
 
792
                    linep->len - screen->column - 1);
 
793
      linep->len--;
 
794
 
 
795
      start = screen->line;
 
796
      column = screen->column;
 
797
 
 
798
      screen->real_column = screen->column;
 
799
 
 
800
      if (update)
 
801
        {
 
802
          for (i = 0; i < screen->nterms; i++)
 
803
            {
 
804
              new_num = get_logical_num_lines (linep, &screen->terms[i]);
 
805
              if (orig_num[i] != new_num)
 
806
                update_screen (screen, &screen->terms[i],
 
807
                               start, column, 0, 0, ALL_LINES);
 
808
              else
 
809
                update_screen (screen, &screen->terms[i],
 
810
                               start, column, 0, 0, SINGLE_LINE);
 
811
            }
 
812
        }
 
813
    }
 
814
  else if (screen->num_lines > screen->line + 1)
 
815
    {
 
816
      struct line *next_linep;
 
817
 
 
818
      next_linep = linep + 1;
 
819
      if (! ensure_space (linep, next_linep->len))
 
820
        return 0;
 
821
 
 
822
      grub_memmove (linep->buf + linep->len, next_linep->buf, next_linep->len);
 
823
      linep->len += next_linep->len;
 
824
 
 
825
      grub_free (next_linep->buf);
 
826
      grub_memmove (next_linep,
 
827
                    next_linep + 1,
 
828
                    (screen->num_lines - screen->line - 2)
 
829
                    * sizeof (struct line));
 
830
      screen->num_lines--;
 
831
 
 
832
      start = screen->line;
 
833
      column = screen->column;
 
834
 
 
835
      screen->real_column = screen->column;
 
836
      if (update)
 
837
        update_screen_all (screen, start, column, 0, 1, ALL_LINES);
 
838
    }
 
839
 
 
840
  return 1;
 
841
}
 
842
 
 
843
static int
 
844
backward_delete_char (struct screen *screen, int update)
 
845
{
 
846
  int saved_column;
 
847
  int saved_line;
 
848
 
 
849
  saved_column = screen->column;
 
850
  saved_line = screen->line;
 
851
 
 
852
  if (! backward_char (screen, 0))
 
853
    return 0;
 
854
 
 
855
  if (saved_column != screen->column || saved_line != screen->line)
 
856
    if (! delete_char (screen, update))
 
857
      return 0;
 
858
 
 
859
  return 1;
 
860
}
 
861
 
 
862
static int
 
863
kill_line (struct screen *screen, int continuous, int update)
 
864
{
 
865
  struct line *linep;
 
866
  char *p;
 
867
  int size;
 
868
  int offset;
 
869
 
 
870
  p = screen->killed_text;
 
871
  if (! continuous && p)
 
872
    p[0] = '\0';
 
873
 
 
874
  linep = screen->lines + screen->line;
 
875
  size = linep->len - screen->column;
 
876
 
 
877
  if (p)
 
878
    offset = grub_strlen (p);
 
879
  else
 
880
    offset = 0;
 
881
 
 
882
  if (size > 0)
 
883
    {
 
884
      int orig_num[screen->nterms], new_num;
 
885
      unsigned i;
 
886
 
 
887
      p = grub_realloc (p, offset + size + 1);
 
888
      if (! p)
 
889
        return 0;
 
890
 
 
891
      grub_memmove (p + offset, linep->buf + screen->column, size);
 
892
      p[offset + size - 1] = '\0';
 
893
 
 
894
      screen->killed_text = p;
 
895
 
 
896
      for (i = 0; i < screen->nterms; i++)
 
897
        orig_num[i] = get_logical_num_lines (linep, &screen->terms[i]);
 
898
      linep->len = screen->column;
 
899
 
 
900
      if (update)
 
901
        {
 
902
          new_num = get_logical_num_lines (linep, &screen->terms[i]);
 
903
          for (i = 0; i < screen->nterms; i++)
 
904
            {
 
905
              if (orig_num[i] != new_num)
 
906
                update_screen (screen, &screen->terms[i],
 
907
                               screen->line, screen->column, 0, 1, ALL_LINES);
 
908
              else
 
909
                update_screen (screen, &screen->terms[i],
 
910
                               screen->line, screen->column, 0, 0, SINGLE_LINE);
 
911
            }
 
912
        }
 
913
    }
 
914
  else if (screen->line + 1 < screen->num_lines)
 
915
    {
 
916
      p = grub_realloc (p, offset + 1 + 1);
 
917
      if (! p)
 
918
        return 0;
 
919
 
 
920
      p[offset] = '\n';
 
921
      p[offset + 1] = '\0';
 
922
 
 
923
      screen->killed_text = p;
 
924
 
 
925
      return delete_char (screen, update);
 
926
    }
 
927
 
 
928
  return 1;
 
929
}
 
930
 
 
931
static int
 
932
yank (struct screen *screen, int update)
 
933
{
 
934
  if (screen->killed_text)
 
935
    return insert_string (screen, screen->killed_text, update);
 
936
 
 
937
  return 1;
 
938
}
 
939
 
 
940
static int
 
941
open_line (struct screen *screen, int update)
 
942
{
 
943
  int saved_y[screen->nterms];
 
944
  unsigned i;
 
945
 
 
946
  for (i = 0; i < screen->nterms; i++)
 
947
    saved_y[i] = screen->terms[i].y;
 
948
 
 
949
  if (! insert_string (screen, "\n", 0))
 
950
    return 0;
 
951
 
 
952
  if (! backward_char (screen, 0))
 
953
    return 0;
 
954
 
 
955
  for (i = 0; i < screen->nterms; i++)
 
956
    screen->terms[i].y = saved_y[i];
 
957
 
 
958
  if (update)
 
959
    update_screen_all (screen, screen->line, screen->column, 0, 1, ALL_LINES);
 
960
 
 
961
  return 1;
 
962
}
 
963
 
 
964
/* A completion hook to print items.  */
 
965
static void
 
966
store_completion (const char *item, grub_completion_type_t type,
 
967
                  int count __attribute__ ((unused)))
 
968
{
 
969
  char *p;
 
970
 
 
971
  completion_type = type;
 
972
 
 
973
  /* Make sure that the completion buffer has enough room.  */
 
974
  if (completion_buffer.max_len < (completion_buffer.len
 
975
                                   + (int) grub_strlen (item) + 1 + 1))
 
976
    {
 
977
      grub_size_t new_len;
 
978
 
 
979
      new_len = completion_buffer.len + grub_strlen (item) + 80;
 
980
      p = grub_realloc (completion_buffer.buf, new_len);
 
981
      if (! p)
 
982
        {
 
983
          /* Possibly not fatal.  */
 
984
          grub_errno = GRUB_ERR_NONE;
 
985
          return;
 
986
        }
 
987
      p[completion_buffer.len] = 0;
 
988
      completion_buffer.buf = p;
 
989
      completion_buffer.max_len = new_len;
 
990
    }
 
991
 
 
992
  p = completion_buffer.buf + completion_buffer.len;
 
993
  if (completion_buffer.len != 0)
 
994
    {
 
995
      *p++ = ' ';
 
996
      completion_buffer.len++;
 
997
    }
 
998
  grub_strcpy (p, item);
 
999
  completion_buffer.len += grub_strlen (item);
 
1000
}
 
1001
 
 
1002
static int
 
1003
complete (struct screen *screen, int continuous, int update)
 
1004
{
 
1005
  char saved_char;
 
1006
  struct line *linep;
 
1007
  int restore;
 
1008
  char *insert;
 
1009
  static int count = -1;
 
1010
  unsigned i;
 
1011
  grub_uint32_t *ucs4;
 
1012
  grub_size_t buflen;
 
1013
  grub_ssize_t ucs4len;
 
1014
 
 
1015
  if (continuous)
 
1016
    count++;
 
1017
  else
 
1018
    count = 0;
 
1019
 
 
1020
  completion_buffer.buf = 0;
 
1021
  completion_buffer.len = 0;
 
1022
  completion_buffer.max_len = 0;
 
1023
 
 
1024
  linep = screen->lines + screen->line;
 
1025
  saved_char = linep->buf[screen->column];
 
1026
  linep->buf[screen->column] = '\0';
 
1027
 
 
1028
  insert = grub_normal_do_completion (linep->buf, &restore, store_completion);
 
1029
 
 
1030
  linep->buf[screen->column] = saved_char;
 
1031
  
 
1032
  if (completion_buffer.buf)
 
1033
    {
 
1034
      buflen = grub_strlen (completion_buffer.buf);
 
1035
      ucs4 = grub_malloc (sizeof (grub_uint32_t) * (buflen + 1));
 
1036
      
 
1037
      if (!ucs4)
 
1038
        {
 
1039
          grub_print_error ();
 
1040
          grub_errno = GRUB_ERR_NONE;
 
1041
          return 1;
 
1042
        }
 
1043
 
 
1044
      ucs4len = grub_utf8_to_ucs4 (ucs4, buflen,
 
1045
                                   (grub_uint8_t *) completion_buffer.buf,
 
1046
                                   buflen, 0);
 
1047
      ucs4[ucs4len] = 0;
 
1048
 
 
1049
      if (restore)
 
1050
        for (i = 0; i < screen->nterms; i++)
 
1051
          {
 
1052
            int num_sections = ((completion_buffer.len
 
1053
                                 + grub_term_width (screen->terms[i].term) 
 
1054
                                 - 8 - 1)
 
1055
                                / (grub_term_width (screen->terms[i].term)
 
1056
                                   - 8));
 
1057
            grub_uint32_t *endp;
 
1058
            grub_uint16_t pos;
 
1059
            grub_uint32_t *p = ucs4;
 
1060
 
 
1061
            pos = grub_term_getxy (screen->terms[i].term);
 
1062
            grub_term_gotoxy (screen->terms[i].term, 0,
 
1063
                              grub_term_height (screen->terms[i].term) - 3);
 
1064
 
 
1065
            screen->completion_shown = 1;
 
1066
 
 
1067
            grub_term_gotoxy (screen->terms[i].term, 0,
 
1068
                              grub_term_height (screen->terms[i].term) - 3);
 
1069
            grub_puts_terminal ("   ", screen->terms[i].term);
 
1070
            switch (completion_type)
 
1071
              {
 
1072
              case GRUB_COMPLETION_TYPE_COMMAND:
 
1073
                grub_puts_terminal (_("Possible commands are:"),
 
1074
                                    screen->terms[i].term);
 
1075
                break;
 
1076
              case GRUB_COMPLETION_TYPE_DEVICE:
 
1077
                grub_puts_terminal (_("Possible devices are:"),
 
1078
                                    screen->terms[i].term);
 
1079
                break;
 
1080
              case GRUB_COMPLETION_TYPE_FILE:
 
1081
                grub_puts_terminal (_("Possible files are:"),
 
1082
                                    screen->terms[i].term);
 
1083
                break;
 
1084
              case GRUB_COMPLETION_TYPE_PARTITION:
 
1085
                grub_puts_terminal (_("Possible partitions are:"),
 
1086
                                    screen->terms[i].term);
 
1087
                break;
 
1088
              case GRUB_COMPLETION_TYPE_ARGUMENT:
 
1089
                grub_puts_terminal (_("Possible arguments are:"),
 
1090
                                    screen->terms[i].term);
 
1091
                break;
 
1092
              default:
 
1093
                grub_puts_terminal (_("Possible things are:"),
 
1094
                                    screen->terms[i].term);
 
1095
                break;
 
1096
              }
 
1097
 
 
1098
            grub_puts_terminal ("\n    ", screen->terms[i].term);
 
1099
 
 
1100
            p += (count % num_sections)
 
1101
              * (grub_term_width (screen->terms[i].term) - 8);
 
1102
            endp = p + (grub_term_width (screen->terms[i].term) - 8);
 
1103
 
 
1104
            if (p != ucs4)
 
1105
              grub_putcode (GRUB_UNICODE_LEFTARROW, screen->terms[i].term);
 
1106
            else
 
1107
              grub_putcode (' ', screen->terms[i].term);
 
1108
 
 
1109
            grub_print_ucs4 (p, ucs4 + ucs4len < endp ? ucs4 + ucs4len : endp,
 
1110
                             0, 0, screen->terms[i].term);
 
1111
 
 
1112
            if (ucs4 + ucs4len > endp)
 
1113
              grub_putcode (GRUB_UNICODE_RIGHTARROW, screen->terms[i].term);
 
1114
            grub_term_gotoxy (screen->terms[i].term, pos >> 8, pos & 0xFF);
 
1115
          }
 
1116
    }
 
1117
 
 
1118
  if (insert)
 
1119
    {
 
1120
      insert_string (screen, insert, update);
 
1121
      count = -1;
 
1122
      grub_free (insert);
 
1123
    }
 
1124
  else if (update)
 
1125
    grub_refresh ();
 
1126
 
 
1127
  grub_free (completion_buffer.buf);
 
1128
  return 1;
 
1129
}
 
1130
 
 
1131
/* Clear displayed completions.  */
 
1132
static void
 
1133
clear_completions (struct per_term_screen *term_screen)
 
1134
{
 
1135
  grub_uint16_t pos;
 
1136
  unsigned i, j;
 
1137
 
 
1138
  pos = grub_term_getxy (term_screen->term);
 
1139
  grub_term_gotoxy (term_screen->term, 0,
 
1140
                    grub_term_height (term_screen->term) - 3);
 
1141
 
 
1142
  for (i = 0; i < 2; i++)
 
1143
    {
 
1144
      for (j = 0; j < grub_term_width (term_screen->term) - 1; j++)
 
1145
        grub_putcode (' ', term_screen->term);
 
1146
      grub_putcode ('\n', term_screen->term);
 
1147
    }
 
1148
 
 
1149
  grub_term_gotoxy (term_screen->term, pos >> 8, pos & 0xFF);
 
1150
  grub_term_refresh (term_screen->term);
 
1151
}
 
1152
 
 
1153
static void
 
1154
clear_completions_all (struct screen *screen)
 
1155
{
 
1156
  unsigned i;
 
1157
 
 
1158
  for (i = 0; i < screen->nterms; i++)
 
1159
    clear_completions (&screen->terms[i]);
 
1160
}
 
1161
 
 
1162
/* Execute the command list in the screen SCREEN.  */
 
1163
static int
 
1164
run (struct screen *screen)
 
1165
{
 
1166
  int currline = 0;
 
1167
  char *nextline;
 
1168
  int errs_before;
 
1169
  grub_menu_t menu;
 
1170
 
 
1171
  auto grub_err_t editor_getline (char **line, int cont);
 
1172
  grub_err_t editor_getline (char **line, int cont __attribute__ ((unused)))
 
1173
    {
 
1174
      struct line *linep = screen->lines + currline;
 
1175
      char *p;
 
1176
 
 
1177
      if (currline > screen->num_lines)
 
1178
        {
 
1179
          *line = 0;
 
1180
          return 0;
 
1181
        }
 
1182
 
 
1183
      /* Trim down space characters.  */
 
1184
      for (p = linep->buf + linep->len - 1;
 
1185
           p >= linep->buf && grub_isspace (*p);
 
1186
           p--)
 
1187
        ;
 
1188
      *++p = '\0';
 
1189
 
 
1190
      linep->len = p - linep->buf;
 
1191
      for (p = linep->buf; grub_isspace (*p); p++)
 
1192
        ;
 
1193
      *line = grub_strdup (p);
 
1194
      currline++;
 
1195
      return 0;
 
1196
    }
 
1197
 
 
1198
  grub_cls ();
 
1199
  grub_printf ("  ");
 
1200
  grub_printf_ (N_("Booting a command list"));
 
1201
  grub_printf ("\n\n");
 
1202
 
 
1203
  errs_before = grub_err_printed_errors;
 
1204
 
 
1205
  if (screen->submenu)
 
1206
    {
 
1207
      grub_env_context_open ();
 
1208
      menu = grub_zalloc (sizeof (*menu));
 
1209
      if (! menu)
 
1210
        return 0;
 
1211
      grub_env_set_menu (menu);
 
1212
    }
 
1213
 
 
1214
  /* Execute the script, line for line.  */
 
1215
  while (currline < screen->num_lines)
 
1216
    {
 
1217
      editor_getline (&nextline, 0);
 
1218
      if (grub_normal_parse_line (nextline, editor_getline))
 
1219
        break;
 
1220
    }
 
1221
 
 
1222
  if (errs_before != grub_err_printed_errors)
 
1223
    grub_wait_after_message ();
 
1224
 
 
1225
  if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ())
 
1226
    /* Implicit execution of boot, only if something is loaded.  */
 
1227
    grub_command_execute ("boot", 0, 0);
 
1228
 
 
1229
  if (screen->submenu)
 
1230
    {
 
1231
      if (menu && menu->size)
 
1232
        {
 
1233
          grub_show_menu (menu, 1);
 
1234
          grub_normal_free_menu (menu);
 
1235
        }
 
1236
      grub_env_context_close ();
 
1237
    }
 
1238
 
 
1239
  if (grub_errno != GRUB_ERR_NONE)
 
1240
    {
 
1241
      grub_print_error ();
 
1242
      grub_errno = GRUB_ERR_NONE;
 
1243
      grub_wait_after_message ();
 
1244
    }
 
1245
 
 
1246
  return 1;
 
1247
}
 
1248
 
 
1249
/* Edit a menu entry with an Emacs-like interface.  */
 
1250
void
 
1251
grub_menu_entry_run (grub_menu_entry_t entry)
 
1252
{
 
1253
  struct screen *screen;
 
1254
  int prev_c;
 
1255
  grub_err_t err = GRUB_ERR_NONE;
 
1256
  unsigned i;
 
1257
  grub_term_output_t term;
 
1258
 
 
1259
  err = grub_auth_check_authentication (NULL);
 
1260
 
 
1261
  if (err)
 
1262
    {
 
1263
      grub_print_error ();
 
1264
      grub_errno = GRUB_ERR_NONE;
 
1265
      return;
 
1266
    }
 
1267
 
 
1268
  screen = make_screen (entry);
 
1269
  if (! screen)
 
1270
    return;
 
1271
 
 
1272
  screen->terms = NULL;
 
1273
 
 
1274
 refresh:
 
1275
  grub_free (screen->terms);
 
1276
  screen->nterms = 0;
 
1277
  FOR_ACTIVE_TERM_OUTPUTS(term)
 
1278
    screen->nterms++;
 
1279
  screen->terms = grub_malloc (screen->nterms * sizeof (screen->terms[0]));
 
1280
  if (!screen->terms)
 
1281
    {
 
1282
      grub_print_error ();
 
1283
      grub_errno = GRUB_ERR_NONE;
 
1284
      return;
 
1285
    }
 
1286
  i = 0;
 
1287
  FOR_ACTIVE_TERM_OUTPUTS(term)
 
1288
  {
 
1289
    screen->terms[i].term = term;
 
1290
    screen->terms[i].x = 0;
 
1291
    screen->terms[i].y = 0;
 
1292
    i++;
 
1293
  }
 
1294
  /* Draw the screen.  */
 
1295
  for (i = 0; i < screen->nterms; i++)
 
1296
    grub_menu_init_page (0, 1, screen->terms[i].term);
 
1297
  update_screen_all (screen, 0, 0, 1, 1, ALL_LINES);
 
1298
  for (i = 0; i < screen->nterms; i++)
 
1299
    grub_term_setcursor (screen->terms[i].term, 1);
 
1300
  prev_c = '\0';
 
1301
 
 
1302
  while (1)
 
1303
    {
 
1304
      int c = grub_getkey ();
 
1305
 
 
1306
      if (screen->completion_shown)
 
1307
        {
 
1308
          clear_completions_all (screen);
 
1309
          screen->completion_shown = 0;
 
1310
        }
 
1311
 
 
1312
      if (grub_normal_exit_level)
 
1313
        {
 
1314
          destroy_screen (screen);
 
1315
          return;
 
1316
        }
 
1317
 
 
1318
      switch (c)
 
1319
        {
 
1320
        case GRUB_TERM_KEY_UP:
 
1321
        case GRUB_TERM_CTRL | 'p':
 
1322
          if (! previous_line (screen, 1))
 
1323
            goto fail;
 
1324
          break;
 
1325
 
 
1326
        case GRUB_TERM_CTRL | 'n':
 
1327
        case GRUB_TERM_KEY_DOWN:
 
1328
          if (! next_line (screen, 1))
 
1329
            goto fail;
 
1330
          break;
 
1331
 
 
1332
        case GRUB_TERM_CTRL | 'f':
 
1333
        case GRUB_TERM_KEY_RIGHT:
 
1334
          if (! forward_char (screen, 1))
 
1335
            goto fail;
 
1336
          break;
 
1337
 
 
1338
        case GRUB_TERM_CTRL | 'b':
 
1339
        case GRUB_TERM_KEY_LEFT:
 
1340
          if (! backward_char (screen, 1))
 
1341
            goto fail;
 
1342
          break;
 
1343
 
 
1344
        case GRUB_TERM_CTRL | 'a':
 
1345
        case GRUB_TERM_KEY_HOME:
 
1346
          if (! beginning_of_line (screen, 1))
 
1347
            goto fail;
 
1348
          break;
 
1349
 
 
1350
        case GRUB_TERM_CTRL | 'e':
 
1351
        case GRUB_TERM_KEY_END:
 
1352
          if (! end_of_line (screen, 1))
 
1353
            goto fail;
 
1354
          break;
 
1355
 
 
1356
        case GRUB_TERM_CTRL | 'i':
 
1357
        case '\t':
 
1358
          if (! complete (screen, prev_c == c, 1))
 
1359
            goto fail;
 
1360
          break;
 
1361
 
 
1362
        case GRUB_TERM_CTRL | 'd':
 
1363
        case GRUB_TERM_KEY_DC:
 
1364
          if (! delete_char (screen, 1))
 
1365
            goto fail;
 
1366
          break;
 
1367
 
 
1368
        case GRUB_TERM_CTRL | 'h':
 
1369
        case '\b':
 
1370
          if (! backward_delete_char (screen, 1))
 
1371
            goto fail;
 
1372
          break;
 
1373
 
 
1374
        case GRUB_TERM_CTRL | 'k':
 
1375
          if (! kill_line (screen, prev_c == c, 1))
 
1376
            goto fail;
 
1377
          break;
 
1378
 
 
1379
        case GRUB_TERM_CTRL | 'u':
 
1380
          /* FIXME: What behavior is good for this key?  */
 
1381
          break;
 
1382
 
 
1383
        case GRUB_TERM_CTRL | 'y':
 
1384
          if (! yank (screen, 1))
 
1385
            goto fail;
 
1386
          break;
 
1387
 
 
1388
        case GRUB_TERM_CTRL | 'l':
 
1389
          /* FIXME: centering.  */
 
1390
          goto refresh;
 
1391
 
 
1392
        case GRUB_TERM_CTRL | 'o':
 
1393
          if (! open_line (screen, 1))
 
1394
            goto fail;
 
1395
          break;
 
1396
 
 
1397
        case '\n':
 
1398
        case '\r':
 
1399
          if (! insert_string (screen, "\n", 1))
 
1400
            goto fail;
 
1401
          break;
 
1402
 
 
1403
        case '\e':
 
1404
          destroy_screen (screen);
 
1405
          return;
 
1406
 
 
1407
        case GRUB_TERM_CTRL | 'c':
 
1408
        case GRUB_TERM_KEY_F2:
 
1409
          grub_cmdline_run (1);
 
1410
          goto refresh;
 
1411
 
 
1412
        case GRUB_TERM_CTRL | 'x':
 
1413
        case GRUB_TERM_KEY_F10:
 
1414
          run (screen);
 
1415
          goto refresh;
 
1416
 
 
1417
        case GRUB_TERM_CTRL | 'r':
 
1418
        case GRUB_TERM_CTRL | 's':
 
1419
        case GRUB_TERM_CTRL | 't':
 
1420
          /* FIXME */
 
1421
          break;
 
1422
 
 
1423
        default:
 
1424
          if (grub_isprint (c))
 
1425
            {
 
1426
              char buf[2];
 
1427
 
 
1428
              buf[0] = c;
 
1429
              buf[1] = '\0';
 
1430
              if (! insert_string (screen, buf, 1))
 
1431
                goto fail;
 
1432
            }
 
1433
          break;
 
1434
        }
 
1435
 
 
1436
      prev_c = c;
 
1437
    }
 
1438
 
 
1439
 fail:
 
1440
  destroy_screen (screen);
 
1441
 
 
1442
  grub_cls ();
 
1443
  grub_print_error ();
 
1444
  grub_errno = GRUB_ERR_NONE;
 
1445
  grub_xputs ("\n");
 
1446
  grub_printf_ (N_("Press any key to continue..."));
 
1447
  (void) grub_getkey ();
 
1448
}