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

« back to all changes in this revision

Viewing changes to normal/menu.c

  • Committer: Bazaar Package Importer
  • Author(s): Otavio Salvador
  • Date: 2006-01-05 15:20:40 UTC
  • mto: (17.3.1 squeeze) (1.9.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20060105152040-b72i5pq1a82z22yi
Tags: upstream-1.92
ImportĀ upstreamĀ versionĀ 1.92

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  GRUB  --  GRand Unified Bootloader
 
3
 *  Copyright (C) 2003,2004,2005  Free Software Foundation, Inc.
 
4
 *
 
5
 *  This program is free software; you can redistribute it and/or modify
 
6
 *  it under the terms of the GNU General Public License as published by
 
7
 *  the Free Software Foundation; either version 2 of the License, or
 
8
 *  (at your option) any later version.
 
9
 *
 
10
 *  This program is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with this program; if not, write to the Free Software
 
17
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
18
 */
 
19
 
 
20
#include <grub/normal.h>
 
21
#include <grub/term.h>
 
22
#include <grub/misc.h>
 
23
#include <grub/loader.h>
 
24
#include <grub/mm.h>
 
25
#include <grub/machine/time.h>
 
26
 
 
27
static void
 
28
draw_border (void)
 
29
{
 
30
  unsigned i;
 
31
  
 
32
  grub_setcolorstate (GRUB_TERM_COLOR_NORMAL);
 
33
  
 
34
  grub_gotoxy (GRUB_TERM_MARGIN, GRUB_TERM_TOP_BORDER_Y);
 
35
  grub_putcode (GRUB_TERM_DISP_UL);
 
36
  for (i = 0; i < (unsigned) GRUB_TERM_BORDER_WIDTH - 2; i++)
 
37
    grub_putcode (GRUB_TERM_DISP_HLINE);
 
38
  grub_putcode (GRUB_TERM_DISP_UR);
 
39
 
 
40
  for (i = 0; i < (unsigned) GRUB_TERM_NUM_ENTRIES; i++)
 
41
    {
 
42
      grub_gotoxy (GRUB_TERM_MARGIN, GRUB_TERM_TOP_BORDER_Y + i + 1);
 
43
      grub_putcode (GRUB_TERM_DISP_VLINE);
 
44
      grub_gotoxy (GRUB_TERM_MARGIN + GRUB_TERM_BORDER_WIDTH - 1,
 
45
                   GRUB_TERM_TOP_BORDER_Y + i + 1);
 
46
      grub_putcode (GRUB_TERM_DISP_VLINE);
 
47
    }
 
48
 
 
49
  grub_gotoxy (GRUB_TERM_MARGIN,
 
50
               GRUB_TERM_TOP_BORDER_Y + GRUB_TERM_NUM_ENTRIES + 1);
 
51
  grub_putcode (GRUB_TERM_DISP_LL);
 
52
  for (i = 0; i < (unsigned) GRUB_TERM_BORDER_WIDTH - 2; i++)
 
53
    grub_putcode (GRUB_TERM_DISP_HLINE);
 
54
  grub_putcode (GRUB_TERM_DISP_LR);
 
55
 
 
56
  grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
 
57
 
 
58
  grub_gotoxy (GRUB_TERM_MARGIN,
 
59
               (GRUB_TERM_TOP_BORDER_Y + GRUB_TERM_NUM_ENTRIES
 
60
                + GRUB_TERM_MARGIN + 1));
 
61
}
 
62
 
 
63
static void
 
64
print_message (int nested, int edit)
 
65
{
 
66
  if (edit)
 
67
    {
 
68
      grub_printf ("\n\
 
69
      Minimum Emacs-like screen editing is supported. TAB lists\n\
 
70
      available completions. Press C-x (\'x\' with Ctrl) to boot,\n\
 
71
      C-c (\'c\' with Ctrl) for a command-line or ESC to return menu.");
 
72
    }
 
73
  else
 
74
    {
 
75
      grub_printf ("\n\
 
76
      Use the %C and %C keys to select which entry is highlighted.\n",
 
77
                   (grub_uint32_t) GRUB_TERM_DISP_UP, (grub_uint32_t) GRUB_TERM_DISP_DOWN);
 
78
      grub_printf ("\
 
79
      Press enter to boot the selected OS, \'e\' to edit the\n\
 
80
      commands before booting or \'c\' for a command-line.");
 
81
      if (nested)
 
82
        grub_printf ("\n\
 
83
      ESC to return previous menu.");
 
84
    }
 
85
  
 
86
}
 
87
 
 
88
static grub_menu_entry_t
 
89
get_entry (grub_menu_t menu, int no)
 
90
{
 
91
  grub_menu_entry_t e;
 
92
 
 
93
  for (e = menu->entry_list; e && no > 0; e = e->next, no--)
 
94
    ;
 
95
 
 
96
  return e;
 
97
}
 
98
 
 
99
static void
 
100
print_entry (int y, int highlight, grub_menu_entry_t entry)
 
101
{
 
102
  int x;
 
103
  const char *title;
 
104
  grub_ssize_t len;
 
105
  grub_uint32_t *unicode_title;
 
106
  grub_ssize_t i;
 
107
  
 
108
  title = entry ? entry->title : "";
 
109
  unicode_title = grub_malloc (grub_strlen (title) * sizeof (*unicode_title));
 
110
  if (! unicode_title)
 
111
    /* XXX How to show this error?  */
 
112
    return;
 
113
  
 
114
  len = grub_utf8_to_ucs4 (unicode_title, title, grub_strlen (title));
 
115
  if (len < 0)
 
116
    {
 
117
      /* It is an invalid sequence.  */
 
118
      grub_free (unicode_title);
 
119
      return;
 
120
    }
 
121
  
 
122
  grub_setcolorstate (highlight
 
123
                      ? GRUB_TERM_COLOR_HIGHLIGHT
 
124
                      : GRUB_TERM_COLOR_NORMAL);
 
125
 
 
126
  grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN, y);
 
127
 
 
128
  for (x = GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1, i = 0;
 
129
       x < GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH - GRUB_TERM_MARGIN;
 
130
       i++)
 
131
    {
 
132
      if (i < len
 
133
          && x <= (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH
 
134
                   - GRUB_TERM_MARGIN - 1))
 
135
        {
 
136
          grub_ssize_t width;
 
137
 
 
138
          width = grub_getcharwidth (unicode_title[i]);
 
139
          
 
140
          if (x + width > (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH
 
141
                           - GRUB_TERM_MARGIN - 1))
 
142
            grub_putcode (GRUB_TERM_DISP_RIGHT);
 
143
          else
 
144
            grub_putcode (unicode_title[i]);
 
145
 
 
146
          x += width;
 
147
        }
 
148
      else
 
149
        {
 
150
          grub_putchar (' ');
 
151
          x++;
 
152
        }
 
153
    }
 
154
  grub_gotoxy (GRUB_TERM_CURSOR_X, y);
 
155
 
 
156
  grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
 
157
  grub_free (unicode_title);
 
158
}
 
159
 
 
160
static void
 
161
print_entries (grub_menu_t menu, int first, int offset)
 
162
{
 
163
  grub_menu_entry_t e;
 
164
  int i;
 
165
  
 
166
  grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH,
 
167
               GRUB_TERM_FIRST_ENTRY_Y);
 
168
 
 
169
  if (first)
 
170
    grub_putcode (GRUB_TERM_DISP_UP);
 
171
  else
 
172
    grub_putchar (' ');
 
173
 
 
174
  e = get_entry (menu, first);
 
175
 
 
176
  for (i = 0; i < GRUB_TERM_NUM_ENTRIES; i++)
 
177
    {
 
178
      print_entry (GRUB_TERM_FIRST_ENTRY_Y + i, offset == i, e);
 
179
      if (e)
 
180
        e = e->next;
 
181
    }
 
182
 
 
183
  grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH,
 
184
               GRUB_TERM_TOP_BORDER_Y + GRUB_TERM_NUM_ENTRIES);
 
185
 
 
186
  if (e)
 
187
    grub_putcode (GRUB_TERM_DISP_DOWN);
 
188
  else
 
189
    grub_putchar (' ');
 
190
 
 
191
  grub_gotoxy (GRUB_TERM_CURSOR_X, GRUB_TERM_FIRST_ENTRY_Y + offset);
 
192
}
 
193
 
 
194
/* Initialize the screen.  If NESTED is non-zero, assume that this menu
 
195
   is run from another menu or a command-line. If EDIT is non-zero, show
 
196
   a message for the menu entry editor.  */
 
197
void
 
198
grub_menu_init_page (int nested, int edit)
 
199
{
 
200
  grub_normal_init_page ();
 
201
  draw_border ();
 
202
  print_message (nested, edit);
 
203
}
 
204
 
 
205
static int
 
206
run_menu (grub_menu_t menu, int nested)
 
207
{
 
208
  int first, offset;
 
209
  unsigned long saved_time;
 
210
  
 
211
  first = 0;
 
212
  offset = menu->default_entry;
 
213
  if (offset > GRUB_TERM_NUM_ENTRIES - 1)
 
214
    {
 
215
      first = offset - (GRUB_TERM_NUM_ENTRIES - 1);
 
216
      offset = GRUB_TERM_NUM_ENTRIES - 1;
 
217
    }
 
218
 
 
219
  /* Initialize the time.  */
 
220
  saved_time = grub_get_rtc ();
 
221
 
 
222
 refresh:
 
223
  grub_setcursor (0);
 
224
  grub_menu_init_page (nested, 0);
 
225
  print_entries (menu, first, offset);
 
226
  grub_refresh ();
 
227
 
 
228
  while (1)
 
229
    {
 
230
      int c;
 
231
 
 
232
      if (menu->timeout > 0)
 
233
        {
 
234
          unsigned long current_time;
 
235
 
 
236
          current_time = grub_get_rtc ();
 
237
          if (current_time - saved_time >= GRUB_TICKS_PER_SECOND)
 
238
            {
 
239
              menu->timeout--;
 
240
              saved_time = current_time;
 
241
            }
 
242
          
 
243
          grub_gotoxy (0, GRUB_TERM_HEIGHT - 3);
 
244
          /* NOTE: Do not remove the trailing space characters.
 
245
             They are required to clear the line.  */
 
246
          grub_printf ("\
 
247
   The highlighted entry will be booted automatically in %d seconds.    ",
 
248
                       menu->timeout);
 
249
          grub_gotoxy (GRUB_TERM_CURSOR_X, GRUB_TERM_FIRST_ENTRY_Y + offset);
 
250
          grub_refresh ();
 
251
        }
 
252
 
 
253
      if (menu->timeout == 0)
 
254
        {
 
255
          menu->timeout = -1;
 
256
          return menu->default_entry;
 
257
        }
 
258
      
 
259
      if (grub_checkkey () >= 0 || menu->timeout < 0)
 
260
        {
 
261
          c = GRUB_TERM_ASCII_CHAR (grub_getkey ());
 
262
          
 
263
          if (menu->timeout >= 0)
 
264
            {
 
265
              grub_gotoxy (0, GRUB_TERM_HEIGHT - 3);
 
266
              grub_printf ("\
 
267
                                                                        ");
 
268
              menu->timeout = -1;
 
269
              menu->fallback_entry = -1;
 
270
              grub_gotoxy (GRUB_TERM_CURSOR_X, GRUB_TERM_FIRST_ENTRY_Y + offset);
 
271
            }
 
272
          
 
273
          switch (c)
 
274
            {
 
275
            case 16:
 
276
            case '^':
 
277
              if (offset > 0)
 
278
                {
 
279
                  print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 0,
 
280
                               get_entry (menu, first + offset));
 
281
                  offset--;
 
282
                  print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 1,
 
283
                               get_entry (menu, first + offset));
 
284
                }
 
285
              else if (first > 0)
 
286
                {
 
287
                  first--;
 
288
                  print_entries (menu, first, offset);
 
289
                }
 
290
              break;
 
291
              
 
292
            case 14:
 
293
            case 'v':
 
294
              if (menu->size > first + offset + 1)
 
295
                {
 
296
                  if (offset < GRUB_TERM_NUM_ENTRIES - 1)
 
297
                    {
 
298
                      print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 0,
 
299
                                   get_entry (menu, first + offset));
 
300
                      offset++;
 
301
                      print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 1,
 
302
                                   get_entry (menu, first + offset));
 
303
                    }
 
304
                  else
 
305
                    {
 
306
                      first++;
 
307
                      print_entries (menu, first, offset);
 
308
                    }
 
309
                }
 
310
              break;
 
311
              
 
312
            case '\n':
 
313
            case '\r':
 
314
            case 6:
 
315
              grub_setcursor (1);
 
316
              return first + offset;
 
317
              
 
318
            case '\e':
 
319
              if (nested)
 
320
                {
 
321
                  grub_setcursor (1);
 
322
                  return -1;
 
323
                }
 
324
              break;
 
325
              
 
326
            case 'c':
 
327
              grub_cmdline_run (1);
 
328
              goto refresh;
 
329
 
 
330
            case 'e':
 
331
              grub_menu_entry_run (get_entry (menu, first + offset));
 
332
              goto refresh;
 
333
              
 
334
            default:
 
335
              break;
 
336
            }
 
337
          
 
338
          grub_refresh ();
 
339
        }
 
340
    }
 
341
 
 
342
  /* Never reach here.  */
 
343
  return -1;
 
344
}
 
