GRUB-1.98 changes
[grub2/jjazz.git] / normal / menu_entry.c
blob644fe90fddb3c555319775734deed043d5401a35
1 /*
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>
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>
27 #include <grub/i18n.h>
29 enum update_mode
31 NO_LINE,
32 SINGLE_LINE,
33 ALL_LINES
36 struct line
38 /* The line buffer. */
39 char *buf;
40 /* The length of the line. */
41 int len;
42 /* The maximum length of the line. */
43 int max_len;
46 struct per_term_screen
48 struct grub_term_output *term;
49 /* The X coordinate. */
50 int x;
51 /* The Y coordinate. */
52 int y;
55 struct screen
57 /* The array of lines. */
58 struct line *lines;
59 /* The number of lines. */
60 int num_lines;
61 /* The current column. */
62 int column;
63 /* The real column. */
64 int real_column;
65 /* The current line. */
66 int line;
67 /* The kill buffer. */
68 char *killed_text;
69 /* The flag of a completion window. */
70 int completion_shown;
72 struct per_term_screen *terms;
73 unsigned nterms;
76 /* Used for storing completion items temporarily. */
77 static struct line completion_buffer;
78 static int completion_type;
80 /* Initialize a line. */
81 static int
82 init_line (struct line *linep)
84 linep->len = 0;
85 linep->max_len = 80; /* XXX */
86 linep->buf = grub_malloc (linep->max_len);
87 if (! linep->buf)
88 return 0;
90 return 1;
93 /* Allocate extra space if necessary. */
94 static int
95 ensure_space (struct line *linep, int extra)
97 if (linep->max_len < linep->len + extra)
99 linep->max_len = linep->len + extra + 80; /* XXX */
100 linep->buf = grub_realloc (linep->buf, linep->max_len + 1);
101 if (! linep->buf)
102 return 0;
105 return 1;
108 /* Return the number of lines occupied by this line on the screen. */
109 static int
110 get_logical_num_lines (struct line *linep, struct per_term_screen *term_screen)
112 return (linep->len / grub_term_entry_width (term_screen->term)) + 1;
115 /* Print a line. */
116 static void
117 print_line (struct line *linep, int offset, int start, int y,
118 struct per_term_screen *term_screen)
120 grub_term_gotoxy (term_screen->term,
121 GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + start + 1,
122 y + GRUB_TERM_FIRST_ENTRY_Y);
124 if (linep->len >= offset + grub_term_entry_width (term_screen->term))
126 char *p, c;
127 p = linep->buf + offset + grub_term_entry_width (term_screen->term);
128 c = *p;
129 *p = 0;
130 grub_puts_terminal (linep->buf + offset + start, term_screen->term);
131 *p = c;
132 grub_putcode ('\\', term_screen->term);
134 else
136 int i;
137 char *p, c;
139 p = linep->buf + linep->len;
140 c = *p;
141 *p = 0;
142 grub_puts_terminal (linep->buf + offset + start, term_screen->term);
143 *p = c;
145 for (i = 0;
146 i <= grub_term_entry_width (term_screen->term) - linep->len + offset;
147 i++)
148 grub_putcode (' ', term_screen->term);
152 /* Print an empty line. */
153 static void
154 print_empty_line (int y, struct per_term_screen *term_screen)
156 int i;
158 grub_term_gotoxy (term_screen->term,
159 GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1,
160 y + GRUB_TERM_FIRST_ENTRY_Y);
162 for (i = 0; i < grub_term_entry_width (term_screen->term) + 1; i++)
163 grub_putcode (' ', term_screen->term);
166 /* Print an up arrow. */
167 static void
168 print_up (int flag, struct per_term_screen *term_screen)
170 grub_term_gotoxy (term_screen->term, GRUB_TERM_LEFT_BORDER_X
171 + grub_term_entry_width (term_screen->term),
172 GRUB_TERM_FIRST_ENTRY_Y);
174 if (flag)
175 grub_putcode (GRUB_TERM_DISP_UP, term_screen->term);
176 else
177 grub_putcode (' ', term_screen->term);
180 /* Print a down arrow. */
181 static void
182 print_down (int flag, struct per_term_screen *term_screen)
184 grub_term_gotoxy (term_screen->term, GRUB_TERM_LEFT_BORDER_X
185 + grub_term_border_width (term_screen->term),
186 GRUB_TERM_TOP_BORDER_Y
187 + grub_term_num_entries (term_screen->term));
189 if (flag)
190 grub_putcode (GRUB_TERM_DISP_DOWN, term_screen->term);
191 else
192 grub_putcode (' ', term_screen->term);
195 /* Draw the lines of the screen SCREEN. */
196 static void
197 update_screen (struct screen *screen, struct per_term_screen *term_screen,
198 int region_start, int region_column,
199 int up, int down, enum update_mode mode)
201 int up_flag = 0;
202 int down_flag = 0;
203 int y;
204 int i;
205 struct line *linep;
207 /* Check if scrolling is necessary. */
208 if (term_screen->y < 0 || term_screen->y
209 >= grub_term_num_entries (term_screen->term))
211 if (term_screen->y < 0)
212 term_screen->y = 0;
213 else
214 term_screen->y = grub_term_num_entries (term_screen->term) - 1;
216 region_start = 0;
217 region_column = 0;
218 up = 1;
219 down = 1;
220 mode = ALL_LINES;
223 if (mode != NO_LINE)
225 /* Draw lines. This code is tricky, because this must calculate logical
226 positions. */
227 y = term_screen->y - screen->column
228 / grub_term_entry_width (term_screen->term);
229 i = screen->line;
230 linep = screen->lines + i;
231 while (y > 0)
233 i--;
234 linep--;
235 y -= get_logical_num_lines (linep, term_screen);
238 if (y < 0 || i > 0)
239 up_flag = 1;
243 int column;
245 for (column = 0;
246 column <= linep->len
247 && y < grub_term_num_entries (term_screen->term);
248 column += grub_term_entry_width (term_screen->term), y++)
250 if (y < 0)
251 continue;
253 if (i == region_start)
255 if (region_column >= column
256 && region_column
257 < (column
258 + grub_term_entry_width (term_screen->term)))
259 print_line (linep, column, region_column - column, y,
260 term_screen);
261 else if (region_column < column)
262 print_line (linep, column, 0, y, term_screen);
264 else if (i > region_start && mode == ALL_LINES)
265 print_line (linep, column, 0, y, term_screen);
268 if (y == grub_term_num_entries (term_screen->term))
270 if (column <= linep->len || i + 1 < screen->num_lines)
271 down_flag = 1;
274 linep++;
275 i++;
277 if (mode == ALL_LINES && i == screen->num_lines)
278 for (; y < grub_term_num_entries (term_screen->term); y++)
279 print_empty_line (y, term_screen);
282 while (y < grub_term_num_entries (term_screen->term));
284 /* Draw up and down arrows. */
285 if (up)
286 print_up (up_flag, term_screen);
287 if (down)
288 print_down (down_flag, term_screen);
291 /* Place the cursor. */
292 grub_term_gotoxy (term_screen->term,
293 GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1
294 + term_screen->x,
295 GRUB_TERM_FIRST_ENTRY_Y + term_screen->y);
297 grub_term_refresh (term_screen->term);
300 static void
301 update_screen_all (struct screen *screen,
302 int region_start, int region_column,
303 int up, int down, enum update_mode mode)
305 unsigned i;
306 for (i = 0; i < screen->nterms; i++)
307 update_screen (screen, &screen->terms[i], region_start, region_column,
308 up, down, mode);
311 static int
312 insert_string (struct screen *screen, char *s, int update)
314 int region_start = screen->num_lines;
315 int region_column = 0;
316 int down[screen->nterms];
317 enum update_mode mode[screen->nterms];
318 unsigned i;
320 for (i = 0; i < screen->nterms; i++)
322 down[i] = 0;
323 mode[i] = NO_LINE;
326 while (*s)
328 if (*s == '\n')
330 /* LF is special because it creates a new line. */
331 struct line *current_linep;
332 struct line *next_linep;
333 int size;
335 /* Make a new line. */
336 screen->num_lines++;
337 screen->lines = grub_realloc (screen->lines,
338 screen->num_lines
339 * sizeof (struct line));
340 if (! screen->lines)
341 return 0;
343 /* Scroll down. */
344 grub_memmove (screen->lines + screen->line + 2,
345 screen->lines + screen->line + 1,
346 ((screen->num_lines - screen->line - 2)
347 * sizeof (struct line)));
349 if (! init_line (screen->lines + screen->line + 1))
350 return 0;
352 /* Fold the line. */
353 current_linep = screen->lines + screen->line;
354 next_linep = current_linep + 1;
355 size = current_linep->len - screen->column;
357 if (! ensure_space (next_linep, size))
358 return 0;
360 grub_memmove (next_linep->buf,
361 current_linep->buf + screen->column,
362 size);
363 current_linep->len = screen->column;
364 next_linep->len = size;
366 /* Update a dirty region. */
367 if (region_start > screen->line)
369 region_start = screen->line;
370 region_column = screen->column;
373 for (i = 0; i < screen->nterms; i++)
375 mode[i] = ALL_LINES;
376 down[i] = 1; /* XXX not optimal. */
379 /* Move the cursor. */
380 screen->column = screen->real_column = 0;
381 screen->line++;
382 for (i = 0; i < screen->nterms; i++)
384 screen->terms[i].x = 0;
385 screen->terms[i].y++;
387 s++;
389 else
391 /* All but LF. */
392 char *p;
393 struct line *current_linep;
394 int size;
395 int orig_num[screen->nterms], new_num[screen->nterms];
397 /* Find a string delimited by LF. */
398 p = grub_strchr (s, '\n');
399 if (! p)
400 p = s + grub_strlen (s);
402 /* Insert the string. */
403 current_linep = screen->lines + screen->line;
404 size = p - s;
405 if (! ensure_space (current_linep, size))
406 return 0;
408 grub_memmove (current_linep->buf + screen->column + size,
409 current_linep->buf + screen->column,
410 current_linep->len - screen->column);
411 grub_memmove (current_linep->buf + screen->column,
413 size);
414 for (i = 0; i < screen->nterms; i++)
415 orig_num[i] = get_logical_num_lines (current_linep,
416 &screen->terms[i]);
417 current_linep->len += size;
418 for (i = 0; i < screen->nterms; i++)
419 new_num[i] = get_logical_num_lines (current_linep,
420 &screen->terms[i]);
422 /* Update the dirty region. */
423 if (region_start > screen->line)
425 region_start = screen->line;
426 region_column = screen->column;
429 for (i = 0; i < screen->nterms; i++)
430 if (orig_num[i] != new_num[i])
432 mode[i] = ALL_LINES;
433 down[i] = 1; /* XXX not optimal. */
435 else if (mode[i] != ALL_LINES)
436 mode[i] = SINGLE_LINE;
438 /* Move the cursor. */
439 screen->column += size;
440 screen->real_column = screen->column;
441 for (i = 0; i < screen->nterms; i++)
443 screen->terms[i].x += size;
444 screen->terms[i].y += screen->terms[i].x
445 / grub_term_entry_width (screen->terms[i].term);
446 screen->terms[i].x
447 %= grub_term_entry_width (screen->terms[i].term);
449 s = p;
453 if (update)
454 for (i = 0; i < screen->nterms; i++)
455 update_screen (screen, &screen->terms[i],
456 region_start, region_column, 0, down[i], mode[i]);
458 return 1;
461 /* Release the resource allocated for SCREEN. */
462 static void
463 destroy_screen (struct screen *screen)
465 int i;
467 if (screen->lines)
468 for (i = 0; i < screen->num_lines; i++)
470 struct line *linep = screen->lines + i;
472 if (linep)
473 grub_free (linep->buf);
476 grub_free (screen->killed_text);
477 grub_free (screen->lines);
478 grub_free (screen->terms);
479 grub_free (screen);
482 /* Make a new screen. */
483 static struct screen *
484 make_screen (grub_menu_entry_t entry)
486 struct screen *screen;
487 unsigned i;
489 /* Initialize the screen. */
490 screen = grub_zalloc (sizeof (*screen));
491 if (! screen)
492 return 0;
494 screen->num_lines = 1;
495 screen->lines = grub_malloc (sizeof (struct line));
496 if (! screen->lines)
497 goto fail;
499 /* Initialize the first line which must be always present. */
500 if (! init_line (screen->lines))
501 goto fail;
503 insert_string (screen, (char *) entry->sourcecode, 0);
505 /* Reset the cursor position. */
506 screen->column = 0;
507 screen->real_column = 0;
508 screen->line = 0;
509 for (i = 0; i < screen->nterms; i++)
511 screen->terms[i].x = 0;
512 screen->terms[i].y = 0;
515 return screen;
517 fail:
518 destroy_screen (screen);
519 return 0;
522 static int
523 forward_char (struct screen *screen, int update)
525 struct line *linep;
526 unsigned i;
528 linep = screen->lines + screen->line;
529 if (screen->column < linep->len)
531 screen->column++;
532 for (i = 0; i < screen->nterms; i++)
534 screen->terms[i].x++;
535 if (screen->terms[i].x
536 == grub_term_entry_width (screen->terms[i].term))
538 screen->terms[i].x = 0;
539 screen->terms[i].y++;
543 else if (screen->num_lines > screen->line + 1)
545 screen->column = 0;
546 screen->line++;
547 for (i = 0; i < screen->nterms; i++)
549 screen->terms[i].x = 0;
550 screen->terms[i].y++;
554 screen->real_column = screen->column;
556 if (update)
557 update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE);
558 return 1;
561 static int
562 backward_char (struct screen *screen, int update)
564 unsigned i;
566 if (screen->column > 0)
568 screen->column--;
569 for (i = 0; i < screen->nterms; i++)
571 screen->terms[i].x--;
572 if (screen->terms[i].x == -1)
574 screen->terms[i].x
575 = grub_term_entry_width (screen->terms[i].term) - 1;
576 screen->terms[i].y--;
580 else if (screen->line > 0)
582 struct line *linep;
584 screen->line--;
585 linep = screen->lines + screen->line;
586 screen->column = linep->len;
587 for (i = 0; i < screen->nterms; i++)
589 screen->terms[i].x = screen->column
590 % grub_term_entry_width (screen->terms[i].term);
591 screen->terms[i].y--;
595 screen->real_column = screen->column;
597 if (update)
598 update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE);
600 return 1;
603 static int
604 previous_line (struct screen *screen, int update)
606 unsigned i;
608 if (screen->line > 0)
610 struct line *linep;
611 int col;
613 /* How many physical lines from the current position
614 to the first physical line? */
615 col = screen->column;
617 screen->line--;
619 linep = screen->lines + screen->line;
620 if (linep->len < screen->real_column)
621 screen->column = linep->len;
622 else
623 screen->column = screen->real_column;
625 for (i = 0; i < screen->nterms; i++)
627 int dy;
628 dy = col / grub_term_entry_width (screen->terms[i].term);
630 /* How many physical lines from the current position
631 to the last physical line? */
632 dy += (linep->len / grub_term_entry_width (screen->terms[i].term)
633 - screen->column
634 / grub_term_entry_width (screen->terms[i].term));
636 screen->terms[i].y -= dy + 1;
637 screen->terms[i].x
638 = screen->column % grub_term_entry_width (screen->terms[i].term);
641 else
643 for (i = 0; i < screen->nterms; i++)
645 screen->terms[i].y
646 -= screen->column / grub_term_entry_width (screen->terms[i].term);
647 screen->terms[i].x = 0;
649 screen->column = 0;
652 if (update)
653 update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE);
655 return 1;
658 static int
659 next_line (struct screen *screen, int update)
661 unsigned i;
663 if (screen->line < screen->num_lines - 1)
665 struct line *linep;
666 int l1, c1;
668 /* How many physical lines from the current position
669 to the last physical line? */
670 linep = screen->lines + screen->line;
671 l1 = linep->len;
672 c1 = screen->column;
674 screen->line++;
676 linep++;
677 if (linep->len < screen->real_column)
678 screen->column = linep->len;
679 else
680 screen->column = screen->real_column;
682 for (i = 0; i < screen->nterms; i++)
684 int dy;
685 dy = l1 / grub_term_entry_width (screen->terms[i].term)
686 - c1 / grub_term_entry_width (screen->terms[i].term);
687 /* How many physical lines from the current position
688 to the first physical line? */
689 dy += screen->column / grub_term_entry_width (screen->terms[i].term);
690 screen->terms[i].y += dy + 1;
691 screen->terms[i].x = screen->column
692 % grub_term_entry_width (screen->terms[i].term);
695 else
697 struct line *linep;
698 int l, s;
700 linep = screen->lines + screen->line;
701 l = linep->len;
702 s = screen->column;
703 screen->column = linep->len;
704 for (i = 0; i < screen->nterms; i++)
706 screen->terms[i].y
707 += (l / grub_term_entry_width (screen->terms[i].term)
708 - s / grub_term_entry_width (screen->terms[i].term));
709 screen->terms[i].x
710 = screen->column % grub_term_entry_width (screen->terms[i].term);
714 if (update)
715 update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE);
717 return 1;
720 static int
721 beginning_of_line (struct screen *screen, int update)
723 unsigned i;
724 int col;
726 col = screen->column;
727 screen->column = screen->real_column = 0;
728 for (i = 0; i < screen->nterms; i++)
730 screen->terms[i].x = 0;
731 screen->terms[i].y -= col / grub_term_entry_width (screen->terms[i].term);
734 if (update)
735 update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE);
737 return 1;
740 static int
741 end_of_line (struct screen *screen, int update)
743 struct line *linep;
744 unsigned i;
745 int col;
747 linep = screen->lines + screen->line;
748 col = screen->column;
749 screen->column = screen->real_column = linep->len;
750 for (i = 0; i < screen->nterms; i++)
752 screen->terms[i].y
753 += (linep->len / grub_term_entry_width (screen->terms->term)
754 - col / grub_term_entry_width (screen->terms->term));
755 screen->terms[i].x
756 = screen->column % grub_term_entry_width (screen->terms->term);
759 if (update)
760 update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE);
762 return 1;
765 static int
766 delete_char (struct screen *screen, int update)
768 struct line *linep;
769 int start = screen->num_lines;
770 int column = 0;
772 linep = screen->lines + screen->line;
773 if (linep->len > screen->column)
775 int orig_num[screen->nterms], new_num;
776 unsigned i;
778 for (i = 0; i < screen->nterms; i++)
779 orig_num[i] = get_logical_num_lines (linep, &screen->terms[i]);
781 grub_memmove (linep->buf + screen->column,
782 linep->buf + screen->column + 1,
783 linep->len - screen->column - 1);
784 linep->len--;
786 start = screen->line;
787 column = screen->column;
789 screen->real_column = screen->column;
791 if (update)
793 for (i = 0; i < screen->nterms; i++)
795 new_num = get_logical_num_lines (linep, &screen->terms[i]);
796 if (orig_num[i] != new_num)
797 update_screen (screen, &screen->terms[i],
798 start, column, 0, 0, ALL_LINES);
799 else
800 update_screen (screen, &screen->terms[i],
801 start, column, 0, 0, SINGLE_LINE);
805 else if (screen->num_lines > screen->line + 1)
807 struct line *next_linep;
809 next_linep = linep + 1;
810 if (! ensure_space (linep, next_linep->len))
811 return 0;
813 grub_memmove (linep->buf + linep->len, next_linep->buf, next_linep->len);
814 linep->len += next_linep->len;
816 grub_free (next_linep->buf);
817 grub_memmove (next_linep,
818 next_linep + 1,
819 (screen->num_lines - screen->line - 2)
820 * sizeof (struct line));
821 screen->num_lines--;
823 start = screen->line;
824 column = screen->column;
826 screen->real_column = screen->column;
827 if (update)
828 update_screen_all (screen, start, column, 0, 1, ALL_LINES);
831 return 1;
834 static int
835 backward_delete_char (struct screen *screen, int update)
837 int saved_column;
838 int saved_line;
840 saved_column = screen->column;
841 saved_line = screen->line;
843 if (! backward_char (screen, 0))
844 return 0;
846 if (saved_column != screen->column || saved_line != screen->line)
847 if (! delete_char (screen, update))
848 return 0;
850 return 1;
853 static int
854 kill_line (struct screen *screen, int continuous, int update)
856 struct line *linep;
857 char *p;
858 int size;
859 int offset;
861 p = screen->killed_text;
862 if (! continuous && p)
863 p[0] = '\0';
865 linep = screen->lines + screen->line;
866 size = linep->len - screen->column;
868 if (p)
869 offset = grub_strlen (p);
870 else
871 offset = 0;
873 if (size > 0)
875 int orig_num[screen->nterms], new_num;
876 unsigned i;
878 p = grub_realloc (p, offset + size + 1);
879 if (! p)
880 return 0;
882 grub_memmove (p + offset, linep->buf + screen->column, size);
883 p[offset + size - 1] = '\0';
885 screen->killed_text = p;
887 for (i = 0; i < screen->nterms; i++)
888 orig_num[i] = get_logical_num_lines (linep, &screen->terms[i]);
889 linep->len = screen->column;
891 if (update)
893 new_num = get_logical_num_lines (linep, &screen->terms[i]);
894 for (i = 0; i < screen->nterms; i++)
896 if (orig_num[i] != new_num)
897 update_screen (screen, &screen->terms[i],
898 screen->line, screen->column, 0, 1, ALL_LINES);
899 else
900 update_screen (screen, &screen->terms[i],
901 screen->line, screen->column, 0, 0, SINGLE_LINE);
905 else if (screen->line + 1 < screen->num_lines)
907 p = grub_realloc (p, offset + 1 + 1);
908 if (! p)
909 return 0;
911 p[offset] = '\n';
912 p[offset + 1] = '\0';
914 screen->killed_text = p;
916 return delete_char (screen, update);
919 return 1;
922 static int
923 yank (struct screen *screen, int update)
925 if (screen->killed_text)
926 return insert_string (screen, screen->killed_text, update);
928 return 1;
931 static int
932 open_line (struct screen *screen, int update)
934 int saved_y[screen->nterms];
935 unsigned i;
937 for (i = 0; i < screen->nterms; i++)
938 saved_y[i] = screen->terms[i].y;
940 if (! insert_string (screen, "\n", 0))
941 return 0;
943 if (! backward_char (screen, 0))
944 return 0;
946 for (i = 0; i < screen->nterms; i++)
947 screen->terms[i].y = saved_y[i];
949 if (update)
950 update_screen_all (screen, screen->line, screen->column, 0, 1, ALL_LINES);
952 return 1;
955 /* A completion hook to print items. */
956 static void
957 store_completion (const char *item, grub_completion_type_t type,
958 int count __attribute__ ((unused)))
960 char *p;
962 completion_type = type;
964 /* Make sure that the completion buffer has enough room. */
965 if (completion_buffer.max_len < (completion_buffer.len
966 + (int) grub_strlen (item) + 1 + 1))
968 grub_size_t new_len;
970 new_len = completion_buffer.len + grub_strlen (item) + 80;
971 p = grub_realloc (completion_buffer.buf, new_len);
972 if (! p)
974 /* Possibly not fatal. */
975 grub_errno = GRUB_ERR_NONE;
976 return;
978 p[completion_buffer.len] = 0;
979 completion_buffer.buf = p;
980 completion_buffer.max_len = new_len;
983 p = completion_buffer.buf + completion_buffer.len;
984 if (completion_buffer.len != 0)
986 *p++ = ' ';
987 completion_buffer.len++;
989 grub_strcpy (p, item);
990 completion_buffer.len += grub_strlen (item);
993 static int
994 complete (struct screen *screen, int continuous, int update)
996 char saved_char;
997 struct line *linep;
998 int restore;
999 char *insert;
1000 static int count = -1;
1001 unsigned i;
1002 grub_uint32_t *ucs4;
1003 grub_size_t buflen;
1004 grub_ssize_t ucs4len;
1006 if (continuous)
1007 count++;
1008 else
1009 count = 0;
1011 completion_buffer.buf = 0;
1012 completion_buffer.len = 0;
1013 completion_buffer.max_len = 0;
1015 linep = screen->lines + screen->line;
1016 saved_char = linep->buf[screen->column];
1017 linep->buf[screen->column] = '\0';
1019 insert = grub_normal_do_completion (linep->buf, &restore, store_completion);
1021 linep->buf[screen->column] = saved_char;
1023 buflen = grub_strlen (completion_buffer.buf);
1024 ucs4 = grub_malloc (sizeof (grub_uint32_t) * (buflen + 1));
1026 if (!ucs4)
1028 grub_print_error ();
1029 grub_errno = GRUB_ERR_NONE;
1030 return 1;
1033 ucs4len = grub_utf8_to_ucs4 (ucs4, buflen,
1034 (grub_uint8_t *) completion_buffer.buf,
1035 buflen, 0);
1036 ucs4[ucs4len] = 0;
1038 if (restore)
1039 for (i = 0; i < screen->nterms; i++)
1041 int num_sections = ((completion_buffer.len
1042 + grub_term_width (screen->terms[i].term) - 8 - 1)
1043 / (grub_term_width (screen->terms[i].term) - 8));
1044 grub_uint32_t *endp;
1045 grub_uint16_t pos;
1046 grub_uint32_t *p = ucs4;
1048 pos = grub_term_getxy (screen->terms[i].term);
1049 grub_term_gotoxy (screen->terms[i].term, 0,
1050 grub_term_height (screen->terms[i].term) - 3);
1052 screen->completion_shown = 1;
1054 grub_term_gotoxy (screen->terms[i].term, 0,
1055 grub_term_height (screen->terms[i].term) - 3);
1056 grub_puts_terminal (" ", screen->terms[i].term);
1057 switch (completion_type)
1059 case GRUB_COMPLETION_TYPE_COMMAND:
1060 grub_puts_terminal (_("Possible commands are:"),
1061 screen->terms[i].term);
1062 break;
1063 case GRUB_COMPLETION_TYPE_DEVICE:
1064 grub_puts_terminal (_("Possible devices are:"),
1065 screen->terms[i].term);
1066 break;
1067 case GRUB_COMPLETION_TYPE_FILE:
1068 grub_puts_terminal (_("Possible files are:"),
1069 screen->terms[i].term);
1070 break;
1071 case GRUB_COMPLETION_TYPE_PARTITION:
1072 grub_puts_terminal (_("Possible partitions are:"),
1073 screen->terms[i].term);
1074 break;
1075 case GRUB_COMPLETION_TYPE_ARGUMENT:
1076 grub_puts_terminal (_("Possible arguments are:"),
1077 screen->terms[i].term);
1078 break;
1079 default:
1080 grub_puts_terminal (_("Possible things are:"),
1081 screen->terms[i].term);
1082 break;
1085 grub_puts_terminal ("\n ", screen->terms[i].term);
1087 p += (count % num_sections)
1088 * (grub_term_width (screen->terms[i].term) - 8);
1089 endp = p + (grub_term_width (screen->terms[i].term) - 8);
1091 if (p != ucs4)
1092 grub_putcode (GRUB_TERM_DISP_LEFT, screen->terms[i].term);
1093 else
1094 grub_putcode (' ', screen->terms[i].term);
1096 while (*p && p < endp)
1097 grub_putcode (*p++, screen->terms[i].term);
1099 if (*p)
1100 grub_putcode (GRUB_TERM_DISP_RIGHT, screen->terms[i].term);
1101 grub_term_gotoxy (screen->terms[i].term, pos >> 8, pos & 0xFF);
1104 if (insert)
1106 insert_string (screen, insert, update);
1107 count = -1;
1108 grub_free (insert);
1110 else if (update)
1111 grub_refresh ();
1113 grub_free (completion_buffer.buf);
1114 return 1;
1117 /* Clear displayed completions. */
1118 static void
1119 clear_completions (struct per_term_screen *term_screen)
1121 grub_uint16_t pos;
1122 unsigned i, j;
1124 pos = grub_term_getxy (term_screen->term);
1125 grub_term_gotoxy (term_screen->term, 0,
1126 grub_term_height (term_screen->term) - 3);
1128 for (i = 0; i < 2; i++)
1130 for (j = 0; j < grub_term_width (term_screen->term) - 1; j++)
1131 grub_putcode (' ', term_screen->term);
1132 grub_putcode ('\n', term_screen->term);
1135 grub_term_gotoxy (term_screen->term, pos >> 8, pos & 0xFF);
1136 grub_term_refresh (term_screen->term);
1139 static void
1140 clear_completions_all (struct screen *screen)
1142 unsigned i;
1144 for (i = 0; i < screen->nterms; i++)
1145 clear_completions (&screen->terms[i]);
1148 /* Execute the command list in the screen SCREEN. */
1149 static int
1150 run (struct screen *screen)
1152 int currline = 0;
1153 char *nextline;
1155 auto grub_err_t editor_getline (char **line, int cont);
1156 grub_err_t editor_getline (char **line, int cont __attribute__ ((unused)))
1158 struct line *linep = screen->lines + currline;
1159 char *p;
1161 if (currline > screen->num_lines)
1163 *line = 0;
1164 return 0;
1167 /* Trim down space characters. */
1168 for (p = linep->buf + linep->len - 1;
1169 p >= linep->buf && grub_isspace (*p);
1170 p--)
1172 *++p = '\0';
1174 linep->len = p - linep->buf;
1175 for (p = linep->buf; grub_isspace (*p); p++)
1177 *line = grub_strdup (p);
1178 currline++;
1179 return 0;
1182 grub_cls ();
1183 grub_printf (" ");
1184 grub_printf_ (N_("Booting a command list"));
1185 grub_printf ("\n\n");
1188 /* Execute the script, line for line. */
1189 while (currline < screen->num_lines)
1191 editor_getline (&nextline, 0);
1192 if (grub_parser_get_current ()->parse_line (nextline, editor_getline))
1193 break;
1196 if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ())
1197 /* Implicit execution of boot, only if something is loaded. */
1198 grub_command_execute ("boot", 0, 0);
1200 if (grub_errno != GRUB_ERR_NONE)
1202 grub_print_error ();
1203 grub_errno = GRUB_ERR_NONE;
1204 grub_wait_after_message ();
1207 return 1;
1210 /* Edit a menu entry with an Emacs-like interface. */
1211 void
1212 grub_menu_entry_run (grub_menu_entry_t entry)
1214 struct screen *screen;
1215 int prev_c;
1216 grub_err_t err = GRUB_ERR_NONE;
1217 unsigned i;
1218 grub_term_output_t term;
1220 err = grub_auth_check_authentication (NULL);
1222 if (err)
1224 grub_print_error ();
1225 grub_errno = GRUB_ERR_NONE;
1226 return;
1229 screen = make_screen (entry);
1230 if (! screen)
1231 return;
1233 screen->terms = NULL;
1235 refresh:
1236 grub_free (screen->terms);
1237 screen->nterms = 0;
1238 FOR_ACTIVE_TERM_OUTPUTS(term)
1239 screen->nterms++;
1240 screen->terms = grub_malloc (screen->nterms * sizeof (screen->terms[0]));
1241 if (!screen->terms)
1243 grub_print_error ();
1244 grub_errno = GRUB_ERR_NONE;
1245 return;
1247 i = 0;
1248 FOR_ACTIVE_TERM_OUTPUTS(term)
1250 screen->terms[i].term = term;
1251 screen->terms[i].x = 0;
1252 screen->terms[i].y = 0;
1253 i++;
1255 /* Draw the screen. */
1256 for (i = 0; i < screen->nterms; i++)
1257 grub_menu_init_page (0, 1, screen->terms[i].term);
1258 update_screen_all (screen, 0, 0, 1, 1, ALL_LINES);
1259 for (i = 0; i < screen->nterms; i++)
1260 grub_term_setcursor (screen->terms[i].term, 1);
1261 prev_c = '\0';
1263 while (1)
1265 int c = GRUB_TERM_ASCII_CHAR (grub_getkey ());
1267 if (screen->completion_shown)
1269 clear_completions_all (screen);
1270 screen->completion_shown = 0;
1273 if (grub_normal_exit_level)
1275 destroy_screen (screen);
1276 return;
1279 switch (c)
1281 case 16: /* C-p */
1282 if (! previous_line (screen, 1))
1283 goto fail;
1284 break;
1286 case 14: /* C-n */
1287 if (! next_line (screen, 1))
1288 goto fail;
1289 break;
1291 case 6: /* C-f */
1292 if (! forward_char (screen, 1))
1293 goto fail;
1294 break;
1296 case 2: /* C-b */
1297 if (! backward_char (screen, 1))
1298 goto fail;
1299 break;
1301 case 1: /* C-a */
1302 if (! beginning_of_line (screen, 1))
1303 goto fail;
1304 break;
1306 case 5: /* C-e */
1307 if (! end_of_line (screen, 1))
1308 goto fail;
1309 break;
1311 case '\t': /* C-i */
1312 if (! complete (screen, prev_c == c, 1))
1313 goto fail;
1314 break;
1316 case 4: /* C-d */
1317 if (! delete_char (screen, 1))
1318 goto fail;
1319 break;
1321 case 8: /* C-h */
1322 if (! backward_delete_char (screen, 1))
1323 goto fail;
1324 break;
1326 case 11: /* C-k */
1327 if (! kill_line (screen, prev_c == c, 1))
1328 goto fail;
1329 break;
1331 case 21: /* C-u */
1332 /* FIXME: What behavior is good for this key? */
1333 break;
1335 case 25: /* C-y */
1336 if (! yank (screen, 1))
1337 goto fail;
1338 break;
1340 case 12: /* C-l */
1341 /* FIXME: centering. */
1342 goto refresh;
1344 case 15: /* C-o */
1345 if (! open_line (screen, 1))
1346 goto fail;
1347 break;
1349 case '\n':
1350 case '\r':
1351 if (! insert_string (screen, "\n", 1))
1352 goto fail;
1353 break;
1355 case '\e':
1356 destroy_screen (screen);
1357 return;
1359 case 3: /* C-c */
1360 grub_cmdline_run (1);
1361 goto refresh;
1363 case 24: /* C-x */
1364 if (! run (screen))
1365 goto fail;
1366 goto refresh;
1368 case 18: /* C-r */
1369 case 19: /* C-s */
1370 case 20: /* C-t */
1371 /* FIXME */
1372 break;
1374 default:
1375 if (grub_isprint (c))
1377 char buf[2];
1379 buf[0] = c;
1380 buf[1] = '\0';
1381 if (! insert_string (screen, buf, 1))
1382 goto fail;
1384 break;
1387 prev_c = c;
1390 fail:
1391 destroy_screen (screen);
1393 grub_cls ();
1394 grub_print_error ();
1395 grub_errno = GRUB_ERR_NONE;
1396 grub_putchar ('\n');
1397 grub_printf_ (N_("Press any key to continue..."));
1398 (void) grub_getkey ();