diff --git a/ChangeLog b/ChangeLog index f554ba858..237ca05b9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2013-04-26 Vladimir Serbinenko + + Replace libcurses with our own vt100 handling for the ease of testing + and decreasing prerequisites. + 2013-04-26 Vladimir Serbinenko * grub-core/Makefile.core.def: Fix grub-emu and grub-emu-lite sources. diff --git a/INSTALL b/INSTALL index 333368696..a626395b6 100644 --- a/INSTALL +++ b/INSTALL @@ -23,11 +23,11 @@ On GNU/Linux, you also need: * libdevmapper 1.02.34 or later (recommended) -To build grub-emu, you need: +For optional grub-emu features, you need: -* ncurses -* libusb (recommended) * SDL (recommended) +* libpciaccess (optional) +* libusb (optional) To build GRUB's graphical terminal (gfxterm), you need: diff --git a/configure.ac b/configure.ac index 7d3aeac9c..5ff7f25ac 100644 --- a/configure.ac +++ b/configure.ac @@ -842,22 +842,6 @@ AC_ARG_ENABLE([grub-emu-pci], [build and install the `grub-emu' debugging utility with PCI support (potentially dangerous) (default=no)])]) if test "$platform" = emu; then - missing_ncurses= -[# Check for curses libraries.] - AC_CHECK_LIB([ncurses], [wgetch], [LIBCURSES="-lncurses"], - [AC_CHECK_LIB([curses], [wgetch], [LIBCURSES="-lcurses"], - [missing_ncurses=[true]])]) - AC_SUBST([LIBCURSES]) -[if [ x"$missing_ncurses" = x ]; then ] - [# Check for headers.] - AC_CHECK_HEADERS([ncurses/curses.h], [], - [AC_CHECK_HEADERS([ncurses.h], [], - [AC_CHECK_HEADERS([curses.h], [], - [missing_ncurses=[true]])])]) -[fi] -if test x"$missing_ncurses" = xtrue ; then - AC_MSG_ERROR([grub-emu can't be compiled without ncurses]) -fi if test x"$enable_grub_emu_usb" != xyes ; then grub_emu_usb_excuse="not enabled" diff --git a/docs/grub.texi b/docs/grub.texi index 920a55850..754e1912b 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -4586,26 +4586,35 @@ On normalized ZFS subvolumes filenames out of normalisation are inaccessible. @chapter Output terminal Firmware output console ``console'' on ARC and IEEE1275 are limited to ASCII. + BIOS firmware console and VGA text are limited to ASCII and some pseudographics. + None of above mentioned is appropriate for displaying international and any unsupported character is replaced with question mark except pseudographics -which we attempt to approximate with ASCII. EFI console on the other hand -nominally supports UTF-16 but actual language coverage depends on firmware and -may be very limited. The encoding used on serial can be chosen with -@command{terminfo} as either ASCII, UTF-8 or ``visual UTF-8''. Last one is -against the specification but results in correct rendering of right-to-left -on some readers which don't have own bidi implementation. When using gfxterm -or gfxmenu GRUB itself is responsible for rendering the text. In this case -GRUB is limited by loaded fonts. If fonts contain all required characters -then bidirectional text, cursive variants and combining marks other than -enclosing, half (e.g. left half tilde or combining overline) and double ones. -Ligatures aren't supported though. This should cover European, Middle Eastern -(if you don't mind lack of lam-alif ligature in Arabic) and East Asian scripts. -Notable unsupported scripts are Brahmic family and derived as well as -Mongolian, Tifinagh, Korean Jamo (precomposed characters have no problem) -and tonal writing (2e5-2e9). GRUB also ignores deprecated (as specified -in Unicode) characters (e.g. tags). GRUB also doesn't handle so called -``annotation characters'' If you can complete either of +which we attempt to approximate with ASCII. + +EFI console on the other hand nominally supports UTF-16 but actual language +coverage depends on firmware and may be very limited. + +The encoding used on serial can be chosen with @command{terminfo} as +either ASCII, UTF-8 or ``visual UTF-8''. Last one is against the specification +but results in correct rendering of right-to-left on some readers which don't +have own bidi implementation. + +On emu GRUB checks if charset is UTF-8 and uses it if so and uses ASCII +otherwise. + +When using gfxterm or gfxmenu GRUB itself is responsible for rendering the +text. In this case GRUB is limited by loaded fonts. If fonts contain all +required characters then bidirectional text, cursive variants and combining +marks other than enclosing, half (e.g. left half tilde or combining overline) +and double ones. Ligatures aren't supported though. This should cover European, +Middle Eastern (if you don't mind lack of lam-alif ligature in Arabic) and +East Asian scripts. Notable unsupported scripts are Brahmic family and +derived as well as Mongolian, Tifinagh, Korean Jamo (precomposed characters +have no problem) and tonal writing (2e5-2e9). GRUB also ignores deprecated +(as specified in Unicode) characters (e.g. tags). GRUB also doesn't handle so +called ``annotation characters'' If you can complete either of two lists or, better, propose a patch to improve rendering, please contact developer team. @@ -4826,7 +4835,7 @@ and mips-qemu_mips can use only memory up to first hole. @multitable @columnfractions .20 .20 .20 .20 .20 @item @tab MIPS qemu @tab emu @item video @tab no @tab yes -@item console charset @tab CP437 @tab ASCII +@item console charset @tab CP437 @tab Unicode (*) @item network @tab no @tab yes @item ATA/AHCI @tab yes @tab no @item AT keyboard @tab yes @tab no diff --git a/gentpl.py b/gentpl.py index b159795a1..8674622f1 100644 --- a/gentpl.py +++ b/gentpl.py @@ -57,7 +57,7 @@ GROUPS["videomodules"] = GRUB_PLATFORMS[:]; for i in GROUPS["videoinkernel"]: GROUPS["videomodules"].remove(i) # Similar for terminfo -GROUPS["terminfoinkernel"] = ["mips_loongson", "mips_arc", "mips_qemu_mips" ] + GROUPS["ieee1275"]; +GROUPS["terminfoinkernel"] = [ "emu", "mips_loongson", "mips_arc", "mips_qemu_mips" ] + GROUPS["ieee1275"]; GROUPS["terminfomodule"] = GRUB_PLATFORMS[:]; for i in GROUPS["terminfoinkernel"]: GROUPS["terminfomodule"].remove(i) diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am index 07aad5086..fa6afcfad 100644 --- a/grub-core/Makefile.am +++ b/grub-core/Makefile.am @@ -216,6 +216,7 @@ if COND_emu KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/datetime.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/misc.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/export.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h if COND_GRUB_EMU_SDL KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/sdl.h endif diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index e2ecff10f..2a8ac6f5b 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -250,7 +250,7 @@ program = { ldadd = 'kernel.exec$(EXEEXT)'; ldadd = '$(MODULE_FILES)'; - ldadd = 'gnulib/libgnu.a $(LIBCURSES) $(LIBINTL) $(LIBUTIL) $(LIBSDL) $(LIBUSB) $(LIBPCIACCESS) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; + ldadd = 'gnulib/libgnu.a $(LIBINTL) $(LIBUTIL) $(LIBSDL) $(LIBUSB) $(LIBPCIACCESS) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; enable = emu; }; @@ -262,7 +262,7 @@ program = { emu_nodist = symlist.c; ldadd = 'kernel.exec$(EXEEXT)'; - ldadd = 'gnulib/libgnu.a $(LIBCURSES) $(LIBINTL) $(LIBUTIL) $(LIBSDL) $(LIBUSB) $(LIBPCIACCESS) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; + ldadd = 'gnulib/libgnu.a $(LIBINTL) $(LIBUTIL) $(LIBSDL) $(LIBUSB) $(LIBPCIACCESS) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; enable = emu; }; diff --git a/grub-core/term/emu/console.c b/grub-core/term/emu/console.c index 5bd5db1d8..d61ade167 100644 --- a/grub-core/term/emu/console.c +++ b/grub-core/term/emu/console.c @@ -1,7 +1,7 @@ -/* console.c -- Ncurses console for GRUB. */ +/* console.c -- console for GRUB. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2003,2005,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2013 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 @@ -20,274 +20,159 @@ #include #include -/* For compatibility. */ -#ifndef A_NORMAL -# define A_NORMAL 0 -#endif /* ! A_NORMAL */ -#ifndef A_STANDOUT -# define A_STANDOUT 0 -#endif /* ! A_STANDOUT */ - -#include #include #include +#include +#include +#include +#include +#include -#if defined(HAVE_NCURSES_CURSES_H) -# include -#elif defined(HAVE_NCURSES_H) -# include -#elif defined(HAVE_CURSES_H) -# include -#else -#error What the hell? -#endif +#include +#include +#include +#include +#include +#include +#include +#include -static int grub_console_attr = A_NORMAL; +#include -grub_uint8_t grub_console_cur_color = 7; - -static const grub_uint8_t grub_console_standard_color = 0x7; - -#define NUM_COLORS 8 - -static grub_uint8_t color_map[NUM_COLORS] = -{ - COLOR_BLACK, - COLOR_BLUE, - COLOR_GREEN, - COLOR_CYAN, - COLOR_RED, - COLOR_MAGENTA, - COLOR_YELLOW, - COLOR_WHITE -}; - -static int use_color; +extern struct grub_terminfo_output_state grub_console_terminfo_output; +static int original_fl; +static int saved_orig; +static struct termios orig_tty; +static struct termios new_tty; static void -grub_ncurses_putchar (struct grub_term_output *term __attribute__ ((unused)), - const struct grub_unicode_glyph *c) +put (struct grub_term_output *term __attribute__ ((unused)), const int c) { - addch (c->base | grub_console_attr); -} + char chr = c; -static void -grub_ncurses_setcolorstate (struct grub_term_output *term, - grub_term_color_state state) -{ - switch (state) - { - case GRUB_TERM_COLOR_STANDARD: - grub_console_cur_color = grub_console_standard_color; - grub_console_attr = A_NORMAL; - break; - case GRUB_TERM_COLOR_NORMAL: - grub_console_cur_color = grub_term_normal_color; - grub_console_attr = A_NORMAL; - break; - case GRUB_TERM_COLOR_HIGHLIGHT: - grub_console_cur_color = grub_term_highlight_color; - grub_console_attr = A_STANDOUT; - break; - default: - break; - } - - if (use_color) - { - grub_uint8_t fg, bg; - - fg = (grub_console_cur_color & 7); - bg = (grub_console_cur_color >> 4) & 7; - - grub_console_attr = (grub_console_cur_color & 8) ? A_BOLD : A_NORMAL; - color_set ((bg << 3) + fg, 0); - } + write (STDOUT_FILENO, &chr, 1); } static int -grub_ncurses_getkey (struct grub_term_input *term __attribute__ ((unused))) +readkey (struct grub_term_input *term __attribute__ ((unused))) { - int c; + grub_uint8_t c; + ssize_t actual; - wtimeout (stdscr, 100); - c = getch (); - - switch (c) - { - case ERR: - return GRUB_TERM_NO_KEY; - case KEY_LEFT: - c = GRUB_TERM_KEY_LEFT; - break; - - case KEY_RIGHT: - c = GRUB_TERM_KEY_RIGHT; - break; - - case KEY_UP: - c = GRUB_TERM_KEY_UP; - break; - - case KEY_DOWN: - c = GRUB_TERM_KEY_DOWN; - break; - - case KEY_IC: - c = 24; - break; - - case KEY_DC: - c = GRUB_TERM_KEY_DC; - break; - - case KEY_BACKSPACE: - /* XXX: For some reason ncurses on xterm does not return - KEY_BACKSPACE. */ - case 127: - c = '\b'; - break; - - case KEY_HOME: - c = GRUB_TERM_KEY_HOME; - break; - - case KEY_END: - c = GRUB_TERM_KEY_END; - break; - - case KEY_NPAGE: - c = GRUB_TERM_KEY_NPAGE; - break; - - case KEY_PPAGE: - c = GRUB_TERM_KEY_PPAGE; - break; - } - - return c; -} - -static grub_uint16_t -grub_ncurses_getxy (struct grub_term_output *term __attribute__ ((unused))) -{ - int x; - int y; - - getyx (stdscr, y, x); - - return (x << 8) | y; -} - -static grub_uint16_t -grub_ncurses_getwh (struct grub_term_output *term __attribute__ ((unused))) -{ - int x; - int y; - - getmaxyx (stdscr, y, x); - - return (x << 8) | y; -} - -static void -grub_ncurses_gotoxy (struct grub_term_output *term __attribute__ ((unused)), - grub_uint8_t x, grub_uint8_t y) -{ - move (y, x); -} - -static void -grub_ncurses_cls (struct grub_term_output *term __attribute__ ((unused))) -{ - clear (); - refresh (); -} - -static void -grub_ncurses_setcursor (struct grub_term_output *term __attribute__ ((unused)), - int on) -{ - curs_set (on ? 1 : 0); -} - -static void -grub_ncurses_refresh (struct grub_term_output *term __attribute__ ((unused))) -{ - refresh (); + actual = read (STDIN_FILENO, &c, 1); + if (actual > 0) + return c; + return -1; } static grub_err_t -grub_ncurses_init (struct grub_term_output *term __attribute__ ((unused))) +grub_console_init_input (struct grub_term_input *term) { - initscr (); - raw (); - noecho (); - scrollok (stdscr, TRUE); - - nonl (); - intrflush (stdscr, FALSE); - keypad (stdscr, TRUE); - - if (has_colors ()) + if (!saved_orig) { - start_color (); - - if ((COLORS >= NUM_COLORS) && (COLOR_PAIRS >= NUM_COLORS * NUM_COLORS)) - { - int i, j, n; - - n = 0; - for (i = 0; i < NUM_COLORS; i++) - for (j = 0; j < NUM_COLORS; j++) - init_pair(n++, color_map[j], color_map[i]); - - use_color = 1; - } + original_fl = fcntl (STDIN_FILENO, F_GETFL); + fcntl (STDIN_FILENO, F_SETFL, original_fl | O_NONBLOCK); } - return 0; + saved_orig = 1; + + tcgetattr(STDIN_FILENO, &orig_tty); + new_tty = orig_tty; + new_tty.c_lflag &= ~(ICANON | ECHO); + new_tty.c_cc[VMIN] = 1; + tcsetattr(STDIN_FILENO, TCSANOW, &new_tty); + + return grub_terminfo_input_init (term); } static grub_err_t -grub_ncurses_fini (struct grub_term_output *term __attribute__ ((unused))) +grub_console_fini_input (struct grub_term_input *term + __attribute__ ((unused))) { - endwin (); + fcntl (STDIN_FILENO, F_SETFL, original_fl); + tcsetattr(STDIN_FILENO, TCSANOW, &orig_tty); + saved_orig = 0; + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_console_init_output (struct grub_term_output *term) +{ + struct winsize size; + if (ioctl (STDOUT_FILENO, TIOCGWINSZ, &size) >= 0) + { + grub_console_terminfo_output.width = size.ws_col; + grub_console_terminfo_output.height = size.ws_row; + } + else + { + grub_console_terminfo_output.width = 80; + grub_console_terminfo_output.height = 24; + } + + grub_terminfo_output_init (term); + return 0; } -static struct grub_term_input grub_ncurses_term_input = + +struct grub_terminfo_input_state grub_console_terminfo_input = { - .name = "console", - .getkey = grub_ncurses_getkey, + .readkey = readkey }; -static struct grub_term_output grub_ncurses_term_output = +struct grub_terminfo_output_state grub_console_terminfo_output = + { + .put = put, + .width = 80, + .height = 24 + }; + +static struct grub_term_input grub_console_term_input = { .name = "console", - .init = grub_ncurses_init, - .fini = grub_ncurses_fini, - .putchar = grub_ncurses_putchar, - .getxy = grub_ncurses_getxy, - .getwh = grub_ncurses_getwh, - .gotoxy = grub_ncurses_gotoxy, - .cls = grub_ncurses_cls, - .setcolorstate = grub_ncurses_setcolorstate, - .setcursor = grub_ncurses_setcursor, - .refresh = grub_ncurses_refresh, - .flags = GRUB_TERM_CODE_TYPE_ASCII + .init = grub_console_init_input, + .fini = grub_console_fini_input, + .getkey = grub_terminfo_getkey, + .data = &grub_console_terminfo_input + }; + +static struct grub_term_output grub_console_term_output = + { + .name = "console", + .init = grub_console_init_output, + .putchar = grub_terminfo_putchar, + .getxy = grub_terminfo_getxy, + .getwh = grub_terminfo_getwh, + .gotoxy = grub_terminfo_gotoxy, + .cls = grub_terminfo_cls, + .setcolorstate = grub_terminfo_setcolorstate, + .setcursor = grub_terminfo_setcursor, + .data = &grub_console_terminfo_output, }; void grub_console_init (void) { - grub_term_register_output ("console", &grub_ncurses_term_output); - grub_term_register_input ("console", &grub_ncurses_term_input); + const char *cs = nl_langinfo (CODESET); + if (cs && grub_strcasecmp (cs, "UTF-8")) + grub_console_term_output.flags = GRUB_TERM_CODE_TYPE_UTF8_LOGICAL; + else + grub_console_term_output.flags = GRUB_TERM_CODE_TYPE_ASCII; + grub_term_register_input ("console", &grub_console_term_input); + grub_term_register_output ("console", &grub_console_term_output); + grub_terminfo_init (); + grub_terminfo_output_register (&grub_console_term_output, "vt100-color"); } void grub_console_fini (void) { - grub_ncurses_fini (&grub_ncurses_term_output); + if (saved_orig) + { + fcntl (STDIN_FILENO, F_SETFL, original_fl); + tcsetattr(STDIN_FILENO, TCSANOW, &orig_tty); + } + saved_orig = 0; } diff --git a/include/grub/terminfo.h b/include/grub/terminfo.h index 20541a949..2bbae1fa3 100644 --- a/include/grub/terminfo.h +++ b/include/grub/terminfo.h @@ -82,9 +82,7 @@ grub_err_t EXPORT_FUNC (grub_terminfo_output_register) (struct grub_term_output const char *type); grub_err_t EXPORT_FUNC (grub_terminfo_output_unregister) (struct grub_term_output *term); -#ifndef GRUB_MACHINE_EMU void grub_terminfo_init (void); void grub_terminfo_fini (void); -#endif #endif /* ! GRUB_TERMINFO_HEADER */