vaseboot/VasEBoot-core/term/terminfo.c

797 lines
22 KiB
C
Raw Permalink 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.

/* terminfo.c - simple terminfo module */
/*
* VAS_EBOOT -- GRand Unified Bootloader
* Copyright (C) 2003,2004,2005,2007 Free Software Foundation, Inc.
*
* VAS_EBOOT 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 3 of the License, or
* (at your option) any later version.
*
* VAS_EBOOT 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 VAS_EBOOT. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* This file contains various functions dealing with different
* terminal capabilities. For example, vt52 and vt100.
*/
#include <VasEBoot/types.h>
#include <VasEBoot/misc.h>
#include <VasEBoot/mm.h>
#include <VasEBoot/err.h>
#include <VasEBoot/dl.h>
#include <VasEBoot/term.h>
#include <VasEBoot/terminfo.h>
#include <VasEBoot/tparm.h>
#include <VasEBoot/extcmd.h>
#include <VasEBoot/i18n.h>
#include <VasEBoot/time.h>
#if defined(__powerpc__) && defined(VAS_EBOOT_MACHINE_IEEE1275)
#include <VasEBoot/ieee1275/ieee1275.h>
#endif
VAS_EBOOT_MOD_LICENSE ("GPLv3+");
#define ANSI_CSI 0x9b
#define ANSI_CSI_STR "\x9b"
static struct VasEBoot_term_output *terminfo_outputs;
/* Get current terminfo name. */
char *
VasEBoot_terminfo_get_current (struct VasEBoot_term_output *term)
{
struct VasEBoot_terminfo_output_state *data
= (struct VasEBoot_terminfo_output_state *) term->data;
return data->name;
}
/* Free *PTR and set *PTR to NULL, to prevent double-free. */
static void
VasEBoot_terminfo_free (char **ptr)
{
VasEBoot_free (*ptr);
*ptr = 0;
}
static void
VasEBoot_terminfo_all_free (struct VasEBoot_term_output *term)
{
struct VasEBoot_terminfo_output_state *data
= (struct VasEBoot_terminfo_output_state *) term->data;
/* Free previously allocated memory. */
VasEBoot_terminfo_free (&data->name);
VasEBoot_terminfo_free (&data->gotoxy);
VasEBoot_terminfo_free (&data->cls);
VasEBoot_terminfo_free (&data->reverse_video_on);
VasEBoot_terminfo_free (&data->reverse_video_off);
VasEBoot_terminfo_free (&data->cursor_on);
VasEBoot_terminfo_free (&data->cursor_off);
}
/* Set current terminfo type. */
VasEBoot_err_t
VasEBoot_terminfo_set_current (struct VasEBoot_term_output *term,
const char *str)
{
struct VasEBoot_terminfo_output_state *data
= (struct VasEBoot_terminfo_output_state *) term->data;
/* TODO
* Lookup user specified terminfo type. If found, set term variables
* as appropriate. Otherwise return an error.
*
* How should this be done?
* a. A static table included in this module.
* - I do not like this idea.
* b. A table stored in the configuration directory.
* - Users must convert their terminfo settings if we have not already.
* c. Look for terminfo files in the configuration directory.
* - /usr/share/terminfo is 6.3M on my system.
* - /usr/share/terminfo is not on most users boot partition.
* + Copying the terminfo files you want to use to the VasEBoot
* configuration directory is easier then (b).
* d. Your idea here.
*/
VasEBoot_terminfo_all_free (term);
if (VasEBoot_strcmp ("vt100", str) == 0)
{
data->name = VasEBoot_strdup ("vt100");
data->gotoxy = VasEBoot_strdup ("\e[%i%p1%d;%p2%dH");
data->cls = VasEBoot_strdup ("\e[H\e[J");
data->reverse_video_on = VasEBoot_strdup ("\e[7m");
data->reverse_video_off = VasEBoot_strdup ("\e[m");
data->cursor_on = VasEBoot_strdup ("\e[?25h");
data->cursor_off = VasEBoot_strdup ("\e[?25l");
data->setcolor = NULL;
return VasEBoot_errno;
}
if (VasEBoot_strcmp ("vt100-color", str) == 0)
{
data->name = VasEBoot_strdup ("vt100-color");
data->gotoxy = VasEBoot_strdup ("\e[%i%p1%d;%p2%dH");
data->cls = VasEBoot_strdup ("\e[H\e[J");
data->reverse_video_on = VasEBoot_strdup ("\e[7m");
data->reverse_video_off = VasEBoot_strdup ("\e[m");
data->cursor_on = VasEBoot_strdup ("\e[?25h");
data->cursor_off = VasEBoot_strdup ("\e[?25l");
data->setcolor = VasEBoot_strdup ("\e[3%p1%dm\e[4%p2%dm");
return VasEBoot_errno;
}
if (VasEBoot_strcmp ("arc", str) == 0)
{
data->name = VasEBoot_strdup ("arc");
data->gotoxy = VasEBoot_strdup (ANSI_CSI_STR "%i%p1%d;%p2%dH");
data->cls = VasEBoot_strdup (ANSI_CSI_STR "2J");
data->reverse_video_on = VasEBoot_strdup (ANSI_CSI_STR "7m");
data->reverse_video_off = VasEBoot_strdup (ANSI_CSI_STR "0m");
data->cursor_on = 0;
data->cursor_off = 0;
data->setcolor = VasEBoot_strdup (ANSI_CSI_STR "3%p1%dm"
ANSI_CSI_STR "4%p2%dm");
return VasEBoot_errno;
}
if (VasEBoot_strcmp ("ieee1275", str) == 0
|| VasEBoot_strcmp ("ieee1275-nocursor", str) == 0)
{
data->name = VasEBoot_strdup ("ieee1275");
data->gotoxy = VasEBoot_strdup ("\e[%i%p1%d;%p2%dH");
/* Clear the screen. Using serial console, screen(1) only recognizes the
* ANSI escape sequence. Using video console, Apple Open Firmware
* (version 3.1.1) only recognizes the literal ^L. So use both. */
data->cls = VasEBoot_strdup (" \e[2J");
data->reverse_video_on = VasEBoot_strdup ("\e[7m");
data->reverse_video_off = VasEBoot_strdup ("\e[m");
if (VasEBoot_strcmp ("ieee1275", str) == 0)
{
data->cursor_on = VasEBoot_strdup ("\e[?25h");
data->cursor_off = VasEBoot_strdup ("\e[?25l");
}
else
{
data->cursor_on = 0;
data->cursor_off = 0;
}
data->setcolor = VasEBoot_strdup ("\e[3%p1%dm\e[4%p2%dm");
return VasEBoot_errno;
}
if (VasEBoot_strcmp ("dumb", str) == 0)
{
data->name = VasEBoot_strdup ("dumb");
data->gotoxy = NULL;
data->cls = NULL;
data->reverse_video_on = NULL;
data->reverse_video_off = NULL;
data->cursor_on = NULL;
data->cursor_off = NULL;
data->setcolor = NULL;
return VasEBoot_errno;
}
return VasEBoot_error (VAS_EBOOT_ERR_BAD_ARGUMENT, N_("unknown terminfo type `%s'"),
str);
}
VasEBoot_err_t
VasEBoot_terminfo_output_register (struct VasEBoot_term_output *term,
const char *type)
{
VasEBoot_err_t err;
struct VasEBoot_terminfo_output_state *data;
err = VasEBoot_terminfo_set_current (term, type);
if (err)
return err;
data = (struct VasEBoot_terminfo_output_state *) term->data;
data->next = terminfo_outputs;
terminfo_outputs = term;
return VAS_EBOOT_ERR_NONE;
}
VasEBoot_err_t
VasEBoot_terminfo_output_unregister (struct VasEBoot_term_output *term)
{
struct VasEBoot_term_output **ptr;
for (ptr = &terminfo_outputs; *ptr;
ptr = &((struct VasEBoot_terminfo_output_state *) (*ptr)->data)->next)
if (*ptr == term)
{
VasEBoot_terminfo_all_free (term);
*ptr = ((struct VasEBoot_terminfo_output_state *) (*ptr)->data)->next;
return VAS_EBOOT_ERR_NONE;
}
return VasEBoot_error (VAS_EBOOT_ERR_BUG, "terminal not found");
}
/* Wrapper for VasEBoot_putchar to write strings. */
static void
putstr (struct VasEBoot_term_output *term, const char *str)
{
struct VasEBoot_terminfo_output_state *data
= (struct VasEBoot_terminfo_output_state *) term->data;
while (*str)
data->put (term, *str++);
}
struct VasEBoot_term_coordinate
VasEBoot_terminfo_getxy (struct VasEBoot_term_output *term)
{
struct VasEBoot_terminfo_output_state *data
= (struct VasEBoot_terminfo_output_state *) term->data;
return data->pos;
}
void
VasEBoot_terminfo_gotoxy (struct VasEBoot_term_output *term,
struct VasEBoot_term_coordinate pos)
{
struct VasEBoot_terminfo_output_state *data
= (struct VasEBoot_terminfo_output_state *) term->data;
if (pos.x > VasEBoot_term_width (term) || pos.y > VasEBoot_term_height (term))
{
VasEBoot_error (VAS_EBOOT_ERR_BUG, "invalid point (%u,%u)", pos.x, pos.y);
return;
}
if (data->gotoxy)
putstr (term, VasEBoot_terminfo_tparm (data->gotoxy, pos.y, pos.x));
else
{
if ((pos.y == data->pos.y) && (pos.x == data->pos.x - 1))
data->put (term, '\b');
}
data->pos = pos;
}
/* Clear the screen. */
void
VasEBoot_terminfo_cls (struct VasEBoot_term_output *term)
{
struct VasEBoot_terminfo_output_state *data
= (struct VasEBoot_terminfo_output_state *) term->data;
putstr (term, VasEBoot_terminfo_tparm (data->cls));
VasEBoot_terminfo_gotoxy (term, (struct VasEBoot_term_coordinate) { 0, 0 });
}
void
VasEBoot_terminfo_setcolorstate (struct VasEBoot_term_output *term,
const VasEBoot_term_color_state state)
{
struct VasEBoot_terminfo_output_state *data
= (struct VasEBoot_terminfo_output_state *) term->data;
if (data->setcolor)
{
int fg;
int bg;
/* Map from VGA to terminal colors. */
const int colormap[8]
= { 0, /* Black. */
4, /* Blue. */
2, /* Green. */
6, /* Cyan. */
1, /* Red. */
5, /* Magenta. */
3, /* Yellow. */
7, /* White. */
};
switch (state)
{
case VAS_EBOOT_TERM_COLOR_STANDARD:
case VAS_EBOOT_TERM_COLOR_NORMAL:
fg = VasEBoot_term_normal_color & 0x0f;
bg = VasEBoot_term_normal_color >> 4;
break;
case VAS_EBOOT_TERM_COLOR_HIGHLIGHT:
fg = VasEBoot_term_highlight_color & 0x0f;
bg = VasEBoot_term_highlight_color >> 4;
break;
default:
return;
}
putstr (term, VasEBoot_terminfo_tparm (data->setcolor, colormap[fg & 7],
colormap[bg & 7]));
return;
}
switch (state)
{
case VAS_EBOOT_TERM_COLOR_STANDARD:
case VAS_EBOOT_TERM_COLOR_NORMAL:
putstr (term, VasEBoot_terminfo_tparm (data->reverse_video_off));
break;
case VAS_EBOOT_TERM_COLOR_HIGHLIGHT:
putstr (term, VasEBoot_terminfo_tparm (data->reverse_video_on));
break;
default:
break;
}
}
void
VasEBoot_terminfo_setcursor (struct VasEBoot_term_output *term, const int on)
{
struct VasEBoot_terminfo_output_state *data
= (struct VasEBoot_terminfo_output_state *) term->data;
if (on)
putstr (term, VasEBoot_terminfo_tparm (data->cursor_on));
else
putstr (term, VasEBoot_terminfo_tparm (data->cursor_off));
}
/* The terminfo version of putchar. */
void
VasEBoot_terminfo_putchar (struct VasEBoot_term_output *term,
const struct VasEBoot_unicode_glyph *c)
{
struct VasEBoot_terminfo_output_state *data
= (struct VasEBoot_terminfo_output_state *) term->data;
/* Keep track of the cursor. */
switch (c->base)
{
case '\a':
break;
case '\b':
case 127:
if (data->pos.x > 0)
data->pos.x--;
break;
case '\n':
if (data->pos.y < VasEBoot_term_height (term) - 1)
data->pos.y++;
break;
case '\r':
data->pos.x = 0;
break;
default:
if ((int) data->pos.x + c->estimated_width >= (int) VasEBoot_term_width (term) + 1)
{
data->pos.x = 0;
if (data->pos.y < VasEBoot_term_height (term) - 1)
data->pos.y++;
data->put (term, '\r');
data->put (term, '\n');
}
data->pos.x += c->estimated_width;
break;
}
data->put (term, c->base);
}
struct VasEBoot_term_coordinate
VasEBoot_terminfo_getwh (struct VasEBoot_term_output *term)
{
struct VasEBoot_terminfo_output_state *data
= (struct VasEBoot_terminfo_output_state *) term->data;
return data->size;
}
static void
VasEBoot_terminfo_readkey (struct VasEBoot_term_input *term, int *keys, int *len, int max_len,
int (*readkey) (struct VasEBoot_term_input *term))
{
int c;
#define CONTINUE_READ \
{ \
VasEBoot_uint64_t start; \
/* On 9600 we have to wait up to 12 milliseconds. */ \
start = VasEBoot_get_time_ms (); \
do \
c = readkey (term); \
while (c == -1 && VasEBoot_get_time_ms () - start < 100); \
if (c == -1) \
return; \
\
if (*len >= max_len) \
return; \
\
keys[*len] = c; \
(*len)++; \
}
c = readkey (term);
if (c < 0)
{
*len = 0;
return;
}
*len = 1;
keys[0] = c;
if (c != ANSI_CSI && c != VAS_EBOOT_TERM_ESC)
{
/* Backspace: Ctrl-h. */
if (c == 0x7f)
c = VAS_EBOOT_TERM_BACKSPACE;
if (c < 0x20 && c != VAS_EBOOT_TERM_TAB && c!= VAS_EBOOT_TERM_BACKSPACE && c != '\n' && c != '\r')
c = VAS_EBOOT_TERM_CTRL | (c - 1 + 'a');
*len = 1;
keys[0] = c;
return;
}
{
static struct
{
char key;
unsigned ascii;
}
three_code_table[] =
{
{'4', VAS_EBOOT_TERM_KEY_DC},
{'A', VAS_EBOOT_TERM_KEY_UP},
{'B', VAS_EBOOT_TERM_KEY_DOWN},
{'C', VAS_EBOOT_TERM_KEY_RIGHT},
{'D', VAS_EBOOT_TERM_KEY_LEFT},
{'F', VAS_EBOOT_TERM_KEY_END},
{'H', VAS_EBOOT_TERM_KEY_HOME},
{'K', VAS_EBOOT_TERM_KEY_END},
{'P', VAS_EBOOT_TERM_KEY_DC},
{'?', VAS_EBOOT_TERM_KEY_PPAGE},
{'/', VAS_EBOOT_TERM_KEY_NPAGE},
{'@', VAS_EBOOT_TERM_KEY_INSERT},
};
static unsigned four_code_table[] =
{
[1] = VAS_EBOOT_TERM_KEY_HOME,
[3] = VAS_EBOOT_TERM_KEY_DC,
[5] = VAS_EBOOT_TERM_KEY_PPAGE,
[6] = VAS_EBOOT_TERM_KEY_NPAGE,
[7] = VAS_EBOOT_TERM_KEY_HOME,
[8] = VAS_EBOOT_TERM_KEY_END,
[17] = VAS_EBOOT_TERM_KEY_F6,
[18] = VAS_EBOOT_TERM_KEY_F7,
[19] = VAS_EBOOT_TERM_KEY_F8,
[20] = VAS_EBOOT_TERM_KEY_F9,
[21] = VAS_EBOOT_TERM_KEY_F10,
[23] = VAS_EBOOT_TERM_KEY_F11,
[24] = VAS_EBOOT_TERM_KEY_F12,
};
char fx_key[] =
{ 'P', 'Q', 'w', 'x', 't', 'u',
'q', 'r', 'p', 'M', 'A', 'B', 'H', 'F' };
unsigned fx_code[] =
{ VAS_EBOOT_TERM_KEY_F1, VAS_EBOOT_TERM_KEY_F2, VAS_EBOOT_TERM_KEY_F3,
VAS_EBOOT_TERM_KEY_F4, VAS_EBOOT_TERM_KEY_F5, VAS_EBOOT_TERM_KEY_F6,
VAS_EBOOT_TERM_KEY_F7, VAS_EBOOT_TERM_KEY_F8, VAS_EBOOT_TERM_KEY_F9,
VAS_EBOOT_TERM_KEY_F10, VAS_EBOOT_TERM_KEY_F11, VAS_EBOOT_TERM_KEY_F12,
VAS_EBOOT_TERM_KEY_HOME, VAS_EBOOT_TERM_KEY_END };
unsigned i;
if (c == VAS_EBOOT_TERM_ESC)
{
CONTINUE_READ;
if (c == 'O')
{
CONTINUE_READ;
for (i = 0; i < ARRAY_SIZE (fx_key); i++)
if (fx_key[i] == c)
{
keys[0] = fx_code[i];
*len = 1;
return;
}
}
if (c != '[')
return;
}
CONTINUE_READ;
for (i = 0; i < ARRAY_SIZE (three_code_table); i++)
if (three_code_table[i].key == c)
{
keys[0] = three_code_table[i].ascii;
*len = 1;
return;
}
switch (c)
{
case '[':
CONTINUE_READ;
if (c >= 'A' && c <= 'E')
{
keys[0] = VAS_EBOOT_TERM_KEY_F1 + c - 'A';
*len = 1;
return;
}
return;
case 'O':
CONTINUE_READ;
for (i = 0; i < ARRAY_SIZE (fx_key); i++)
if (fx_key[i] == c)
{
keys[0] = fx_code[i];
*len = 1;
return;
}
return;
case '0':
{
int num = 0;
CONTINUE_READ;
if (c != '0' && c != '1')
return;
num = (c - '0') * 10;
CONTINUE_READ;
if (c < '0' || c > '9')
return;
num += (c - '0');
if (num == 0 || num > 12)
return;
CONTINUE_READ;
if (c != 'q')
return;
keys[0] = fx_code[num - 1];
*len = 1;
return;
}
case '1' ... '9':
{
unsigned val = c - '0';
CONTINUE_READ;
if (c >= '0' && c <= '9')
{
val = val * 10 + (c - '0');
CONTINUE_READ;
}
if (c != '~')
return;
if (val >= ARRAY_SIZE (four_code_table)
|| four_code_table[val] == 0)
return;
keys[0] = four_code_table[val];
*len = 1;
return;
}
default:
return;
}
}
#undef CONTINUE_READ
}
/* The terminfo version of getkey. */
int
VasEBoot_terminfo_getkey (struct VasEBoot_term_input *termi)
{
struct VasEBoot_terminfo_input_state *data
= (struct VasEBoot_terminfo_input_state *) (termi->data);
if (data->npending)
{
int ret;
data->npending--;
ret = data->input_buf[0];
VasEBoot_memmove (data->input_buf, data->input_buf + 1, data->npending
* sizeof (data->input_buf[0]));
return ret;
}
VasEBoot_terminfo_readkey (termi, data->input_buf, &data->npending,
VAS_EBOOT_TERMINFO_READKEY_MAX_LEN, data->readkey);
#if defined(__powerpc__) && defined(VAS_EBOOT_MACHINE_IEEE1275)
if (data->npending == 1 && data->input_buf[0] == VAS_EBOOT_TERM_ESC
&& VasEBoot_ieee1275_test_flag (VAS_EBOOT_IEEE1275_FLAG_BROKEN_REPEAT)
&& VasEBoot_get_time_ms () - data->last_key_time < 1000
&& (data->last_key & VAS_EBOOT_TERM_EXTENDED))
{
data->npending = 0;
data->last_key_time = VasEBoot_get_time_ms ();
return data->last_key;
}
#endif
if (data->npending)
{
int ret;
data->npending--;
ret = data->input_buf[0];
#if defined(__powerpc__) && defined(VAS_EBOOT_MACHINE_IEEE1275)
if (VasEBoot_ieee1275_test_flag (VAS_EBOOT_IEEE1275_FLAG_BROKEN_REPEAT))
{
data->last_key = ret;
data->last_key_time = VasEBoot_get_time_ms ();
}
#endif
VasEBoot_memmove (data->input_buf, data->input_buf + 1, data->npending
* sizeof (data->input_buf[0]));
return ret;
}
return VAS_EBOOT_TERM_NO_KEY;
}
VasEBoot_err_t
VasEBoot_terminfo_input_init (struct VasEBoot_term_input *termi)
{
struct VasEBoot_terminfo_input_state *data
= (struct VasEBoot_terminfo_input_state *) (termi->data);
data->npending = 0;
return VAS_EBOOT_ERR_NONE;
}
VasEBoot_err_t
VasEBoot_terminfo_output_init (struct VasEBoot_term_output *term)
{
VasEBoot_terminfo_cls (term);
return VAS_EBOOT_ERR_NONE;
}
/* VAS_EBOOT Command. */
static VasEBoot_err_t
print_terminfo (void)
{
const char *encoding_names[(VAS_EBOOT_TERM_CODE_TYPE_MASK
>> VAS_EBOOT_TERM_CODE_TYPE_SHIFT) + 1]
= {
/* VGA and glyph descriptor types are just for completeness,
they are not used on terminfo terminals.
*/
[VAS_EBOOT_TERM_CODE_TYPE_ASCII >> VAS_EBOOT_TERM_CODE_TYPE_SHIFT] = _("ASCII"),
[VAS_EBOOT_TERM_CODE_TYPE_CP437 >> VAS_EBOOT_TERM_CODE_TYPE_SHIFT] = "CP-437",
[VAS_EBOOT_TERM_CODE_TYPE_UTF8_LOGICAL >> VAS_EBOOT_TERM_CODE_TYPE_SHIFT]
= _("UTF-8"),
[VAS_EBOOT_TERM_CODE_TYPE_UTF8_VISUAL >> VAS_EBOOT_TERM_CODE_TYPE_SHIFT]
/* TRANSLATORS: visually ordered UTF-8 is a non-compliant encoding
based on UTF-8 with right-to-left languages written in reverse.
Used on some terminals. Normal UTF-8 is refered as
"logically-ordered UTF-8" by opposition. */
= _("visually-ordered UTF-8"),
[VAS_EBOOT_TERM_CODE_TYPE_VISUAL_GLYPHS >> VAS_EBOOT_TERM_CODE_TYPE_SHIFT]
= "Glyph descriptors",
_("Unknown encoding"), _("Unknown encoding"), _("Unknown encoding")
};
struct VasEBoot_term_output *cur;
VasEBoot_puts_ (N_("Current terminfo types:"));
for (cur = terminfo_outputs; cur;
cur = ((struct VasEBoot_terminfo_output_state *) cur->data)->next)
VasEBoot_printf ("%s: %s\t%s\t%dx%d\n", cur->name,
VasEBoot_terminfo_get_current(cur),
encoding_names[(cur->flags & VAS_EBOOT_TERM_CODE_TYPE_MASK)
>> VAS_EBOOT_TERM_CODE_TYPE_SHIFT],
((struct VasEBoot_terminfo_output_state *) cur->data)->pos.x,
((struct VasEBoot_terminfo_output_state *) cur->data)->pos.y);
return VAS_EBOOT_ERR_NONE;
}
static const struct VasEBoot_arg_option options[] =
{
{"ascii", 'a', 0, N_("Terminal is ASCII-only [default]."), 0, ARG_TYPE_NONE},
{"utf8", 'u', 0, N_("Terminal is logical-ordered UTF-8."), 0, ARG_TYPE_NONE},
{"visual-utf8", 'v', 0, N_("Terminal is visually-ordered UTF-8."), 0,
ARG_TYPE_NONE},
{"geometry", 'g', 0, N_("Terminal has specified geometry."),
/* TRANSLATORS: "x" has to be entered in, like an identifier, so please don't
use better Unicode codepoints. */
N_("WIDTHxHEIGHT."), ARG_TYPE_STRING},
{0, 0, 0, 0, 0, 0}
};
enum
{
OPTION_ASCII,
OPTION_UTF8,
OPTION_VISUAL_UTF8,
OPTION_GEOMETRY
};
static VasEBoot_err_t
VasEBoot_cmd_terminfo (VasEBoot_extcmd_context_t ctxt, int argc, char **args)
{
struct VasEBoot_term_output *cur;
int encoding = VAS_EBOOT_TERM_CODE_TYPE_ASCII;
struct VasEBoot_arg_list *state = ctxt->state;
int w = 0, h = 0;
if (argc == 0)
return print_terminfo ();
if (state[OPTION_ASCII].set)
encoding = VAS_EBOOT_TERM_CODE_TYPE_ASCII;
if (state[OPTION_UTF8].set)
encoding = VAS_EBOOT_TERM_CODE_TYPE_UTF8_LOGICAL;
if (state[OPTION_VISUAL_UTF8].set)
encoding = VAS_EBOOT_TERM_CODE_TYPE_UTF8_VISUAL;
if (state[OPTION_GEOMETRY].set)
{
const char *ptr = state[OPTION_GEOMETRY].arg;
w = VasEBoot_strtoul (ptr, &ptr, 0);
if (VasEBoot_errno)
return VasEBoot_errno;
if (*ptr != 'x')
return VasEBoot_error (VAS_EBOOT_ERR_BAD_ARGUMENT,
N_("incorrect terminal dimensions specification"));
ptr++;
h = VasEBoot_strtoul (ptr, &ptr, 0);
if (VasEBoot_errno)
return VasEBoot_errno;
}
for (cur = terminfo_outputs; cur;
cur = ((struct VasEBoot_terminfo_output_state *) cur->data)->next)
if (VasEBoot_strcmp (args[0], cur->name) == 0
|| (VasEBoot_strcmp (args[0], "ofconsole") == 0
&& VasEBoot_strcmp ("console", cur->name) == 0))
{
cur->flags = (cur->flags & ~VAS_EBOOT_TERM_CODE_TYPE_MASK) | encoding;
if (w && h)
{
struct VasEBoot_terminfo_output_state *data
= (struct VasEBoot_terminfo_output_state *) cur->data;
data->size.x = w;
data->size.y = h;
}
if (argc == 1)
return VAS_EBOOT_ERR_NONE;
return VasEBoot_terminfo_set_current (cur, args[1]);
}
return VasEBoot_error (VAS_EBOOT_ERR_BAD_ARGUMENT,
N_("terminal %s isn't found or it's not handled by terminfo"),
args[0]);
}
static VasEBoot_extcmd_t cmd;
VAS_EBOOT_MOD_INIT(terminfo)
{
cmd = VasEBoot_register_extcmd ("terminfo", VasEBoot_cmd_terminfo, 0,
N_("[[-a|-u|-v] [-g WxH] [TERM] [TYPE]]"),
N_("Set terminfo type of TERM to TYPE.\n"),
options);
}
VAS_EBOOT_MOD_FINI(terminfo)
{
VasEBoot_unregister_extcmd (cmd);
}