grub2/grub2-s390x-03-output-7-bit-ascii.patch

531 lines
14 KiB
Diff
Raw Normal View History

Vn:
* recognize 'dev/sclp_line0' as 3215-look-alike. [bnc#876743]
Vn+1:
* revamp readkey_dumb().
Vn+2:
* support hotkeys on all line-mode terminals, not only 3215. [bnc#885668]
---
grub-core/kern/emu/main.c | 8 +
grub-core/normal/menu_text.c | 54 +++++++-
grub-core/normal/term.c | 2
grub-core/osdep/unix/emuconsole.c | 238 +++++++++++++++++++++++++++++++++++++-
include/grub/term.h | 4
5 files changed, 294 insertions(+), 12 deletions(-)
--- a/grub-core/osdep/unix/emuconsole.c
+++ b/grub-core/osdep/unix/emuconsole.c
@@ -39,17 +39,61 @@
#include <grub/emu/console.h>
+#include <stdio.h>
+#include <errno.h>
+
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 int console_mode = 0;
+
+#define MAX_LEN 1023
+#if defined(__s390x__)
+static int
+dummy (void)
+{
+ return 0;
+}
+#endif
+#if 0
+static char msg[MAX_LEN+1];
+static void
+dprint (int len)
+{
+ if (len < 0)
+ return;
+ if (len > MAX_LEN)
+ len = MAX_LEN;
+ write (2, msg, len);
+}
+#define dprintf(fmt, vargs...) dprint(snprintf(msg, MAX_LEN, fmt, ## vargs))
+#else
+#define dprintf(fmt, vargs...) {}
+#endif
static void
-put (struct grub_term_output *term __attribute__ ((unused)), const int c)
+put (struct grub_term_output *term, const int c)
{
char chr = c;
ssize_t actual;
+ struct grub_terminfo_output_state *data
+ = (struct grub_terminfo_output_state *) term->data;
+
+ if (term->flags & GRUB_TERM_DUMB) {
+ if (c == '\n') {
+ data->pos.y++;
+ data->pos.x = 0;
+ } else {
+ data->pos.x++;
+ }
+ if (0) {
+ if (c == ' ') chr = '_';
+ if (c == GRUB_TERM_BACKSPACE) chr = '{';
+ if (c == '\b') chr = '<';
+ }
+ }
actual = write (STDOUT_FILENO, &chr, 1);
if (actual < 1)
@@ -60,17 +104,152 @@
}
static int
-readkey (struct grub_term_input *term __attribute__ ((unused)))
+readkey (struct grub_term_input *term)
{
grub_uint8_t c;
ssize_t actual;
+ fd_set readfds;
+ struct timeval timeout;
+ int sel;
+ FD_SET (0, &readfds);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 500000;
+ if ((sel=select (1, &readfds, (fd_set *)0, (fd_set *)0, &timeout)) <= 0)
+ {
+ if (sel < 0 && errno == EINTR)
+ return 0x03; /* '^C' */
+ return -1;
+ }
+
actual = read (STDIN_FILENO, &c, 1);
if (actual > 0)
return c;
return -1;
}
+#define NO_KEY ((grub_uint8_t)-1)
+static int
+readkey_dumb (struct grub_term_input *term)
+{
+ grub_uint8_t c;
+ static grub_uint8_t p = NO_KEY;
+
+ c = readkey (term);
+ if (c == NO_KEY)
+ return -1;
+ if ((p == '^' || p == '\n') && c == '\n') /* solitary '^' or '\n'? */
+ {
+ c = p; /* use immediately! */
+ p = '\n';
+ }
+ else if ((c == '\n' || c == '^') && p != c) /* non-duplicate specials? */
+ {
+ p = c; /* remember! */
+ c = NO_KEY;
+ }
+ else if (p == '^')
+ {
+ if (c != '^')
+ c &= 0x1F;
+ p = NO_KEY;
+ }
+ else
+ p = c;
+ return c;
+}
+
+static void
+grub_dumb_putchar (struct grub_term_output *term,
+ const struct grub_unicode_glyph *c)
+{
+ unsigned i;
+
+ /* For now, do not try to use a surrogate pair. */
+ if (c->base > 0xffff)
+ put (term, '?');
+ else
+ put (term, (c->base & 0xffff));
+
+ if (0) {
+ for (i = 0; i < c->ncomb; i++)
+ if (c->base < 0xffff)
+ put (term, grub_unicode_get_comb (c)[i].code);
+ }
+}
+
+static struct grub_term_coordinate
+grub_dumb_getxy (struct grub_term_output *term)
+{
+ struct grub_terminfo_output_state *data
+ = (struct grub_terminfo_output_state *) term->data;
+
+ dprintf ("<%d,%d>", data->pos.x, data->pos.y);
+ return data->pos;
+}
+
+static struct grub_term_coordinate
+grub_dumb_getwh (struct grub_term_output *term)
+{
+ static int once = 0;
+ struct grub_terminfo_output_state *data
+ = (struct grub_terminfo_output_state *) term->data;
+
+ if (!once++)
+ dprintf ("dumb_getwh: w=%d h=%d\n", data->size.x, data->size.y);
+ return data->size;
+}
+
+static void
+grub_dumb_gotoxy (struct grub_term_output *term,
+ struct grub_term_coordinate pos)
+{
+ struct grub_terminfo_output_state *data
+ = (struct grub_terminfo_output_state *) term->data;
+
+ if (pos.x > grub_term_width (term) || pos.y > grub_term_height (term))
+ {
+ grub_error (GRUB_ERR_BUG, "invalid point (%u,%u)", pos.x, pos.y);
+ return;
+ }
+
+ dprintf("goto(%d,%d)", pos.x, pos.y);
+ if (pos.x > (grub_term_width (term) - 4)) {
+ dprintf (" really?");
+ //return;
+ }
+
+ if (data->gotoxy)
+ {
+ int i;
+ dprintf ("data-gotoxy");
+ if (data->pos.y != pos.y) {
+ put (term, '\n');
+
+ for (i = 1; i < pos.x; i++ )
+ put (term, ' ');
+ }
+ }
+ else
+ {
+ int i = 0;
+ if (data->pos.y != pos.y || data->pos.x > pos.x) {
+ if (data->pos.y >= pos.y) data->pos.y = pos.y - 1;
+ if (pos.y - data->pos.y > 3) data->pos.y = pos.y - 2;
+ dprintf (" <%dnl>+%d", (pos.y - data->pos.y), pos.x);
+ for (i = data->pos.y; i < pos.y; i++ )
+ put (term, '\n');
+ }
+ for (i = data->pos.x; i < pos.x; i++ )
+ put (term, ' ');
+ dprintf ("#%d", i);
+ grub_dumb_getxy (term);
+ }
+
+ dprintf ("\n");
+ data->pos = pos;
+}
+
static grub_err_t
grub_console_init_input (struct grub_term_input *term)
{
@@ -105,7 +284,8 @@
grub_console_init_output (struct grub_term_output *term)
{
struct winsize size;
- if (ioctl (STDOUT_FILENO, TIOCGWINSZ, &size) >= 0)
+ if (ioctl (STDOUT_FILENO, TIOCGWINSZ, &size) >= 0 &&
+ size.ws_col > 0 && size.ws_row > 0)
{
grub_console_terminfo_output.size.x = size.ws_col;
grub_console_terminfo_output.size.y = size.ws_row;
@@ -115,6 +295,8 @@
grub_console_terminfo_output.size.x = 80;
grub_console_terminfo_output.size.y = 24;
}
+ if (console_mode == 3215)
+ grub_console_terminfo_output.size.x -= 1;
grub_terminfo_output_init (term);
@@ -161,24 +343,72 @@
void
grub_console_init (void)
{
+#if ! defined(__s390x__)
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;
+#else
+ char link[MAX_LEN+1];
+ ssize_t len = readlink ("/proc/self/fd/0", link, MAX_LEN);
+
+ if (len > 0)
+ link[len] = 0;
+ else
+ link[0] = 0;
+ if (grub_strncmp ("/dev/ttyS", link, 9) == 0 )
+ console_mode = 3215;
+ else if (grub_strncmp ("/dev/3270/tty", link, 13) == 0 )
+ console_mode = 3270;
+ else if (grub_strncmp ("/dev/sclp_line", link, 14) == 0 )
+ console_mode = 3215;
+ grub_console_term_output.flags = GRUB_TERM_CODE_TYPE_ASCII;
+ switch (console_mode)
+ {
+ case 3215:
+ grub_console_term_output.flags |= GRUB_TERM_DUMB;
+ /* FALLTHROUGH */
+ case 3270:
+ grub_console_term_output.flags |= GRUB_TERM_LINE;
+ grub_console_term_output.flags |= GRUB_TERM_NO_ECHO;
+ grub_console_terminfo_input.readkey = readkey_dumb;
+ break;
+ default:
+ break;
+ }
+#endif
+ if (grub_console_term_output.flags & GRUB_TERM_DUMB)
+ {
+ grub_console_term_output.putchar = grub_dumb_putchar,
+ grub_console_term_output.getxy = grub_dumb_getxy;
+ grub_console_term_output.getwh = grub_dumb_getwh;
+ grub_console_term_output.gotoxy = grub_dumb_gotoxy;
+ grub_console_term_output.cls = (void *) dummy;
+ grub_console_term_output.setcolorstate = (void *) dummy;
+ grub_console_term_output.setcursor = (void *) dummy;
+ grub_console_term_output.progress_update_divisor = GRUB_PROGRESS_NO_UPDATE;
+ }
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");
+ grub_terminfo_output_register (&grub_console_term_output,
+ (grub_console_term_output.flags & GRUB_TERM_DUMB) ? "dumb":"vt100-color");
}
void
grub_console_fini (void)
{
+ dprintf( "grub_console_fini: %d\n", grub_console_term_output.flags & GRUB_TERM_DUMB);
if (saved_orig)
{
fcntl (STDIN_FILENO, F_SETFL, original_fl);
tcsetattr(STDIN_FILENO, TCSANOW, &orig_tty);
}
+ if (!(grub_console_term_output.flags & GRUB_TERM_DUMB))
+ {
+ const char clear[] = { 0x1b, 'c', 0 };
+ write (STDOUT_FILENO, clear, 2);
+ }
saved_orig = 0;
}
--- a/grub-core/normal/menu_text.c
+++ b/grub-core/normal/menu_text.c
@@ -113,6 +113,7 @@
{
int i;
+ if (! (term->flags & GRUB_TERM_DUMB)) {
grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
grub_term_gotoxy (term, (struct grub_term_coordinate) { geo->first_entry_x - 1,
@@ -142,7 +143,7 @@
grub_putcode (GRUB_UNICODE_CORNER_LR, term);
grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
-
+ }
grub_term_gotoxy (term,
(struct grub_term_coordinate) { geo->first_entry_x - 1,
(geo->first_entry_y - 1 + geo->num_entries
@@ -155,6 +156,15 @@
int ret = 0;
grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
+ if (edit && (term->flags & GRUB_TERM_LINE))
+ {
+ ret += grub_print_message_indented_real
+ (_("Minimum Emacs-like screen editing is supported. '^i' lists "
+ "completions. Type '^x' to boot, '^c' for a command-line "
+ "or '^[' to discard edits and return to the GRUB menu."),
+ STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
+ }
+ else
if (edit)
{
ret += grub_print_message_indented_real (_("Minimum Emacs-like screen editing is \
@@ -165,10 +175,15 @@
}
else
{
+#if defined(__s390x__hotkey)
+ ret += grub_print_message_indented_real
+ (_("Select a menu option by pressing the hotkey specified. "),
+ STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
+#else
char *msg_translated;
msg_translated = grub_xasprintf (_("Use the %C and %C keys to select which "
- "entry is highlighted."),
+ "entry is highlighted. "),
GRUB_UNICODE_UPARROW,
GRUB_UNICODE_DOWNARROW);
if (!msg_translated)
@@ -177,6 +192,7 @@
STANDARD_MARGIN, term, dry_run);
grub_free (msg_translated);
+#endif
if (nested)
{
@@ -211,6 +227,10 @@
title = entry ? entry->title : "";
title_len = grub_strlen (title);
+
+ if ((data->term->flags & GRUB_TERM_DUMB) && title[0] == '\0')
+ return;
+
unicode_title = grub_calloc (title_len, sizeof (*unicode_title));
if (! unicode_title)
/* XXX How to show this error? */
@@ -244,6 +264,14 @@
if (data->geo.num_entries > 1)
grub_putcode (highlight ? '*' : ' ', data->term);
+ if ((data->term->flags & GRUB_TERM_LINE) && title[0] != '\0') {
+ grub_putcode('(', data->term);
+ grub_putcode((entry && entry->hotkey >= '0' && entry->hotkey <= 'z') ?
+ entry->hotkey : ' ', data->term);
+ grub_putcode(')', data->term);
+ grub_putcode(' ', data->term);
+ }
+
grub_print_ucs4_menu (unicode_title,
unicode_title + len,
0,
@@ -416,6 +444,8 @@
grub_term_highlight_color = old_color_highlight;
geo->timeout_y = geo->first_entry_y + geo->num_entries
+ geo->border + empty_lines;
+ if (term->flags & GRUB_TERM_DUMB)
+ geo->timeout_y = 1;
if (bottom_message)
{
grub_term_gotoxy (term,
@@ -425,6 +455,8 @@
print_message (nested, edit, term, 0);
geo->timeout_y += msg_num_lines;
}
+ if (term->flags & GRUB_TERM_DUMB)
+ geo->timeout_y = 1;
geo->right_margin = grub_term_width (term)
- geo->first_entry_x
- geo->entry_width - 1;
@@ -436,12 +468,19 @@
struct menu_viewer_data *data = dataptr;
char *msg_translated = 0;
- grub_term_gotoxy (data->term,
+ if (data->geo.timeout_y)
+ grub_term_gotoxy (data->term,
(struct grub_term_coordinate) { 0, data->geo.timeout_y });
+ if (data->term->flags & GRUB_TERM_DUMB)
+ {
+ if (! data->geo.timeout_y)
+ data->timeout_msg = TIMEOUT_TERSE;
+ data->geo.timeout_y = 0;
+ }
if (data->timeout_msg == TIMEOUT_TERSE
|| data->timeout_msg == TIMEOUT_TERSE_NO_MARGIN)
- msg_translated = grub_xasprintf (_("%ds"), timeout);
+ msg_translated = grub_xasprintf (_(" %ds"), timeout);
else
msg_translated = grub_xasprintf (_("The highlighted entry will be executed automatically in %ds."), timeout);
if (!msg_translated)
@@ -471,6 +510,8 @@
data->term);
grub_free (msg_translated);
+ if (data->term->flags & GRUB_TERM_DUMB)
+ return;
grub_term_gotoxy (data->term,
(struct grub_term_coordinate) {
grub_term_cursor_x (&data->geo),
@@ -498,7 +539,7 @@
data->first = entry;
complete_redraw = 1;
}
- if (complete_redraw)
+ if (complete_redraw || (data->term->flags & GRUB_TERM_DUMB))
print_entries (data->menu, data);
else
{
@@ -528,6 +569,9 @@
struct menu_viewer_data *data = dataptr;
int i;
+ if ((data->term->flags & GRUB_TERM_DUMB))
+ return;
+
for (i = 0; i < data->geo.timeout_lines;i++)
{
grub_term_gotoxy (data->term, (struct grub_term_coordinate) {
--- a/grub-core/normal/term.c
+++ b/grub-core/normal/term.c
@@ -981,7 +981,7 @@
{
print_ucs4_real (str, last_position, margin_left, margin_right,
term, 0, 0, 1, skip_lines, max_lines,
- contchar, 1, pos);
+ contchar, (term->flags & GRUB_TERM_DUMB)? 0 : 1, pos);
}
void
--- a/grub-core/kern/emu/main.c
+++ b/grub-core/kern/emu/main.c
@@ -190,6 +190,12 @@
NULL, help_filter, NULL
};
+void
+ignore (int num __attribute__ ((unused)))
+{
+ return;
+}
+
#pragma GCC diagnostic ignored "-Wmissing-prototypes"
@@ -259,7 +265,7 @@
sleep (1);
}
- signal (SIGINT, SIG_IGN);
+ signal (SIGINT, (sighandler_t) &ignore);
grub_console_init ();
grub_host_init ();
--- a/include/grub/term.h
+++ b/include/grub/term.h
@@ -102,8 +102,10 @@
#define GRUB_TERM_NO_EDIT (1 << 1)
/* Set when the terminal cannot do fancy things. */
#define GRUB_TERM_DUMB (1 << 2)
+/* Set when the terminal is line oriented. */
+#define GRUB_TERM_LINE (1 << 3)
/* Which encoding does terminal expect stream to be. */
-#define GRUB_TERM_CODE_TYPE_SHIFT 3
+#define GRUB_TERM_CODE_TYPE_SHIFT 4
#define GRUB_TERM_CODE_TYPE_MASK (7 << GRUB_TERM_CODE_TYPE_SHIFT)
/* Only ASCII characters accepted. */
#define GRUB_TERM_CODE_TYPE_ASCII (0 << GRUB_TERM_CODE_TYPE_SHIFT)