345
 
 
346
/* Run a menu entry.  */
 
347
static void
 
348
run_menu_entry (grub_menu_entry_t entry)
 
349
{
 
350
  grub_command_list_t cl;
 
351
 
 
352
  for (cl = entry->command_list; cl != 0; cl = cl->next)
 
353
    {
 
354
      if (cl->command[0] == '\0')
 
355
        /* Ignore an empty command line.  */
 
356
        continue;
 
357
      
 
358
      if (grub_command_execute (cl->command, 0) != 0)
 
359
        break;
 
360
    }
 
361
  
 
362
  if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ())
 
363
    /* Implicit execution of boot, only if something is loaded.  */
 
364
    grub_command_execute ("boot", 0);
 
365
}
 
366
 
 
367
void
 
368
grub_menu_run (grub_menu_t menu, int nested)
 
369
{
 
370
  while (1)
 
371
    {
 
372
      int boot_entry;
 
373
      grub_menu_entry_t e;
 
374
      
 
375
      boot_entry = run_menu (menu, nested);
 
376
      if (boot_entry < 0)
 
377
        break;
 
378
 
 
379
      grub_cls ();
 
380
      grub_setcursor (1);
 
381
 
 
382
      e = get_entry (menu, boot_entry);
 
383
      grub_printf ("  Booting \'%s\'\n\n", e->title);
 
384
  
 
385
      run_menu_entry (e);
 
386
 
 
387
      /* Deal with a fallback entry.  */
 
388
      /* FIXME: Multiple fallback entries like GRUB Legacy.  */
 
389
      if (menu->fallback_entry >= 0)
 
390
        {
 
391
          grub_print_error ();
 
392
          grub_errno = GRUB_ERR_NONE;
 
393
          
 
394
          e = get_entry (menu, menu->fallback_entry);
 
395
          menu->fallback_entry = -1;
 
396
          grub_printf ("\n  Falling back to \'%s\'\n\n", e->title);
 
397
          run_menu_entry (e);
 
398
        }
 
399
 
 
400
      if (grub_errno != GRUB_ERR_NONE)
 
401
        {
 
402
          grub_print_error ();
 
403
          grub_errno = GRUB_ERR_NONE;
 
404
 
 
405
          /* Wait until the user pushes any key so that the user
 
406
             can see what happened.  */
 
407
          grub_printf ("\nPress any key to continue...");
 
408
          (void) grub_getkey ();
 
409
        }
 
410
    }
 
411
}