diff --git a/ChangeLog b/ChangeLog index ecf35f482..a8d9133a2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,84 @@ +2005-02-19 Yoshinori K. Okuji + + This implements an Emacs-like menu entry editor. + + * normal/menu_entry.c: New file. + + * util/console.c (grub_ncurses_putchar): Translate some Unicode + characters to ASCII. + (saved_char): New variable. + (grub_ncurses_checkkey): Rewritten completely. + (grub_ncurses_getkey): Likewise. + (grub_ncurses_init): Call raw instead of cbreak. + + * normal/menu.c (print_entry): Do not put a space. + (init_page): Renamed to ... + (grub_menu_init_page): ... this. All callers changed. + (edit_menu_entry): Removed. + (run_menu): Call grub_menu_entry_run instead of edit_menu_entry. + + * normal/cmdline.c (grub_cmdline_run): Call grub_setcursor. + + * kern/misc.c (grub_vprintf): Call grub_refresh. + + * normal/menu.c (DISP_LEFT): Renamed to ... + * include/grub/term.h (GRUB_TERM_DISP_LEFT): ... this. + * normal/menu.c (DISP_UP): Renamed to ... + * include/grub/term.h (GRUB_TERM_DISP_UP): ... this. + * normal/menu.c (DISP_RIGHT): Renamed to ... + * include/grub/term.h (GRUB_TERM_DISP_RIGHT): ... this. + * normal/menu.c (DISP_DOWN): Renamed to ... + * include/grub/term.h (GRUB_TERM_DISP_DOWN): ... this. + * normal/menu.c (DISP_HLINE): Renamed to ... + * include/grub/term.h (GRUB_TERM_DISP_HLINE): ... this. + * normal/menu.c (DISP_VLINE): Renamed to ... + * include/grub/term.h (GRUB_TERM_DISP_VLINE): ... this. + * normal/menu.c (DISP_UL): Renamed to ... + * include/grub/term.h (GRUB_TERM_DISP_UL): ... this. + * normal/menu.c (DISP_UR): Renamed to ... + * include/grub/term.h (GRUB_TERM_DISP_UR): ... this. + * normal/menu.c (DISP_LL): Renamed to ... + * include/grub/term.h (GRUB_TERM_DISP_LL): ... this. + * normal/menu.c (DISP_LR): Renamed to ... + * include/grub/term.h (GRUB_TERM_DISP_LR): ... this. + * normal/menu.c (TERM_WIDTH): Renamed to ... + * include/grub/term.h (GRUB_TERM_WIDTH): ... this. + * normal/menu.c (TERM_HEIGHT): Renamed to ... + * include/grub/term.h (GRUB_TERM_HEIGHT): ... this. + * normal/menu.c (TERM_INFO_HEIGHT): Renamed to ... + * include/grub/term.h (GRUB_TERM_INFO_HEIGHT): ... this. + * normal/menu.c (TERM_MARGIN): Renamed to ... + * include/grub/term.h (GRUB_TERM_MARGIN): ... this. + * normal/menu.c (TERM_SCROLL_WIDTH): Renamed to ... + * include/grub/term.h (GRUB_TERM_SCROLL_WIDTH): ... this. + * normal/menu.c (TERM_TOP_BORDER_Y): Renamed to ... + * include/grub/term.h (GRUB_TERM_TOP_BORDER_Y): ... this. + * normal/menu.c (TERM_LEFT_BORDER_X): Renamed to ... + * include/grub/term.h (GRUB_TERM_LEFT_BORDER_X): ... this. + * normal/menu.c (TERM_BORDER_WIDTH): Renamed to ... + * include/grub/term.h (GRUB_TERM_BORDER_WIDTH): ... this. + * normal/menu.c (TERM_MESSAGE_HEIGHT): Renamed to ... + * include/grub/term.h (GRUB_TERM_MESSAGE_HEIGHT): ... this. + * normal/menu.c (TERM_BORDER_HEIGHT): Renamed to ... + * include/grub/term.h (GRUB_TERM_BORDER_HEIGHT): ... this. + * normal/menu.c (TERM_NUM_ENTRIES): Renamed to ... + * include/grub/term.h (GRUB_TERM_NUM_ENTRIES): ... this. + * normal/menu.c (TERM_FIRST_ENTRY_Y): Renamed to ... + * include/grub/term.h (GRUB_TERM_FIRST_ENTRY_Y): ... this. + * normal/menu.c (TERM_ENTRY_WIDTH): Renamed to ... + * include/grub/term.h (GRUB_TERM_ENTRY_WIDTH): ... this. + * normal/menu.c (TERM_CURSOR_X): Renamed to ... + * include/grub/term.h (GRUB_TERM_CURSOR_X): ... this. + All callers changed. + + * include/grub/normal.h: New prototype. + + * conf/i386-pc.rmk (grub_emu_SOURCES): Added + normal/menu_entry.c. + (normal_mod_SOURCES): Likewise. + * conf/powerpc-ieee1275.rmk (grub_emu_SOURCES): Likewise. + (normal_mod_SOURCES): Likewise. + 2005-02-15 Yoshinori K. Okuji * include/grub/normal.h (grub_halt_init): New prototype. diff --git a/conf/i386-pc.mk b/conf/i386-pc.mk index a99cac8bf..5b26d4e94 100644 --- a/conf/i386-pc.mk +++ b/conf/i386-pc.mk @@ -507,15 +507,15 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c \ kern/file.c kern/fs.c kern/loader.c kern/main.c kern/misc.c \ kern/partition.c kern/rescue.c kern/term.c \ normal/arg.c normal/cmdline.c normal/command.c normal/main.c \ - normal/menu.c \ + normal/menu.c normal/menu_entry.c \ partmap/amiga.c partmap/apple.c partmap/pc.c \ util/console.c util/grub-emu.c util/misc.c \ util/i386/pc/biosdisk.c util/i386/pc/getroot.c \ util/i386/pc/misc.c -CLEANFILES += grub-emu grub_emu-commands_boot.o grub_emu-commands_cat.o grub_emu-commands_cmp.o grub_emu-commands_help.o grub_emu-commands_terminal.o grub_emu-commands_ls.o grub_emu-commands_i386_pc_halt.o grub_emu-commands_i386_pc_reboot.o grub_emu-disk_loopback.o grub_emu-fs_ext2.o grub_emu-fs_fat.o grub_emu-fs_fshelp.o grub_emu-fs_hfs.o grub_emu-fs_iso9660.o grub_emu-fs_jfs.o grub_emu-fs_minix.o grub_emu-fs_ufs.o grub_emu-kern_device.o grub_emu-kern_disk.o grub_emu-kern_dl.o grub_emu-kern_env.o grub_emu-kern_err.o grub_emu-kern_file.o grub_emu-kern_fs.o grub_emu-kern_loader.o grub_emu-kern_main.o grub_emu-kern_misc.o grub_emu-kern_partition.o grub_emu-kern_rescue.o grub_emu-kern_term.o grub_emu-normal_arg.o grub_emu-normal_cmdline.o grub_emu-normal_command.o grub_emu-normal_main.o grub_emu-normal_menu.o grub_emu-partmap_amiga.o grub_emu-partmap_apple.o grub_emu-partmap_pc.o grub_emu-util_console.o grub_emu-util_grub_emu.o grub_emu-util_misc.o grub_emu-util_i386_pc_biosdisk.o grub_emu-util_i386_pc_getroot.o grub_emu-util_i386_pc_misc.o -MOSTLYCLEANFILES += grub_emu-commands_boot.d grub_emu-commands_cat.d grub_emu-commands_cmp.d grub_emu-commands_help.d grub_emu-commands_terminal.d grub_emu-commands_ls.d grub_emu-commands_i386_pc_halt.d grub_emu-commands_i386_pc_reboot.d grub_emu-disk_loopback.d grub_emu-fs_ext2.d grub_emu-fs_fat.d grub_emu-fs_fshelp.d grub_emu-fs_hfs.d grub_emu-fs_iso9660.d grub_emu-fs_jfs.d grub_emu-fs_minix.d grub_emu-fs_ufs.d grub_emu-kern_device.d grub_emu-kern_disk.d grub_emu-kern_dl.d grub_emu-kern_env.d grub_emu-kern_err.d grub_emu-kern_file.d grub_emu-kern_fs.d grub_emu-kern_loader.d grub_emu-kern_main.d grub_emu-kern_misc.d grub_emu-kern_partition.d grub_emu-kern_rescue.d grub_emu-kern_term.d grub_emu-normal_arg.d grub_emu-normal_cmdline.d grub_emu-normal_command.d grub_emu-normal_main.d grub_emu-normal_menu.d grub_emu-partmap_amiga.d grub_emu-partmap_apple.d grub_emu-partmap_pc.d grub_emu-util_console.d grub_emu-util_grub_emu.d grub_emu-util_misc.d grub_emu-util_i386_pc_biosdisk.d grub_emu-util_i386_pc_getroot.d grub_emu-util_i386_pc_misc.d +CLEANFILES += grub-emu grub_emu-commands_boot.o grub_emu-commands_cat.o grub_emu-commands_cmp.o grub_emu-commands_help.o grub_emu-commands_terminal.o grub_emu-commands_ls.o grub_emu-commands_i386_pc_halt.o grub_emu-commands_i386_pc_reboot.o grub_emu-disk_loopback.o grub_emu-fs_ext2.o grub_emu-fs_fat.o grub_emu-fs_fshelp.o grub_emu-fs_hfs.o grub_emu-fs_iso9660.o grub_emu-fs_jfs.o grub_emu-fs_minix.o grub_emu-fs_ufs.o grub_emu-kern_device.o grub_emu-kern_disk.o grub_emu-kern_dl.o grub_emu-kern_env.o grub_emu-kern_err.o grub_emu-kern_file.o grub_emu-kern_fs.o grub_emu-kern_loader.o grub_emu-kern_main.o grub_emu-kern_misc.o grub_emu-kern_partition.o grub_emu-kern_rescue.o grub_emu-kern_term.o grub_emu-normal_arg.o grub_emu-normal_cmdline.o grub_emu-normal_command.o grub_emu-normal_main.o grub_emu-normal_menu.o grub_emu-normal_menu_entry.o grub_emu-partmap_amiga.o grub_emu-partmap_apple.o grub_emu-partmap_pc.o grub_emu-util_console.o grub_emu-util_grub_emu.o grub_emu-util_misc.o grub_emu-util_i386_pc_biosdisk.o grub_emu-util_i386_pc_getroot.o grub_emu-util_i386_pc_misc.o +MOSTLYCLEANFILES += grub_emu-commands_boot.d grub_emu-commands_cat.d grub_emu-commands_cmp.d grub_emu-commands_help.d grub_emu-commands_terminal.d grub_emu-commands_ls.d grub_emu-commands_i386_pc_halt.d grub_emu-commands_i386_pc_reboot.d grub_emu-disk_loopback.d grub_emu-fs_ext2.d grub_emu-fs_fat.d grub_emu-fs_fshelp.d grub_emu-fs_hfs.d grub_emu-fs_iso9660.d grub_emu-fs_jfs.d grub_emu-fs_minix.d grub_emu-fs_ufs.d grub_emu-kern_device.d grub_emu-kern_disk.d grub_emu-kern_dl.d grub_emu-kern_env.d grub_emu-kern_err.d grub_emu-kern_file.d grub_emu-kern_fs.d grub_emu-kern_loader.d grub_emu-kern_main.d grub_emu-kern_misc.d grub_emu-kern_partition.d grub_emu-kern_rescue.d grub_emu-kern_term.d grub_emu-normal_arg.d grub_emu-normal_cmdline.d grub_emu-normal_command.d grub_emu-normal_main.d grub_emu-normal_menu.d grub_emu-normal_menu_entry.d grub_emu-partmap_amiga.d grub_emu-partmap_apple.d grub_emu-partmap_pc.d grub_emu-util_console.d grub_emu-util_grub_emu.d grub_emu-util_misc.d grub_emu-util_i386_pc_biosdisk.d grub_emu-util_i386_pc_getroot.d grub_emu-util_i386_pc_misc.d -grub-emu: grub_emu-commands_boot.o grub_emu-commands_cat.o grub_emu-commands_cmp.o grub_emu-commands_help.o grub_emu-commands_terminal.o grub_emu-commands_ls.o grub_emu-commands_i386_pc_halt.o grub_emu-commands_i386_pc_reboot.o grub_emu-disk_loopback.o grub_emu-fs_ext2.o grub_emu-fs_fat.o grub_emu-fs_fshelp.o grub_emu-fs_hfs.o grub_emu-fs_iso9660.o grub_emu-fs_jfs.o grub_emu-fs_minix.o grub_emu-fs_ufs.o grub_emu-kern_device.o grub_emu-kern_disk.o grub_emu-kern_dl.o grub_emu-kern_env.o grub_emu-kern_err.o grub_emu-kern_file.o grub_emu-kern_fs.o grub_emu-kern_loader.o grub_emu-kern_main.o grub_emu-kern_misc.o grub_emu-kern_partition.o grub_emu-kern_rescue.o grub_emu-kern_term.o grub_emu-normal_arg.o grub_emu-normal_cmdline.o grub_emu-normal_command.o grub_emu-normal_main.o grub_emu-normal_menu.o grub_emu-partmap_amiga.o grub_emu-partmap_apple.o grub_emu-partmap_pc.o grub_emu-util_console.o grub_emu-util_grub_emu.o grub_emu-util_misc.o grub_emu-util_i386_pc_biosdisk.o grub_emu-util_i386_pc_getroot.o grub_emu-util_i386_pc_misc.o +grub-emu: grub_emu-commands_boot.o grub_emu-commands_cat.o grub_emu-commands_cmp.o grub_emu-commands_help.o grub_emu-commands_terminal.o grub_emu-commands_ls.o grub_emu-commands_i386_pc_halt.o grub_emu-commands_i386_pc_reboot.o grub_emu-disk_loopback.o grub_emu-fs_ext2.o grub_emu-fs_fat.o grub_emu-fs_fshelp.o grub_emu-fs_hfs.o grub_emu-fs_iso9660.o grub_emu-fs_jfs.o grub_emu-fs_minix.o grub_emu-fs_ufs.o grub_emu-kern_device.o grub_emu-kern_disk.o grub_emu-kern_dl.o grub_emu-kern_env.o grub_emu-kern_err.o grub_emu-kern_file.o grub_emu-kern_fs.o grub_emu-kern_loader.o grub_emu-kern_main.o grub_emu-kern_misc.o grub_emu-kern_partition.o grub_emu-kern_rescue.o grub_emu-kern_term.o grub_emu-normal_arg.o grub_emu-normal_cmdline.o grub_emu-normal_command.o grub_emu-normal_main.o grub_emu-normal_menu.o grub_emu-normal_menu_entry.o grub_emu-partmap_amiga.o grub_emu-partmap_apple.o grub_emu-partmap_pc.o grub_emu-util_console.o grub_emu-util_grub_emu.o grub_emu-util_misc.o grub_emu-util_i386_pc_biosdisk.o grub_emu-util_i386_pc_getroot.o grub_emu-util_i386_pc_misc.o $(BUILD_CC) -o $@ $^ $(BUILD_LDFLAGS) $(grub_emu_LDFLAGS) grub_emu-commands_boot.o: commands/boot.c @@ -798,6 +798,14 @@ grub_emu-normal_menu.d: normal/menu.c -include grub_emu-normal_menu.d +grub_emu-normal_menu_entry.o: normal/menu_entry.c + $(BUILD_CC) -Inormal -I$(srcdir)/normal $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -c -o $@ $< + +grub_emu-normal_menu_entry.d: normal/menu_entry.c + set -e; $(BUILD_CC) -Inormal -I$(srcdir)/normal $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -M $< | sed 's,menu_entry\.o[ :]*,grub_emu-normal_menu_entry.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + +-include grub_emu-normal_menu_entry.d + grub_emu-partmap_amiga.o: partmap/amiga.c $(BUILD_CC) -Ipartmap -I$(srcdir)/partmap $(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -c -o $@ $< @@ -1330,10 +1338,11 @@ linux_mod-loader_i386_pc_linux_normal.d: loader/i386/pc/linux_normal.c linux_mod_CFLAGS = $(COMMON_CFLAGS) # For normal.mod. -normal_mod_SOURCES = normal/cmdline.c normal/command.c normal/main.c \ - normal/menu.c normal/arg.c normal/i386/setjmp.S -CLEANFILES += normal.mod mod-normal.o mod-normal.c pre-normal.o normal_mod-normal_cmdline.o normal_mod-normal_command.o normal_mod-normal_main.o normal_mod-normal_menu.o normal_mod-normal_arg.o normal_mod-normal_i386_setjmp.o def-normal.lst und-normal.lst -MOSTLYCLEANFILES += normal_mod-normal_cmdline.d normal_mod-normal_command.d normal_mod-normal_main.d normal_mod-normal_menu.d normal_mod-normal_arg.d normal_mod-normal_i386_setjmp.d +normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c \ + normal/main.c normal/menu.c normal/menu_entry.c \ + normal/i386/setjmp.S +CLEANFILES += normal.mod mod-normal.o mod-normal.c pre-normal.o normal_mod-normal_arg.o normal_mod-normal_cmdline.o normal_mod-normal_command.o normal_mod-normal_main.o normal_mod-normal_menu.o normal_mod-normal_menu_entry.o normal_mod-normal_i386_setjmp.o def-normal.lst und-normal.lst +MOSTLYCLEANFILES += normal_mod-normal_arg.d normal_mod-normal_cmdline.d normal_mod-normal_command.d normal_mod-normal_main.d normal_mod-normal_menu.d normal_mod-normal_menu_entry.d normal_mod-normal_i386_setjmp.d DEFSYMFILES += def-normal.lst UNDSYMFILES += und-normal.lst @@ -1342,7 +1351,7 @@ normal.mod: pre-normal.o mod-normal.o $(LD) -r -d -o $@ $^ $(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -R .note -R .comment $@ -pre-normal.o: normal_mod-normal_cmdline.o normal_mod-normal_command.o normal_mod-normal_main.o normal_mod-normal_menu.o normal_mod-normal_arg.o normal_mod-normal_i386_setjmp.o +pre-normal.o: normal_mod-normal_arg.o normal_mod-normal_cmdline.o normal_mod-normal_command.o normal_mod-normal_main.o normal_mod-normal_menu.o normal_mod-normal_menu_entry.o normal_mod-normal_i386_setjmp.o -rm -f $@ $(LD) -r -d -o $@ $^ @@ -1359,6 +1368,14 @@ und-normal.lst: pre-normal.o echo 'normal' > $@ $(NM) -u -P -p $< | cut -f1 -d' ' >> $@ +normal_mod-normal_arg.o: normal/arg.c + $(CC) -Inormal -I$(srcdir)/normal $(CPPFLAGS) $(CFLAGS) $(normal_mod_CFLAGS) -c -o $@ $< + +normal_mod-normal_arg.d: normal/arg.c + set -e; $(CC) -Inormal -I$(srcdir)/normal $(CPPFLAGS) $(CFLAGS) $(normal_mod_CFLAGS) -M $< | sed 's,arg\.o[ :]*,normal_mod-normal_arg.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + +-include normal_mod-normal_arg.d + normal_mod-normal_cmdline.o: normal/cmdline.c $(CC) -Inormal -I$(srcdir)/normal $(CPPFLAGS) $(CFLAGS) $(normal_mod_CFLAGS) -c -o $@ $< @@ -1391,13 +1408,13 @@ normal_mod-normal_menu.d: normal/menu.c -include normal_mod-normal_menu.d -normal_mod-normal_arg.o: normal/arg.c +normal_mod-normal_menu_entry.o: normal/menu_entry.c $(CC) -Inormal -I$(srcdir)/normal $(CPPFLAGS) $(CFLAGS) $(normal_mod_CFLAGS) -c -o $@ $< -normal_mod-normal_arg.d: normal/arg.c - set -e; $(CC) -Inormal -I$(srcdir)/normal $(CPPFLAGS) $(CFLAGS) $(normal_mod_CFLAGS) -M $< | sed 's,arg\.o[ :]*,normal_mod-normal_arg.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ +normal_mod-normal_menu_entry.d: normal/menu_entry.c + set -e; $(CC) -Inormal -I$(srcdir)/normal $(CPPFLAGS) $(CFLAGS) $(normal_mod_CFLAGS) -M $< | sed 's,menu_entry\.o[ :]*,normal_mod-normal_menu_entry.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ --include normal_mod-normal_arg.d +-include normal_mod-normal_menu_entry.d normal_mod-normal_i386_setjmp.o: normal/i386/setjmp.S $(CC) -Inormal/i386 -I$(srcdir)/normal/i386 $(CPPFLAGS) $(ASFLAGS) $(normal_mod_ASFLAGS) -c -o $@ $< diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index d5728e251..d649c359e 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -75,7 +75,7 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c \ kern/file.c kern/fs.c kern/loader.c kern/main.c kern/misc.c \ kern/partition.c kern/rescue.c kern/term.c \ normal/arg.c normal/cmdline.c normal/command.c normal/main.c \ - normal/menu.c \ + normal/menu.c normal/menu_entry.c \ partmap/amiga.c partmap/apple.c partmap/pc.c \ util/console.c util/grub-emu.c util/misc.c \ util/i386/pc/biosdisk.c util/i386/pc/getroot.c \ @@ -141,8 +141,9 @@ linux_mod_SOURCES = loader/i386/pc/linux_normal.c linux_mod_CFLAGS = $(COMMON_CFLAGS) # For normal.mod. -normal_mod_SOURCES = normal/cmdline.c normal/command.c normal/main.c \ - normal/menu.c normal/arg.c normal/i386/setjmp.S +normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c \ + normal/main.c normal/menu.c normal/menu_entry.c \ + normal/i386/setjmp.S normal_mod_CFLAGS = $(COMMON_CFLAGS) normal_mod_ASFLAGS = $(COMMON_ASFLAGS) diff --git a/conf/powerpc-ieee1275.rmk b/conf/powerpc-ieee1275.rmk index a06a58f66..25a038862 100644 --- a/conf/powerpc-ieee1275.rmk +++ b/conf/powerpc-ieee1275.rmk @@ -39,7 +39,7 @@ grub_emu_SOURCES = kern/main.c kern/device.c \ util/i386/pc/biosdisk.c fs/fat.c fs/ext2.c fs/ufs.c fs/minix.c fs/hfs.c \ fs/jfs.c fs/iso9660.c \ normal/cmdline.c normal/command.c normal/main.c normal/menu.c \ - normal/arg.c kern/partition.c \ + normal/menu_entry.c normal/arg.c kern/partition.c \ util/console.c util/grub-emu.c util/misc.c util/i386/pc/getroot.c \ kern/env.c disk/loopback.c commands/ls.c commands/help.c \ commands/terminal.c commands/boot.c commands/cmp.c commands/cat.c @@ -108,8 +108,9 @@ linux_mod_SOURCES = loader/powerpc/ieee1275/linux_normal.c linux_mod_CFLAGS = $(COMMON_CFLAGS) # For normal.mod. -normal_mod_SOURCES = normal/cmdline.c normal/command.c normal/main.c \ - normal/menu.c normal/arg.c normal/powerpc/setjmp.S +normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c \ + normal/main.c normal/menu.c normal/menu_entry.c \ + normal/powerpc/setjmp.S normal_mod_CFLAGS = $(COMMON_CFLAGS) normal_mod_ASFLAGS = $(COMMON_ASFLAGS) diff --git a/include/grub/normal.h b/include/grub/normal.h index 3ab367fe2..f89b6c7cb 100644 --- a/include/grub/normal.h +++ b/include/grub/normal.h @@ -140,6 +140,7 @@ int grub_iterate_commands (int (*iterate) (grub_command_t)); int grub_command_execute (char *cmdline); void grub_command_init (void); void grub_normal_init_page (void); +void grub_menu_init_page (int nested, int edit); int grub_arg_parse (grub_command_t parser, int argc, char **argv, struct grub_arg_list *usr, char ***args, int *argnum); void grub_arg_show_help (grub_command_t cmd); diff --git a/include/grub/term.h b/include/grub/term.h index 594648542..8612272a1 100644 --- a/include/grub/term.h +++ b/include/grub/term.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2003 Free Software Foundation, Inc. + * Copyright (C) 2002,2003,2005 Free Software Foundation, Inc. * * GRUB is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -55,6 +55,73 @@ grub_term_color_state; /* Set when the terminal needs to be initialized. */ #define GRUB_TERM_NEED_INIT (1 << 16) + +/* Unicode characters for fancy graphics. */ +#define GRUB_TERM_DISP_LEFT 0x2190 +#define GRUB_TERM_DISP_UP 0x2191 +#define GRUB_TERM_DISP_RIGHT 0x2192 +#define GRUB_TERM_DISP_DOWN 0x2193 +#define GRUB_TERM_DISP_HLINE 0x2501 +#define GRUB_TERM_DISP_VLINE 0x2503 +#define GRUB_TERM_DISP_UL 0x250F +#define GRUB_TERM_DISP_UR 0x2513 +#define GRUB_TERM_DISP_LL 0x2517 +#define GRUB_TERM_DISP_LR 0x251B + + +/* Menu-related geometrical constants. */ + +/* FIXME: These should be dynamically obtained from a terminal. */ +#define GRUB_TERM_WIDTH 80 +#define GRUB_TERM_HEIGHT 25 + +/* The number of lines of "GRUB version..." at the top. */ +#define GRUB_TERM_INFO_HEIGHT 1 + +/* The number of columns/lines between messages/borders/etc. */ +#define GRUB_TERM_MARGIN 1 + +/* The number of columns of scroll information. */ +#define GRUB_TERM_SCROLL_WIDTH 1 + +/* The Y position of the top border. */ +#define GRUB_TERM_TOP_BORDER_Y (GRUB_TERM_MARGIN + GRUB_TERM_INFO_HEIGHT \ + + GRUB_TERM_MARGIN) + +/* The X position of the left border. */ +#define GRUB_TERM_LEFT_BORDER_X GRUB_TERM_MARGIN + +/* The width of the border. */ +#define GRUB_TERM_BORDER_WIDTH (GRUB_TERM_WIDTH \ + - GRUB_TERM_MARGIN * 3 \ + - GRUB_TERM_SCROLL_WIDTH) + +/* The number of lines of messages at the bottom. */ +#define GRUB_TERM_MESSAGE_HEIGHT 8 + +/* The height of the border. */ +#define GRUB_TERM_BORDER_HEIGHT (GRUB_TERM_HEIGHT \ + - GRUB_TERM_TOP_BORDER_Y \ + - GRUB_TERM_MESSAGE_HEIGHT) + +/* The number of entries shown at a time. */ +#define GRUB_TERM_NUM_ENTRIES (GRUB_TERM_BORDER_HEIGHT - 2) + +/* The Y position of the first entry. */ +#define GRUB_TERM_FIRST_ENTRY_Y (GRUB_TERM_TOP_BORDER_Y + 1) + +/* The max column number of an entry. The last "-1" is for a + continuation marker. */ +#define GRUB_TERM_ENTRY_WIDTH (GRUB_TERM_BORDER_WIDTH - 2 \ + - GRUB_TERM_MARGIN * 2 - 1) + +/* The standard X position of the cursor. */ +#define GRUB_TERM_CURSOR_X (GRUB_TERM_LEFT_BORDER_X \ + + GRUB_TERM_BORDER_WIDTH \ + - GRUB_TERM_MARGIN \ + - 1) + + struct grub_term { /* The terminal name. */ diff --git a/kern/misc.c b/kern/misc.c index 1352a6fe5..da809ff5c 100644 --- a/kern/misc.c +++ b/kern/misc.c @@ -131,7 +131,11 @@ grub_printf (const char *fmt, ...) int grub_vprintf (const char *fmt, va_list args) { - return grub_vsprintf (0, fmt, args); + int ret; + + ret = grub_vsprintf (0, fmt, args); + grub_refresh (); + return ret; } int diff --git a/normal/cmdline.c b/normal/cmdline.c index 694d33133..d235803f4 100644 --- a/normal/cmdline.c +++ b/normal/cmdline.c @@ -431,6 +431,7 @@ void grub_cmdline_run (int nested) { grub_normal_init_page (); + grub_setcursor (1); grub_printf ("\ [ Minimal BASH-like line editing is supported. For the first word, TAB\n\ diff --git a/normal/menu.c b/normal/menu.c index 1debeb27a..e8d77070a 100644 --- a/normal/menu.c +++ b/normal/menu.c @@ -24,67 +24,6 @@ #include #include -/* FIXME: These below are all runaround. */ - -#define DISP_LEFT 0x2190 -#define DISP_UP 0x2191 -#define DISP_RIGHT 0x2192 -#define DISP_DOWN 0x2193 -#define DISP_HLINE 0x2501 -#define DISP_VLINE 0x2503 -#define DISP_UL 0x250F -#define DISP_UR 0x2513 -#define DISP_LL 0x2517 -#define DISP_LR 0x251B - -/* FIXME: These should be dynamically obtained from a terminal. */ -#define TERM_WIDTH 80 -#define TERM_HEIGHT 25 - -/* The number of lines of "GRUB version..." at the top. */ -#define TERM_INFO_HEIGHT 1 - -/* The number of columns/lines between messages/borders/etc. */ -#define TERM_MARGIN 1 - -/* The number of columns of scroll information. */ -#define TERM_SCROLL_WIDTH 1 - -/* The Y position of the top border. */ -#define TERM_TOP_BORDER_Y (TERM_MARGIN + TERM_INFO_HEIGHT + TERM_MARGIN) - -/* The X position of the left border. */ -#define TERM_LEFT_BORDER_X TERM_MARGIN - -/* The width of the border. */ -#define TERM_BORDER_WIDTH (TERM_WIDTH \ - - TERM_MARGIN * 3 \ - - TERM_SCROLL_WIDTH) - -/* The number of lines of messages at the bottom. */ -#define TERM_MESSAGE_HEIGHT 8 - -/* The height of the border. */ -#define TERM_BORDER_HEIGHT (TERM_HEIGHT \ - - TERM_TOP_BORDER_Y \ - - TERM_MESSAGE_HEIGHT) - -/* The number of entries shown at a time. */ -#define TERM_NUM_ENTRIES (TERM_BORDER_HEIGHT - 2) - -/* The Y position of the first entry. */ -#define TERM_FIRST_ENTRY_Y (TERM_TOP_BORDER_Y + 1) - -/* The max column number of an entry. The last "-1" is for a - continuation marker. */ -#define TERM_ENTRY_WIDTH (TERM_BORDER_WIDTH - 2 - TERM_MARGIN * 2 - 1) - -/* The standard X position of the cursor. */ -#define TERM_CURSOR_X (TERM_LEFT_BORDER_X \ - + TERM_BORDER_WIDTH \ - - TERM_MARGIN \ - - 1) - static void draw_border (void) { @@ -92,29 +31,29 @@ draw_border (void) grub_setcolorstate (GRUB_TERM_COLOR_NORMAL); - grub_gotoxy (TERM_MARGIN, TERM_TOP_BORDER_Y); - grub_putcode (DISP_UL); - for (i = 0; i < TERM_BORDER_WIDTH - 2; i++) - grub_putcode (DISP_HLINE); - grub_putcode (DISP_UR); + grub_gotoxy (GRUB_TERM_MARGIN, GRUB_TERM_TOP_BORDER_Y); + grub_putcode (GRUB_TERM_DISP_UL); + for (i = 0; i < GRUB_TERM_BORDER_WIDTH - 2; i++) + grub_putcode (GRUB_TERM_DISP_HLINE); + grub_putcode (GRUB_TERM_DISP_UR); - for (i = 0; i < (unsigned) TERM_NUM_ENTRIES; i++) + for (i = 0; i < (unsigned) GRUB_TERM_NUM_ENTRIES; i++) { - grub_gotoxy (TERM_MARGIN, TERM_TOP_BORDER_Y + i + 1); - grub_putcode (DISP_VLINE); - grub_gotoxy (TERM_MARGIN + TERM_BORDER_WIDTH - 1, TERM_TOP_BORDER_Y + i + 1); - grub_putcode (DISP_VLINE); + grub_gotoxy (GRUB_TERM_MARGIN, GRUB_TERM_TOP_BORDER_Y + i + 1); + grub_putcode (GRUB_TERM_DISP_VLINE); + grub_gotoxy (GRUB_TERM_MARGIN + GRUB_TERM_BORDER_WIDTH - 1, GRUB_TERM_TOP_BORDER_Y + i + 1); + grub_putcode (GRUB_TERM_DISP_VLINE); } - grub_gotoxy (TERM_MARGIN, TERM_TOP_BORDER_Y + TERM_NUM_ENTRIES + 1); - grub_putcode (DISP_LL); - for (i = 0; i < TERM_BORDER_WIDTH - 2; i++) - grub_putcode (DISP_HLINE); - grub_putcode (DISP_LR); + grub_gotoxy (GRUB_TERM_MARGIN, GRUB_TERM_TOP_BORDER_Y + GRUB_TERM_NUM_ENTRIES + 1); + grub_putcode (GRUB_TERM_DISP_LL); + for (i = 0; i < GRUB_TERM_BORDER_WIDTH - 2; i++) + grub_putcode (GRUB_TERM_DISP_HLINE); + grub_putcode (GRUB_TERM_DISP_LR); grub_setcolorstate (GRUB_TERM_COLOR_STANDARD); - grub_gotoxy (TERM_MARGIN, TERM_TOP_BORDER_Y + TERM_NUM_ENTRIES + TERM_MARGIN + 1); + grub_gotoxy (GRUB_TERM_MARGIN, GRUB_TERM_TOP_BORDER_Y + GRUB_TERM_NUM_ENTRIES + GRUB_TERM_MARGIN + 1); } static void @@ -131,7 +70,7 @@ print_message (int nested, int edit) { grub_printf ("\n\ Use the %C and %C keys to select which entry is highlighted.\n", - (grub_uint32_t) DISP_UP, (grub_uint32_t) DISP_DOWN); + (grub_uint32_t) GRUB_TERM_DISP_UP, (grub_uint32_t) GRUB_TERM_DISP_DOWN); grub_printf ("\ Press enter to boot the selected OS, \'e\' to edit the\n\ commands before booting or \'c\' for a command-line."); @@ -165,23 +104,23 @@ print_entry (int y, int highlight, grub_menu_entry_t entry) ? GRUB_TERM_COLOR_HIGHLIGHT : GRUB_TERM_COLOR_NORMAL); - grub_gotoxy (TERM_LEFT_BORDER_X + TERM_MARGIN, y); - grub_putchar (' '); - for (x = TERM_LEFT_BORDER_X + TERM_MARGIN + 1; - x < TERM_LEFT_BORDER_X + TERM_BORDER_WIDTH - TERM_MARGIN; + grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN, y); + + for (x = GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1; + x < GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH - GRUB_TERM_MARGIN; x++) { - if (*title && x <= TERM_LEFT_BORDER_X + TERM_BORDER_WIDTH - TERM_MARGIN - 1) + if (*title && x <= GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH - GRUB_TERM_MARGIN - 1) { - if (x == TERM_LEFT_BORDER_X + TERM_BORDER_WIDTH - TERM_MARGIN - 1) - grub_putcode (DISP_RIGHT); + if (x == GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH - GRUB_TERM_MARGIN - 1) + grub_putcode (GRUB_TERM_DISP_RIGHT); else grub_putchar (*title++); } else grub_putchar (' '); } - grub_gotoxy (TERM_CURSOR_X, y); + grub_gotoxy (GRUB_TERM_CURSOR_X, y); grub_setcolorstate (GRUB_TERM_COLOR_STANDARD); } @@ -192,49 +131,45 @@ print_entries (grub_menu_t menu, int first, int offset) grub_menu_entry_t e; int i; - grub_gotoxy (TERM_LEFT_BORDER_X + TERM_BORDER_WIDTH, - TERM_FIRST_ENTRY_Y); + grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH, + GRUB_TERM_FIRST_ENTRY_Y); if (first) - grub_putcode (DISP_UP); + grub_putcode (GRUB_TERM_DISP_UP); else grub_putchar (' '); e = get_entry (menu, first); - for (i = 0; i < TERM_NUM_ENTRIES; i++) + for (i = 0; i < GRUB_TERM_NUM_ENTRIES; i++) { - print_entry (TERM_FIRST_ENTRY_Y + i, offset == i, e); + print_entry (GRUB_TERM_FIRST_ENTRY_Y + i, offset == i, e); if (e) e = e->next; } - grub_gotoxy (TERM_LEFT_BORDER_X + TERM_BORDER_WIDTH, - TERM_TOP_BORDER_Y + TERM_NUM_ENTRIES); + grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH, + GRUB_TERM_TOP_BORDER_Y + GRUB_TERM_NUM_ENTRIES); if (e) - grub_putcode (DISP_DOWN); + grub_putcode (GRUB_TERM_DISP_DOWN); else grub_putchar (' '); - grub_gotoxy (TERM_CURSOR_X, TERM_FIRST_ENTRY_Y + offset); + grub_gotoxy (GRUB_TERM_CURSOR_X, GRUB_TERM_FIRST_ENTRY_Y + offset); } -static void -init_page (int nested, int edit) +/* Initialize the screen. If NESTED is non-zero, assume that this menu + is run from another menu or a command-line. If EDIT is non-zero, show + a message for the menu entry editor. */ +void +grub_menu_init_page (int nested, int edit) { grub_normal_init_page (); draw_border (); print_message (nested, edit); } -/* Edit a menu entry with an Emacs-like interface. */ -static void -edit_menu_entry (grub_menu_entry_t entry) -{ - /* Not yet implemented. */ -} - static int run_menu (grub_menu_t menu, int nested) { @@ -243,10 +178,10 @@ run_menu (grub_menu_t menu, int nested) first = 0; offset = menu->default_entry; - if (offset > TERM_NUM_ENTRIES - 1) + if (offset > GRUB_TERM_NUM_ENTRIES - 1) { - first = offset - (TERM_NUM_ENTRIES - 1); - offset = TERM_NUM_ENTRIES - 1; + first = offset - (GRUB_TERM_NUM_ENTRIES - 1); + offset = GRUB_TERM_NUM_ENTRIES - 1; } /* Initialize the time. */ @@ -254,7 +189,7 @@ run_menu (grub_menu_t menu, int nested) refresh: grub_setcursor (0); - init_page (nested, 0); + grub_menu_init_page (nested, 0); print_entries (menu, first, offset); grub_refresh (); @@ -273,13 +208,13 @@ run_menu (grub_menu_t menu, int nested) saved_time = current_time; } - grub_gotoxy (0, TERM_HEIGHT - 3); + grub_gotoxy (0, GRUB_TERM_HEIGHT - 3); /* NOTE: Do not remove the trailing space characters. They are required to clear the line. */ grub_printf ("\ The highlighted entry will be booted automatically in %d seconds. ", menu->timeout); - grub_gotoxy (TERM_CURSOR_X, TERM_FIRST_ENTRY_Y + offset); + grub_gotoxy (GRUB_TERM_CURSOR_X, GRUB_TERM_FIRST_ENTRY_Y + offset); grub_refresh (); } @@ -292,12 +227,12 @@ run_menu (grub_menu_t menu, int nested) if (menu->timeout >= 0) { - grub_gotoxy (0, TERM_HEIGHT - 3); + grub_gotoxy (0, GRUB_TERM_HEIGHT - 3); grub_printf ("\ "); menu->timeout = -1; menu->fallback_entry = -1; - grub_gotoxy (TERM_CURSOR_X, TERM_FIRST_ENTRY_Y + offset); + grub_gotoxy (GRUB_TERM_CURSOR_X, GRUB_TERM_FIRST_ENTRY_Y + offset); } switch (c) @@ -306,10 +241,10 @@ run_menu (grub_menu_t menu, int nested) case '^': if (offset > 0) { - print_entry (TERM_FIRST_ENTRY_Y + offset, 0, + print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 0, get_entry (menu, first + offset)); offset--; - print_entry (TERM_FIRST_ENTRY_Y + offset, 1, + print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 1, get_entry (menu, first + offset)); } else if (first > 0) @@ -323,12 +258,12 @@ run_menu (grub_menu_t menu, int nested) case 'v': if (menu->size > first + offset + 1) { - if (offset < TERM_NUM_ENTRIES - 1) + if (offset < GRUB_TERM_NUM_ENTRIES - 1) { - print_entry (TERM_FIRST_ENTRY_Y + offset, 0, + print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 0, get_entry (menu, first + offset)); offset++; - print_entry (TERM_FIRST_ENTRY_Y + offset, 1, + print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 1, get_entry (menu, first + offset)); } else @@ -354,12 +289,11 @@ run_menu (grub_menu_t menu, int nested) break; case 'c': - grub_setcursor (1); grub_cmdline_run (1); goto refresh; case 'e': - edit_menu_entry (get_entry (menu, first + offset)); + grub_menu_entry_run (get_entry (menu, first + offset)); goto refresh; default: diff --git a/normal/menu_entry.c b/normal/menu_entry.c new file mode 100644 index 000000000..5b11ed90f --- /dev/null +++ b/normal/menu_entry.c @@ -0,0 +1,1016 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +enum update_mode + { + NO_LINE, + SINGLE_LINE, + ALL_LINES + }; + +struct line +{ + /* The line buffer. */ + char *buf; + /* The length of the line. */ + int len; + /* The maximum length of the line. */ + int max_len; +}; + +struct screen +{ + /* The array of lines. */ + struct line *lines; + /* The number of lines. */ + int num_lines; + /* The current column. */ + int column; + /* The real column. */ + int real_column; + /* The current line. */ + int line; + /* The X coordinate. */ + int x; + /* The Y coordinate. */ + int y; + /* The kill buffer. */ + char *killed_text; +}; + +/* Initialize a line. */ +static int +init_line (struct line *linep) +{ + linep->len = 0; + linep->max_len = 80; /* XXX */ + linep->buf = grub_malloc (linep->max_len); + if (! linep->buf) + return 0; + + return 1; +} + +/* Allocate extra space if necessary. */ +static int +ensure_space (struct line *linep, int extra) +{ + if (linep->max_len < linep->len + extra) + { + linep->max_len = linep->len + extra + 80; /* XXX */ + linep->buf = grub_realloc (linep->buf, linep->max_len + 1); + if (! linep->buf) + return 0; + } + + return 1; +} + +/* Return the number of lines occupied by this line on the screen. */ +static int +get_logical_num_lines (struct line *linep) +{ + return (linep->len / GRUB_TERM_ENTRY_WIDTH) + 1; +} + +/* Print a line. */ +static void +print_line (struct line *linep, int offset, int start, int y) +{ + int i; + char *p; + + grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + start + 1, + y + GRUB_TERM_FIRST_ENTRY_Y); + + for (p = linep->buf + offset + start, i = start; + i < GRUB_TERM_ENTRY_WIDTH && offset + i < linep->len; + p++, i++) + grub_putchar (*p); + + for (; i < GRUB_TERM_ENTRY_WIDTH; i++) + grub_putchar (' '); + + if (linep->len >= offset + GRUB_TERM_ENTRY_WIDTH) + grub_putchar ('\\'); + else + grub_putchar (' '); +} + +/* Print an empty line. */ +static void +print_empty_line (int y) +{ + int i; + + grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1, + y + GRUB_TERM_FIRST_ENTRY_Y); + + for (i = 0; i < GRUB_TERM_ENTRY_WIDTH + 1; i++) + grub_putchar (' '); +} + +/* Print an up arrow. */ +static void +print_up (int flag) +{ + grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH, + GRUB_TERM_FIRST_ENTRY_Y); + + if (flag) + grub_putcode (GRUB_TERM_DISP_UP); + else + grub_putchar (' '); +} + +/* Print a down arrow. */ +static void +print_down (int flag) +{ + grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH, + GRUB_TERM_TOP_BORDER_Y + GRUB_TERM_NUM_ENTRIES); + + if (flag) + grub_putcode (GRUB_TERM_DISP_DOWN); + else + grub_putchar (' '); +} + +/* Draw the lines of the screen SCREEN. */ +static void +update_screen (struct screen *screen, int region_start, int region_column, + int up, int down, enum update_mode mode) +{ + int up_flag = 0; + int down_flag = 0; + int y; + int i; + struct line *linep; + + /* Check if scrolling is necessary. */ + if (screen->y < 0 || screen->y >= GRUB_TERM_NUM_ENTRIES) + { + if (screen->y < 0) + screen->y = 0; + else + screen->y = GRUB_TERM_NUM_ENTRIES - 1; + + region_start = 0; + region_column = 0; + up = 1; + down = 1; + mode = ALL_LINES; + } + + if (mode != NO_LINE) + { + /* Draw lines. This code is tricky, because this must calculate logical + positions. */ + y = screen->y - screen->column / GRUB_TERM_ENTRY_WIDTH; + i = screen->line; + linep = screen->lines + i; + while (y > 0) + { + i--; + linep--; + y -= get_logical_num_lines (linep); + } + + if (y < 0 || i > 0) + up_flag = 1; + + do + { + int column; + + for (column = 0; + column <= linep->len && y < GRUB_TERM_NUM_ENTRIES; + column += GRUB_TERM_ENTRY_WIDTH, y++) + { + if (y < 0) + continue; + + if (i == region_start) + { + if (region_column >= column + && region_column < column + GRUB_TERM_ENTRY_WIDTH) + print_line (linep, column, region_column - column, y); + else if (region_column < column) + print_line (linep, column, 0, y); + } + else if (i > region_start && mode == ALL_LINES) + print_line (linep, column, 0, y); + } + + if (y == GRUB_TERM_NUM_ENTRIES) + { + if (column <= linep->len || i + 1 < screen->num_lines) + down_flag = 1; + } + + linep++; + i++; + + if (mode == ALL_LINES && i == screen->num_lines) + for (; y < GRUB_TERM_NUM_ENTRIES; y++) + print_empty_line (y); + + } + while (y < GRUB_TERM_NUM_ENTRIES); + + /* Draw up and down arrows. */ + if (up) + print_up (up_flag); + if (down) + print_down (down_flag); + } + + /* Place the cursor. */ + grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1 + screen->x, + GRUB_TERM_FIRST_ENTRY_Y + screen->y); + + grub_refresh (); +} + +/* Insert the string S into the screen SCREEN. This updates the cursor + position and redraw the screen. Return zero if fails. */ +static int +insert_string (struct screen *screen, char *s, int update) +{ + int region_start = screen->num_lines; + int region_column = 0; + int down = 0; + enum update_mode mode = NO_LINE; + + while (*s) + { + if (*s == '\n') + { + /* LF is special because it creates a new line. */ + struct line *current_linep; + struct line *next_linep; + int size; + + /* Make a new line. */ + screen->num_lines++; + screen->lines = grub_realloc (screen->lines, + screen->num_lines + * sizeof (struct line)); + if (! screen->lines) + return 0; + + /* Scroll down. */ + grub_memmove (screen->lines + screen->line + 2, + screen->lines + screen->line + 1, + ((screen->num_lines - screen->line - 2) + * sizeof (struct line))); + + if (! init_line (screen->lines + screen->line + 1)) + return 0; + + /* Fold the line. */ + current_linep = screen->lines + screen->line; + next_linep = current_linep + 1; + size = current_linep->len - screen->column; + + if (! ensure_space (next_linep, size)) + return 0; + + grub_memmove (next_linep->buf, + current_linep->buf + screen->column, + size); + current_linep->len = screen->column; + next_linep->len = size; + + /* Update a dirty region. */ + if (region_start > screen->line) + { + region_start = screen->line; + region_column = screen->column; + } + + mode = ALL_LINES; + down = 1; /* XXX not optimal. */ + + /* Move the cursor. */ + screen->column = screen->real_column = 0; + screen->line++; + screen->x = 0; + screen->y++; + + s++; + } + else + { + /* All but LF. */ + char *p; + struct line *current_linep; + int size; + int orig_num, new_num; + + /* Find a string delimitted by LF. */ + p = grub_strchr (s, '\n'); + if (! p) + p = s + grub_strlen (s); + + /* Insert the string. */ + current_linep = screen->lines + screen->line; + size = p - s; + if (! ensure_space (current_linep, size)) + return 0; + + grub_memmove (current_linep->buf + screen->column + size, + current_linep->buf + screen->column, + current_linep->len - screen->column); + grub_memmove (current_linep->buf + screen->column, + s, + size); + orig_num = get_logical_num_lines (current_linep); + current_linep->len += size; + new_num = get_logical_num_lines (current_linep); + + /* Update the dirty region. */ + if (region_start > screen->line) + { + region_start = screen->line; + region_column = screen->column; + } + + if (orig_num != new_num) + { + mode = ALL_LINES; + down = 1; /* XXX not optimal. */ + } + else if (mode != ALL_LINES) + mode = SINGLE_LINE; + + /* Move the cursor. */ + screen->column += size; + screen->real_column = screen->column; + screen->x += size; + screen->y += screen->x / GRUB_TERM_ENTRY_WIDTH; + screen->x %= GRUB_TERM_ENTRY_WIDTH; + + s = p; + } + } + + if (update) + update_screen (screen, region_start, region_column, 0, down, mode); + + return 1; +} + +/* Release the resource allocated for SCREEN. */ +static void +destroy_screen (struct screen *screen) +{ + int i; + + if (screen->lines) + for (i = 0; i < screen->num_lines; i++) + { + struct line *linep = screen->lines + i; + + if (linep) + grub_free (linep->buf); + } + + grub_free (screen->killed_text); + grub_free (screen->lines); + grub_free (screen); +} + +/* Make a new screen. */ +static struct screen * +make_screen (grub_menu_entry_t entry) +{ + struct screen *screen; + grub_command_list_t cl; + + /* Initialize the screen. */ + screen = grub_malloc (sizeof (*screen)); + if (! screen) + return 0; + + screen->num_lines = 1; + screen->column = 0; + screen->real_column = 0; + screen->line = 0; + screen->x = 0; + screen->y = 0; + screen->killed_text = 0; + screen->lines = grub_malloc (sizeof (struct line)); + if (! screen->lines) + goto fail; + + /* Initialize the first line which must be always present. */ + if (! init_line (screen->lines)) + goto fail; + + /* Input the entry. */ + for (cl = entry->command_list; cl; cl = cl->next) + { + if (! insert_string (screen, cl->command, 0)) + goto fail; + + if (! insert_string (screen, "\n", 0)) + goto fail; + } + + /* Reset the cursor position. */ + screen->column = 0; + screen->real_column = 0; + screen->line = 0; + screen->x = 0; + screen->y = 0; + + return screen; + + fail: + destroy_screen (screen); + return 0; +} + +static int +forward_char (struct screen *screen, int update) +{ + struct line *linep; + + linep = screen->lines + screen->line; + if (screen->column < linep->len) + { + screen->column++; + screen->x++; + if (screen->x == GRUB_TERM_ENTRY_WIDTH) + { + screen->x = 0; + screen->y++; + } + } + else if (screen->num_lines > screen->line + 1) + { + screen->column = 0; + screen->line++; + screen->x = 0; + screen->y++; + } + + screen->real_column = screen->column; + + if (update) + update_screen (screen, screen->num_lines, 0, 0, 0, NO_LINE); + return 1; +} + +static int +backward_char (struct screen *screen, int update) +{ + if (screen->column > 0) + { + screen->column--; + screen->x--; + if (screen->x == -1) + { + screen->x = GRUB_TERM_ENTRY_WIDTH - 1; + screen->y--; + } + } + else if (screen->line > 0) + { + struct line *linep; + + screen->line--; + linep = screen->lines + screen->line; + screen->column = linep->len; + screen->x = screen->column % GRUB_TERM_ENTRY_WIDTH; + screen->y--; + } + + screen->real_column = screen->column; + + if (update) + update_screen (screen, screen->num_lines, 0, 0, 0, NO_LINE); + + return 1; +} + +static int +previous_line (struct screen *screen, int update) +{ + if (screen->line > 0) + { + struct line *linep; + int dy; + + /* How many physical lines from the current position + to the first physical line? */ + dy = screen->column / GRUB_TERM_ENTRY_WIDTH; + + screen->line--; + + linep = screen->lines + screen->line; + if (linep->len < screen->real_column) + screen->column = linep->len; + else + screen->column = screen->real_column; + + /* How many physical lines from the current position + to the last physical line? */ + dy += (linep->len / GRUB_TERM_ENTRY_WIDTH + - screen->column / GRUB_TERM_ENTRY_WIDTH); + + screen->y -= dy + 1; + screen->x = screen->column % GRUB_TERM_ENTRY_WIDTH; + } + else + { + screen->y -= screen->column / GRUB_TERM_ENTRY_WIDTH; + screen->column = 0; + screen->x = 0; + } + + if (update) + update_screen (screen, screen->num_lines, 0, 0, 0, NO_LINE); + + return 1; +} + +static int +next_line (struct screen *screen, int update) +{ + if (screen->line < screen->num_lines - 1) + { + struct line *linep; + int dy; + + /* How many physical lines from the current position + to the last physical line? */ + linep = screen->lines + screen->line; + dy = (linep->len / GRUB_TERM_ENTRY_WIDTH + - screen->column / GRUB_TERM_ENTRY_WIDTH); + + screen->line++; + + linep++; + if (linep->len < screen->real_column) + screen->column = linep->len; + else + screen->column = screen->real_column; + + /* How many physical lines from the current position + to the first physical line? */ + dy += screen->column / GRUB_TERM_ENTRY_WIDTH; + + screen->y += dy + 1; + screen->x = screen->column % GRUB_TERM_ENTRY_WIDTH; + } + else + { + struct line *linep; + + linep = screen->lines + screen->line; + screen->y += (linep->len / GRUB_TERM_ENTRY_WIDTH + - screen->column / GRUB_TERM_ENTRY_WIDTH); + screen->column = linep->len; + screen->x = screen->column % GRUB_TERM_ENTRY_WIDTH; + } + + if (update) + update_screen (screen, screen->num_lines, 0, 0, 0, NO_LINE); + + return 1; +} + +static int +beginning_of_line (struct screen *screen, int update) +{ + screen->y -= screen->column / GRUB_TERM_ENTRY_WIDTH; + screen->column = screen->real_column = 0; + screen->x = 0; + + if (update) + update_screen (screen, screen->num_lines, 0, 0, 0, NO_LINE); + + return 1; +} + +static int +end_of_line (struct screen *screen, int update) +{ + struct line *linep; + + linep = screen->lines + screen->line; + screen->y += (linep->len / GRUB_TERM_ENTRY_WIDTH + - screen->column / GRUB_TERM_ENTRY_WIDTH); + screen->column = screen->real_column = linep->len; + screen->x = screen->column % GRUB_TERM_ENTRY_WIDTH; + + if (update) + update_screen (screen, screen->num_lines, 0, 0, 0, NO_LINE); + + return 1; +} + +static int +delete_char (struct screen *screen, int update) +{ + struct line *linep; + enum update_mode mode = NO_LINE; + int start = screen->num_lines; + int column = 0; + int down = 0; + + linep = screen->lines + screen->line; + if (linep->len > screen->column) + { + int orig_num, new_num; + + orig_num = get_logical_num_lines (linep); + + grub_memmove (linep->buf + screen->column, + linep->buf + screen->column + 1, + linep->len - screen->column - 1); + linep->len--; + + new_num = get_logical_num_lines (linep); + + if (orig_num != new_num) + mode = ALL_LINES; + else + mode = SINGLE_LINE; + + start = screen->line; + column = screen->column; + } + else if (screen->num_lines > screen->line + 1) + { + struct line *next_linep; + + next_linep = linep + 1; + if (! ensure_space (linep, next_linep->len)) + return 0; + + grub_memmove (linep->buf + linep->len, next_linep->buf, next_linep->len); + linep->len += next_linep->len; + + grub_free (next_linep->buf); + grub_memmove (next_linep, + next_linep + 1, + (screen->num_lines - screen->line - 2) + * sizeof (struct line)); + screen->num_lines--; + + mode = ALL_LINES; + start = screen->line; + column = screen->column; + down = 1; + } + + screen->real_column = screen->column; + + if (update) + update_screen (screen, start, column, 0, down, mode); + + return 1; +} + +static int +backward_delete_char (struct screen *screen, int update) +{ + int saved_column; + int saved_line; + + saved_column = screen->column; + saved_line = screen->line; + + if (! backward_char (screen, 0)) + return 0; + + if (saved_column != screen->column || saved_line != screen->line) + if (! delete_char (screen, update)) + return 0; + + return 1; +} + +static int +kill_line (struct screen *screen, int continuous, int update) +{ + struct line *linep; + char *p; + int size; + int offset; + + p = screen->killed_text; + if (! continuous && p) + p[0] = '\0'; + + linep = screen->lines + screen->line; + size = linep->len - screen->column; + + if (p) + offset = grub_strlen (p); + else + offset = 0; + + if (size > 0) + { + enum update_mode mode = SINGLE_LINE; + int down = 0; + int orig_num, new_num; + + p = grub_realloc (p, offset + size + 1); + if (! p) + return 0; + + grub_memmove (p + offset, linep->buf + screen->column, size); + p[offset + size - 1] = '\0'; + + screen->killed_text = p; + + orig_num = get_logical_num_lines (linep); + linep->len = screen->column; + new_num = get_logical_num_lines (linep); + + if (orig_num != new_num) + { + mode = ALL_LINES; + down = 1; + } + + if (update) + update_screen (screen, screen->line, screen->column, 0, down, mode); + } + else if (screen->line + 1 < screen->num_lines) + { + p = grub_realloc (p, offset + 1 + 1); + if (! p) + return 0; + + p[offset] = '\n'; + p[offset + 1] = '\0'; + + screen->killed_text = p; + + return delete_char (screen, update); + } + + return 1; +} + +static int +yank (struct screen *screen, int update) +{ + if (screen->killed_text) + return insert_string (screen, screen->killed_text, update); + + return 1; +} + +static int +open_line (struct screen *screen, int update) +{ + int saved_y = screen->y; + + if (! insert_string (screen, "\n", 0)) + return 0; + + if (! backward_char (screen, 0)) + return 0; + + screen->y = saved_y; + + if (update) + update_screen (screen, screen->line, screen->column, 0, 1, ALL_LINES); + + return 1; +} + +/* Execute the command list in the screen SCREEN. */ +static int +run (struct screen *screen) +{ + int i; + + grub_cls (); + grub_printf (" Booting a command list\n\n"); + + for (i = 0; i < screen->num_lines; i++) + { + struct line *linep = screen->lines + i; + char *p; + grub_command_t c; + + /* Trim down space characters. */ + for (p = linep->buf + linep->len - 1; + p >= linep->buf && grub_isspace (*p); + p--) + ; + *++p = '\0'; + linep->len = p - linep->buf; + + for (p = linep->buf; grub_isspace (*p); p++) + ; + + if (*p == '\0') + /* Ignore an empty command line. */ + continue; + + c = grub_command_find (p); + if (! c) + break; + + if (! (c->flags & GRUB_COMMAND_FLAG_CMDLINE)) + { + grub_error (GRUB_ERR_INVALID_COMMAND, "invalid command `%s'", p); + break; + } + + if (! (c->flags & GRUB_COMMAND_FLAG_NO_ECHO)) + grub_printf ("%s\n", p); + + if (grub_command_execute (p) != 0) + break; + } + + if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ()) + /* Implicit execution of boot, only if something is loaded. */ + grub_command_execute ("boot"); + + if (grub_errno != GRUB_ERR_NONE) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + /* Wait until the user pushes any key so that the user + can see what happened. */ + grub_printf ("\nPress any key to continue..."); + (void) grub_getkey (); + } + + return 1; +} + +/* Edit a menu entry with an Emacs-like interface. */ +void +grub_menu_entry_run (grub_menu_entry_t entry) +{ + struct screen *screen; + int prev_c; + + screen = make_screen (entry); + if (! screen) + return; + + refresh: + /* Draw the screen. */ + grub_menu_init_page (0, 1); + update_screen (screen, 0, 0, 1, 1, ALL_LINES); + grub_setcursor (1); + prev_c = '\0'; + + while (1) + { + int c = GRUB_TERM_ASCII_CHAR (grub_getkey ()); + + switch (c) + { + case 16: /* C-p */ + if (! previous_line (screen, 1)) + goto fail; + break; + + case 14: /* C-n */ + if (! next_line (screen, 1)) + goto fail; + break; + + case 6: /* C-f */ + if (! forward_char (screen, 1)) + goto fail; + break; + + case 2: /* C-b */ + if (! backward_char (screen, 1)) + goto fail; + break; + + case 1: /* C-a */ + if (! beginning_of_line (screen, 1)) + goto fail; + break; + + case 5: /* C-e */ + if (! end_of_line (screen, 1)) + goto fail; + break; + + case '\t': /* C-i */ + /* FIXME: Completion */ + break; + + case 4: /* C-d */ + if (! delete_char (screen, 1)) + goto fail; + break; + + case 8: /* C-h */ + if (! backward_delete_char (screen, 1)) + goto fail; + break; + + case 11: /* C-k */ + if (! kill_line (screen, prev_c == c, 1)) + goto fail; + break; + + case 21: /* C-u */ + /* FIXME: What behavior is good for this key? */ + break; + + case 25: /* C-y */ + if (! yank (screen, 1)) + goto fail; + break; + + case 12: /* C-l */ + /* FIXME: centering. */ + goto refresh; + + case 15: /* C-o */ + if (! open_line (screen, 1)) + goto fail; + break; + + case '\n': + case '\r': + if (! insert_string (screen, "\n", 1)) + goto fail; + break; + + case '\e': + destroy_screen (screen); + return; + + case 3: /* C-c */ + grub_cmdline_run (1); + goto refresh; + + case 24: /* C-x */ + if (! run (screen)) + goto fail; + goto refresh; + + case 18: /* C-r */ + case 19: /* C-s */ + case 20: /* C-t */ + /* FIXME */ + break; + + default: + if (grub_isprint (c)) + { + char buf[2]; + + buf[0] = c; + buf[1] = '\0'; + if (! insert_string (screen, buf, 1)) + goto fail; + } + break; + } + + prev_c = c; + } + + fail: + destroy_screen (screen); + + grub_cls (); + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + grub_printf ("\nPress any key to continue..."); + (void) grub_getkey (); +} diff --git a/util/console.c b/util/console.c index 574059080..3f00b7335 100644 --- a/util/console.c +++ b/util/console.c @@ -28,6 +28,44 @@ static int grub_console_attr = A_NORMAL; static void grub_ncurses_putchar (grub_uint32_t c) { + /* Better than nothing. */ + switch (c) + { + case GRUB_TERM_DISP_LEFT: + c = '<'; + break; + + case GRUB_TERM_DISP_UP: + c = '^'; + break; + + case GRUB_TERM_DISP_RIGHT: + c = '>'; + break; + + case GRUB_TERM_DISP_DOWN: + c = 'v'; + break; + + case GRUB_TERM_DISP_HLINE: + c = '-'; + break; + + case GRUB_TERM_DISP_VLINE: + c = '|'; + break; + + case GRUB_TERM_DISP_UL: + case GRUB_TERM_DISP_UR: + case GRUB_TERM_DISP_LL: + case GRUB_TERM_DISP_LR: + c = '+'; + break; + + default: + break; + } + addch (c | grub_console_attr); } @@ -57,16 +95,46 @@ grub_ncurses_setcolor (grub_uint8_t normal_color, grub_uint8_t highlight_color) color_set (normal_color << 8 | highlight_color, 0); } +static int saved_char = ERR; + static int grub_ncurses_checkkey (void) { - return 1; + int c; + + /* Check for SAVED_CHAR. This should not be true, because this + means checkkey is called twice continuously. */ + if (saved_char != ERR) + return 1; + + wtimeout (stdscr, 100); + c = getch (); + /* If C is not ERR, then put it back in the input queue. */ + if (c != ERR) + { + saved_char = c; + return 1; + } + + return 0; } static int grub_ncurses_getkey (void) { - int c = getch (); + int c; + + /* If checkkey has already got a character, then return it. */ + if (saved_char != ERR) + { + c = saved_char; + saved_char = ERR; + } + else + { + wtimeout (stdscr, -1); + c = getch (); + } switch (c) { @@ -161,7 +229,7 @@ static grub_err_t grub_ncurses_init (void) { initscr (); - cbreak (); + raw (); noecho (); scrollok (stdscr, TRUE);