2009-11-21 Samuel Thibault <samuel.thibault@ens-lyon.org>
[grub2/phcoder/solaris.git] / normal / menu_entry.c
blob75a63779fea1234d436ea61ef40b09bac1976c39
1 /*
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>
22 #include <grub/mm.h>
23 #include <grub/loader.h>
24 #include <grub/command.h>
25 #include <grub/parser.h>
26 #include <grub/auth.h>
28 enum update_mode
30 NO_LINE,
31 SINGLE_LINE,
32 ALL_LINES
35 struct line
37 /* The line buffer. */
38 char *buf;
39 /* The length of the line. */
40 int len;
41 /* The maximum length of the line. */
42 int max_len;
45 struct screen
47 /* The array of lines. */
48 struct line *lines;
49 /* The number of lines. */
50 int num_lines;
51 /* The current column. */
52 int column;
53 /* The real column. */
54 int real_column;
55 /* The current line. */
56 int line;
57 /* The X coordinate. */
58 int x;
59 /* The Y coordinate. */
60 int y;
61 /* The kill buffer. */
62 char *killed_text;
63 /* The flag of a completion window. */
64 int completion_shown;
67 /* Used for storing completion items temporarily. */
68 static struct line completion_buffer;
70 /* Initialize a line. */
71 static int
72 init_line (struct line *linep)
74 linep->len = 0;
75 linep->max_len = 80; /* XXX */
76 linep->buf = grub_malloc (linep->max_len);
77 if (! linep->buf)
78 return 0;
80 return 1;
83 /* Allocate extra space if necessary. */
84 static int
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);
91 if (! linep->buf)
92 return 0;
95 return 1;
98 /* Return the number of lines occupied by this line on the screen. */
99 static int
100 get_logical_num_lines (struct line *linep)
102 return (linep->len / GRUB_TERM_ENTRY_WIDTH) + 1;
105 /* Print a line. */
106 static void
107 print_line (struct line *linep, int offset, int start, int y)
109 int i;
110 char *p;
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;
117 p++, i++)
118 grub_putchar (*p);
120 for (; i < GRUB_TERM_ENTRY_WIDTH; i++)
121 grub_putchar (' ');
123 if (linep->len >= offset + GRUB_TERM_ENTRY_WIDTH)
124 grub_putchar ('\\');
125 else
126 grub_putchar (' ');
129 /* Print an empty line. */
130 static void
131 print_empty_line (int y)
133 int i;
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++)
139 grub_putchar (' ');
142 /* Print an up arrow. */
143 static void
144 print_up (int flag)
146 grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH,
147 GRUB_TERM_FIRST_ENTRY_Y);
149 if (flag)
150 grub_putcode (GRUB_TERM_DISP_UP);
151 else
152 grub_putchar (' ');
155 /* Print a down arrow. */
156 static void
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);
162 if (flag)
163 grub_putcode (GRUB_TERM_DISP_DOWN);
164 else
165 grub_putchar (' ');
168 /* Draw the lines of the screen SCREEN. */
169 static void
170 update_screen (struct screen *screen, int region_start, int region_column,
171 int up, int down, enum update_mode mode)
173 int up_flag = 0;
174 int down_flag = 0;
175 int y;
176 int i;
177 struct line *linep;
179 /* Check if scrolling is necessary. */
180 if (screen->y < 0 || screen->y >= GRUB_TERM_NUM_ENTRIES)
182 if (screen->y < 0)
183 screen->y = 0;
184 else
185 screen->y = GRUB_TERM_NUM_ENTRIES - 1;
187 region_start = 0;
188 region_column = 0;
189 up = 1;
190 down = 1;
191 mode = ALL_LINES;
194 if (mode != NO_LINE)
196 /* Draw lines. This code is tricky, because this must calculate logical
197 positions. */
198 y = screen->y - screen->column / GRUB_TERM_ENTRY_WIDTH;
199 i = screen->line;
200 linep = screen->lines + i;
201 while (y > 0)
203 i--;
204 linep--;
205 y -= get_logical_num_lines (linep);
208 if (y < 0 || i > 0)
209 up_flag = 1;
213 int column;
215 for (column = 0;
216 column <= linep->len && y < GRUB_TERM_NUM_ENTRIES;
217 column += GRUB_TERM_ENTRY_WIDTH, y++)
219 if (y < 0)
220 continue;
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)
237 down_flag = 1;
240 linep++;
241 i++;
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. */
251 if (up)
252 print_up (up_flag);
253 if (down)
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);
261 grub_refresh ();
264 /* Insert the string S into the screen SCREEN. This updates the cursor
265 position and redraw the screen. Return zero if fails. */
266 static int
267 insert_string (struct screen *screen, char *s, int update)
269 int region_start = screen->num_lines;
270 int region_column = 0;
271 int down = 0;
272 enum update_mode mode = NO_LINE;
274 while (*s)
276 if (*s == '\n')
278 /* LF is special because it creates a new line. */
279 struct line *current_linep;
280 struct line *next_linep;
281 int size;
283 /* Make a new line. */
284 screen->num_lines++;
285 screen->lines = grub_realloc (screen->lines,
286 screen->num_lines
287 * sizeof (struct line));
288 if (! screen->lines)
289 return 0;
291 /* Scroll down. */
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))
298 return 0;
300 /* Fold the line. */
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))
306 return 0;
308 grub_memmove (next_linep->buf,
309 current_linep->buf + screen->column,
310 size);
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;
321 mode = ALL_LINES;
322 down = 1; /* XXX not optimal. */
324 /* Move the cursor. */
325 screen->column = screen->real_column = 0;
326 screen->line++;
327 screen->x = 0;
328 screen->y++;
330 s++;
332 else
334 /* All but LF. */
335 char *p;
336 struct line *current_linep;
337 int size;
338 int orig_num, new_num;
340 /* Find a string delimited by LF. */
341 p = grub_strchr (s, '\n');
342 if (! p)
343 p = s + grub_strlen (s);
345 /* Insert the string. */
346 current_linep = screen->lines + screen->line;
347 size = p - s;
348 if (! ensure_space (current_linep, size))
349 return 0;
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,
356 size);
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)
370 mode = ALL_LINES;
371 down = 1; /* XXX not optimal. */
373 else if (mode != ALL_LINES)
374 mode = SINGLE_LINE;
376 /* Move the cursor. */
377 screen->column += size;
378 screen->real_column = screen->column;
379 screen->x += size;
380 screen->y += screen->x / GRUB_TERM_ENTRY_WIDTH;
381 screen->x %= GRUB_TERM_ENTRY_WIDTH;
383 s = p;
387 if (update)
388 update_screen (screen, region_start, region_column, 0, down, mode);
390 return 1;
393 /* Release the resource allocated for SCREEN. */
394 static void
395 destroy_screen (struct screen *screen)
397 int i;
399 if (screen->lines)
400 for (i = 0; i < screen->num_lines; i++)
402 struct line *linep = screen->lines + i;
404 if (linep)
405 grub_free (linep->buf);
408 grub_free (screen->killed_text);
409 grub_free (screen->lines);
410 grub_free (screen);
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));
421 if (! screen)
422 return 0;
424 screen->num_lines = 1;
425 screen->lines = grub_malloc (sizeof (struct line));
426 if (! screen->lines)
427 goto fail;
429 /* Initialize the first line which must be always present. */
430 if (! init_line (screen->lines))
431 goto fail;
433 insert_string (screen, (char *) entry->sourcecode, 0);
435 /* Reset the cursor position. */
436 screen->column = 0;
437 screen->real_column = 0;
438 screen->line = 0;
439 screen->x = 0;
440 screen->y = 0;
442 return screen;
444 fail:
445 destroy_screen (screen);
446 return 0;
449 static int
450 forward_char (struct screen *screen, int update)
452 struct line *linep;
454 linep = screen->lines + screen->line;
455 if (screen->column < linep->len)
457 screen->column++;
458 screen->x++;
459 if (screen->x == GRUB_TERM_ENTRY_WIDTH)
461 screen->x = 0;
462 screen->y++;
465 else if (screen->num_lines > screen->line + 1)
467 screen->column = 0;
468 screen->line++;
469 screen->x = 0;
470 screen->y++;
473 screen->real_column = screen->column;
475 if (update)
476 update_screen (screen, screen->num_lines, 0, 0, 0, NO_LINE);
477 return 1;
480 static int
481 backward_char (struct screen *screen, int update)
483 if (screen->column > 0)
485 screen->column--;
486 screen->x--;
487 if (screen->x == -1)
489 screen->x = GRUB_TERM_ENTRY_WIDTH - 1;
490 screen->y--;
493 else if (screen->line > 0)
495 struct line *linep;
497 screen->line--;
498 linep = screen->lines + screen->line;
499 screen->column = linep->len;
500 screen->x = screen->column % GRUB_TERM_ENTRY_WIDTH;
501 screen->y--;
504 screen->real_column = screen->column;
506 if (update)
507 update_screen (screen, screen->num_lines, 0, 0, 0, NO_LINE);
509 return 1;
512 static int
513 previous_line (struct screen *screen, int update)
515 if (screen->line > 0)
517 struct line *linep;
518 int dy;
520 /* How many physical lines from the current position
521 to the first physical line? */
522 dy = screen->column / GRUB_TERM_ENTRY_WIDTH;
524 screen->line--;
526 linep = screen->lines + screen->line;
527 if (linep->len < screen->real_column)
528 screen->column = linep->len;
529 else
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);
537 screen->y -= dy + 1;
538 screen->x = screen->column % GRUB_TERM_ENTRY_WIDTH;
540 else
542 screen->y -= screen->column / GRUB_TERM_ENTRY_WIDTH;
543 screen->column = 0;
544 screen->x = 0;
547 if (update)
548 update_screen (screen, screen->num_lines, 0, 0, 0, NO_LINE);
550 return 1;
553 static int
554 next_line (struct screen *screen, int update)
556 if (screen->line < screen->num_lines - 1)
558 struct line *linep;
559 int dy;
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);
567 screen->line++;
569 linep++;
570 if (linep->len < screen->real_column)
571 screen->column = linep->len;
572 else
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;
579 screen->y += dy + 1;
580 screen->x = screen->column % GRUB_TERM_ENTRY_WIDTH;
582 else
584 struct line *linep;
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;
593 if (update)
594 update_screen (screen, screen->num_lines, 0, 0, 0, NO_LINE);
596 return 1;
599 static int
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;
604 screen->x = 0;
606 if (update)
607 update_screen (screen, screen->num_lines, 0, 0, 0, NO_LINE);
609 return 1;
612 static int
613 end_of_line (struct screen *screen, int update)
615 struct line *linep;
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;
623 if (update)
624 update_screen (screen, screen->num_lines, 0, 0, 0, NO_LINE);
626 return 1;
629 static int
630 delete_char (struct screen *screen, int update)
632 struct line *linep;
633 enum update_mode mode = NO_LINE;
634 int start = screen->num_lines;
635 int column = 0;
636 int down = 0;
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);
648 linep->len--;
650 new_num = get_logical_num_lines (linep);
652 if (orig_num != new_num)
653 mode = ALL_LINES;
654 else
655 mode = SINGLE_LINE;
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))
666 return 0;
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,
673 next_linep + 1,
674 (screen->num_lines - screen->line - 2)
675 * sizeof (struct line));
676 screen->num_lines--;
678 mode = ALL_LINES;
679 start = screen->line;
680 column = screen->column;
681 down = 1;
684 screen->real_column = screen->column;
686 if (update)
687 update_screen (screen, start, column, 0, down, mode);
689 return 1;
692 static int
693 backward_delete_char (struct screen *screen, int update)
695 int saved_column;
696 int saved_line;
698 saved_column = screen->column;
699 saved_line = screen->line;
701 if (! backward_char (screen, 0))
702 return 0;
704 if (saved_column != screen->column || saved_line != screen->line)
705 if (! delete_char (screen, update))
706 return 0;
708 return 1;
711 static int
712 kill_line (struct screen *screen, int continuous, int update)
714 struct line *linep;
715 char *p;
716 int size;
717 int offset;
719 p = screen->killed_text;
720 if (! continuous && p)
721 p[0] = '\0';
723 linep = screen->lines + screen->line;
724 size = linep->len - screen->column;
726 if (p)
727 offset = grub_strlen (p);
728 else
729 offset = 0;
731 if (size > 0)
733 enum update_mode mode = SINGLE_LINE;
734 int down = 0;
735 int orig_num, new_num;
737 p = grub_realloc (p, offset + size + 1);
738 if (! p)
739 return 0;
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)
752 mode = ALL_LINES;
753 down = 1;
756 if (update)
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);
762 if (! p)
763 return 0;
765 p[offset] = '\n';
766 p[offset + 1] = '\0';
768 screen->killed_text = p;
770 return delete_char (screen, update);
773 return 1;
776 static int
777 yank (struct screen *screen, int update)
779 if (screen->killed_text)
780 return insert_string (screen, screen->killed_text, update);
782 return 1;
785 static int
786 open_line (struct screen *screen, int update)
788 int saved_y = screen->y;
790 if (! insert_string (screen, "\n", 0))
791 return 0;
793 if (! backward_char (screen, 0))
794 return 0;
796 screen->y = saved_y;
798 if (update)
799 update_screen (screen, screen->line, screen->column, 0, 1, ALL_LINES);
801 return 1;
804 /* A completion hook to print items. */
805 static void
806 store_completion (const char *item, grub_completion_type_t type, int count)
808 char *p;
810 if (count == 0)
812 /* If this is the first time, print a label. */
813 const char *what;
815 switch (type)
817 case GRUB_COMPLETION_TYPE_COMMAND:
818 what = "commands";
819 break;
820 case GRUB_COMPLETION_TYPE_DEVICE:
821 what = "devices";
822 break;
823 case GRUB_COMPLETION_TYPE_FILE:
824 what = "files";
825 break;
826 case GRUB_COMPLETION_TYPE_PARTITION:
827 what = "partitions";
828 break;
829 case GRUB_COMPLETION_TYPE_ARGUMENT:
830 what = "arguments";
831 break;
832 default:
833 what = "things";
834 break;
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))
845 grub_size_t new_len;
847 new_len = completion_buffer.len + grub_strlen (item) + 80;
848 p = grub_realloc (completion_buffer.buf, new_len);
849 if (! p)
851 /* Possibly not fatal. */
852 grub_errno = GRUB_ERR_NONE;
853 return;
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)
863 *p++ = ' ';
864 completion_buffer.len++;
866 grub_strcpy (p, item);
867 completion_buffer.len += grub_strlen (item);
870 static int
871 complete (struct screen *screen, int continuous, int update)
873 grub_uint16_t pos;
874 char saved_char;
875 struct line *linep;
876 int restore;
877 char *insert;
878 static int count = -1;
880 if (continuous)
881 count++;
882 else
883 count = 0;
885 pos = grub_getxy ();
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;
900 if (restore)
902 char *p = completion_buffer.buf;
904 screen->completion_shown = 1;
906 if (p)
908 int num_sections = ((completion_buffer.len + GRUB_TERM_WIDTH - 8 - 1)
909 / (GRUB_TERM_WIDTH - 8));
910 char *endp;
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);
917 else
918 grub_putchar (' ');
920 while (*p && p < endp)
921 grub_putchar (*p++);
923 if (*p)
924 grub_putcode (GRUB_TERM_DISP_RIGHT);
928 grub_gotoxy (pos >> 8, pos & 0xFF);
930 if (insert)
932 insert_string (screen, insert, update);
933 count = -1;
934 grub_free (insert);
936 else if (update)
937 grub_refresh ();
939 grub_free (completion_buffer.buf);
940 return 1;
943 /* Clear displayed completions. */
944 static void
945 clear_completions (void)
947 grub_uint16_t pos;
948 int i, j;
950 pos = grub_getxy ();
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++)
956 grub_putchar (' ');
957 grub_putchar ('\n');
960 grub_gotoxy (pos >> 8, pos & 0xFF);
961 grub_refresh ();
964 /* Execute the command list in the screen SCREEN. */
965 static int
966 run (struct screen *screen)
968 int currline = 0;
969 char *nextline;
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;
975 char *p;
977 if (currline > screen->num_lines)
979 *line = 0;
980 return 0;
983 /* Trim down space characters. */
984 for (p = linep->buf + linep->len - 1;
985 p >= linep->buf && grub_isspace (*p);
986 p--)
988 *++p = '\0';
990 linep->len = p - linep->buf;
991 for (p = linep->buf; grub_isspace (*p); p++)
993 *line = grub_strdup (p);
994 currline++;
995 return 0;
998 grub_cls ();
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))
1007 break;
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 ();
1021 return 1;
1024 /* Edit a menu entry with an Emacs-like interface. */
1025 void
1026 grub_menu_entry_run (grub_menu_entry_t entry)
1028 struct screen *screen;
1029 int prev_c;
1030 grub_err_t err = GRUB_ERR_NONE;
1032 err = grub_auth_check_authentication (NULL);
1034 if (err)
1036 grub_print_error ();
1037 grub_errno = GRUB_ERR_NONE;
1038 return;
1041 screen = make_screen (entry);
1042 if (! screen)
1043 return;
1045 refresh:
1046 /* Draw the screen. */
1047 grub_menu_init_page (0, 1);
1048 update_screen (screen, 0, 0, 1, 1, ALL_LINES);
1049 grub_setcursor (1);
1050 prev_c = '\0';
1052 while (1)
1054 int c = GRUB_TERM_ASCII_CHAR (grub_getkey ());
1056 if (screen->completion_shown)
1058 clear_completions ();
1059 screen->completion_shown = 0;
1062 switch (c)
1064 case 16: /* C-p */
1065 if (! previous_line (screen, 1))
1066 goto fail;
1067 break;
1069 case 14: /* C-n */
1070 if (! next_line (screen, 1))
1071 goto fail;
1072 break;
1074 case 6: /* C-f */
1075 if (! forward_char (screen, 1))
1076 goto fail;
1077 break;
1079 case 2: /* C-b */
1080 if (! backward_char (screen, 1))
1081 goto fail;
1082 break;
1084 case 1: /* C-a */
1085 if (! beginning_of_line (screen, 1))
1086 goto fail;
1087 break;
1089 case 5: /* C-e */
1090 if (! end_of_line (screen, 1))
1091 goto fail;
1092 break;
1094 case '\t': /* C-i */
1095 if (! complete (screen, prev_c == c, 1))
1096 goto fail;
1097 break;
1099 case 4: /* C-d */
1100 if (! delete_char (screen, 1))
1101 goto fail;
1102 break;
1104 case 8: /* C-h */
1105 if (! backward_delete_char (screen, 1))
1106 goto fail;
1107 break;
1109 case 11: /* C-k */
1110 if (! kill_line (screen, prev_c == c, 1))
1111 goto fail;
1112 break;
1114 case 21: /* C-u */
1115 /* FIXME: What behavior is good for this key? */
1116 break;
1118 case 25: /* C-y */
1119 if (! yank (screen, 1))
1120 goto fail;
1121 break;
1123 case 12: /* C-l */
1124 /* FIXME: centering. */
1125 goto refresh;
1127 case 15: /* C-o */
1128 if (! open_line (screen, 1))
1129 goto fail;
1130 break;
1132 case '\n':
1133 case '\r':
1134 if (! insert_string (screen, "\n", 1))
1135 goto fail;
1136 break;
1138 case '\e':
1139 destroy_screen (screen);
1140 return;
1142 case 3: /* C-c */
1143 grub_cmdline_run (1);
1144 goto refresh;
1146 case 24: /* C-x */
1147 if (! run (screen))
1148 goto fail;
1149 goto refresh;
1151 case 18: /* C-r */
1152 case 19: /* C-s */
1153 case 20: /* C-t */
1154 /* FIXME */
1155 break;
1157 default:
1158 if (grub_isprint (c))
1160 char buf[2];
1162 buf[0] = c;
1163 buf[1] = '\0';
1164 if (! insert_string (screen, buf, 1))
1165 goto fail;
1167 break;
1170 prev_c = c;
1173 fail:
1174 destroy_screen (screen);
1176 grub_cls ();
1177 grub_print_error ();
1178 grub_errno = GRUB_ERR_NONE;
1179 grub_printf ("\nPress any key to continue...");
1180 (void) grub_getkey ();