2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2005,2006,2007,2008,2009 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/script_sh.h>
27 #include <grub/auth.h>
28 #include <grub/i18n.h>
29 #include <grub/charset.h>
40 /* The line buffer. */
42 /* The length of the line. */
44 /* The maximum length of the line. */
46 struct grub_term_pos **pos;
49 struct per_term_screen
51 struct grub_term_output *term;
53 struct grub_term_screen_geometry geo;
54 /* Scratch variables used when updating. Having them here avoids
55 loads of small mallocs. */
58 enum update_mode mode;
63 /* The array of lines. */
65 /* The number of lines. */
67 /* The current column. */
69 /* The real column. */
71 /* The current line. */
73 /* The kill buffer. */
75 /* The flag of a completion window. */
80 struct per_term_screen *terms;
84 /* Used for storing completion items temporarily. */
90 static int completion_type;
92 /* Initialize a line. */
94 init_line (struct screen *screen, struct line *linep)
98 linep->buf = grub_malloc ((linep->max_len + 1) * sizeof (linep->buf[0]));
99 linep->pos = grub_zalloc (screen->nterms * sizeof (linep->pos[0]));
100 if (! linep->buf || !linep->pos)
102 grub_free (linep->buf);
103 grub_free (linep->pos);
110 /* Allocate extra space if necessary. */
112 ensure_space (struct line *linep, int extra)
114 if (linep->max_len < linep->len + extra)
116 linep->max_len = 2 * (linep->len + extra);
117 linep->buf = grub_realloc (linep->buf, (linep->max_len + 1) * sizeof (linep->buf[0]));
125 /* Return the number of lines occupied by this line on the screen. */
127 get_logical_num_lines (struct line *linep, struct per_term_screen *term_screen)
129 grub_size_t width = grub_getstringwidth (linep->buf, linep->buf + linep->len,
132 /* Empty line still consumes space on screen */
133 return width ? (width + (unsigned) term_screen->geo.entry_width - 1) /
134 (unsigned) term_screen->geo.entry_width
139 advance_to (struct screen *screen, int c)
141 if (c > screen->lines[screen->line].len)
142 c = screen->lines[screen->line].len;
144 screen->column = grub_unicode_get_comb_end (screen->lines[screen->line].buf
145 + screen->lines[screen->line].len,
146 screen->lines[screen->line].buf
148 - screen->lines[screen->line].buf;
151 /* Print an empty line. */
153 print_empty_line (int y, struct per_term_screen *term_screen)
157 grub_term_gotoxy (term_screen->term,
158 (struct grub_term_coordinate) { term_screen->geo.first_entry_x,
159 y + term_screen->geo.first_entry_y });
161 for (i = 0; i < term_screen->geo.entry_width + 1; i++)
162 grub_putcode (' ', term_screen->term);
166 print_updown (int upflag, int downflag, struct per_term_screen *term_screen)
168 grub_term_gotoxy (term_screen->term,
169 (struct grub_term_coordinate) { term_screen->geo.first_entry_x
170 + term_screen->geo.entry_width + 1
171 + term_screen->geo.border,
172 term_screen->geo.first_entry_y });
174 if (upflag && downflag)
175 grub_putcode (GRUB_UNICODE_UPDOWNARROW, term_screen->term);
177 grub_putcode (GRUB_UNICODE_UPARROW, term_screen->term);
179 grub_putcode (GRUB_UNICODE_DOWNARROW, term_screen->term);
181 grub_putcode (' ', term_screen->term);
184 /* Print an up arrow. */
186 print_up (int flag, struct per_term_screen *term_screen)
188 grub_term_gotoxy (term_screen->term,
189 (struct grub_term_coordinate) { term_screen->geo.first_entry_x
190 + term_screen->geo.entry_width + 1
191 + term_screen->geo.border,
192 term_screen->geo.first_entry_y });
195 grub_putcode (GRUB_UNICODE_UPARROW, term_screen->term);
197 grub_putcode (' ', term_screen->term);
200 /* Print a down arrow. */
202 print_down (int flag, struct per_term_screen *term_screen)
204 grub_term_gotoxy (term_screen->term,
205 (struct grub_term_coordinate) { term_screen->geo.first_entry_x
206 + term_screen->geo.entry_width + 1
207 + term_screen->geo.border,
208 term_screen->geo.first_entry_y
209 + term_screen->geo.num_entries - 1 });
212 grub_putcode (GRUB_UNICODE_DOWNARROW, term_screen->term);
214 grub_putcode (' ', term_screen->term);
217 /* Draw the lines of the screen SCREEN. */
219 update_screen (struct screen *screen, struct per_term_screen *term_screen,
220 int region_start, int region_column __attribute__ ((unused)),
221 int up, int down, enum update_mode mode)
229 y = term_screen->y_line_start;
230 linep = screen->lines;
232 for (i = 0; i < screen->line; i++, linep++)
233 y += get_logical_num_lines (linep, term_screen);
234 linep = screen->lines + screen->line;
235 grub_size_t t = grub_getstringwidth (linep->buf, linep->buf + screen->column,
237 y += t / (unsigned) term_screen->geo.entry_width;
238 if (t % (unsigned) term_screen->geo.entry_width == 0
239 && t != 0 && screen->column == linep->len)
241 /* Check if scrolling is necessary. */
242 if (y < 0 || y >= term_screen->geo.num_entries)
248 delta = term_screen->geo.num_entries - 1 - y;
249 term_screen->y_line_start += delta;
257 grub_term_setcursor (term_screen->term, 0);
261 /* Draw lines. This code is tricky, because this must calculate logical
263 y = term_screen->y_line_start;
265 linep = screen->lines;
269 add = get_logical_num_lines (linep, term_screen);
282 struct grub_term_pos **pos;
284 if (linep >= screen->lines + screen->num_lines)
287 pos = linep->pos + (term_screen - screen->terms);
290 *pos = grub_zalloc ((linep->len + 1) * sizeof (**pos));
292 if (i == region_start || linep == screen->lines + screen->line
293 || (i > region_start && mode == ALL_LINES))
295 grub_term_gotoxy (term_screen->term,
296 (struct grub_term_coordinate) { term_screen->geo.first_entry_x,
298 + term_screen->geo.first_entry_y });
300 grub_print_ucs4_menu (linep->buf,
301 linep->buf + linep->len,
302 term_screen->geo.first_entry_x,
303 term_screen->geo.right_margin,
306 term_screen->geo.num_entries
307 - ((y > 0) ? y : 0), '\\',
310 y += get_logical_num_lines (linep, term_screen);
311 if (y >= term_screen->geo.num_entries)
313 if (i + 1 < screen->num_lines)
320 if (mode == ALL_LINES && i == screen->num_lines)
321 for (; y < term_screen->geo.num_entries; y++)
322 print_empty_line (y, term_screen);
324 while (y < term_screen->geo.num_entries);
326 /* Draw up and down arrows. */
328 if (term_screen->geo.num_entries == 1)
331 print_updown (up_flag, down_flag, term_screen);
336 print_up (up_flag, term_screen);
338 print_down (down_flag, term_screen);
342 /* Place the cursor. */
343 if (screen->lines[screen->line].pos[term_screen - screen->terms])
345 const struct grub_term_pos *cpos;
346 for (cpos = &(screen->lines[screen->line].pos[term_screen - screen->terms])[screen->column];
347 cpos >= &(screen->lines[screen->line].pos[term_screen - screen->terms])[0];
351 y = term_screen->y_line_start;
352 for (i = 0; i < screen->line; i++)
353 y += get_logical_num_lines (screen->lines + i, term_screen);
354 if (cpos >= &(screen->lines[screen->line].pos[term_screen - screen->terms])[0])
355 grub_term_gotoxy (term_screen->term,
356 (struct grub_term_coordinate) { cpos->x + term_screen->geo.first_entry_x,
358 + term_screen->geo.first_entry_y });
360 grub_term_gotoxy (term_screen->term,
361 (struct grub_term_coordinate) { term_screen->geo.first_entry_x,
362 y + term_screen->geo.first_entry_y });
366 grub_term_setcursor (term_screen->term, 1);
368 grub_term_refresh (term_screen->term);
372 update_screen_all (struct screen *screen,
373 int region_start, int region_column,
374 int up, int down, enum update_mode mode)
377 for (i = 0; i < screen->nterms; i++)
378 update_screen (screen, &screen->terms[i], region_start, region_column,
383 insert_string (struct screen *screen, const char *s, int update)
385 int region_start = screen->num_lines;
386 int region_column = 0;
389 for (i = 0; i < screen->nterms; i++)
391 screen->terms[i].down = 0;
392 screen->terms[i].mode = NO_LINE;
399 /* LF is special because it creates a new line. */
400 struct line *current_linep;
401 struct line *next_linep;
404 /* Make a new line. */
406 screen->lines = grub_realloc (screen->lines,
408 * sizeof (screen->lines[0]));
412 /* Shift down if not appending after the last line. */
413 if (screen->line < screen->num_lines - 2)
414 grub_memmove (screen->lines + screen->line + 2,
415 screen->lines + screen->line + 1,
416 ((screen->num_lines - screen->line - 2)
417 * sizeof (struct line)));
419 if (! init_line (screen, screen->lines + screen->line + 1))
423 current_linep = screen->lines + screen->line;
424 next_linep = current_linep + 1;
425 size = current_linep->len - screen->column;
427 if (! ensure_space (next_linep, size))
430 grub_memmove (next_linep->buf,
431 current_linep->buf + screen->column,
432 size * sizeof (next_linep->buf[0]));
433 current_linep->len = screen->column;
434 for (i = 0; i < screen->nterms; i++)
436 grub_free (current_linep->pos[i]);
437 current_linep->pos[i] = 0;
439 next_linep->len = size;
441 /* Update a dirty region. */
442 if (region_start > screen->line)
444 region_start = screen->line;
445 region_column = screen->column;
448 for (i = 0; i < screen->nterms; i++)
450 screen->terms[i].mode = ALL_LINES;
451 screen->terms[i].down = 1; /* XXX not optimal. */
454 /* Move the cursor. */
455 screen->column = screen->real_column = 0;
463 struct line *current_linep;
465 grub_uint32_t *unicode_msg;
467 /* Find a string delimited by LF. */
468 p = grub_strchr (s, '\n');
470 p = s + grub_strlen (s);
472 /* Insert the string. */
473 current_linep = screen->lines + screen->line;
474 unicode_msg = grub_malloc ((p - s) * sizeof (grub_uint32_t));
479 size = grub_utf8_to_ucs4 (unicode_msg, (p - s),
480 (grub_uint8_t *) s, (p - s), 0);
482 if (! ensure_space (current_linep, size))
484 grub_free (unicode_msg);
488 grub_memmove (current_linep->buf + screen->column + size,
489 current_linep->buf + screen->column,
490 (current_linep->len - screen->column)
491 * sizeof (current_linep->buf[0]));
492 grub_memmove (current_linep->buf + screen->column,
494 size * sizeof (current_linep->buf[0]));
495 grub_free (unicode_msg);
497 for (i = 0; i < screen->nterms; i++)
499 grub_free (current_linep->pos[i]);
500 current_linep->pos[i] = 0;
503 for (i = 0; i < screen->nterms; i++)
504 screen->terms[i].orig_num = get_logical_num_lines (current_linep,
506 current_linep->len += size;
508 /* Update the dirty region. */
509 if (region_start > screen->line)
511 region_start = screen->line;
512 region_column = screen->column;
515 for (i = 0; i < screen->nterms; i++)
517 int new_num = get_logical_num_lines (current_linep,
519 if (screen->terms[i].orig_num != new_num)
521 screen->terms[i].mode = ALL_LINES;
522 screen->terms[i].down = 1; /* XXX not optimal. */
524 else if (screen->terms[i].mode != ALL_LINES)
525 screen->terms[i].mode = SINGLE_LINE;
528 /* Move the cursor. */
529 advance_to (screen, screen->column + size);
531 screen->real_column = screen->column;
537 for (i = 0; i < screen->nterms; i++)
538 update_screen (screen, &screen->terms[i],
539 region_start, region_column, 0, screen->terms[i].down,
540 screen->terms[i].mode);
545 /* Release the resource allocated for SCREEN. */
547 destroy_screen (struct screen *screen)
552 for (i = 0; i < screen->num_lines; i++)
554 struct line *linep = screen->lines + i;
560 for (j = 0; j < screen->nterms; j++)
561 grub_free (linep->pos[j]);
563 grub_free (linep->buf);
564 grub_free (linep->pos);
568 grub_free (screen->killed_text);
569 grub_free (screen->lines);
570 grub_free (screen->terms);
574 /* Make a new screen. */
575 static struct screen *
576 make_screen (grub_menu_entry_t entry)
578 struct screen *screen;
581 /* Initialize the screen. */
582 screen = grub_zalloc (sizeof (*screen));
586 screen->submenu = entry->submenu;
588 screen->num_lines = 1;
589 screen->lines = grub_malloc (sizeof (struct line));
593 /* Initialize the first line which must be always present. */
594 if (! init_line (screen, screen->lines))
597 insert_string (screen, (char *) entry->sourcecode, 0);
599 /* Reset the cursor position. */
601 screen->real_column = 0;
603 for (i = 0; i < screen->nterms; i++)
605 screen->terms[i].y_line_start = 0;
611 destroy_screen (screen);
616 forward_char (struct screen *screen, int update)
620 linep = screen->lines + screen->line;
621 if (screen->column < linep->len)
623 screen->column = grub_unicode_get_comb_end (screen->lines[screen->line].buf
624 + screen->lines[screen->line].len,
625 screen->lines[screen->line].buf
626 + screen->column + 1)
627 - screen->lines[screen->line].buf;
629 else if (screen->num_lines > screen->line + 1)
635 screen->real_column = screen->column;
638 update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE);
643 backward_char (struct screen *screen, int update)
645 if (screen->column > 0)
647 struct grub_unicode_glyph glyph;
650 linep = screen->lines + screen->line;
653 screen->column = grub_unicode_get_comb_start (linep->buf,
654 linep->buf + screen->column)
657 grub_unicode_aglomerate_comb (screen->lines[screen->line].buf + screen->column,
658 screen->lines[screen->line].len - screen->column,
660 screen->column = grub_unicode_get_comb_start (linep->buf,
661 linep->buf + screen->column)
664 grub_unicode_destroy_glyph (&glyph);
666 else if (screen->line > 0)
669 screen->column = screen->lines[screen->line].len;
672 screen->real_column = screen->column;
675 update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE);
681 previous_line (struct screen *screen, int update)
683 if (screen->line > 0)
690 linep = screen->lines + screen->line;
691 if (linep->len < screen->real_column)
694 col = screen->real_column;
697 advance_to (screen, col);
705 update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE);
711 next_line (struct screen *screen, int update)
713 if (screen->line < screen->num_lines - 1)
718 /* How many physical lines from the current position
719 to the last physical line? */
720 linep = screen->lines + screen->line;
723 if ((linep + 1)->len < screen->real_column)
724 c = (linep + 1)->len;
726 c = screen->real_column;
729 advance_to (screen, c);
732 advance_to (screen, screen->lines[screen->line].len);
735 update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE);
741 beginning_of_line (struct screen *screen, int update)
743 screen->column = screen->real_column = 0;
746 update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE);
752 end_of_line (struct screen *screen, int update)
754 advance_to (screen, screen->lines[screen->line].len);
757 update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE);
763 delete_char (struct screen *screen, int update)
766 int start = screen->num_lines;
769 linep = screen->lines + screen->line;
770 if (linep->len > screen->column)
774 for (i = 0; i < screen->nterms; i++)
775 screen->terms[i].orig_num = get_logical_num_lines (linep, &screen->terms[i]);
777 grub_memmove (linep->buf + screen->column,
778 linep->buf + screen->column + 1,
779 (linep->len - screen->column - 1)
780 * sizeof (linep->buf[0]));
783 for (i = 0; i < screen->nterms; i++)
785 grub_free (linep->pos[i]);
788 start = screen->line;
789 column = screen->column;
791 screen->real_column = screen->column;
795 for (i = 0; i < screen->nterms; i++)
798 new_num = get_logical_num_lines (linep, &screen->terms[i]);
799 if (screen->terms[i].orig_num != new_num)
800 update_screen (screen, &screen->terms[i],
801 start, column, 0, 0, ALL_LINES);
803 update_screen (screen, &screen->terms[i],
804 start, column, 0, 0, SINGLE_LINE);
808 else if (screen->num_lines > screen->line + 1)
810 struct line *next_linep;
813 next_linep = linep + 1;
814 if (! ensure_space (linep, next_linep->len))
817 grub_memmove (linep->buf + linep->len, next_linep->buf,
818 next_linep->len * sizeof (linep->buf[0]));
819 linep->len += next_linep->len;
820 for (i = 0; i < screen->nterms; i++)
822 grub_free (linep->pos[i]);
826 grub_free (next_linep->buf);
827 grub_memmove (next_linep,
829 (screen->num_lines - screen->line - 2)
830 * sizeof (struct line));
833 start = screen->line;
834 column = screen->column;
836 screen->real_column = screen->column;
838 update_screen_all (screen, start, column, 0, 1, ALL_LINES);
845 backward_delete_char (struct screen *screen, int update)
850 saved_column = screen->column;
851 saved_line = screen->line;
853 if (! backward_char (screen, 0))
856 if (saved_column != screen->column || saved_line != screen->line)
857 if (! delete_char (screen, update))
864 kill_line (struct screen *screen, int continuous, int update)
871 p = screen->killed_text;
872 if (! continuous && p)
875 linep = screen->lines + screen->line;
876 size = linep->len - screen->column;
879 offset = grub_strlen (p);
887 p = grub_realloc (p, offset + size + 1);
891 grub_memmove (p + offset, linep->buf + screen->column, size);
892 p[offset + size] = '\0';
894 screen->killed_text = p;
896 for (i = 0; i < screen->nterms; i++)
897 screen->terms[i].orig_num = get_logical_num_lines (linep, &screen->terms[i]);
898 linep->len = screen->column;
902 for (i = 0; i < screen->nterms; i++)
905 new_num = get_logical_num_lines (linep, &screen->terms[i]);
906 if (screen->terms[i].orig_num != new_num)
907 update_screen (screen, &screen->terms[i],
908 screen->line, screen->column, 0, 1, ALL_LINES);
910 update_screen (screen, &screen->terms[i],
911 screen->line, screen->column, 0, 0, SINGLE_LINE);
915 else if (screen->line + 1 < screen->num_lines)
917 p = grub_realloc (p, offset + 1 + 1);
922 p[offset + 1] = '\0';
924 screen->killed_text = p;
926 return delete_char (screen, update);
933 yank (struct screen *screen, int update)
935 if (screen->killed_text)
936 return insert_string (screen, screen->killed_text, update);
942 open_line (struct screen *screen, int update)
944 if (! insert_string (screen, "\n", 0))
947 if (! backward_char (screen, 0))
951 update_screen_all (screen, screen->line, screen->column, 0, 1, ALL_LINES);
956 /* A completion hook to print items. */
958 store_completion (const char *item, grub_completion_type_t type,
959 int count __attribute__ ((unused)))
963 completion_type = type;
965 /* Make sure that the completion buffer has enough room. */
966 if (completion_buffer.max_len < (completion_buffer.len
967 + (int) grub_strlen (item) + 1 + 1))
971 new_len = completion_buffer.len + grub_strlen (item) + 80;
972 p = grub_realloc (completion_buffer.buf, new_len);
975 /* Possibly not fatal. */
976 grub_errno = GRUB_ERR_NONE;
979 p[completion_buffer.len] = 0;
980 completion_buffer.buf = p;
981 completion_buffer.max_len = new_len;
984 p = completion_buffer.buf + completion_buffer.len;
985 if (completion_buffer.len != 0)
988 completion_buffer.len++;
990 grub_strcpy (p, item);
991 completion_buffer.len += grub_strlen (item);
995 complete (struct screen *screen, int continuous, int update)
1000 static int count = -1;
1002 grub_uint32_t *ucs4;
1004 grub_ssize_t ucs4len;
1012 completion_buffer.buf = 0;
1013 completion_buffer.len = 0;
1014 completion_buffer.max_len = 0;
1016 linep = screen->lines + screen->line;
1017 u8 = grub_ucs4_to_utf8_alloc (linep->buf, screen->column);
1021 insert = grub_normal_do_completion (u8, &restore, store_completion);
1023 if (completion_buffer.buf)
1025 buflen = grub_strlen (completion_buffer.buf);
1026 ucs4 = grub_malloc (sizeof (grub_uint32_t) * (buflen + 1));
1030 grub_print_error ();
1031 grub_errno = GRUB_ERR_NONE;
1035 ucs4len = grub_utf8_to_ucs4 (ucs4, buflen,
1036 (grub_uint8_t *) completion_buffer.buf,
1041 for (i = 0; i < screen->nterms; i++)
1043 unsigned width = grub_term_width (screen->terms[i].term);
1048 unsigned num_sections = ((completion_buffer.len
1051 grub_uint32_t *endp;
1052 struct grub_term_coordinate pos;
1053 grub_uint32_t *p = ucs4;
1055 pos = grub_term_getxy (screen->terms[i].term);
1057 screen->completion_shown = 1;
1059 grub_term_gotoxy (screen->terms[i].term,
1060 (struct grub_term_coordinate) { 0,
1061 screen->terms[i].geo.timeout_y });
1062 if (screen->terms[i].geo.timeout_lines >= 2)
1064 grub_puts_terminal (" ", screen->terms[i].term);
1065 switch (completion_type)
1067 case GRUB_COMPLETION_TYPE_COMMAND:
1068 grub_puts_terminal (_("Possible commands are:"),
1069 screen->terms[i].term);
1071 case GRUB_COMPLETION_TYPE_DEVICE:
1072 grub_puts_terminal (_("Possible devices are:"),
1073 screen->terms[i].term);
1075 case GRUB_COMPLETION_TYPE_FILE:
1076 grub_puts_terminal (_("Possible files are:"),
1077 screen->terms[i].term);
1079 case GRUB_COMPLETION_TYPE_PARTITION:
1080 grub_puts_terminal (_("Possible partitions are:"),
1081 screen->terms[i].term);
1083 case GRUB_COMPLETION_TYPE_ARGUMENT:
1084 grub_puts_terminal (_("Possible arguments are:"),
1085 screen->terms[i].term);
1088 grub_puts_terminal (_("Possible things are:"),
1089 screen->terms[i].term);
1093 grub_puts_terminal ("\n ", screen->terms[i].term);
1096 p += ((unsigned) count % num_sections) * width;
1100 grub_putcode (GRUB_UNICODE_LEFTARROW, screen->terms[i].term);
1102 grub_putcode (' ', screen->terms[i].term);
1104 grub_print_ucs4 (p, ucs4 + ucs4len < endp ? ucs4 + ucs4len : endp,
1105 0, 0, screen->terms[i].term);
1107 if (ucs4 + ucs4len > endp)
1108 grub_putcode (GRUB_UNICODE_RIGHTARROW, screen->terms[i].term);
1109 grub_term_gotoxy (screen->terms[i].term, pos);
1115 insert_string (screen, insert, update);
1122 grub_free (completion_buffer.buf);
1126 /* Clear displayed completions. */
1128 clear_completions (struct per_term_screen *term_screen)
1130 struct grub_term_coordinate pos;
1134 pos = grub_term_getxy (term_screen->term);
1135 grub_term_gotoxy (term_screen->term,
1136 (struct grub_term_coordinate) { 0,
1137 term_screen->geo.timeout_y });
1139 for (i = 0; i < term_screen->geo.timeout_lines; i++)
1141 for (j = 0; j < grub_term_width (term_screen->term) - 1; j++)
1142 grub_putcode (' ', term_screen->term);
1143 if (i + 1 < term_screen->geo.timeout_lines)
1144 grub_putcode ('\n', term_screen->term);
1147 grub_term_gotoxy (term_screen->term, pos);
1148 grub_term_refresh (term_screen->term);
1152 clear_completions_all (struct screen *screen)
1156 for (i = 0; i < screen->nterms; i++)
1157 clear_completions (&screen->terms[i]);
1160 /* Execute the command list in the screen SCREEN. */
1162 run (struct screen *screen)
1166 grub_menu_t menu = NULL;
1167 char *dummy[1] = { NULL };
1171 grub_printf_ (N_("Booting a command list"));
1172 grub_printf ("\n\n");
1174 errs_before = grub_err_printed_errors;
1176 if (screen->submenu)
1178 grub_env_context_open ();
1179 menu = grub_zalloc (sizeof (*menu));
1182 grub_env_set_menu (menu);
1185 /* Execute the script, line for line. */
1188 grub_size_t size = 0, tot_size = 0;
1190 for (i = 0; i < screen->num_lines; i++)
1191 tot_size += grub_get_num_of_utf8_bytes (screen->lines[i].buf,
1192 screen->lines[i].len) + 1;
1194 script = grub_malloc (tot_size + 1);
1198 for (i = 0; i < screen->num_lines; i++)
1200 size += grub_ucs4_to_utf8 (screen->lines[i].buf, screen->lines[i].len,
1201 (grub_uint8_t *) script + size,
1203 script[size++] = '\n';
1205 script[size] = '\0';
1207 grub_script_execute_new_scope (script, 0, dummy);
1210 if (errs_before != grub_err_printed_errors)
1211 grub_wait_after_message ();
1213 if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ())
1214 /* Implicit execution of boot, only if something is loaded. */
1215 grub_command_execute ("boot", 0, 0);
1217 if (screen->submenu)
1219 if (menu && menu->size)
1221 grub_show_menu (menu, 1, 0);
1222 grub_normal_free_menu (menu);
1224 grub_env_context_close ();
1227 if (grub_errno != GRUB_ERR_NONE)
1229 grub_print_error ();
1230 grub_errno = GRUB_ERR_NONE;
1231 grub_wait_after_message ();
1237 /* Edit a menu entry with an Emacs-like interface. */
1239 grub_menu_entry_run (grub_menu_entry_t entry)
1241 struct screen *screen;
1243 grub_err_t err = GRUB_ERR_NONE;
1245 grub_term_output_t term;
1247 err = grub_auth_check_authentication (NULL);
1251 grub_print_error ();
1252 grub_errno = GRUB_ERR_NONE;
1256 screen = make_screen (entry);
1260 screen->terms = NULL;
1263 grub_free (screen->terms);
1265 FOR_ACTIVE_TERM_OUTPUTS(term)
1268 for (i = 0; i < (unsigned) screen->num_lines; i++)
1270 grub_free (screen->lines[i].pos);
1271 screen->lines[i].pos = grub_zalloc (screen->nterms * sizeof (screen->lines[i].pos[0]));
1272 if (! screen->lines[i].pos)
1274 grub_print_error ();
1275 destroy_screen (screen);
1276 grub_errno = GRUB_ERR_NONE;
1281 screen->terms = grub_zalloc (screen->nterms * sizeof (screen->terms[0]));
1284 grub_print_error ();
1285 destroy_screen (screen);
1286 grub_errno = GRUB_ERR_NONE;
1290 FOR_ACTIVE_TERM_OUTPUTS(term)
1292 screen->terms[i].term = term;
1293 screen->terms[i].y_line_start = 0;
1296 /* Draw the screen. */
1297 for (i = 0; i < screen->nterms; i++)
1298 grub_menu_init_page (0, 1, &screen->terms[i].geo,
1299 screen->terms[i].term);
1300 update_screen_all (screen, 0, 0, 1, 1, ALL_LINES);
1301 for (i = 0; i < screen->nterms; i++)
1302 grub_term_setcursor (screen->terms[i].term, 1);
1307 int c = grub_getkey ();
1309 if (screen->completion_shown)
1311 clear_completions_all (screen);
1312 screen->completion_shown = 0;
1315 if (grub_normal_exit_level)
1317 destroy_screen (screen);
1323 case GRUB_TERM_KEY_UP:
1324 case GRUB_TERM_CTRL | 'p':
1325 if (! previous_line (screen, 1))
1329 case GRUB_TERM_CTRL | 'n':
1330 case GRUB_TERM_KEY_DOWN:
1331 if (! next_line (screen, 1))
1335 case GRUB_TERM_CTRL | 'f':
1336 case GRUB_TERM_KEY_RIGHT:
1337 if (! forward_char (screen, 1))
1341 case GRUB_TERM_CTRL | 'b':
1342 case GRUB_TERM_KEY_LEFT:
1343 if (! backward_char (screen, 1))
1347 case GRUB_TERM_CTRL | 'a':
1348 case GRUB_TERM_KEY_HOME:
1349 if (! beginning_of_line (screen, 1))
1353 case GRUB_TERM_CTRL | 'e':
1354 case GRUB_TERM_KEY_END:
1355 if (! end_of_line (screen, 1))
1359 case GRUB_TERM_CTRL | 'i':
1361 if (! complete (screen, prev_c == c, 1))
1365 case GRUB_TERM_CTRL | 'd':
1366 case GRUB_TERM_KEY_DC:
1367 if (! delete_char (screen, 1))
1371 case GRUB_TERM_CTRL | 'h':
1373 if (! backward_delete_char (screen, 1))
1377 case GRUB_TERM_CTRL | 'k':
1378 if (! kill_line (screen, prev_c == c, 1))
1382 case GRUB_TERM_CTRL | 'u':
1383 /* FIXME: What behavior is good for this key? */
1386 case GRUB_TERM_CTRL | 'y':
1387 if (! yank (screen, 1))
1391 case GRUB_TERM_CTRL | 'l':
1392 /* FIXME: centering. */
1395 case GRUB_TERM_CTRL | 'o':
1396 if (! open_line (screen, 1))
1402 if (! insert_string (screen, "\n", 1))
1407 destroy_screen (screen);
1410 case GRUB_TERM_CTRL | 'c':
1411 case GRUB_TERM_KEY_F2:
1412 grub_cmdline_run (1, 0);
1415 case GRUB_TERM_CTRL | 'x':
1416 case GRUB_TERM_KEY_F10:
1420 case GRUB_TERM_CTRL | 'r':
1421 case GRUB_TERM_CTRL | 's':
1422 case GRUB_TERM_CTRL | 't':
1427 if (grub_isprint (c))
1433 if (! insert_string (screen, buf, 1))
1443 destroy_screen (screen);
1446 grub_print_error ();
1447 grub_errno = GRUB_ERR_NONE;
1449 grub_printf_ (N_("Press any key to continue..."));
1450 (void) grub_getkey ();