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>
26 #include <grub/auth.h>
37 /* The line buffer. */
39 /* The length of the line. */
41 /* The maximum length of the line. */
47 /* The array of lines. */
49 /* The number of lines. */
51 /* The current column. */
53 /* The real column. */
55 /* The current line. */
57 /* The X coordinate. */
59 /* The Y coordinate. */
61 /* The kill buffer. */
63 /* The flag of a completion window. */
67 /* Used for storing completion items temporarily. */
68 static struct line completion_buffer
;
70 /* Initialize a line. */
72 init_line (struct line
*linep
)
75 linep
->max_len
= 80; /* XXX */
76 linep
->buf
= grub_malloc (linep
->max_len
);
83 /* Allocate extra space if necessary. */
85 ensure_space (struct line
*linep
, int extra
)
87 if (linep
->max_len
< linep
->len
+ extra
)
89 linep
->max_len
= linep
->len
+ extra
+ 80; /* XXX */
90 linep
->buf
= grub_realloc (linep
->buf
, linep
->max_len
+ 1);
98 /* Return the number of lines occupied by this line on the screen. */
100 get_logical_num_lines (struct line
*linep
)
102 return (linep
->len
/ GRUB_TERM_ENTRY_WIDTH
) + 1;
107 print_line (struct line
*linep
, int offset
, int start
, int y
)
112 grub_gotoxy (GRUB_TERM_LEFT_BORDER_X
+ GRUB_TERM_MARGIN
+ start
+ 1,
113 y
+ GRUB_TERM_FIRST_ENTRY_Y
);
115 for (p
= linep
->buf
+ offset
+ start
, i
= start
;
116 i
< GRUB_TERM_ENTRY_WIDTH
&& offset
+ i
< linep
->len
;
120 for (; i
< GRUB_TERM_ENTRY_WIDTH
; i
++)
123 if (linep
->len
>= offset
+ GRUB_TERM_ENTRY_WIDTH
)
129 /* Print an empty line. */
131 print_empty_line (int y
)
135 grub_gotoxy (GRUB_TERM_LEFT_BORDER_X
+ GRUB_TERM_MARGIN
+ 1,
136 y
+ GRUB_TERM_FIRST_ENTRY_Y
);
138 for (i
= 0; i
< GRUB_TERM_ENTRY_WIDTH
+ 1; i
++)
142 /* Print an up arrow. */
146 grub_gotoxy (GRUB_TERM_LEFT_BORDER_X
+ GRUB_TERM_BORDER_WIDTH
,
147 GRUB_TERM_FIRST_ENTRY_Y
);
150 grub_putcode (GRUB_TERM_DISP_UP
);
155 /* Print a down arrow. */
157 print_down (int flag
)
159 grub_gotoxy (GRUB_TERM_LEFT_BORDER_X
+ GRUB_TERM_BORDER_WIDTH
,
160 GRUB_TERM_TOP_BORDER_Y
+ GRUB_TERM_NUM_ENTRIES
);
163 grub_putcode (GRUB_TERM_DISP_DOWN
);
168 /* Draw the lines of the screen SCREEN. */
170 update_screen (struct screen
*screen
, int region_start
, int region_column
,
171 int up
, int down
, enum update_mode mode
)
179 /* Check if scrolling is necessary. */
180 if (screen
->y
< 0 || screen
->y
>= GRUB_TERM_NUM_ENTRIES
)
185 screen
->y
= GRUB_TERM_NUM_ENTRIES
- 1;
196 /* Draw lines. This code is tricky, because this must calculate logical
198 y
= screen
->y
- screen
->column
/ GRUB_TERM_ENTRY_WIDTH
;
200 linep
= screen
->lines
+ i
;
205 y
-= get_logical_num_lines (linep
);
216 column
<= linep
->len
&& y
< GRUB_TERM_NUM_ENTRIES
;
217 column
+= GRUB_TERM_ENTRY_WIDTH
, y
++)
222 if (i
== region_start
)
224 if (region_column
>= column
225 && region_column
< column
+ GRUB_TERM_ENTRY_WIDTH
)
226 print_line (linep
, column
, region_column
- column
, y
);
227 else if (region_column
< column
)
228 print_line (linep
, column
, 0, y
);
230 else if (i
> region_start
&& mode
== ALL_LINES
)
231 print_line (linep
, column
, 0, y
);
234 if (y
== GRUB_TERM_NUM_ENTRIES
)
236 if (column
<= linep
->len
|| i
+ 1 < screen
->num_lines
)
243 if (mode
== ALL_LINES
&& i
== screen
->num_lines
)
244 for (; y
< GRUB_TERM_NUM_ENTRIES
; y
++)
245 print_empty_line (y
);
248 while (y
< GRUB_TERM_NUM_ENTRIES
);
250 /* Draw up and down arrows. */
254 print_down (down_flag
);
257 /* Place the cursor. */
258 grub_gotoxy (GRUB_TERM_LEFT_BORDER_X
+ GRUB_TERM_MARGIN
+ 1 + screen
->x
,
259 GRUB_TERM_FIRST_ENTRY_Y
+ screen
->y
);
264 /* Insert the string S into the screen SCREEN. This updates the cursor
265 position and redraw the screen. Return zero if fails. */
267 insert_string (struct screen
*screen
, char *s
, int update
)
269 int region_start
= screen
->num_lines
;
270 int region_column
= 0;
272 enum update_mode mode
= NO_LINE
;
278 /* LF is special because it creates a new line. */
279 struct line
*current_linep
;
280 struct line
*next_linep
;
283 /* Make a new line. */
285 screen
->lines
= grub_realloc (screen
->lines
,
287 * sizeof (struct line
));
292 grub_memmove (screen
->lines
+ screen
->line
+ 2,
293 screen
->lines
+ screen
->line
+ 1,
294 ((screen
->num_lines
- screen
->line
- 2)
295 * sizeof (struct line
)));
297 if (! init_line (screen
->lines
+ screen
->line
+ 1))
301 current_linep
= screen
->lines
+ screen
->line
;
302 next_linep
= current_linep
+ 1;
303 size
= current_linep
->len
- screen
->column
;
305 if (! ensure_space (next_linep
, size
))
308 grub_memmove (next_linep
->buf
,
309 current_linep
->buf
+ screen
->column
,
311 current_linep
->len
= screen
->column
;
312 next_linep
->len
= size
;
314 /* Update a dirty region. */
315 if (region_start
> screen
->line
)
317 region_start
= screen
->line
;
318 region_column
= screen
->column
;
322 down
= 1; /* XXX not optimal. */
324 /* Move the cursor. */
325 screen
->column
= screen
->real_column
= 0;
336 struct line
*current_linep
;
338 int orig_num
, new_num
;
340 /* Find a string delimited by LF. */
341 p
= grub_strchr (s
, '\n');
343 p
= s
+ grub_strlen (s
);
345 /* Insert the string. */
346 current_linep
= screen
->lines
+ screen
->line
;
348 if (! ensure_space (current_linep
, size
))
351 grub_memmove (current_linep
->buf
+ screen
->column
+ size
,
352 current_linep
->buf
+ screen
->column
,
353 current_linep
->len
- screen
->column
);
354 grub_memmove (current_linep
->buf
+ screen
->column
,
357 orig_num
= get_logical_num_lines (current_linep
);
358 current_linep
->len
+= size
;
359 new_num
= get_logical_num_lines (current_linep
);
361 /* Update the dirty region. */
362 if (region_start
> screen
->line
)
364 region_start
= screen
->line
;
365 region_column
= screen
->column
;
368 if (orig_num
!= new_num
)
371 down
= 1; /* XXX not optimal. */
373 else if (mode
!= ALL_LINES
)
376 /* Move the cursor. */
377 screen
->column
+= size
;
378 screen
->real_column
= screen
->column
;
380 screen
->y
+= screen
->x
/ GRUB_TERM_ENTRY_WIDTH
;
381 screen
->x
%= GRUB_TERM_ENTRY_WIDTH
;
388 update_screen (screen
, region_start
, region_column
, 0, down
, mode
);
393 /* Release the resource allocated for SCREEN. */
395 destroy_screen (struct screen
*screen
)
400 for (i
= 0; i
< screen
->num_lines
; i
++)
402 struct line
*linep
= screen
->lines
+ i
;
405 grub_free (linep
->buf
);
408 grub_free (screen
->killed_text
);
409 grub_free (screen
->lines
);
413 /* Make a new screen. */
414 static struct screen
*
415 make_screen (grub_menu_entry_t entry
)
417 struct screen
*screen
;
419 /* Initialize the screen. */
420 screen
= grub_zalloc (sizeof (*screen
));
424 screen
->num_lines
= 1;
425 screen
->lines
= grub_malloc (sizeof (struct line
));
429 /* Initialize the first line which must be always present. */
430 if (! init_line (screen
->lines
))
433 insert_string (screen
, (char *) entry
->sourcecode
, 0);
435 /* Reset the cursor position. */
437 screen
->real_column
= 0;
445 destroy_screen (screen
);
450 forward_char (struct screen
*screen
, int update
)
454 linep
= screen
->lines
+ screen
->line
;
455 if (screen
->column
< linep
->len
)
459 if (screen
->x
== GRUB_TERM_ENTRY_WIDTH
)
465 else if (screen
->num_lines
> screen
->line
+ 1)
473 screen
->real_column
= screen
->column
;
476 update_screen (screen
, screen
->num_lines
, 0, 0, 0, NO_LINE
);
481 backward_char (struct screen
*screen
, int update
)
483 if (screen
->column
> 0)
489 screen
->x
= GRUB_TERM_ENTRY_WIDTH
- 1;
493 else if (screen
->line
> 0)
498 linep
= screen
->lines
+ screen
->line
;
499 screen
->column
= linep
->len
;
500 screen
->x
= screen
->column
% GRUB_TERM_ENTRY_WIDTH
;
504 screen
->real_column
= screen
->column
;
507 update_screen (screen
, screen
->num_lines
, 0, 0, 0, NO_LINE
);
513 previous_line (struct screen
*screen
, int update
)
515 if (screen
->line
> 0)
520 /* How many physical lines from the current position
521 to the first physical line? */
522 dy
= screen
->column
/ GRUB_TERM_ENTRY_WIDTH
;
526 linep
= screen
->lines
+ screen
->line
;
527 if (linep
->len
< screen
->real_column
)
528 screen
->column
= linep
->len
;
530 screen
->column
= screen
->real_column
;
532 /* How many physical lines from the current position
533 to the last physical line? */
534 dy
+= (linep
->len
/ GRUB_TERM_ENTRY_WIDTH
535 - screen
->column
/ GRUB_TERM_ENTRY_WIDTH
);
538 screen
->x
= screen
->column
% GRUB_TERM_ENTRY_WIDTH
;
542 screen
->y
-= screen
->column
/ GRUB_TERM_ENTRY_WIDTH
;
548 update_screen (screen
, screen
->num_lines
, 0, 0, 0, NO_LINE
);
554 next_line (struct screen
*screen
, int update
)
556 if (screen
->line
< screen
->num_lines
- 1)
561 /* How many physical lines from the current position
562 to the last physical line? */
563 linep
= screen
->lines
+ screen
->line
;
564 dy
= (linep
->len
/ GRUB_TERM_ENTRY_WIDTH
565 - screen
->column
/ GRUB_TERM_ENTRY_WIDTH
);
570 if (linep
->len
< screen
->real_column
)
571 screen
->column
= linep
->len
;
573 screen
->column
= screen
->real_column
;
575 /* How many physical lines from the current position
576 to the first physical line? */
577 dy
+= screen
->column
/ GRUB_TERM_ENTRY_WIDTH
;
580 screen
->x
= screen
->column
% GRUB_TERM_ENTRY_WIDTH
;
586 linep
= screen
->lines
+ screen
->line
;
587 screen
->y
+= (linep
->len
/ GRUB_TERM_ENTRY_WIDTH
588 - screen
->column
/ GRUB_TERM_ENTRY_WIDTH
);
589 screen
->column
= linep
->len
;
590 screen
->x
= screen
->column
% GRUB_TERM_ENTRY_WIDTH
;
594 update_screen (screen
, screen
->num_lines
, 0, 0, 0, NO_LINE
);
600 beginning_of_line (struct screen
*screen
, int update
)
602 screen
->y
-= screen
->column
/ GRUB_TERM_ENTRY_WIDTH
;
603 screen
->column
= screen
->real_column
= 0;
607 update_screen (screen
, screen
->num_lines
, 0, 0, 0, NO_LINE
);
613 end_of_line (struct screen
*screen
, int update
)
617 linep
= screen
->lines
+ screen
->line
;
618 screen
->y
+= (linep
->len
/ GRUB_TERM_ENTRY_WIDTH
619 - screen
->column
/ GRUB_TERM_ENTRY_WIDTH
);
620 screen
->column
= screen
->real_column
= linep
->len
;
621 screen
->x
= screen
->column
% GRUB_TERM_ENTRY_WIDTH
;
624 update_screen (screen
, screen
->num_lines
, 0, 0, 0, NO_LINE
);
630 delete_char (struct screen
*screen
, int update
)
633 enum update_mode mode
= NO_LINE
;
634 int start
= screen
->num_lines
;
638 linep
= screen
->lines
+ screen
->line
;
639 if (linep
->len
> screen
->column
)
641 int orig_num
, new_num
;
643 orig_num
= get_logical_num_lines (linep
);
645 grub_memmove (linep
->buf
+ screen
->column
,
646 linep
->buf
+ screen
->column
+ 1,
647 linep
->len
- screen
->column
- 1);
650 new_num
= get_logical_num_lines (linep
);
652 if (orig_num
!= new_num
)
657 start
= screen
->line
;
658 column
= screen
->column
;
660 else if (screen
->num_lines
> screen
->line
+ 1)
662 struct line
*next_linep
;
664 next_linep
= linep
+ 1;
665 if (! ensure_space (linep
, next_linep
->len
))
668 grub_memmove (linep
->buf
+ linep
->len
, next_linep
->buf
, next_linep
->len
);
669 linep
->len
+= next_linep
->len
;
671 grub_free (next_linep
->buf
);
672 grub_memmove (next_linep
,
674 (screen
->num_lines
- screen
->line
- 2)
675 * sizeof (struct line
));
679 start
= screen
->line
;
680 column
= screen
->column
;
684 screen
->real_column
= screen
->column
;
687 update_screen (screen
, start
, column
, 0, down
, mode
);
693 backward_delete_char (struct screen
*screen
, int update
)
698 saved_column
= screen
->column
;
699 saved_line
= screen
->line
;
701 if (! backward_char (screen
, 0))
704 if (saved_column
!= screen
->column
|| saved_line
!= screen
->line
)
705 if (! delete_char (screen
, update
))
712 kill_line (struct screen
*screen
, int continuous
, int update
)
719 p
= screen
->killed_text
;
720 if (! continuous
&& p
)
723 linep
= screen
->lines
+ screen
->line
;
724 size
= linep
->len
- screen
->column
;
727 offset
= grub_strlen (p
);
733 enum update_mode mode
= SINGLE_LINE
;
735 int orig_num
, new_num
;
737 p
= grub_realloc (p
, offset
+ size
+ 1);
741 grub_memmove (p
+ offset
, linep
->buf
+ screen
->column
, size
);
742 p
[offset
+ size
- 1] = '\0';
744 screen
->killed_text
= p
;
746 orig_num
= get_logical_num_lines (linep
);
747 linep
->len
= screen
->column
;
748 new_num
= get_logical_num_lines (linep
);
750 if (orig_num
!= new_num
)
757 update_screen (screen
, screen
->line
, screen
->column
, 0, down
, mode
);
759 else if (screen
->line
+ 1 < screen
->num_lines
)
761 p
= grub_realloc (p
, offset
+ 1 + 1);
766 p
[offset
+ 1] = '\0';
768 screen
->killed_text
= p
;
770 return delete_char (screen
, update
);
777 yank (struct screen
*screen
, int update
)
779 if (screen
->killed_text
)
780 return insert_string (screen
, screen
->killed_text
, update
);
786 open_line (struct screen
*screen
, int update
)
788 int saved_y
= screen
->y
;
790 if (! insert_string (screen
, "\n", 0))
793 if (! backward_char (screen
, 0))
799 update_screen (screen
, screen
->line
, screen
->column
, 0, 1, ALL_LINES
);
804 /* A completion hook to print items. */
806 store_completion (const char *item
, grub_completion_type_t type
, int count
)
812 /* If this is the first time, print a label. */
817 case GRUB_COMPLETION_TYPE_COMMAND
:
820 case GRUB_COMPLETION_TYPE_DEVICE
:
823 case GRUB_COMPLETION_TYPE_FILE
:
826 case GRUB_COMPLETION_TYPE_PARTITION
:
829 case GRUB_COMPLETION_TYPE_ARGUMENT
:
837 grub_gotoxy (0, GRUB_TERM_HEIGHT
- 3);
838 grub_printf (" Possible %s are:\n ", what
);
841 /* Make sure that the completion buffer has enough room. */
842 if (completion_buffer
.max_len
< (completion_buffer
.len
843 + (int) grub_strlen (item
) + 1 + 1))
847 new_len
= completion_buffer
.len
+ grub_strlen (item
) + 80;
848 p
= grub_realloc (completion_buffer
.buf
, new_len
);
851 /* Possibly not fatal. */
852 grub_errno
= GRUB_ERR_NONE
;
855 p
[completion_buffer
.len
] = 0;
856 completion_buffer
.buf
= p
;
857 completion_buffer
.max_len
= new_len
;
860 p
= completion_buffer
.buf
+ completion_buffer
.len
;
861 if (completion_buffer
.len
!= 0)
864 completion_buffer
.len
++;
866 grub_strcpy (p
, item
);
867 completion_buffer
.len
+= grub_strlen (item
);
871 complete (struct screen
*screen
, int continuous
, int update
)
878 static int count
= -1;
886 grub_gotoxy (0, GRUB_TERM_HEIGHT
- 3);
888 completion_buffer
.buf
= 0;
889 completion_buffer
.len
= 0;
890 completion_buffer
.max_len
= 0;
892 linep
= screen
->lines
+ screen
->line
;
893 saved_char
= linep
->buf
[screen
->column
];
894 linep
->buf
[screen
->column
] = '\0';
896 insert
= grub_normal_do_completion (linep
->buf
, &restore
, store_completion
);
898 linep
->buf
[screen
->column
] = saved_char
;
902 char *p
= completion_buffer
.buf
;
904 screen
->completion_shown
= 1;
908 int num_sections
= ((completion_buffer
.len
+ GRUB_TERM_WIDTH
- 8 - 1)
909 / (GRUB_TERM_WIDTH
- 8));
912 p
+= (count
% num_sections
) * (GRUB_TERM_WIDTH
- 8);
913 endp
= p
+ (GRUB_TERM_WIDTH
- 8);
915 if (p
!= completion_buffer
.buf
)
916 grub_putcode (GRUB_TERM_DISP_LEFT
);
920 while (*p
&& p
< endp
)
924 grub_putcode (GRUB_TERM_DISP_RIGHT
);
928 grub_gotoxy (pos
>> 8, pos
& 0xFF);
932 insert_string (screen
, insert
, update
);
939 grub_free (completion_buffer
.buf
);
943 /* Clear displayed completions. */
945 clear_completions (void)
951 grub_gotoxy (0, GRUB_TERM_HEIGHT
- 3);
953 for (i
= 0; i
< 2; i
++)
955 for (j
= 0; j
< GRUB_TERM_WIDTH
- 1; j
++)
960 grub_gotoxy (pos
>> 8, pos
& 0xFF);
964 /* Execute the command list in the screen SCREEN. */
966 run (struct screen
*screen
)
971 auto grub_err_t
editor_getline (char **line
, int cont
);
972 grub_err_t
editor_getline (char **line
, int cont
__attribute__ ((unused
)))
974 struct line
*linep
= screen
->lines
+ currline
;
977 if (currline
> screen
->num_lines
)
983 /* Trim down space characters. */
984 for (p
= linep
->buf
+ linep
->len
- 1;
985 p
>= linep
->buf
&& grub_isspace (*p
);
990 linep
->len
= p
- linep
->buf
;
991 for (p
= linep
->buf
; grub_isspace (*p
); p
++)
993 *line
= grub_strdup (p
);
999 grub_printf (" Booting a command list\n\n");
1002 /* Execute the script, line for line. */
1003 while (currline
< screen
->num_lines
)
1005 editor_getline (&nextline
, 0);
1006 if (grub_parser_get_current ()->parse_line (nextline
, editor_getline
))
1010 if (grub_errno
== GRUB_ERR_NONE
&& grub_loader_is_loaded ())
1011 /* Implicit execution of boot, only if something is loaded. */
1012 grub_command_execute ("boot", 0, 0);
1014 if (grub_errno
!= GRUB_ERR_NONE
)
1016 grub_print_error ();
1017 grub_errno
= GRUB_ERR_NONE
;
1018 grub_wait_after_message ();
1024 /* Edit a menu entry with an Emacs-like interface. */
1026 grub_menu_entry_run (grub_menu_entry_t entry
)
1028 struct screen
*screen
;
1030 grub_err_t err
= GRUB_ERR_NONE
;
1032 err
= grub_auth_check_authentication (NULL
);
1036 grub_print_error ();
1037 grub_errno
= GRUB_ERR_NONE
;
1041 screen
= make_screen (entry
);
1046 /* Draw the screen. */
1047 grub_menu_init_page (0, 1);
1048 update_screen (screen
, 0, 0, 1, 1, ALL_LINES
);
1054 int c
= GRUB_TERM_ASCII_CHAR (grub_getkey ());
1056 if (screen
->completion_shown
)
1058 clear_completions ();
1059 screen
->completion_shown
= 0;
1065 if (! previous_line (screen
, 1))
1070 if (! next_line (screen
, 1))
1075 if (! forward_char (screen
, 1))
1080 if (! backward_char (screen
, 1))
1085 if (! beginning_of_line (screen
, 1))
1090 if (! end_of_line (screen
, 1))
1094 case '\t': /* C-i */
1095 if (! complete (screen
, prev_c
== c
, 1))
1100 if (! delete_char (screen
, 1))
1105 if (! backward_delete_char (screen
, 1))
1110 if (! kill_line (screen
, prev_c
== c
, 1))
1115 /* FIXME: What behavior is good for this key? */
1119 if (! yank (screen
, 1))
1124 /* FIXME: centering. */
1128 if (! open_line (screen
, 1))
1134 if (! insert_string (screen
, "\n", 1))
1139 destroy_screen (screen
);
1143 grub_cmdline_run (1);
1158 if (grub_isprint (c
))
1164 if (! insert_string (screen
, buf
, 1))
1174 destroy_screen (screen
);
1177 grub_print_error ();
1178 grub_errno
= GRUB_ERR_NONE
;
1179 grub_printf ("\nPress any key to continue...");
1180 (void) grub_getkey ();