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

531 lines
14 KiB
Diff
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)