2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2005,2006,2007,2008 Free Software Foundation, Inc.
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.
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.
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/>.
19 #include <grub/normal.h>
20 #include <grub/term.h>
21 #include <grub/misc.h>
23 #include <grub/loader.h>
24 #include <grub/script.h>
35 /* The line buffer. */
37 /* The length of the line. */
39 /* The maximum length of the line. */
45 /* The array of lines. */
47 /* The number of lines. */
49 /* The current column. */
51 /* The real column. */
53 /* The current line. */
55 /* The X coordinate. */
57 /* The Y coordinate. */
59 /* The kill buffer. */
61 /* The flag of a completion window. */
65 /* Used for storing completion items temporarily. */
66 static struct line completion_buffer
;
68 /* Initialize a line. */
70 init_line (struct line
*linep
)
73 linep
->max_len
= 80; /* XXX */
74 linep
->buf
= grub_malloc (linep
->max_len
);
81 /* Allocate extra space if necessary. */
83 ensure_space (struct line
*linep
, int extra
)
85 if (linep
->max_len
< linep
->len
+ extra
)
87 linep
->max_len
= linep
->len
+ extra
+ 80; /* XXX */
88 linep
->buf
= grub_realloc (linep
->buf
, linep
->max_len
+ 1);
96 /* Return the number of lines occupied by this line on the screen. */
98 get_logical_num_lines (struct line
*linep
)
100 return (linep
->len
/ GRUB_TERM_ENTRY_WIDTH
) + 1;
105 print_line (struct line
*linep
, int offset
, int start
, int y
)
110 grub_gotoxy (GRUB_TERM_LEFT_BORDER_X
+ GRUB_TERM_MARGIN
+ start
+ 1,
111 y
+ GRUB_TERM_FIRST_ENTRY_Y
);
113 for (p
= linep
->buf
+ offset
+ start
, i
= start
;
114 i
< GRUB_TERM_ENTRY_WIDTH
&& offset
+ i
< linep
->len
;
118 for (; i
< GRUB_TERM_ENTRY_WIDTH
; i
++)
121 if (linep
->len
>= offset
+ GRUB_TERM_ENTRY_WIDTH
)
127 /* Print an empty line. */
129 print_empty_line (int y
)
133 grub_gotoxy (GRUB_TERM_LEFT_BORDER_X
+ GRUB_TERM_MARGIN
+ 1,
134 y
+ GRUB_TERM_FIRST_ENTRY_Y
);
136 for (i
= 0; i
< GRUB_TERM_ENTRY_WIDTH
+ 1; i
++)
140 /* Print an up arrow. */
144 grub_gotoxy (GRUB_TERM_LEFT_BORDER_X
+ GRUB_TERM_BORDER_WIDTH
,
145 GRUB_TERM_FIRST_ENTRY_Y
);
148 grub_putcode (GRUB_TERM_DISP_UP
);
153 /* Print a down arrow. */
155 print_down (int flag
)
157 grub_gotoxy (GRUB_TERM_LEFT_BORDER_X
+ GRUB_TERM_BORDER_WIDTH
,
158 GRUB_TERM_TOP_BORDER_Y
+ GRUB_TERM_NUM_ENTRIES
);
161 grub_putcode (GRUB_TERM_DISP_DOWN
);
166 /* Draw the lines of the screen SCREEN. */
168 update_screen (struct screen
*screen
, int region_start
, int region_column
,
169 int up
, int down
, enum update_mode mode
)
177 /* Check if scrolling is necessary. */
178 if (screen
->y
< 0 || screen
->y
>= GRUB_TERM_NUM_ENTRIES
)
183 screen
->y
= GRUB_TERM_NUM_ENTRIES
- 1;
194 /* Draw lines. This code is tricky, because this must calculate logical
196 y
= screen
->y
- screen
->column
/ GRUB_TERM_ENTRY_WIDTH
;
198 linep
= screen
->lines
+ i
;
203 y
-= get_logical_num_lines (linep
);
214 column
<= linep
->len
&& y
< GRUB_TERM_NUM_ENTRIES
;
215 column
+= GRUB_TERM_ENTRY_WIDTH
, y
++)
220 if (i
== region_start
)
222 if (region_column
>= column
223 && region_column
< column
+ GRUB_TERM_ENTRY_WIDTH
)
224 print_line (linep
, column
, region_column
- column
, y
);
225 else if (region_column
< column
)
226 print_line (linep
, column
, 0, y
);
228 else if (i
> region_start
&& mode
== ALL_LINES
)
229 print_line (linep
, column
, 0, y
);
232 if (y
== GRUB_TERM_NUM_ENTRIES
)
234 if (column
<= linep
->len
|| i
+ 1 < screen
->num_lines
)
241 if (mode
== ALL_LINES
&& i
== screen
->num_lines
)
242 for (; y
< GRUB_TERM_NUM_ENTRIES
; y
++)
243 print_empty_line (y
);
246 while (y
< GRUB_TERM_NUM_ENTRIES
);
248 /* Draw up and down arrows. */
252 print_down (down_flag
);
255 /* Place the cursor. */
256 grub_gotoxy (GRUB_TERM_LEFT_BORDER_X
+ GRUB_TERM_MARGIN
+ 1 + screen
->x
,
257 GRUB_TERM_FIRST_ENTRY_Y
+ screen
->y
);
262 /* Insert the string S into the screen SCREEN. This updates the cursor
263 position and redraw the screen. Return zero if fails. */
265 insert_string (struct screen
*screen
, char *s
, int update
)
267 int region_start
= screen
->num_lines
;
268 int region_column
= 0;
270 enum update_mode mode
= NO_LINE
;
276 /* LF is special because it creates a new line. */
277 struct line
*current_linep
;
278 struct line
*next_linep
;
281 /* Make a new line. */
283 screen
->lines
= grub_realloc (screen
->lines
,
285 * sizeof (struct line
));
290 grub_memmove (screen
->lines
+ screen
->line
+ 2,
291 screen
->lines
+ screen
->line
+ 1,
292 ((screen
->num_lines
- screen
->line
- 2)
293 * sizeof (struct line
)));
295 if (! init_line (screen
->lines
+ screen
->line
+ 1))
299 current_linep
= screen
->lines
+ screen
->line
;
300 next_linep
= current_linep
+ 1;
301 size
= current_linep
->len
- screen
->column
;
303 if (! ensure_space (next_linep
, size
))
306 grub_memmove (next_linep
->buf
,
307 current_linep
->buf
+ screen
->column
,
309 current_linep
->len
= screen
->column
;
310 next_linep
->len
= size
;
312 /* Update a dirty region. */
313 if (region_start
> screen
->line
)
315 region_start
= screen
->line
;
316 region_column
= screen
->column
;
320 down
= 1; /* XXX not optimal. */
322 /* Move the cursor. */
323 screen
->column
= screen
->real_column
= 0;
334 struct line
*current_linep
;
336 int orig_num
, new_num
;
338 /* Find a string delimited by LF. */
339 p
= grub_strchr (s
, '\n');
341 p
= s
+ grub_strlen (s
);
343 /* Insert the string. */
344 current_linep
= screen
->lines
+ screen
->line
;
346 if (! ensure_space (current_linep
, size
))
349 grub_memmove (current_linep
->buf
+ screen
->column
+ size
,
350 current_linep
->buf
+ screen
->column
,
351 current_linep
->len
- screen
->column
);
352 grub_memmove (current_linep
->buf
+ screen
->column
,
355 orig_num
= get_logical_num_lines (current_linep
);
356 current_linep
->len
+= size
;
357 new_num
= get_logical_num_lines (current_linep
);
359 /* Update the dirty region. */
360 if (region_start
> screen
->line
)
362 region_start
= screen
->line
;
363 region_column
= screen
->column
;
366 if (orig_num
!= new_num
)
369 down
= 1; /* XXX not optimal. */
371 else if (mode
!= ALL_LINES
)
374 /* Move the cursor. */
375 screen
->column
+= size
;
376 screen
->real_column
= screen
->column
;
378 screen
->y
+= screen
->x
/ GRUB_TERM_ENTRY_WIDTH
;
379 screen
->x
%= GRUB_TERM_ENTRY_WIDTH
;
386 update_screen (screen
, region_start
, region_column
, 0, down
, mode
);
391 /* Release the resource allocated for SCREEN. */
393 destroy_screen (struct screen
*screen
)
398 for (i
= 0; i
< screen
->num_lines
; i
++)
400 struct line
*linep
= screen
->lines
+ i
;
403 grub_free (linep
->buf
);
406 grub_free (screen
->killed_text
);
407 grub_free (screen
->lines
);
411 /* Make a new screen. */
412 static struct screen
*
413 make_screen (grub_menu_entry_t entry
)
415 struct screen
*screen
;
417 /* Initialize the screen. */
418 screen
= grub_malloc (sizeof (*screen
));
422 screen
->num_lines
= 1;
424 screen
->real_column
= 0;
428 screen
->killed_text
= 0;
429 screen
->completion_shown
= 0;
430 screen
->lines
= grub_malloc (sizeof (struct line
));
434 /* Initialize the first line which must be always present. */
435 if (! init_line (screen
->lines
))
438 insert_string (screen
, (char *) entry
->sourcecode
, 0);
440 /* Reset the cursor position. */
442 screen
->real_column
= 0;
450 destroy_screen (screen
);
455 forward_char (struct screen
*screen
, int update
)
459 linep
= screen
->lines
+ screen
->line
;
460 if (screen
->column
< linep
->len
)
464 if (screen
->x
== GRUB_TERM_ENTRY_WIDTH
)
470 else if (screen
->num_lines
> screen
->line
+ 1)
478 screen
->real_column
= screen
->column
;
481 update_screen (screen
, screen
->num_lines
, 0, 0, 0, NO_LINE
);
486 backward_char (struct screen
*screen
, int update
)
488 if (screen
->column
> 0)
494 screen
->x
= GRUB_TERM_ENTRY_WIDTH
- 1;
498 else if (screen
->line
> 0)
503 linep
= screen
->lines
+ screen
->line
;
504 screen
->column
= linep
->len
;
505 screen
->x
= screen
->column
% GRUB_TERM_ENTRY_WIDTH
;
509 screen
->real_column
= screen
->column
;
512 update_screen (screen
, screen
->num_lines
, 0, 0, 0, NO_LINE
);
518 previous_line (struct screen
*screen
, int update
)
520 if (screen
->line
> 0)
525 /* How many physical lines from the current position
526 to the first physical line? */
527 dy
= screen
->column
/ GRUB_TERM_ENTRY_WIDTH
;
531 linep
= screen
->lines
+ screen
->line
;
532 if (linep
->len
< screen
->real_column
)
533 screen
->column
= linep
->len
;
535 screen
->column
= screen
->real_column
;
537 /* How many physical lines from the current position
538 to the last physical line? */
539 dy
+= (linep
->len
/ GRUB_TERM_ENTRY_WIDTH
540 - screen
->column
/ GRUB_TERM_ENTRY_WIDTH
);
543 screen
->x
= screen
->column
% GRUB_TERM_ENTRY_WIDTH
;
547 screen
->y
-= screen
->column
/ GRUB_TERM_ENTRY_WIDTH
;
553 update_screen (screen
, screen
->num_lines
, 0, 0, 0, NO_LINE
);
559 next_line (struct screen
*screen
, int update
)
561 if (screen
->line
< screen
->num_lines
- 1)
566 /* How many physical lines from the current position
567 to the last physical line? */
568 linep
= screen
->lines
+ screen
->line
;
569 dy
= (linep
->len
/ GRUB_TERM_ENTRY_WIDTH
570 - screen
->column
/ GRUB_TERM_ENTRY_WIDTH
);
575 if (linep
->len
< screen
->real_column
)
576 screen
->column
= linep
->len
;
578 screen
->column
= screen
->real_column
;
580 /* How many physical lines from the current position
581 to the first physical line? */
582 dy
+= screen
->column
/ GRUB_TERM_ENTRY_WIDTH
;
585 screen
->x
= screen
->column
% GRUB_TERM_ENTRY_WIDTH
;
591 linep
= screen
->lines
+ screen
->line
;
592 screen
->y
+= (linep
->len
/ GRUB_TERM_ENTRY_WIDTH
593 - screen
->column
/ GRUB_TERM_ENTRY_WIDTH
);
594 screen
->column
= linep
->len
;
595 screen
->x
= screen
->column
% GRUB_TERM_ENTRY_WIDTH
;
599 update_screen (screen
, screen
->num_lines
, 0, 0, 0, NO_LINE
);
605 beginning_of_line (struct screen
*screen
, int update
)
607 screen
->y
-= screen
->column
/ GRUB_TERM_ENTRY_WIDTH
;
608 screen
->column
= screen
->real_column
= 0;
612 update_screen (screen
, screen
->num_lines
, 0, 0, 0, NO_LINE
);
618 end_of_line (struct screen
*screen
, int update
)
622 linep
= screen
->lines
+ screen
->line
;
623 screen
->y
+= (linep
->len
/ GRUB_TERM_ENTRY_WIDTH
624 - screen
->column
/ GRUB_TERM_ENTRY_WIDTH
);
625 screen
->column
= screen
->real_column
= linep
->len
;
626 screen
->x
= screen
->column
% GRUB_TERM_ENTRY_WIDTH
;
629 update_screen (screen
, screen
->num_lines
, 0, 0, 0, NO_LINE
);
635 delete_char (struct screen
*screen
, int update
)
638 enum update_mode mode
= NO_LINE
;
639 int start
= screen
->num_lines
;
643 linep
= screen
->lines
+ screen
->line
;
644 if (linep
->len
> screen
->column
)
646 int orig_num
, new_num
;
648 orig_num
= get_logical_num_lines (linep
);
650 grub_memmove (linep
->buf
+ screen
->column
,
651 linep
->buf
+ screen
->column
+ 1,
652 linep
->len
- screen
->column
- 1);
655 new_num
= get_logical_num_lines (linep
);
657 if (orig_num
!= new_num
)
662 start
= screen
->line
;
663 column
= screen
->column
;
665 else if (screen
->num_lines
> screen
->line
+ 1)
667 struct line
*next_linep
;
669 next_linep
= linep
+ 1;
670 if (! ensure_space (linep
, next_linep
->len
))
673 grub_memmove (linep
->buf
+ linep
->len
, next_linep
->buf
, next_linep
->len
);
674 linep
->len
+= next_linep
->len
;
676 grub_free (next_linep
->buf
);
677 grub_memmove (next_linep
,
679 (screen
->num_lines
- screen
->line
- 2)
680 * sizeof (struct line
));
684 start
= screen
->line
;
685 column
= screen
->column
;
689 screen
->real_column
= screen
->column
;
692 update_screen (screen
, start
, column
, 0, down
, mode
);
698 backward_delete_char (struct screen
*screen
, int update
)
703 saved_column
= screen
->column
;
704 saved_line
= screen
->line
;
706 if (! backward_char (screen
, 0))
709 if (saved_column
!= screen
->column
|| saved_line
!= screen
->line
)
710 if (! delete_char (screen
, update
))
717 kill_line (struct screen
*screen
, int continuous
, int update
)
724 p
= screen
->killed_text
;
725 if (! continuous
&& p
)
728 linep
= screen
->lines
+ screen
->line
;
729 size
= linep
->len
- screen
->column
;
732 offset
= grub_strlen (p
);
738 enum update_mode mode
= SINGLE_LINE
;
740 int orig_num
, new_num
;
742 p
= grub_realloc (p
, offset
+ size
+ 1);
746 grub_memmove (p
+ offset
, linep
->buf
+ screen
->column
, size
);
747 p
[offset
+ size
- 1] = '\0';
749 screen
->killed_text
= p
;
751 orig_num
= get_logical_num_lines (linep
);
752 linep
->len
= screen
->column
;
753 new_num
= get_logical_num_lines (linep
);
755 if (orig_num
!= new_num
)
762 update_screen (screen
, screen
->line
, screen
->column
, 0, down
, mode
);
764 else if (screen
->line
+ 1 < screen
->num_lines
)
766 p
= grub_realloc (p
, offset
+ 1 + 1);
771 p
[offset
+ 1] = '\0';
773 screen
->killed_text
= p
;
775 return delete_char (screen
, update
);
782 yank (struct screen
*screen
, int update
)
784 if (screen
->killed_text
)
785 return insert_string (screen
, screen
->killed_text
, update
);
791 open_line (struct screen
*screen
, int update
)
793 int saved_y
= screen
->y
;
795 if (! insert_string (screen
, "\n", 0))
798 if (! backward_char (screen
, 0))
804 update_screen (screen
, screen
->line
, screen
->column
, 0, 1, ALL_LINES
);
809 /* A completion hook to print items. */
811 store_completion (const char *item
, grub_completion_type_t type
, int count
)
817 /* If this is the first time, print a label. */
822 case GRUB_COMPLETION_TYPE_COMMAND
:
825 case GRUB_COMPLETION_TYPE_DEVICE
:
828 case GRUB_COMPLETION_TYPE_FILE
:
831 case GRUB_COMPLETION_TYPE_PARTITION
:
834 case GRUB_COMPLETION_TYPE_ARGUMENT
:
842 grub_gotoxy (0, GRUB_TERM_HEIGHT
- 3);
843 grub_printf (" Possible %s are:\n ", what
);
846 /* Make sure that the completion buffer has enough room. */
847 if (completion_buffer
.max_len
< (completion_buffer
.len
848 + (int) grub_strlen (item
) + 1 + 1))
852 new_len
= completion_buffer
.len
+ grub_strlen (item
) + 80;
853 p
= grub_realloc (completion_buffer
.buf
, new_len
);
856 /* Possibly not fatal. */
857 grub_errno
= GRUB_ERR_NONE
;
860 p
[completion_buffer
.len
] = 0;
861 completion_buffer
.buf
= p
;
862 completion_buffer
.max_len
= new_len
;
865 p
= completion_buffer
.buf
+ completion_buffer
.len
;
866 if (completion_buffer
.len
!= 0)
869 completion_buffer
.len
++;
871 grub_strcpy (p
, item
);
872 completion_buffer
.len
+= grub_strlen (item
);
876 complete (struct screen
*screen
, int continuous
, int update
)
883 static int count
= -1;
891 grub_gotoxy (0, GRUB_TERM_HEIGHT
- 3);
893 completion_buffer
.buf
= 0;
894 completion_buffer
.len
= 0;
895 completion_buffer
.max_len
= 0;
897 linep
= screen
->lines
+ screen
->line
;
898 saved_char
= linep
->buf
[screen
->column
];
899 linep
->buf
[screen
->column
] = '\0';
901 insert
= grub_normal_do_completion (linep
->buf
, &restore
, store_completion
);
903 linep
->buf
[screen
->column
] = saved_char
;
907 char *p
= completion_buffer
.buf
;
909 screen
->completion_shown
= 1;
913 int num_sections
= ((completion_buffer
.len
+ GRUB_TERM_WIDTH
- 8 - 1)
914 / (GRUB_TERM_WIDTH
- 8));
917 p
+= (count
% num_sections
) * (GRUB_TERM_WIDTH
- 8);
918 endp
= p
+ (GRUB_TERM_WIDTH
- 8);
920 if (p
!= completion_buffer
.buf
)
921 grub_putcode (GRUB_TERM_DISP_LEFT
);
925 while (*p
&& p
< endp
)
929 grub_putcode (GRUB_TERM_DISP_RIGHT
);
933 grub_gotoxy (pos
>> 8, pos
& 0xFF);
937 insert_string (screen
, insert
, update
);
944 grub_free (completion_buffer
.buf
);
948 /* Clear displayed completions. */
950 clear_completions (void)
956 grub_gotoxy (0, GRUB_TERM_HEIGHT
- 3);
958 for (i
= 0; i
< 2; i
++)
960 for (j
= 0; j
< GRUB_TERM_WIDTH
- 1; j
++)
965 grub_gotoxy (pos
>> 8, pos
& 0xFF);
969 /* Execute the command list in the screen SCREEN. */
971 run (struct screen
*screen
)
973 struct grub_script
*parsed_script
= 0;
977 auto grub_err_t
editor_getline (char **line
);
978 grub_err_t
editor_getline (char **line
)
980 struct line
*linep
= screen
->lines
+ currline
;
983 if (currline
> screen
->num_lines
)
989 /* Trim down space characters. */
990 for (p
= linep
->buf
+ linep
->len
- 1;
991 p
>= linep
->buf
&& grub_isspace (*p
);
996 linep
->len
= p
- linep
->buf
;
997 for (p
= linep
->buf
; grub_isspace (*p
); p
++)
999 *line
= grub_strdup (p
);
1005 grub_printf (" Booting a command list\n\n");
1008 /* Execute the script, line for line. */
1009 while (currline
< screen
->num_lines
)
1011 editor_getline (&nextline
);
1012 parsed_script
= grub_script_parse (nextline
, editor_getline
);
1015 /* Execute the command(s). */
1016 grub_script_execute (parsed_script
);
1018 /* The parsed script was executed, throw it away. */
1019 grub_script_free (parsed_script
);
1025 if (grub_errno
== GRUB_ERR_NONE
&& grub_loader_is_loaded ())
1026 /* Implicit execution of boot, only if something is loaded. */
1027 grub_command_execute ("boot", 0);
1029 if (grub_errno
!= GRUB_ERR_NONE
)
1031 grub_print_error ();
1032 grub_errno
= GRUB_ERR_NONE
;
1033 grub_wait_after_message ();
1039 /* Edit a menu entry with an Emacs-like interface. */
1041 grub_menu_entry_run (grub_menu_entry_t entry
)
1043 struct screen
*screen
;
1046 screen
= make_screen (entry
);
1051 /* Draw the screen. */
1052 grub_menu_init_page (0, 1);
1053 update_screen (screen
, 0, 0, 1, 1, ALL_LINES
);
1059 int c
= GRUB_TERM_ASCII_CHAR (grub_getkey ());
1061 if (screen
->completion_shown
)
1063 clear_completions ();
1064 screen
->completion_shown
= 0;
1070 if (! previous_line (screen
, 1))
1075 if (! next_line (screen
, 1))
1080 if (! forward_char (screen
, 1))
1085 if (! backward_char (screen
, 1))
1090 if (! beginning_of_line (screen
, 1))
1095 if (! end_of_line (screen
, 1))
1099 case '\t': /* C-i */
1100 if (! complete (screen
, prev_c
== c
, 1))
1105 if (! delete_char (screen
, 1))
1110 if (! backward_delete_char (screen
, 1))
1115 if (! kill_line (screen
, prev_c
== c
, 1))
1120 /* FIXME: What behavior is good for this key? */
1124 if (! yank (screen
, 1))
1129 /* FIXME: centering. */
1133 if (! open_line (screen
, 1))
1139 if (! insert_string (screen
, "\n", 1))
1144 destroy_screen (screen
);
1148 grub_cmdline_run (1);
1163 if (grub_isprint (c
))
1169 if (! insert_string (screen
, buf
, 1))
1179 destroy_screen (screen
);
1182 grub_print_error ();
1183 grub_errno
= GRUB_ERR_NONE
;
1184 grub_printf ("\nPress any key to continue...");
1185 (void) grub_getkey ();