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_malloc (sizeof (*screen
));
423 screen
->num_lines
= 1;
425 screen
->real_column
= 0;
429 screen
->killed_text
= 0;
430 screen
->completion_shown
= 0;
431 screen
->lines
= grub_malloc (sizeof (struct line
));
435 /* Initialize the first line which must be always present. */
436 if (! init_line (screen
->lines
))
439 insert_string (screen
, (char *) entry
->sourcecode
, 0);
441 /* Reset the cursor position. */
443 screen
->real_column
= 0;
451 destroy_screen (screen
);
456 forward_char (struct screen
*screen
, int update
)
460 linep
= screen
->lines
+ screen
->line
;
461 if (screen
->column
< linep
->len
)
465 if (screen
->x
== GRUB_TERM_ENTRY_WIDTH
)
471 else if (screen
->num_lines
> screen
->line
+ 1)
479 screen
->real_column
= screen
->column
;
482 update_screen (screen
, screen
->num_lines
, 0, 0, 0, NO_LINE
);
487 backward_char (struct screen
*screen
, int update
)
489 if (screen
->column
> 0)
495 screen
->x
= GRUB_TERM_ENTRY_WIDTH
- 1;
499 else if (screen
->line
> 0)
504 linep
= screen
->lines
+ screen
->line
;
505 screen
->column
= linep
->len
;
506 screen
->x
= screen
->column
% GRUB_TERM_ENTRY_WIDTH
;
510 screen
->real_column
= screen
->column
;
513 update_screen (screen
, screen
->num_lines
, 0, 0, 0, NO_LINE
);
519 previous_line (struct screen
*screen
, int update
)
521 if (screen
->line
> 0)
526 /* How many physical lines from the current position
527 to the first physical line? */
528 dy
= screen
->column
/ GRUB_TERM_ENTRY_WIDTH
;
532 linep
= screen
->lines
+ screen
->line
;
533 if (linep
->len
< screen
->real_column
)
534 screen
->column
= linep
->len
;
536 screen
->column
= screen
->real_column
;
538 /* How many physical lines from the current position
539 to the last physical line? */
540 dy
+= (linep
->len
/ GRUB_TERM_ENTRY_WIDTH
541 - screen
->column
/ GRUB_TERM_ENTRY_WIDTH
);
544 screen
->x
= screen
->column
% GRUB_TERM_ENTRY_WIDTH
;
548 screen
->y
-= screen
->column
/ GRUB_TERM_ENTRY_WIDTH
;
554 update_screen (screen
, screen
->num_lines
, 0, 0, 0, NO_LINE
);
560 next_line (struct screen
*screen
, int update
)
562 if (screen
->line
< screen
->num_lines
- 1)
567 /* How many physical lines from the current position
568 to the last physical line? */
569 linep
= screen
->lines
+ screen
->line
;
570 dy
= (linep
->len
/ GRUB_TERM_ENTRY_WIDTH
571 - screen
->column
/ GRUB_TERM_ENTRY_WIDTH
);
576 if (linep
->len
< screen
->real_column
)
577 screen
->column
= linep
->len
;
579 screen
->column
= screen
->real_column
;
581 /* How many physical lines from the current position
582 to the first physical line? */
583 dy
+= screen
->column
/ GRUB_TERM_ENTRY_WIDTH
;
586 screen
->x
= screen
->column
% GRUB_TERM_ENTRY_WIDTH
;
592 linep
= screen
->lines
+ screen
->line
;
593 screen
->y
+= (linep
->len
/ GRUB_TERM_ENTRY_WIDTH
594 - screen
->column
/ GRUB_TERM_ENTRY_WIDTH
);
595 screen
->column
= linep
->len
;
596 screen
->x
= screen
->column
% GRUB_TERM_ENTRY_WIDTH
;
600 update_screen (screen
, screen
->num_lines
, 0, 0, 0, NO_LINE
);
606 beginning_of_line (struct screen
*screen
, int update
)
608 screen
->y
-= screen
->column
/ GRUB_TERM_ENTRY_WIDTH
;
609 screen
->column
= screen
->real_column
= 0;
613 update_screen (screen
, screen
->num_lines
, 0, 0, 0, NO_LINE
);
619 end_of_line (struct screen
*screen
, int update
)
623 linep
= screen
->lines
+ screen
->line
;
624 screen
->y
+= (linep
->len
/ GRUB_TERM_ENTRY_WIDTH
625 - screen
->column
/ GRUB_TERM_ENTRY_WIDTH
);
626 screen
->column
= screen
->real_column
= linep
->len
;
627 screen
->x
= screen
->column
% GRUB_TERM_ENTRY_WIDTH
;
630 update_screen (screen
, screen
->num_lines
, 0, 0, 0, NO_LINE
);
636 delete_char (struct screen
*screen
, int update
)
639 enum update_mode mode
= NO_LINE
;
640 int start
= screen
->num_lines
;
644 linep
= screen
->lines
+ screen
->line
;
645 if (linep
->len
> screen
->column
)
647 int orig_num
, new_num
;
649 orig_num
= get_logical_num_lines (linep
);
651 grub_memmove (linep
->buf
+ screen
->column
,
652 linep
->buf
+ screen
->column
+ 1,
653 linep
->len
- screen
->column
- 1);
656 new_num
= get_logical_num_lines (linep
);
658 if (orig_num
!= new_num
)
663 start
= screen
->line
;
664 column
= screen
->column
;
666 else if (screen
->num_lines
> screen
->line
+ 1)
668 struct line
*next_linep
;
670 next_linep
= linep
+ 1;
671 if (! ensure_space (linep
, next_linep
->len
))
674 grub_memmove (linep
->buf
+ linep
->len
, next_linep
->buf
, next_linep
->len
);
675 linep
->len
+= next_linep
->len
;
677 grub_free (next_linep
->buf
);
678 grub_memmove (next_linep
,
680 (screen
->num_lines
- screen
->line
- 2)
681 * sizeof (struct line
));
685 start
= screen
->line
;
686 column
= screen
->column
;
690 screen
->real_column
= screen
->column
;
693 update_screen (screen
, start
, column
, 0, down
, mode
);
699 backward_delete_char (struct screen
*screen
, int update
)
704 saved_column
= screen
->column
;
705 saved_line
= screen
->line
;
707 if (! backward_char (screen
, 0))
710 if (saved_column
!= screen
->column
|| saved_line
!= screen
->line
)
711 if (! delete_char (screen
, update
))
718 kill_line (struct screen
*screen
, int continuous
, int update
)
725 p
= screen
->killed_text
;
726 if (! continuous
&& p
)
729 linep
= screen
->lines
+ screen
->line
;
730 size
= linep
->len
- screen
->column
;
733 offset
= grub_strlen (p
);
739 enum update_mode mode
= SINGLE_LINE
;
741 int orig_num
, new_num
;
743 p
= grub_realloc (p
, offset
+ size
+ 1);
747 grub_memmove (p
+ offset
, linep
->buf
+ screen
->column
, size
);
748 p
[offset
+ size
- 1] = '\0';
750 screen
->killed_text
= p
;
752 orig_num
= get_logical_num_lines (linep
);
753 linep
->len
= screen
->column
;
754 new_num
= get_logical_num_lines (linep
);
756 if (orig_num
!= new_num
)
763 update_screen (screen
, screen
->line
, screen
->column
, 0, down
, mode
);
765 else if (screen
->line
+ 1 < screen
->num_lines
)
767 p
= grub_realloc (p
, offset
+ 1 + 1);
772 p
[offset
+ 1] = '\0';
774 screen
->killed_text
= p
;
776 return delete_char (screen
, update
);
783 yank (struct screen
*screen
, int update
)
785 if (screen
->killed_text
)
786 return insert_string (screen
, screen
->killed_text
, update
);
792 open_line (struct screen
*screen
, int update
)
794 int saved_y
= screen
->y
;
796 if (! insert_string (screen
, "\n", 0))
799 if (! backward_char (screen
, 0))
805 update_screen (screen
, screen
->line
, screen
->column
, 0, 1, ALL_LINES
);
810 /* A completion hook to print items. */
812 store_completion (const char *item
, grub_completion_type_t type
, int count
)
818 /* If this is the first time, print a label. */
823 case GRUB_COMPLETION_TYPE_COMMAND
:
826 case GRUB_COMPLETION_TYPE_DEVICE
:
829 case GRUB_COMPLETION_TYPE_FILE
:
832 case GRUB_COMPLETION_TYPE_PARTITION
:
835 case GRUB_COMPLETION_TYPE_ARGUMENT
:
843 grub_gotoxy (0, GRUB_TERM_HEIGHT
- 3);
844 grub_printf (" Possible %s are:\n ", what
);
847 /* Make sure that the completion buffer has enough room. */
848 if (completion_buffer
.max_len
< (completion_buffer
.len
849 + (int) grub_strlen (item
) + 1 + 1))
853 new_len
= completion_buffer
.len
+ grub_strlen (item
) + 80;
854 p
= grub_realloc (completion_buffer
.buf
, new_len
);
857 /* Possibly not fatal. */
858 grub_errno
= GRUB_ERR_NONE
;
861 p
[completion_buffer
.len
] = 0;
862 completion_buffer
.buf
= p
;
863 completion_buffer
.max_len
= new_len
;
866 p
= completion_buffer
.buf
+ completion_buffer
.len
;
867 if (completion_buffer
.len
!= 0)
870 completion_buffer
.len
++;
872 grub_strcpy (p
, item
);
873 completion_buffer
.len
+= grub_strlen (item
);
877 complete (struct screen
*screen
, int continuous
, int update
)
884 static int count
= -1;
892 grub_gotoxy (0, GRUB_TERM_HEIGHT
- 3);
894 completion_buffer
.buf
= 0;
895 completion_buffer
.len
= 0;
896 completion_buffer
.max_len
= 0;
898 linep
= screen
->lines
+ screen
->line
;
899 saved_char
= linep
->buf
[screen
->column
];
900 linep
->buf
[screen
->column
] = '\0';
902 insert
= grub_normal_do_completion (linep
->buf
, &restore
, store_completion
);
904 linep
->buf
[screen
->column
] = saved_char
;
908 char *p
= completion_buffer
.buf
;
910 screen
->completion_shown
= 1;
914 int num_sections
= ((completion_buffer
.len
+ GRUB_TERM_WIDTH
- 8 - 1)
915 / (GRUB_TERM_WIDTH
- 8));
918 p
+= (count
% num_sections
) * (GRUB_TERM_WIDTH
- 8);
919 endp
= p
+ (GRUB_TERM_WIDTH
- 8);
921 if (p
!= completion_buffer
.buf
)
922 grub_putcode (GRUB_TERM_DISP_LEFT
);
926 while (*p
&& p
< endp
)
930 grub_putcode (GRUB_TERM_DISP_RIGHT
);
934 grub_gotoxy (pos
>> 8, pos
& 0xFF);
938 insert_string (screen
, insert
, update
);
945 grub_free (completion_buffer
.buf
);
949 /* Clear displayed completions. */
951 clear_completions (void)
957 grub_gotoxy (0, GRUB_TERM_HEIGHT
- 3);
959 for (i
= 0; i
< 2; i
++)
961 for (j
= 0; j
< GRUB_TERM_WIDTH
- 1; j
++)
966 grub_gotoxy (pos
>> 8, pos
& 0xFF);
970 /* Execute the command list in the screen SCREEN. */
972 run (struct screen
*screen
)
977 auto grub_err_t
editor_getline (char **line
, int cont
);
978 grub_err_t
editor_getline (char **line
, int cont
__attribute__ ((unused
)))
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
, 0);
1012 if (grub_parser_get_current ()->parse_line (nextline
, editor_getline
))
1016 if (grub_errno
== GRUB_ERR_NONE
&& grub_loader_is_loaded ())
1017 /* Implicit execution of boot, only if something is loaded. */
1018 grub_command_execute ("boot", 0, 0);
1020 if (grub_errno
!= GRUB_ERR_NONE
)
1022 grub_print_error ();
1023 grub_errno
= GRUB_ERR_NONE
;
1024 grub_wait_after_message ();
1030 /* Edit a menu entry with an Emacs-like interface. */
1032 grub_menu_entry_run (grub_menu_entry_t entry
)
1034 struct screen
*screen
;
1037 screen
= make_screen (entry
);
1042 /* Draw the screen. */
1043 grub_menu_init_page (0, 1);
1044 update_screen (screen
, 0, 0, 1, 1, ALL_LINES
);
1050 int c
= GRUB_TERM_ASCII_CHAR (grub_getkey ());
1052 if (screen
->completion_shown
)
1054 clear_completions ();
1055 screen
->completion_shown
= 0;
1061 if (! previous_line (screen
, 1))
1066 if (! next_line (screen
, 1))
1071 if (! forward_char (screen
, 1))
1076 if (! backward_char (screen
, 1))
1081 if (! beginning_of_line (screen
, 1))
1086 if (! end_of_line (screen
, 1))
1090 case '\t': /* C-i */
1091 if (! complete (screen
, prev_c
== c
, 1))
1096 if (! delete_char (screen
, 1))
1101 if (! backward_delete_char (screen
, 1))
1106 if (! kill_line (screen
, prev_c
== c
, 1))
1111 /* FIXME: What behavior is good for this key? */
1115 if (! yank (screen
, 1))
1120 /* FIXME: centering. */
1124 if (! open_line (screen
, 1))
1130 if (! insert_string (screen
, "\n", 1))
1135 destroy_screen (screen
);
1139 grub_cmdline_run (1);
1154 if (grub_isprint (c
))
1160 if (! insert_string (screen
, buf
, 1))
1170 destroy_screen (screen
);
1173 grub_print_error ();
1174 grub_errno
= GRUB_ERR_NONE
;
1175 grub_printf ("\nPress any key to continue...");
1176 (void) grub_getkey ();