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/command.h>
25 #include <grub/parser.h>
36 /* The line buffer. */
38 /* The length of the line. */
40 /* The maximum length of the line. */
46 /* The array of lines. */
48 /* The number of lines. */
50 /* The current column. */
52 /* The real column. */
54 /* The current line. */
56 /* The X coordinate. */
58 /* The Y coordinate. */
60 /* The kill buffer. */
62 /* The flag of a completion window. */
66 /* Used for storing completion items temporarily. */
67 static struct line completion_buffer
;
69 /* Initialize a line. */
71 init_line (struct line
*linep
)
74 linep
->max_len
= 80; /* XXX */
75 linep
->buf
= grub_malloc (linep
->max_len
);
82 /* Allocate extra space if necessary. */
84 ensure_space (struct line
*linep
, int extra
)
86 if (linep
->max_len
< linep
->len
+ extra
)
88 linep
->max_len
= linep
->len
+ extra
+ 80; /* XXX */
89 linep
->buf
= grub_realloc (linep
->buf
, linep
->max_len
+ 1);
97 /* Return the number of lines occupied by this line on the screen. */
99 get_logical_num_lines (struct line
*linep
)
101 return (linep
->len
/ GRUB_TERM_ENTRY_WIDTH
) + 1;
106 print_line (struct line
*linep
, int offset
, int start
, int y
)
111 grub_gotoxy (GRUB_TERM_LEFT_BORDER_X
+ GRUB_TERM_MARGIN
+ start
+ 1,
112 y
+ GRUB_TERM_FIRST_ENTRY_Y
);
114 for (p
= linep
->buf
+ offset
+ start
, i
= start
;
115 i
< GRUB_TERM_ENTRY_WIDTH
&& offset
+ i
< linep
->len
;
119 for (; i
< GRUB_TERM_ENTRY_WIDTH
; i
++)
122 if (linep
->len
>= offset
+ GRUB_TERM_ENTRY_WIDTH
)
128 /* Print an empty line. */
130 print_empty_line (int y
)
134 grub_gotoxy (GRUB_TERM_LEFT_BORDER_X
+ GRUB_TERM_MARGIN
+ 1,
135 y
+ GRUB_TERM_FIRST_ENTRY_Y
);
137 for (i
= 0; i
< GRUB_TERM_ENTRY_WIDTH
+ 1; i
++)
141 /* Print an up arrow. */
145 grub_gotoxy (GRUB_TERM_LEFT_BORDER_X
+ GRUB_TERM_BORDER_WIDTH
,
146 GRUB_TERM_FIRST_ENTRY_Y
);
149 grub_putcode (GRUB_TERM_DISP_UP
);
154 /* Print a down arrow. */
156 print_down (int flag
)
158 grub_gotoxy (GRUB_TERM_LEFT_BORDER_X
+ GRUB_TERM_BORDER_WIDTH
,
159 GRUB_TERM_TOP_BORDER_Y
+ GRUB_TERM_NUM_ENTRIES
);
162 grub_putcode (GRUB_TERM_DISP_DOWN
);
167 /* Draw the lines of the screen SCREEN. */
169 update_screen (struct screen
*screen
, int region_start
, int region_column
,
170 int up
, int down
, enum update_mode mode
)
178 /* Check if scrolling is necessary. */
179 if (screen
->y
< 0 || screen
->y
>= GRUB_TERM_NUM_ENTRIES
)
184 screen
->y
= GRUB_TERM_NUM_ENTRIES
- 1;
195 /* Draw lines. This code is tricky, because this must calculate logical
197 y
= screen
->y
- screen
->column
/ GRUB_TERM_ENTRY_WIDTH
;
199 linep
= screen
->lines
+ i
;
204 y
-= get_logical_num_lines (linep
);
215 column
<= linep
->len
&& y
< GRUB_TERM_NUM_ENTRIES
;
216 column
+= GRUB_TERM_ENTRY_WIDTH
, y
++)
221 if (i
== region_start
)
223 if (region_column
>= column
224 && region_column
< column
+ GRUB_TERM_ENTRY_WIDTH
)
225 print_line (linep
, column
, region_column
- column
, y
);
226 else if (region_column
< column
)
227 print_line (linep
, column
, 0, y
);
229 else if (i
> region_start
&& mode
== ALL_LINES
)
230 print_line (linep
, column
, 0, y
);
233 if (y
== GRUB_TERM_NUM_ENTRIES
)
235 if (column
<= linep
->len
|| i
+ 1 < screen
->num_lines
)
242 if (mode
== ALL_LINES
&& i
== screen
->num_lines
)
243 for (; y
< GRUB_TERM_NUM_ENTRIES
; y
++)
244 print_empty_line (y
);
247 while (y
< GRUB_TERM_NUM_ENTRIES
);
249 /* Draw up and down arrows. */
253 print_down (down_flag
);
256 /* Place the cursor. */
257 grub_gotoxy (GRUB_TERM_LEFT_BORDER_X
+ GRUB_TERM_MARGIN
+ 1 + screen
->x
,
258 GRUB_TERM_FIRST_ENTRY_Y
+ screen
->y
);
263 /* Insert the string S into the screen SCREEN. This updates the cursor
264 position and redraw the screen. Return zero if fails. */
266 insert_string (struct screen
*screen
, char *s
, int update
)
268 int region_start
= screen
->num_lines
;
269 int region_column
= 0;
271 enum update_mode mode
= NO_LINE
;
277 /* LF is special because it creates a new line. */
278 struct line
*current_linep
;
279 struct line
*next_linep
;
282 /* Make a new line. */
284 screen
->lines
= grub_realloc (screen
->lines
,
286 * sizeof (struct line
));
291 grub_memmove (screen
->lines
+ screen
->line
+ 2,
292 screen
->lines
+ screen
->line
+ 1,
293 ((screen
->num_lines
- screen
->line
- 2)
294 * sizeof (struct line
)));
296 if (! init_line (screen
->lines
+ screen
->line
+ 1))
300 current_linep
= screen
->lines
+ screen
->line
;
301 next_linep
= current_linep
+ 1;
302 size
= current_linep
->len
- screen
->column
;
304 if (! ensure_space (next_linep
, size
))
307 grub_memmove (next_linep
->buf
,
308 current_linep
->buf
+ screen
->column
,
310 current_linep
->len
= screen
->column
;
311 next_linep
->len
= size
;
313 /* Update a dirty region. */
314 if (region_start
> screen
->line
)
316 region_start
= screen
->line
;
317 region_column
= screen
->column
;
321 down
= 1; /* XXX not optimal. */
323 /* Move the cursor. */
324 screen
->column
= screen
->real_column
= 0;
335 struct line
*current_linep
;
337 int orig_num
, new_num
;
339 /* Find a string delimited by LF. */
340 p
= grub_strchr (s
, '\n');
342 p
= s
+ grub_strlen (s
);
344 /* Insert the string. */
345 current_linep
= screen
->lines
+ screen
->line
;
347 if (! ensure_space (current_linep
, size
))
350 grub_memmove (current_linep
->buf
+ screen
->column
+ size
,
351 current_linep
->buf
+ screen
->column
,
352 current_linep
->len
- screen
->column
);
353 grub_memmove (current_linep
->buf
+ screen
->column
,
356 orig_num
= get_logical_num_lines (current_linep
);
357 current_linep
->len
+= size
;
358 new_num
= get_logical_num_lines (current_linep
);
360 /* Update the dirty region. */
361 if (region_start
> screen
->line
)
363 region_start
= screen
->line
;
364 region_column
= screen
->column
;
367 if (orig_num
!= new_num
)
370 down
= 1; /* XXX not optimal. */
372 else if (mode
!= ALL_LINES
)
375 /* Move the cursor. */
376 screen
->column
+= size
;
377 screen
->real_column
= screen
->column
;
379 screen
->y
+= screen
->x
/ GRUB_TERM_ENTRY_WIDTH
;
380 screen
->x
%= GRUB_TERM_ENTRY_WIDTH
;
387 update_screen (screen
, region_start
, region_column
, 0, down
, mode
);
392 /* Release the resource allocated for SCREEN. */
394 destroy_screen (struct screen
*screen
)
399 for (i
= 0; i
< screen
->num_lines
; i
++)
401 struct line
*linep
= screen
->lines
+ i
;
404 grub_free (linep
->buf
);
407 grub_free (screen
->killed_text
);
408 grub_free (screen
->lines
);
412 /* Make a new screen. */
413 static struct screen
*
414 make_screen (grub_menu_entry_t entry
)
416 struct screen
*screen
;
418 /* Initialize the screen. */
419 screen
= grub_zalloc (sizeof (*screen
));
423 screen
->num_lines
= 1;
424 screen
->lines
= grub_malloc (sizeof (struct line
));
428 /* Initialize the first line which must be always present. */
429 if (! init_line (screen
->lines
))
432 insert_string (screen
, (char *) entry
->sourcecode
, 0);
434 /* Reset the cursor position. */
436 screen
->real_column
= 0;
444 destroy_screen (screen
);
449 forward_char (struct screen
*screen
, int update
)
453 linep
= screen
->lines
+ screen
->line
;
454 if (screen
->column
< linep
->len
)
458 if (screen
->x
== GRUB_TERM_ENTRY_WIDTH
)
464 else if (screen
->num_lines
> screen
->line
+ 1)
472 screen
->real_column
= screen
->column
;
475 update_screen (screen
, screen
->num_lines
, 0, 0, 0, NO_LINE
);
480 backward_char (struct screen
*screen
, int update
)
482 if (screen
->column
> 0)
488 screen
->x
= GRUB_TERM_ENTRY_WIDTH
- 1;
492 else if (screen
->line
> 0)
497 linep
= screen
->lines
+ screen
->line
;
498 screen
->column
= linep
->len
;
499 screen
->x
= screen
->column
% GRUB_TERM_ENTRY_WIDTH
;
503 screen
->real_column
= screen
->column
;
506 update_screen (screen
, screen
->num_lines
, 0, 0, 0, NO_LINE
);
512 previous_line (struct screen
*screen
, int update
)
514 if (screen
->line
> 0)
519 /* How many physical lines from the current position
520 to the first physical line? */
521 dy
= screen
->column
/ GRUB_TERM_ENTRY_WIDTH
;
525 linep
= screen
->lines
+ screen
->line
;
526 if (linep
->len
< screen
->real_column
)
527 screen
->column
= linep
->len
;
529 screen
->column
= screen
->real_column
;
531 /* How many physical lines from the current position
532 to the last physical line? */
533 dy
+= (linep
->len
/ GRUB_TERM_ENTRY_WIDTH
534 - screen
->column
/ GRUB_TERM_ENTRY_WIDTH
);
537 screen
->x
= screen
->column
% GRUB_TERM_ENTRY_WIDTH
;
541 screen
->y
-= screen
->column
/ GRUB_TERM_ENTRY_WIDTH
;
547 update_screen (screen
, screen
->num_lines
, 0, 0, 0, NO_LINE
);
553 next_line (struct screen
*screen
, int update
)
555 if (screen
->line
< screen
->num_lines
- 1)
560 /* How many physical lines from the current position
561 to the last physical line? */
562 linep
= screen
->lines
+ screen
->line
;
563 dy
= (linep
->len
/ GRUB_TERM_ENTRY_WIDTH
564 - screen
->column
/ GRUB_TERM_ENTRY_WIDTH
);
569 if (linep
->len
< screen
->real_column
)
570 screen
->column
= linep
->len
;
572 screen
->column
= screen
->real_column
;
574 /* How many physical lines from the current position
575 to the first physical line? */
576 dy
+= screen
->column
/ GRUB_TERM_ENTRY_WIDTH
;
579 screen
->x
= screen
->column
% GRUB_TERM_ENTRY_WIDTH
;
585 linep
= screen
->lines
+ screen
->line
;
586 screen
->y
+= (linep
->len
/ GRUB_TERM_ENTRY_WIDTH
587 - screen
->column
/ GRUB_TERM_ENTRY_WIDTH
);
588 screen
->column
= linep
->len
;
589 screen
->x
= screen
->column
% GRUB_TERM_ENTRY_WIDTH
;
593 update_screen (screen
, screen
->num_lines
, 0, 0, 0, NO_LINE
);
599 beginning_of_line (struct screen
*screen
, int update
)
601 screen
->y
-= screen
->column
/ GRUB_TERM_ENTRY_WIDTH
;
602 screen
->column
= screen
->real_column
= 0;
606 update_screen (screen
, screen
->num_lines
, 0, 0, 0, NO_LINE
);
612 end_of_line (struct screen
*screen
, int update
)
616 linep
= screen
->lines
+ screen
->line
;
617 screen
->y
+= (linep
->len
/ GRUB_TERM_ENTRY_WIDTH
618 - screen
->column
/ GRUB_TERM_ENTRY_WIDTH
);
619 screen
->column
= screen
->real_column
= linep
->len
;
620 screen
->x
= screen
->column
% GRUB_TERM_ENTRY_WIDTH
;
623 update_screen (screen
, screen
->num_lines
, 0, 0, 0, NO_LINE
);
629 delete_char (struct screen
*screen
, int update
)
632 enum update_mode mode
= NO_LINE
;
633 int start
= screen
->num_lines
;
637 linep
= screen
->lines
+ screen
->line
;
638 if (linep
->len
> screen
->column
)
640 int orig_num
, new_num
;
642 orig_num
= get_logical_num_lines (linep
);
644 grub_memmove (linep
->buf
+ screen
->column
,
645 linep
->buf
+ screen
->column
+ 1,
646 linep
->len
- screen
->column
- 1);
649 new_num
= get_logical_num_lines (linep
);
651 if (orig_num
!= new_num
)
656 start
= screen
->line
;
657 column
= screen
->column
;
659 else if (screen
->num_lines
> screen
->line
+ 1)
661 struct line
*next_linep
;
663 next_linep
= linep
+ 1;
664 if (! ensure_space (linep
, next_linep
->len
))
667 grub_memmove (linep
->buf
+ linep
->len
, next_linep
->buf
, next_linep
->len
);
668 linep
->len
+= next_linep
->len
;
670 grub_free (next_linep
->buf
);
671 grub_memmove (next_linep
,
673 (screen
->num_lines
- screen
->line
- 2)
674 * sizeof (struct line
));
678 start
= screen
->line
;
679 column
= screen
->column
;
683 screen
->real_column
= screen
->column
;
686 update_screen (screen
, start
, column
, 0, down
, mode
);
692 backward_delete_char (struct screen
*screen
, int update
)
697 saved_column
= screen
->column
;
698 saved_line
= screen
->line
;
700 if (! backward_char (screen
, 0))
703 if (saved_column
!= screen
->column
|| saved_line
!= screen
->line
)
704 if (! delete_char (screen
, update
))
711 kill_line (struct screen
*screen
, int continuous
, int update
)
718 p
= screen
->killed_text
;
719 if (! continuous
&& p
)
722 linep
= screen
->lines
+ screen
->line
;
723 size
= linep
->len
- screen
->column
;
726 offset
= grub_strlen (p
);
732 enum update_mode mode
= SINGLE_LINE
;
734 int orig_num
, new_num
;
736 p
= grub_realloc (p
, offset
+ size
+ 1);
740 grub_memmove (p
+ offset
, linep
->buf
+ screen
->column
, size
);
741 p
[offset
+ size
- 1] = '\0';
743 screen
->killed_text
= p
;
745 orig_num
= get_logical_num_lines (linep
);
746 linep
->len
= screen
->column
;
747 new_num
= get_logical_num_lines (linep
);
749 if (orig_num
!= new_num
)
756 update_screen (screen
, screen
->line
, screen
->column
, 0, down
, mode
);
758 else if (screen
->line
+ 1 < screen
->num_lines
)
760 p
= grub_realloc (p
, offset
+ 1 + 1);
765 p
[offset
+ 1] = '\0';
767 screen
->killed_text
= p
;
769 return delete_char (screen
, update
);
776 yank (struct screen
*screen
, int update
)
778 if (screen
->killed_text
)
779 return insert_string (screen
, screen
->killed_text
, update
);
785 open_line (struct screen
*screen
, int update
)
787 int saved_y
= screen
->y
;
789 if (! insert_string (screen
, "\n", 0))
792 if (! backward_char (screen
, 0))
798 update_screen (screen
, screen
->line
, screen
->column
, 0, 1, ALL_LINES
);
803 /* A completion hook to print items. */
805 store_completion (const char *item
, grub_completion_type_t type
, int count
)
811 /* If this is the first time, print a label. */
816 case GRUB_COMPLETION_TYPE_COMMAND
:
819 case GRUB_COMPLETION_TYPE_DEVICE
:
822 case GRUB_COMPLETION_TYPE_FILE
:
825 case GRUB_COMPLETION_TYPE_PARTITION
:
828 case GRUB_COMPLETION_TYPE_ARGUMENT
:
836 grub_gotoxy (0, GRUB_TERM_HEIGHT
- 3);
837 grub_printf (" Possible %s are:\n ", what
);
840 /* Make sure that the completion buffer has enough room. */
841 if (completion_buffer
.max_len
< (completion_buffer
.len
842 + (int) grub_strlen (item
) + 1 + 1))
846 new_len
= completion_buffer
.len
+ grub_strlen (item
) + 80;
847 p
= grub_realloc (completion_buffer
.buf
, new_len
);
850 /* Possibly not fatal. */
851 grub_errno
= GRUB_ERR_NONE
;
854 p
[completion_buffer
.len
] = 0;
855 completion_buffer
.buf
= p
;
856 completion_buffer
.max_len
= new_len
;
859 p
= completion_buffer
.buf
+ completion_buffer
.len
;
860 if (completion_buffer
.len
!= 0)
863 completion_buffer
.len
++;
865 grub_strcpy (p
, item
);
866 completion_buffer
.len
+= grub_strlen (item
);
870 complete (struct screen
*screen
, int continuous
, int update
)
877 static int count
= -1;
885 grub_gotoxy (0, GRUB_TERM_HEIGHT
- 3);
887 completion_buffer
.buf
= 0;
888 completion_buffer
.len
= 0;
889 completion_buffer
.max_len
= 0;
891 linep
= screen
->lines
+ screen
->line
;
892 saved_char
= linep
->buf
[screen
->column
];
893 linep
->buf
[screen
->column
] = '\0';
895 insert
= grub_normal_do_completion (linep
->buf
, &restore
, store_completion
);
897 linep
->buf
[screen
->column
] = saved_char
;
901 char *p
= completion_buffer
.buf
;
903 screen
->completion_shown
= 1;
907 int num_sections
= ((completion_buffer
.len
+ GRUB_TERM_WIDTH
- 8 - 1)
908 / (GRUB_TERM_WIDTH
- 8));
911 p
+= (count
% num_sections
) * (GRUB_TERM_WIDTH
- 8);
912 endp
= p
+ (GRUB_TERM_WIDTH
- 8);
914 if (p
!= completion_buffer
.buf
)
915 grub_putcode (GRUB_TERM_DISP_LEFT
);
919 while (*p
&& p
< endp
)
923 grub_putcode (GRUB_TERM_DISP_RIGHT
);
927 grub_gotoxy (pos
>> 8, pos
& 0xFF);
931 insert_string (screen
, insert
, update
);
938 grub_free (completion_buffer
.buf
);
942 /* Clear displayed completions. */
944 clear_completions (void)
950 grub_gotoxy (0, GRUB_TERM_HEIGHT
- 3);
952 for (i
= 0; i
< 2; i
++)
954 for (j
= 0; j
< GRUB_TERM_WIDTH
- 1; j
++)
959 grub_gotoxy (pos
>> 8, pos
& 0xFF);
963 /* Execute the command list in the screen SCREEN. */
965 run (struct screen
*screen
)
970 auto grub_err_t
editor_getline (char **line
, int cont
);
971 grub_err_t
editor_getline (char **line
, int cont
__attribute__ ((unused
)))
973 struct line
*linep
= screen
->lines
+ currline
;
976 if (currline
> screen
->num_lines
)
982 /* Trim down space characters. */
983 for (p
= linep
->buf
+ linep
->len
- 1;
984 p
>= linep
->buf
&& grub_isspace (*p
);
989 linep
->len
= p
- linep
->buf
;
990 for (p
= linep
->buf
; grub_isspace (*p
); p
++)
992 *line
= grub_strdup (p
);
998 grub_printf (" Booting a command list\n\n");
1001 /* Execute the script, line for line. */
1002 while (currline
< screen
->num_lines
)
1004 editor_getline (&nextline
, 0);
1005 if (grub_parser_get_current ()->parse_line (nextline
, editor_getline
))
1009 if (grub_errno
== GRUB_ERR_NONE
&& grub_loader_is_loaded ())
1010 /* Implicit execution of boot, only if something is loaded. */
1011 grub_command_execute ("boot", 0, 0);
1013 if (grub_errno
!= GRUB_ERR_NONE
)
1015 grub_print_error ();
1016 grub_errno
= GRUB_ERR_NONE
;
1017 grub_wait_after_message ();
1023 /* Edit a menu entry with an Emacs-like interface. */
1025 grub_menu_entry_run (grub_menu_entry_t entry
)
1027 struct screen
*screen
;
1030 screen
= make_screen (entry
);
1035 /* Draw the screen. */
1036 grub_menu_init_page (0, 1);
1037 update_screen (screen
, 0, 0, 1, 1, ALL_LINES
);
1043 int c
= GRUB_TERM_ASCII_CHAR (grub_getkey ());
1045 if (screen
->completion_shown
)
1047 clear_completions ();
1048 screen
->completion_shown
= 0;
1054 if (! previous_line (screen
, 1))
1059 if (! next_line (screen
, 1))
1064 if (! forward_char (screen
, 1))
1069 if (! backward_char (screen
, 1))
1074 if (! beginning_of_line (screen
, 1))
1079 if (! end_of_line (screen
, 1))
1083 case '\t': /* C-i */
1084 if (! complete (screen
, prev_c
== c
, 1))
1089 if (! delete_char (screen
, 1))
1094 if (! backward_delete_char (screen
, 1))
1099 if (! kill_line (screen
, prev_c
== c
, 1))
1104 /* FIXME: What behavior is good for this key? */
1108 if (! yank (screen
, 1))
1113 /* FIXME: centering. */
1117 if (! open_line (screen
, 1))
1123 if (! insert_string (screen
, "\n", 1))
1128 destroy_screen (screen
);
1132 grub_cmdline_run (1);
1147 if (grub_isprint (c
))
1153 if (! insert_string (screen
, buf
, 1))
1163 destroy_screen (screen
);
1166 grub_print_error ();
1167 grub_errno
= GRUB_ERR_NONE
;
1168 grub_printf ("\nPress any key to continue...");
1169 (void) grub_getkey ();