]> git.proxmox.com Git - grub2.git/blob - normal/menu_entry.c
2007-07-22 Yoshinori K. Okuji <okuji@enbug.org>
[grub2.git] / normal / menu_entry.c
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2005,2006,2007 Free Software Foundation, Inc.
4 *
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.
9 *
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.
14 *
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/>.
17 */
18
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/script.h>
25
26 enum update_mode
27 {
28 NO_LINE,
29 SINGLE_LINE,
30 ALL_LINES
31 };
32
33 struct line
34 {
35 /* The line buffer. */
36 char *buf;
37 /* The length of the line. */
38 int len;
39 /* The maximum length of the line. */
40 int max_len;
41 };
42
43 struct screen
44 {
45 /* The array of lines. */
46 struct line *lines;
47 /* The number of lines. */
48 int num_lines;
49 /* The current column. */
50 int column;
51 /* The real column. */
52 int real_column;
53 /* The current line. */
54 int line;
55 /* The X coordinate. */
56 int x;
57 /* The Y coordinate. */
58 int y;
59 /* The kill buffer. */
60 char *killed_text;
61 /* The flag of a completion window. */
62 int completion_shown;
63 };
64
65 /* Used for storing completion items temporarily. */
66 static struct line completion_buffer;
67
68 /* Initialize a line. */
69 static int
70 init_line (struct line *linep)
71 {
72 linep->len = 0;
73 linep->max_len = 80; /* XXX */
74 linep->buf = grub_malloc (linep->max_len);
75 if (! linep->buf)
76 return 0;
77
78 return 1;
79 }
80
81 /* Allocate extra space if necessary. */
82 static int
83 ensure_space (struct line *linep, int extra)
84 {
85 if (linep->max_len < linep->len + extra)
86 {
87 linep->max_len = linep->len + extra + 80; /* XXX */
88 linep->buf = grub_realloc (linep->buf, linep->max_len + 1);
89 if (! linep->buf)
90 return 0;
91 }
92
93 return 1;
94 }
95
96 /* Return the number of lines occupied by this line on the screen. */
97 static int
98 get_logical_num_lines (struct line *linep)
99 {
100 return (linep->len / GRUB_TERM_ENTRY_WIDTH) + 1;
101 }
102
103 /* Print a line. */
104 static void
105 print_line (struct line *linep, int offset, int start, int y)
106 {
107 int i;
108 char *p;
109
110 grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + start + 1,
111 y + GRUB_TERM_FIRST_ENTRY_Y);
112
113 for (p = linep->buf + offset + start, i = start;
114 i < GRUB_TERM_ENTRY_WIDTH && offset + i < linep->len;
115 p++, i++)
116 grub_putchar (*p);
117
118 for (; i < GRUB_TERM_ENTRY_WIDTH; i++)
119 grub_putchar (' ');
120
121 if (linep->len >= offset + GRUB_TERM_ENTRY_WIDTH)
122 grub_putchar ('\\');
123 else
124 grub_putchar (' ');
125 }
126
127 /* Print an empty line. */
128 static void
129 print_empty_line (int y)
130 {
131 int i;
132
133 grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1,
134 y + GRUB_TERM_FIRST_ENTRY_Y);
135
136 for (i = 0; i < GRUB_TERM_ENTRY_WIDTH + 1; i++)
137 grub_putchar (' ');
138 }
139
140 /* Print an up arrow. */
141 static void
142 print_up (int flag)
143 {
144 grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH,
145 GRUB_TERM_FIRST_ENTRY_Y);
146
147 if (flag)
148 grub_putcode (GRUB_TERM_DISP_UP);
149 else
150 grub_putchar (' ');
151 }
152
153 /* Print a down arrow. */
154 static void
155 print_down (int flag)
156 {
157 grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH,
158 GRUB_TERM_TOP_BORDER_Y + GRUB_TERM_NUM_ENTRIES);
159
160 if (flag)
161 grub_putcode (GRUB_TERM_DISP_DOWN);
162 else
163 grub_putchar (' ');
164 }
165
166 /* Draw the lines of the screen SCREEN. */
167 static void
168 update_screen (struct screen *screen, int region_start, int region_column,
169 int up, int down, enum update_mode mode)
170 {
171 int up_flag = 0;
172 int down_flag = 0;
173 int y;
174 int i;
175 struct line *linep;
176
177 /* Check if scrolling is necessary. */
178 if (screen->y < 0 || screen->y >= GRUB_TERM_NUM_ENTRIES)
179 {
180 if (screen->y < 0)
181 screen->y = 0;
182 else
183 screen->y = GRUB_TERM_NUM_ENTRIES - 1;
184
185 region_start = 0;
186 region_column = 0;
187 up = 1;
188 down = 1;
189 mode = ALL_LINES;
190 }
191
192 if (mode != NO_LINE)
193 {
194 /* Draw lines. This code is tricky, because this must calculate logical
195 positions. */
196 y = screen->y - screen->column / GRUB_TERM_ENTRY_WIDTH;
197 i = screen->line;
198 linep = screen->lines + i;
199 while (y > 0)
200 {
201 i--;
202 linep--;
203 y -= get_logical_num_lines (linep);
204 }
205
206 if (y < 0 || i > 0)
207 up_flag = 1;
208
209 do
210 {
211 int column;
212
213 for (column = 0;
214 column <= linep->len && y < GRUB_TERM_NUM_ENTRIES;
215 column += GRUB_TERM_ENTRY_WIDTH, y++)
216 {
217 if (y < 0)
218 continue;
219
220 if (i == region_start)
221 {
222 if (region_column >= column
223 && region_column < column + GRUB_TERM_ENTRY_WIDTH)
224 print_line (linep, column, region_column - column, y);
225 else if (region_column < column)
226 print_line (linep, column, 0, y);
227 }
228 else if (i > region_start && mode == ALL_LINES)
229 print_line (linep, column, 0, y);
230 }
231
232 if (y == GRUB_TERM_NUM_ENTRIES)
233 {
234 if (column <= linep->len || i + 1 < screen->num_lines)
235 down_flag = 1;
236 }
237
238 linep++;
239 i++;
240
241 if (mode == ALL_LINES && i == screen->num_lines)
242 for (; y < GRUB_TERM_NUM_ENTRIES; y++)
243 print_empty_line (y);
244
245 }
246 while (y < GRUB_TERM_NUM_ENTRIES);
247
248 /* Draw up and down arrows. */
249 if (up)
250 print_up (up_flag);
251 if (down)
252 print_down (down_flag);
253 }
254
255 /* Place the cursor. */
256 grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1 + screen->x,
257 GRUB_TERM_FIRST_ENTRY_Y + screen->y);
258
259 grub_refresh ();
260 }
261
262 /* Insert the string S into the screen SCREEN. This updates the cursor
263 position and redraw the screen. Return zero if fails. */
264 static int
265 insert_string (struct screen *screen, char *s, int update)
266 {
267 int region_start = screen->num_lines;
268 int region_column = 0;
269 int down = 0;
270 enum update_mode mode = NO_LINE;
271
272 while (*s)
273 {
274 if (*s == '\n')
275 {
276 /* LF is special because it creates a new line. */
277 struct line *current_linep;
278 struct line *next_linep;
279 int size;
280
281 /* Make a new line. */
282 screen->num_lines++;
283 screen->lines = grub_realloc (screen->lines,
284 screen->num_lines
285 * sizeof (struct line));
286 if (! screen->lines)
287 return 0;
288
289 /* Scroll down. */
290 grub_memmove (screen->lines + screen->line + 2,
291 screen->lines + screen->line + 1,
292 ((screen->num_lines - screen->line - 2)
293 * sizeof (struct line)));
294
295 if (! init_line (screen->lines + screen->line + 1))
296 return 0;
297
298 /* Fold the line. */
299 current_linep = screen->lines + screen->line;
300 next_linep = current_linep + 1;
301 size = current_linep->len - screen->column;
302
303 if (! ensure_space (next_linep, size))
304 return 0;
305
306 grub_memmove (next_linep->buf,
307 current_linep->buf + screen->column,
308 size);
309 current_linep->len = screen->column;
310 next_linep->len = size;
311
312 /* Update a dirty region. */
313 if (region_start > screen->line)
314 {
315 region_start = screen->line;
316 region_column = screen->column;
317 }
318
319 mode = ALL_LINES;
320 down = 1; /* XXX not optimal. */
321
322 /* Move the cursor. */
323 screen->column = screen->real_column = 0;
324 screen->line++;
325 screen->x = 0;
326 screen->y++;
327
328 s++;
329 }
330 else
331 {
332 /* All but LF. */
333 char *p;
334 struct line *current_linep;
335 int size;
336 int orig_num, new_num;
337
338 /* Find a string delimitted by LF. */
339 p = grub_strchr (s, '\n');
340 if (! p)
341 p = s + grub_strlen (s);
342
343 /* Insert the string. */
344 current_linep = screen->lines + screen->line;
345 size = p - s;
346 if (! ensure_space (current_linep, size))
347 return 0;
348
349 grub_memmove (current_linep->buf + screen->column + size,
350 current_linep->buf + screen->column,
351 current_linep->len - screen->column);
352 grub_memmove (current_linep->buf + screen->column,
353 s,
354 size);
355 orig_num = get_logical_num_lines (current_linep);
356 current_linep->len += size;
357 new_num = get_logical_num_lines (current_linep);
358
359 /* Update the dirty region. */
360 if (region_start > screen->line)
361 {
362 region_start = screen->line;
363 region_column = screen->column;
364 }
365
366 if (orig_num != new_num)
367 {
368 mode = ALL_LINES;
369 down = 1; /* XXX not optimal. */
370 }
371 else if (mode != ALL_LINES)
372 mode = SINGLE_LINE;
373
374 /* Move the cursor. */
375 screen->column += size;
376 screen->real_column = screen->column;
377 screen->x += size;
378 screen->y += screen->x / GRUB_TERM_ENTRY_WIDTH;
379 screen->x %= GRUB_TERM_ENTRY_WIDTH;
380
381 s = p;
382 }
383 }
384
385 if (update)
386 update_screen (screen, region_start, region_column, 0, down, mode);
387
388 return 1;
389 }
390
391 /* Release the resource allocated for SCREEN. */
392 static void
393 destroy_screen (struct screen *screen)
394 {
395 int i;
396
397 if (screen->lines)
398 for (i = 0; i < screen->num_lines; i++)
399 {
400 struct line *linep = screen->lines + i;
401
402 if (linep)
403 grub_free (linep->buf);
404 }
405
406 grub_free (screen->killed_text);
407 grub_free (screen->lines);
408 grub_free (screen);
409 }
410
411 /* Make a new screen. */
412 static struct screen *
413 make_screen (grub_menu_entry_t entry)
414 {
415 struct screen *screen;
416
417 /* Initialize the screen. */
418 screen = grub_malloc (sizeof (*screen));
419 if (! screen)
420 return 0;
421
422 screen->num_lines = 1;
423 screen->column = 0;
424 screen->real_column = 0;
425 screen->line = 0;
426 screen->x = 0;
427 screen->y = 0;
428 screen->killed_text = 0;
429 screen->completion_shown = 0;
430 screen->lines = grub_malloc (sizeof (struct line));
431 if (! screen->lines)
432 goto fail;
433
434 /* Initialize the first line which must be always present. */
435 if (! init_line (screen->lines))
436 goto fail;
437
438 insert_string (screen, (char *) entry->sourcecode, 0);
439
440 /* Reset the cursor position. */
441 screen->column = 0;
442 screen->real_column = 0;
443 screen->line = 0;
444 screen->x = 0;
445 screen->y = 0;
446
447 return screen;
448
449 fail:
450 destroy_screen (screen);
451 return 0;
452 }
453
454 static int
455 forward_char (struct screen *screen, int update)
456 {
457 struct line *linep;
458
459 linep = screen->lines + screen->line;
460 if (screen->column < linep->len)
461 {
462 screen->column++;
463 screen->x++;
464 if (screen->x == GRUB_TERM_ENTRY_WIDTH)
465 {
466 screen->x = 0;
467 screen->y++;
468 }
469 }
470 else if (screen->num_lines > screen->line + 1)
471 {
472 screen->column = 0;
473 screen->line++;
474 screen->x = 0;
475 screen->y++;
476 }
477
478 screen->real_column = screen->column;
479
480 if (update)
481 update_screen (screen, screen->num_lines, 0, 0, 0, NO_LINE);
482 return 1;
483 }
484
485 static int
486 backward_char (struct screen *screen, int update)
487 {
488 if (screen->column > 0)
489 {
490 screen->column--;
491 screen->x--;
492 if (screen->x == -1)
493 {
494 screen->x = GRUB_TERM_ENTRY_WIDTH - 1;
495 screen->y--;
496 }
497 }
498 else if (screen->line > 0)
499 {
500 struct line *linep;
501
502 screen->line--;
503 linep = screen->lines + screen->line;
504 screen->column = linep->len;
505 screen->x = screen->column % GRUB_TERM_ENTRY_WIDTH;
506 screen->y--;
507 }
508
509 screen->real_column = screen->column;
510
511 if (update)
512 update_screen (screen, screen->num_lines, 0, 0, 0, NO_LINE);
513
514 return 1;
515 }
516
517 static int
518 previous_line (struct screen *screen, int update)
519 {
520 if (screen->line > 0)
521 {
522 struct line *linep;
523 int dy;
524
525 /* How many physical lines from the current position
526 to the first physical line? */
527 dy = screen->column / GRUB_TERM_ENTRY_WIDTH;
528
529 screen->line--;
530
531 linep = screen->lines + screen->line;
532 if (linep->len < screen->real_column)
533 screen->column = linep->len;
534 else
535 screen->column = screen->real_column;
536
537 /* How many physical lines from the current position
538 to the last physical line? */
539 dy += (linep->len / GRUB_TERM_ENTRY_WIDTH
540 - screen->column / GRUB_TERM_ENTRY_WIDTH);
541
542 screen->y -= dy + 1;
543 screen->x = screen->column % GRUB_TERM_ENTRY_WIDTH;
544 }
545 else
546 {
547 screen->y -= screen->column / GRUB_TERM_ENTRY_WIDTH;
548 screen->column = 0;
549 screen->x = 0;
550 }
551
552 if (update)
553 update_screen (screen, screen->num_lines, 0, 0, 0, NO_LINE);
554
555 return 1;
556 }
557
558 static int
559 next_line (struct screen *screen, int update)
560 {
561 if (screen->line < screen->num_lines - 1)
562 {
563 struct line *linep;
564 int dy;
565
566 /* How many physical lines from the current position
567 to the last physical line? */
568 linep = screen->lines + screen->line;
569 dy = (linep->len / GRUB_TERM_ENTRY_WIDTH
570 - screen->column / GRUB_TERM_ENTRY_WIDTH);
571
572 screen->line++;
573
574 linep++;
575 if (linep->len < screen->real_column)
576 screen->column = linep->len;
577 else
578 screen->column = screen->real_column;
579
580 /* How many physical lines from the current position
581 to the first physical line? */
582 dy += screen->column / GRUB_TERM_ENTRY_WIDTH;
583
584 screen->y += dy + 1;
585 screen->x = screen->column % GRUB_TERM_ENTRY_WIDTH;
586 }
587 else
588 {
589 struct line *linep;
590
591 linep = screen->lines + screen->line;
592 screen->y += (linep->len / GRUB_TERM_ENTRY_WIDTH
593 - screen->column / GRUB_TERM_ENTRY_WIDTH);
594 screen->column = linep->len;
595 screen->x = screen->column % GRUB_TERM_ENTRY_WIDTH;
596 }
597
598 if (update)
599 update_screen (screen, screen->num_lines, 0, 0, 0, NO_LINE);
600
601 return 1;
602 }
603
604 static int
605 beginning_of_line (struct screen *screen, int update)
606 {
607 screen->y -= screen->column / GRUB_TERM_ENTRY_WIDTH;
608 screen->column = screen->real_column = 0;
609 screen->x = 0;
610
611 if (update)
612 update_screen (screen, screen->num_lines, 0, 0, 0, NO_LINE);
613
614 return 1;
615 }
616
617 static int
618 end_of_line (struct screen *screen, int update)
619 {
620 struct line *linep;
621
622 linep = screen->lines + screen->line;
623 screen->y += (linep->len / GRUB_TERM_ENTRY_WIDTH
624 - screen->column / GRUB_TERM_ENTRY_WIDTH);
625 screen->column = screen->real_column = linep->len;
626 screen->x = screen->column % GRUB_TERM_ENTRY_WIDTH;
627
628 if (update)
629 update_screen (screen, screen->num_lines, 0, 0, 0, NO_LINE);
630
631 return 1;
632 }
633
634 static int
635 delete_char (struct screen *screen, int update)
636 {
637 struct line *linep;
638 enum update_mode mode = NO_LINE;
639 int start = screen->num_lines;
640 int column = 0;
641 int down = 0;
642
643 linep = screen->lines + screen->line;
644 if (linep->len > screen->column)
645 {
646 int orig_num, new_num;
647
648 orig_num = get_logical_num_lines (linep);
649
650 grub_memmove (linep->buf + screen->column,
651 linep->buf + screen->column + 1,
652 linep->len - screen->column - 1);
653 linep->len--;
654
655 new_num = get_logical_num_lines (linep);
656
657 if (orig_num != new_num)
658 mode = ALL_LINES;
659 else
660 mode = SINGLE_LINE;
661
662 start = screen->line;
663 column = screen->column;
664 }
665 else if (screen->num_lines > screen->line + 1)
666 {
667 struct line *next_linep;
668
669 next_linep = linep + 1;
670 if (! ensure_space (linep, next_linep->len))
671 return 0;
672
673 grub_memmove (linep->buf + linep->len, next_linep->buf, next_linep->len);
674 linep->len += next_linep->len;
675
676 grub_free (next_linep->buf);
677 grub_memmove (next_linep,
678 next_linep + 1,
679 (screen->num_lines - screen->line - 2)
680 * sizeof (struct line));
681 screen->num_lines--;
682
683 mode = ALL_LINES;
684 start = screen->line;
685 column = screen->column;
686 down = 1;
687 }
688
689 screen->real_column = screen->column;
690
691 if (update)
692 update_screen (screen, start, column, 0, down, mode);
693
694 return 1;
695 }
696
697 static int
698 backward_delete_char (struct screen *screen, int update)
699 {
700 int saved_column;
701 int saved_line;
702
703 saved_column = screen->column;
704 saved_line = screen->line;
705
706 if (! backward_char (screen, 0))
707 return 0;
708
709 if (saved_column != screen->column || saved_line != screen->line)
710 if (! delete_char (screen, update))
711 return 0;
712
713 return 1;
714 }
715
716 static int
717 kill_line (struct screen *screen, int continuous, int update)
718 {
719 struct line *linep;
720 char *p;
721 int size;
722 int offset;
723
724 p = screen->killed_text;
725 if (! continuous && p)
726 p[0] = '\0';
727
728 linep = screen->lines + screen->line;
729 size = linep->len - screen->column;
730
731 if (p)
732 offset = grub_strlen (p);
733 else
734 offset = 0;
735
736 if (size > 0)
737 {
738 enum update_mode mode = SINGLE_LINE;
739 int down = 0;
740 int orig_num, new_num;
741
742 p = grub_realloc (p, offset + size + 1);
743 if (! p)
744 return 0;
745
746 grub_memmove (p + offset, linep->buf + screen->column, size);
747 p[offset + size - 1] = '\0';
748
749 screen->killed_text = p;
750
751 orig_num = get_logical_num_lines (linep);
752 linep->len = screen->column;
753 new_num = get_logical_num_lines (linep);
754
755 if (orig_num != new_num)
756 {
757 mode = ALL_LINES;
758 down = 1;
759 }
760
761 if (update)
762 update_screen (screen, screen->line, screen->column, 0, down, mode);
763 }
764 else if (screen->line + 1 < screen->num_lines)
765 {
766 p = grub_realloc (p, offset + 1 + 1);
767 if (! p)
768 return 0;
769
770 p[offset] = '\n';
771 p[offset + 1] = '\0';
772
773 screen->killed_text = p;
774
775 return delete_char (screen, update);
776 }
777
778 return 1;
779 }
780
781 static int
782 yank (struct screen *screen, int update)
783 {
784 if (screen->killed_text)
785 return insert_string (screen, screen->killed_text, update);
786
787 return 1;
788 }
789
790 static int
791 open_line (struct screen *screen, int update)
792 {
793 int saved_y = screen->y;
794
795 if (! insert_string (screen, "\n", 0))
796 return 0;
797
798 if (! backward_char (screen, 0))
799 return 0;
800
801 screen->y = saved_y;
802
803 if (update)
804 update_screen (screen, screen->line, screen->column, 0, 1, ALL_LINES);
805
806 return 1;
807 }
808
809 /* A completion hook to print items. */
810 static void
811 store_completion (const char *item, grub_completion_type_t type, int count)
812 {
813 char *p;
814
815 if (count == 0)
816 {
817 /* If this is the first time, print a label. */
818 const char *what;
819
820 switch (type)
821 {
822 case GRUB_COMPLETION_TYPE_COMMAND:
823 what = "commands";
824 break;
825 case GRUB_COMPLETION_TYPE_DEVICE:
826 what = "devices";
827 break;
828 case GRUB_COMPLETION_TYPE_FILE:
829 what = "files";
830 break;
831 case GRUB_COMPLETION_TYPE_PARTITION:
832 what = "partitions";
833 break;
834 case GRUB_COMPLETION_TYPE_ARGUMENT:
835 what = "arguments";
836 break;
837 default:
838 what = "things";
839 break;
840 }
841
842 grub_gotoxy (0, GRUB_TERM_HEIGHT - 3);
843 grub_printf (" Possible %s are:\n ", what);
844 }
845
846 /* Make sure that the completion buffer has enough room. */
847 if (completion_buffer.max_len < (completion_buffer.len
848 + (int) grub_strlen (item) + 1 + 1))
849 {
850 grub_size_t new_len;
851
852 new_len = completion_buffer.len + grub_strlen (item) + 80;
853 p = grub_realloc (completion_buffer.buf, new_len);
854 if (! p)
855 {
856 /* Possibly not fatal. */
857 grub_errno = GRUB_ERR_NONE;
858 return;
859 }
860 p[completion_buffer.len] = 0;
861 completion_buffer.buf = p;
862 completion_buffer.max_len = new_len;
863 }
864
865 p = completion_buffer.buf + completion_buffer.len;
866 if (completion_buffer.len != 0)
867 {
868 *p++ = ' ';
869 completion_buffer.len++;
870 }
871 grub_strcpy (p, item);
872 completion_buffer.len += grub_strlen (item);
873 }
874
875 static int
876 complete (struct screen *screen, int continuous, int update)
877 {
878 grub_uint16_t pos;
879 char saved_char;
880 struct line *linep;
881 int restore;
882 char *insert;
883 static int count = -1;
884
885 if (continuous)
886 count++;
887 else
888 count = 0;
889
890 pos = grub_getxy ();
891 grub_gotoxy (0, GRUB_TERM_HEIGHT - 3);
892
893 completion_buffer.buf = 0;
894 completion_buffer.len = 0;
895 completion_buffer.max_len = 0;
896
897 linep = screen->lines + screen->line;
898 saved_char = linep->buf[screen->column];
899 linep->buf[screen->column] = '\0';
900
901 insert = grub_normal_do_completion (linep->buf, &restore, store_completion);
902
903 linep->buf[screen->column] = saved_char;
904
905 if (restore)
906 {
907 char *p = completion_buffer.buf;
908
909 screen->completion_shown = 1;
910
911 if (p)
912 {
913 int num_sections = ((completion_buffer.len + GRUB_TERM_WIDTH - 8 - 1)
914 / (GRUB_TERM_WIDTH - 8));
915 char *endp;
916
917 p += (count % num_sections) * (GRUB_TERM_WIDTH - 8);
918 endp = p + (GRUB_TERM_WIDTH - 8);
919
920 if (p != completion_buffer.buf)
921 grub_putcode (GRUB_TERM_DISP_LEFT);
922 else
923 grub_putchar (' ');
924
925 while (*p && p < endp)
926 grub_putchar (*p++);
927
928 if (*p)
929 grub_putcode (GRUB_TERM_DISP_RIGHT);
930 }
931 }
932
933 grub_gotoxy (pos >> 8, pos & 0xFF);
934
935 if (insert)
936 {
937 insert_string (screen, insert, update);
938 count = -1;
939 grub_free (insert);
940 }
941 else if (update)
942 grub_refresh ();
943
944 grub_free (completion_buffer.buf);
945 return 1;
946 }
947
948 /* Clear displayed completions. */
949 static void
950 clear_completions (void)
951 {
952 grub_uint16_t pos;
953 int i, j;
954
955 pos = grub_getxy ();
956 grub_gotoxy (0, GRUB_TERM_HEIGHT - 3);
957
958 for (i = 0; i < 2; i++)
959 {
960 for (j = 0; j < GRUB_TERM_WIDTH - 1; j++)
961 grub_putchar (' ');
962 grub_putchar ('\n');
963 }
964
965 grub_gotoxy (pos >> 8, pos & 0xFF);
966 grub_refresh ();
967 }
968
969 /* Execute the command list in the screen SCREEN. */
970 static int
971 run (struct screen *screen)
972 {
973 struct grub_script *parsed_script = 0;
974 int currline = 0;
975 char *nextline;
976
977 auto grub_err_t editor_getline (char **line);
978 grub_err_t editor_getline (char **line)
979 {
980 struct line *linep = screen->lines + currline;
981 char *p;
982
983 if (currline > screen->num_lines)
984 {
985 *line = 0;
986 return 0;
987 }
988
989 /* Trim down space characters. */
990 for (p = linep->buf + linep->len - 1;
991 p >= linep->buf && grub_isspace (*p);
992 p--)
993 ;
994 *++p = '\0';
995
996 linep->len = p - linep->buf;
997 for (p = linep->buf; grub_isspace (*p); p++)
998 ;
999 *line = p;
1000 currline++;
1001 return 0;
1002 }
1003
1004 grub_cls ();
1005 grub_printf (" Booting a command list\n\n");
1006
1007
1008 /* Execute the script, line for line. */
1009 while (currline < screen->num_lines)
1010 {
1011 editor_getline (&nextline);
1012 parsed_script = grub_script_parse (nextline, editor_getline);
1013 if (parsed_script)
1014 {
1015 /* Execute the command(s). */
1016 grub_script_execute (parsed_script);
1017
1018 /* The parsed script was executed, throw it away. */
1019 grub_script_free (parsed_script);
1020 }
1021 else
1022 break;
1023 }
1024
1025 if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ())
1026 /* Implicit execution of boot, only if something is loaded. */
1027 grub_command_execute ("boot", 0);
1028
1029 if (grub_errno != GRUB_ERR_NONE)
1030 {
1031 grub_print_error ();
1032 grub_errno = GRUB_ERR_NONE;
1033 /* Wait until the user pushes any key so that the user
1034 can see what happened. */
1035 grub_printf ("\nPress any key to continue...");
1036 (void) grub_getkey ();
1037 }
1038
1039 return 1;
1040 }
1041
1042 /* Edit a menu entry with an Emacs-like interface. */
1043 void
1044 grub_menu_entry_run (grub_menu_entry_t entry)
1045 {
1046 struct screen *screen;
1047 int prev_c;
1048
1049 screen = make_screen (entry);
1050 if (! screen)
1051 return;
1052
1053 refresh:
1054 /* Draw the screen. */
1055 grub_menu_init_page (0, 1);
1056 update_screen (screen, 0, 0, 1, 1, ALL_LINES);
1057 grub_setcursor (1);
1058 prev_c = '\0';
1059
1060 while (1)
1061 {
1062 int c = GRUB_TERM_ASCII_CHAR (grub_getkey ());
1063
1064 if (screen->completion_shown)
1065 {
1066 clear_completions ();
1067 screen->completion_shown = 0;
1068 }
1069
1070 switch (c)
1071 {
1072 case 16: /* C-p */
1073 if (! previous_line (screen, 1))
1074 goto fail;
1075 break;
1076
1077 case 14: /* C-n */
1078 if (! next_line (screen, 1))
1079 goto fail;
1080 break;
1081
1082 case 6: /* C-f */
1083 if (! forward_char (screen, 1))
1084 goto fail;
1085 break;
1086
1087 case 2: /* C-b */
1088 if (! backward_char (screen, 1))
1089 goto fail;
1090 break;
1091
1092 case 1: /* C-a */
1093 if (! beginning_of_line (screen, 1))
1094 goto fail;
1095 break;
1096
1097 case 5: /* C-e */
1098 if (! end_of_line (screen, 1))
1099 goto fail;
1100 break;
1101
1102 case '\t': /* C-i */
1103 if (! complete (screen, prev_c == c, 1))
1104 goto fail;
1105 break;
1106
1107 case 4: /* C-d */
1108 if (! delete_char (screen, 1))
1109 goto fail;
1110 break;
1111
1112 case 8: /* C-h */
1113 if (! backward_delete_char (screen, 1))
1114 goto fail;
1115 break;
1116
1117 case 11: /* C-k */
1118 if (! kill_line (screen, prev_c == c, 1))
1119 goto fail;
1120 break;
1121
1122 case 21: /* C-u */
1123 /* FIXME: What behavior is good for this key? */
1124 break;
1125
1126 case 25: /* C-y */
1127 if (! yank (screen, 1))
1128 goto fail;
1129 break;
1130
1131 case 12: /* C-l */
1132 /* FIXME: centering. */
1133 goto refresh;
1134
1135 case 15: /* C-o */
1136 if (! open_line (screen, 1))
1137 goto fail;
1138 break;
1139
1140 case '\n':
1141 case '\r':
1142 if (! insert_string (screen, "\n", 1))
1143 goto fail;
1144 break;
1145
1146 case '\e':
1147 destroy_screen (screen);
1148 return;
1149
1150 case 3: /* C-c */
1151 grub_cmdline_run (1);
1152 goto refresh;
1153
1154 case 24: /* C-x */
1155 if (! run (screen))
1156 goto fail;
1157 goto refresh;
1158
1159 case 18: /* C-r */
1160 case 19: /* C-s */
1161 case 20: /* C-t */
1162 /* FIXME */
1163 break;
1164
1165 default:
1166 if (grub_isprint (c))
1167 {
1168 char buf[2];
1169
1170 buf[0] = c;
1171 buf[1] = '\0';
1172 if (! insert_string (screen, buf, 1))
1173 goto fail;
1174 }
1175 break;
1176 }
1177
1178 prev_c = c;
1179 }
1180
1181 fail:
1182 destroy_screen (screen);
1183
1184 grub_cls ();
1185 grub_print_error ();
1186 grub_errno = GRUB_ERR_NONE;
1187 grub_printf ("\nPress any key to continue...");
1188 (void) grub_getkey ();
1189 }