2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2003,2004,2005 Free Software Foundation, Inc.
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.
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.
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.
20 #include <grub/normal.h>
21 #include <grub/term.h>
22 #include <grub/misc.h>
23 #include <grub/loader.h>
25 #include <grub/machine/time.h>
32 grub_setcolorstate (GRUB_TERM_COLOR_NORMAL
);
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
);
40 for (i
= 0; i
< (unsigned) GRUB_TERM_NUM_ENTRIES
; i
++)
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
);
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
);
56 grub_setcolorstate (GRUB_TERM_COLOR_STANDARD
);
58 grub_gotoxy (GRUB_TERM_MARGIN
,
59 (GRUB_TERM_TOP_BORDER_Y
+ GRUB_TERM_NUM_ENTRIES
60 + GRUB_TERM_MARGIN
+ 1));
64 print_message (int nested
, int edit
)
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.");
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
);
79 Press enter to boot the selected OS, \'e\' to edit the\n\
80 commands before booting or \'c\' for a command-line.");
83 ESC to return previous menu.");
88 static grub_menu_entry_t
89 get_entry (grub_menu_t menu
, int no
)
93 for (e
= menu
->entry_list
; e
&& no
> 0; e
= e
->next
, no
--)
100 print_entry (int y
, int highlight
, grub_menu_entry_t entry
)
105 grub_uint32_t
*unicode_title
;
108 title
= entry
? entry
->title
: "";
109 unicode_title
= grub_malloc (grub_strlen (title
) * sizeof (*unicode_title
));
111 /* XXX How to show this error? */
114 len
= grub_utf8_to_ucs4 (unicode_title
, title
, grub_strlen (title
));
117 /* It is an invalid sequence. */
118 grub_free (unicode_title
);
122 grub_setcolorstate (highlight
123 ? GRUB_TERM_COLOR_HIGHLIGHT
124 : GRUB_TERM_COLOR_NORMAL
);
126 grub_gotoxy (GRUB_TERM_LEFT_BORDER_X
+ GRUB_TERM_MARGIN
, y
);
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
;
133 && x
<= (GRUB_TERM_LEFT_BORDER_X
+ GRUB_TERM_BORDER_WIDTH
134 - GRUB_TERM_MARGIN
- 1))
138 width
= grub_getcharwidth (unicode_title
[i
]);
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
);
144 grub_putcode (unicode_title
[i
]);
154 grub_gotoxy (GRUB_TERM_CURSOR_X
, y
);
156 grub_setcolorstate (GRUB_TERM_COLOR_STANDARD
);
157 grub_free (unicode_title
);
161 print_entries (grub_menu_t menu
, int first
, int offset
)
166 grub_gotoxy (GRUB_TERM_LEFT_BORDER_X
+ GRUB_TERM_BORDER_WIDTH
,
167 GRUB_TERM_FIRST_ENTRY_Y
);
170 grub_putcode (GRUB_TERM_DISP_UP
);
174 e
= get_entry (menu
, first
);
176 for (i
= 0; i
< GRUB_TERM_NUM_ENTRIES
; i
++)
178 print_entry (GRUB_TERM_FIRST_ENTRY_Y
+ i
, offset
== i
, e
);
183 grub_gotoxy (GRUB_TERM_LEFT_BORDER_X
+ GRUB_TERM_BORDER_WIDTH
,
184 GRUB_TERM_TOP_BORDER_Y
+ GRUB_TERM_NUM_ENTRIES
);
187 grub_putcode (GRUB_TERM_DISP_DOWN
);
191 grub_gotoxy (GRUB_TERM_CURSOR_X
, GRUB_TERM_FIRST_ENTRY_Y
+ offset
);
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. */
198 grub_menu_init_page (int nested
, int edit
)
200 grub_normal_init_page ();
202 print_message (nested
, edit
);
206 run_menu (grub_menu_t menu
, int nested
)
209 unsigned long saved_time
;
212 offset
= menu
->default_entry
;
213 if (offset
> GRUB_TERM_NUM_ENTRIES
- 1)
215 first
= offset
- (GRUB_TERM_NUM_ENTRIES
- 1);
216 offset
= GRUB_TERM_NUM_ENTRIES
- 1;
219 /* Initialize the time. */
220 saved_time
= grub_get_rtc ();
224 grub_menu_init_page (nested
, 0);
225 print_entries (menu
, first
, offset
);
232 if (menu
->timeout
> 0)
234 unsigned long current_time
;
236 current_time
= grub_get_rtc ();
237 if (current_time
- saved_time
>= GRUB_TICKS_PER_SECOND
)
240 saved_time
= current_time
;
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. */
247 The highlighted entry will be booted automatically in %d seconds. ",
249 grub_gotoxy (GRUB_TERM_CURSOR_X
, GRUB_TERM_FIRST_ENTRY_Y
+ offset
);
253 if (menu
->timeout
== 0)
256 return menu
->default_entry
;
259 if (grub_checkkey () >= 0 || menu
->timeout
< 0)
261 c
= GRUB_TERM_ASCII_CHAR (grub_getkey ());
263 if (menu
->timeout
>= 0)
265 grub_gotoxy (0, GRUB_TERM_HEIGHT
- 3);
269 menu
->fallback_entry
= -1;
270 grub_gotoxy (GRUB_TERM_CURSOR_X
, GRUB_TERM_FIRST_ENTRY_Y
+ offset
);
279 print_entry (GRUB_TERM_FIRST_ENTRY_Y
+ offset
, 0,
280 get_entry (menu
, first
+ offset
));
282 print_entry (GRUB_TERM_FIRST_ENTRY_Y
+ offset
, 1,
283 get_entry (menu
, first
+ offset
));
288 print_entries (menu
, first
, offset
);
294 if (menu
->size
> first
+ offset
+ 1)
296 if (offset
< GRUB_TERM_NUM_ENTRIES
- 1)
298 print_entry (GRUB_TERM_FIRST_ENTRY_Y
+ offset
, 0,
299 get_entry (menu
, first
+ offset
));
301 print_entry (GRUB_TERM_FIRST_ENTRY_Y
+ offset
, 1,
302 get_entry (menu
, first
+ offset
));
307 print_entries (menu
, first
, offset
);
316 return first
+ offset
;
327 grub_cmdline_run (1);
331 grub_menu_entry_run (get_entry (menu
, first
+ offset
));
342 /* Never reach here. */
346 /* Run a menu entry. */
348 run_menu_entry (grub_menu_entry_t entry
)
350 grub_command_list_t cl
;
352 for (cl
= entry
->command_list
; cl
!= 0; cl
= cl
->next
)
354 if (cl
->command
[0] == '\0')
355 /* Ignore an empty command line. */
358 if (grub_command_execute (cl
->command
, 0) != 0)
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);
368 grub_menu_run (grub_menu_t menu
, int nested
)
375 boot_entry
= run_menu (menu
, nested
);
382 e
= get_entry (menu
, boot_entry
);
383 grub_printf (" Booting \'%s\'\n\n", e
->title
);
387 /* Deal with a fallback entry. */
388 /* FIXME: Multiple fallback entries like GRUB Legacy. */
389 if (menu
->fallback_entry
>= 0)
392 grub_errno
= GRUB_ERR_NONE
;
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
);
400 if (grub_errno
!= GRUB_ERR_NONE
)
403 grub_errno
= GRUB_ERR_NONE
;
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 ();