2005-09-03 Yoshinori K. Okuji <okuji@enbug.org>
* normal/completion.c (complete_arguments): Add the qualifier const into OPTIONS. From Omniflux <omniflux+lists@omniflux.com>: * include/grub/terminfo.h: New file. * include/grub/tparm.h: Likewise. * include/grub/i386/pc/serial.h: Likewise. * term/terminfo.c: Likewise. * term/tparm.c: Likewise. * term/i386/pc/serial.c: Likewise. * conf/i386-pc.rmk (pkgdata_MODULES): Added terminfo.mod and serial.mod. (terminfo_mod_SOURCES): New variable. (terminfo_mod_CFLAGS): Likewise. (serial_mod_SOURCES): Likewise. (serial_mod_CFLAGS): Likewise.
This commit is contained in:
parent
48b671ff70
commit
47d2d65e33
12 changed files with 1892 additions and 4 deletions
13
AUTHORS
13
AUTHORS
|
@ -8,3 +8,16 @@ in ext2fs.
|
|||
|
||||
Marco Gerards added ext2fs support, grub-emu, a new command-line
|
||||
engine, and fixed many bugs.
|
||||
|
||||
Omniflux added terminfo and serial support.
|
||||
|
||||
Vincent Pelletier added Sparc64 support.
|
||||
|
||||
Hollis Blanchard implemented many parts of PowerPC support.
|
||||
|
||||
Tomas Ebenlendr added the command chainloader into the normal mode,
|
||||
fixed some bugs.
|
||||
|
||||
Guillem Jover merged architecture-independent ELF support code.
|
||||
|
||||
Vesa Jaaskelainen added VBE support.
|
||||
|
|
19
ChangeLog
19
ChangeLog
|
@ -1,3 +1,22 @@
|
|||
2005-09-03 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
|
||||
* normal/completion.c (complete_arguments): Add the qualifier
|
||||
const into OPTIONS.
|
||||
|
||||
From Omniflux <omniflux+lists@omniflux.com>:
|
||||
* include/grub/terminfo.h: New file.
|
||||
* include/grub/tparm.h: Likewise.
|
||||
* include/grub/i386/pc/serial.h: Likewise.
|
||||
* term/terminfo.c: Likewise.
|
||||
* term/tparm.c: Likewise.
|
||||
* term/i386/pc/serial.c: Likewise.
|
||||
* conf/i386-pc.rmk (pkgdata_MODULES): Added terminfo.mod and
|
||||
serial.mod.
|
||||
(terminfo_mod_SOURCES): New variable.
|
||||
(terminfo_mod_CFLAGS): Likewise.
|
||||
(serial_mod_SOURCES): Likewise.
|
||||
(serial_mod_CFLAGS): Likewise.
|
||||
|
||||
2005-08-31 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
|
||||
* DISTLIST: Replaced boot/powerpc/ieee1275/crt0.S and
|
||||
|
|
2
THANKS
2
THANKS
|
@ -12,11 +12,13 @@ Johan Rydberg <jrydberg@night.trouble.net>
|
|||
Hollis Blanchard <hollis@penguinppc.org>
|
||||
Marco Gerards <metgerards@student.han.nl>
|
||||
NIIBE Yutaka <gniibe@m17n.org>
|
||||
Omniflux <omniflux@omniflux.com>
|
||||
Robert Bihlmeyer <robbe@orcus.priv.at>
|
||||
Ruslan Nikolaev <nruslan@mail.com>
|
||||
Timothy Baldwin <T.E.Baldwin99@members.leeds.ac.uk>
|
||||
Tomas Ebenlendr <ebik@ucw.cz>
|
||||
Tsuneyoshi Yasuo <tuneyoshi@naic.co.jp>
|
||||
Vesa Jaaskelainen <chaac@nic.fi>
|
||||
Vincent Guffens <guffens@inma.ucl.ac.be>
|
||||
Vincent Pelletier <subdino2004@yahoo.fr>
|
||||
Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
|
122
conf/i386-pc.mk
122
conf/i386-pc.mk
|
@ -1168,7 +1168,8 @@ pkgdata_MODULES = _chain.mod _linux.mod linux.mod fat.mod ufs.mod \
|
|||
terminal.mod fshelp.mod chain.mod multiboot.mod amiga.mod \
|
||||
apple.mod pc.mod sun.mod loopback.mod reboot.mod halt.mod \
|
||||
help.mod default.mod timeout.mod configfile.mod vbe.mod \
|
||||
vesafb.mod vbetest.mod vbeinfo.mod search.mod gzio.mod
|
||||
vesafb.mod vbetest.mod vbeinfo.mod search.mod gzio.mod \
|
||||
terminfo.mod serial.mod
|
||||
|
||||
# For _chain.mod.
|
||||
_chain_mod_SOURCES = loader/i386/pc/chainloader.c
|
||||
|
@ -2499,6 +2500,125 @@ fs-manager.lst: font/manager.c genfslist.sh
|
|||
|
||||
font_mod_CFLAGS = $(COMMON_CFLAGS)
|
||||
|
||||
# For terminfo.mod.
|
||||
terminfo_mod_SOURCES = term/terminfo.c term/tparm.c
|
||||
CLEANFILES += terminfo.mod mod-terminfo.o mod-terminfo.c pre-terminfo.o terminfo_mod-term_terminfo.o terminfo_mod-term_tparm.o def-terminfo.lst und-terminfo.lst
|
||||
MOSTLYCLEANFILES += terminfo_mod-term_terminfo.d terminfo_mod-term_tparm.d
|
||||
DEFSYMFILES += def-terminfo.lst
|
||||
UNDSYMFILES += und-terminfo.lst
|
||||
|
||||
terminfo.mod: pre-terminfo.o mod-terminfo.o
|
||||
-rm -f $@
|
||||
$(LD) -r -d -o $@ $^
|
||||
$(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -R .note -R .comment $@
|
||||
|
||||
pre-terminfo.o: terminfo_mod-term_terminfo.o terminfo_mod-term_tparm.o
|
||||
-rm -f $@
|
||||
$(LD) -r -d -o $@ $^
|
||||
|
||||
mod-terminfo.o: mod-terminfo.c
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) $(terminfo_mod_CFLAGS) -c -o $@ $<
|
||||
|
||||
mod-terminfo.c: moddep.lst genmodsrc.sh
|
||||
sh $(srcdir)/genmodsrc.sh 'terminfo' $< > $@ || (rm -f $@; exit 1)
|
||||
|
||||
def-terminfo.lst: pre-terminfo.o
|
||||
$(NM) -g --defined-only -P -p $< | sed 's/^\([^ ]*\).*/\1 terminfo/' > $@
|
||||
|
||||
und-terminfo.lst: pre-terminfo.o
|
||||
echo 'terminfo' > $@
|
||||
$(NM) -u -P -p $< | cut -f1 -d' ' >> $@
|
||||
|
||||
terminfo_mod-term_terminfo.o: term/terminfo.c
|
||||
$(CC) -Iterm -I$(srcdir)/term $(CPPFLAGS) $(CFLAGS) $(terminfo_mod_CFLAGS) -c -o $@ $<
|
||||
|
||||
terminfo_mod-term_terminfo.d: term/terminfo.c
|
||||
set -e; $(CC) -Iterm -I$(srcdir)/term $(CPPFLAGS) $(CFLAGS) $(terminfo_mod_CFLAGS) -M $< | sed 's,terminfo\.o[ :]*,terminfo_mod-term_terminfo.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
|
||||
|
||||
-include terminfo_mod-term_terminfo.d
|
||||
|
||||
CLEANFILES += cmd-terminfo.lst fs-terminfo.lst
|
||||
COMMANDFILES += cmd-terminfo.lst
|
||||
FSFILES += fs-terminfo.lst
|
||||
|
||||
cmd-terminfo.lst: term/terminfo.c gencmdlist.sh
|
||||
set -e; $(CC) -Iterm -I$(srcdir)/term $(CPPFLAGS) $(CFLAGS) $(terminfo_mod_CFLAGS) -E $< | sh $(srcdir)/gencmdlist.sh terminfo > $@ || (rm -f $@; exit 1)
|
||||
|
||||
fs-terminfo.lst: term/terminfo.c genfslist.sh
|
||||
set -e; $(CC) -Iterm -I$(srcdir)/term $(CPPFLAGS) $(CFLAGS) $(terminfo_mod_CFLAGS) -E $< | sh $(srcdir)/genfslist.sh terminfo > $@ || (rm -f $@; exit 1)
|
||||
|
||||
|
||||
terminfo_mod-term_tparm.o: term/tparm.c
|
||||
$(CC) -Iterm -I$(srcdir)/term $(CPPFLAGS) $(CFLAGS) $(terminfo_mod_CFLAGS) -c -o $@ $<
|
||||
|
||||
terminfo_mod-term_tparm.d: term/tparm.c
|
||||
set -e; $(CC) -Iterm -I$(srcdir)/term $(CPPFLAGS) $(CFLAGS) $(terminfo_mod_CFLAGS) -M $< | sed 's,tparm\.o[ :]*,terminfo_mod-term_tparm.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
|
||||
|
||||
-include terminfo_mod-term_tparm.d
|
||||
|
||||
CLEANFILES += cmd-tparm.lst fs-tparm.lst
|
||||
COMMANDFILES += cmd-tparm.lst
|
||||
FSFILES += fs-tparm.lst
|
||||
|
||||
cmd-tparm.lst: term/tparm.c gencmdlist.sh
|
||||
set -e; $(CC) -Iterm -I$(srcdir)/term $(CPPFLAGS) $(CFLAGS) $(terminfo_mod_CFLAGS) -E $< | sh $(srcdir)/gencmdlist.sh terminfo > $@ || (rm -f $@; exit 1)
|
||||
|
||||
fs-tparm.lst: term/tparm.c genfslist.sh
|
||||
set -e; $(CC) -Iterm -I$(srcdir)/term $(CPPFLAGS) $(CFLAGS) $(terminfo_mod_CFLAGS) -E $< | sh $(srcdir)/genfslist.sh terminfo > $@ || (rm -f $@; exit 1)
|
||||
|
||||
|
||||
terminfo_mod_CFLAGS = $(COMMON_CFLAGS)
|
||||
|
||||
# For serial.mod.
|
||||
serial_mod_SOURCES = term/i386/pc/serial.c
|
||||
CLEANFILES += serial.mod mod-serial.o mod-serial.c pre-serial.o serial_mod-term_i386_pc_serial.o def-serial.lst und-serial.lst
|
||||
MOSTLYCLEANFILES += serial_mod-term_i386_pc_serial.d
|
||||
DEFSYMFILES += def-serial.lst
|
||||
UNDSYMFILES += und-serial.lst
|
||||
|
||||
serial.mod: pre-serial.o mod-serial.o
|
||||
-rm -f $@
|
||||
$(LD) -r -d -o $@ $^
|
||||
$(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -R .note -R .comment $@
|
||||
|
||||
pre-serial.o: serial_mod-term_i386_pc_serial.o
|
||||
-rm -f $@
|
||||
$(LD) -r -d -o $@ $^
|
||||
|
||||
mod-serial.o: mod-serial.c
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) $(serial_mod_CFLAGS) -c -o $@ $<
|
||||
|
||||
mod-serial.c: moddep.lst genmodsrc.sh
|
||||
sh $(srcdir)/genmodsrc.sh 'serial' $< > $@ || (rm -f $@; exit 1)
|
||||
|
||||
def-serial.lst: pre-serial.o
|
||||
$(NM) -g --defined-only -P -p $< | sed 's/^\([^ ]*\).*/\1 serial/' > $@
|
||||
|
||||
und-serial.lst: pre-serial.o
|
||||
echo 'serial' > $@
|
||||
$(NM) -u -P -p $< | cut -f1 -d' ' >> $@
|
||||
|
||||
serial_mod-term_i386_pc_serial.o: term/i386/pc/serial.c
|
||||
$(CC) -Iterm/i386/pc -I$(srcdir)/term/i386/pc $(CPPFLAGS) $(CFLAGS) $(serial_mod_CFLAGS) -c -o $@ $<
|
||||
|
||||
serial_mod-term_i386_pc_serial.d: term/i386/pc/serial.c
|
||||
set -e; $(CC) -Iterm/i386/pc -I$(srcdir)/term/i386/pc $(CPPFLAGS) $(CFLAGS) $(serial_mod_CFLAGS) -M $< | sed 's,serial\.o[ :]*,serial_mod-term_i386_pc_serial.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
|
||||
|
||||
-include serial_mod-term_i386_pc_serial.d
|
||||
|
||||
CLEANFILES += cmd-serial.lst fs-serial.lst
|
||||
COMMANDFILES += cmd-serial.lst
|
||||
FSFILES += fs-serial.lst
|
||||
|
||||
cmd-serial.lst: term/i386/pc/serial.c gencmdlist.sh
|
||||
set -e; $(CC) -Iterm/i386/pc -I$(srcdir)/term/i386/pc $(CPPFLAGS) $(CFLAGS) $(serial_mod_CFLAGS) -E $< | sh $(srcdir)/gencmdlist.sh serial > $@ || (rm -f $@; exit 1)
|
||||
|
||||
fs-serial.lst: term/i386/pc/serial.c genfslist.sh
|
||||
set -e; $(CC) -Iterm/i386/pc -I$(srcdir)/term/i386/pc $(CPPFLAGS) $(CFLAGS) $(serial_mod_CFLAGS) -E $< | sh $(srcdir)/genfslist.sh serial > $@ || (rm -f $@; exit 1)
|
||||
|
||||
|
||||
serial_mod_CFLAGS = $(COMMON_CFLAGS)
|
||||
|
||||
# For _multiboot.mod.
|
||||
_multiboot_mod_SOURCES = loader/i386/pc/multiboot.c
|
||||
CLEANFILES += _multiboot.mod mod-_multiboot.o mod-_multiboot.c pre-_multiboot.o _multiboot_mod-loader_i386_pc_multiboot.o def-_multiboot.lst und-_multiboot.lst
|
||||
|
|
|
@ -114,7 +114,8 @@ pkgdata_MODULES = _chain.mod _linux.mod linux.mod fat.mod ufs.mod \
|
|||
terminal.mod fshelp.mod chain.mod multiboot.mod amiga.mod \
|
||||
apple.mod pc.mod sun.mod loopback.mod reboot.mod halt.mod \
|
||||
help.mod default.mod timeout.mod configfile.mod vbe.mod \
|
||||
vesafb.mod vbetest.mod vbeinfo.mod search.mod gzio.mod
|
||||
vesafb.mod vbetest.mod vbeinfo.mod search.mod gzio.mod \
|
||||
terminfo.mod serial.mod
|
||||
|
||||
# For _chain.mod.
|
||||
_chain_mod_SOURCES = loader/i386/pc/chainloader.c
|
||||
|
@ -216,6 +217,14 @@ vga_mod_CFLAGS = $(COMMON_CFLAGS)
|
|||
font_mod_SOURCES = font/manager.c
|
||||
font_mod_CFLAGS = $(COMMON_CFLAGS)
|
||||
|
||||
# For terminfo.mod.
|
||||
terminfo_mod_SOURCES = term/terminfo.c term/tparm.c
|
||||
terminfo_mod_CFLAGS = $(COMMON_CFLAGS)
|
||||
|
||||
# For serial.mod.
|
||||
serial_mod_SOURCES = term/i386/pc/serial.c
|
||||
serial_mod_CFLAGS = $(COMMON_CFLAGS)
|
||||
|
||||
# For _multiboot.mod.
|
||||
_multiboot_mod_SOURCES = loader/i386/pc/multiboot.c
|
||||
_multiboot_mod_CFLAGS = $(COMMON_CFLAGS)
|
||||
|
|
68
include/grub/i386/pc/serial.h
Normal file
68
include/grub/i386/pc/serial.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
/* serial.h - serial device interface */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2000,2001,2002,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.
|
||||
*/
|
||||
|
||||
#ifndef GRUB_SERIAL_MACHINE_HEADER
|
||||
#define GRUB_SERIAL_MACHINE_HEADER 1
|
||||
|
||||
/* Macros. */
|
||||
|
||||
/* The offsets of UART registers. */
|
||||
#define UART_TX 0
|
||||
#define UART_RX 0
|
||||
#define UART_DLL 0
|
||||
#define UART_IER 1
|
||||
#define UART_DLH 1
|
||||
#define UART_IIR 2
|
||||
#define UART_FCR 2
|
||||
#define UART_LCR 3
|
||||
#define UART_MCR 4
|
||||
#define UART_LSR 5
|
||||
#define UART_MSR 6
|
||||
#define UART_SR 7
|
||||
|
||||
/* For LSR bits. */
|
||||
#define UART_DATA_READY 0x01
|
||||
#define UART_EMPTY_TRANSMITTER 0x20
|
||||
|
||||
/* The type of parity. */
|
||||
#define UART_NO_PARITY 0x00
|
||||
#define UART_ODD_PARITY 0x08
|
||||
#define UART_EVEN_PARITY 0x18
|
||||
|
||||
/* The type of word length. */
|
||||
#define UART_5BITS_WORD 0x00
|
||||
#define UART_6BITS_WORD 0x01
|
||||
#define UART_7BITS_WORD 0x02
|
||||
#define UART_8BITS_WORD 0x03
|
||||
|
||||
/* The type of the length of stop bit. */
|
||||
#define UART_1_STOP_BIT 0x00
|
||||
#define UART_2_STOP_BITS 0x04
|
||||
|
||||
/* the switch of DLAB. */
|
||||
#define UART_DLAB 0x80
|
||||
|
||||
/* Enable the FIFO. */
|
||||
#define UART_ENABLE_FIFO 0xC7
|
||||
|
||||
/* Turn on DTR, RTS, and OUT2. */
|
||||
#define UART_ENABLE_MODEM 0x0B
|
||||
|
||||
#endif /* ! GRUB_SERIAL_MACHINE_HEADER */
|
36
include/grub/terminfo.h
Normal file
36
include/grub/terminfo.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* 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
|
||||
* 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 GRUB; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef GRUB_TERMINFO_HEADER
|
||||
#define GRUB_TERMINFO_HEADER 1
|
||||
|
||||
#include <grub/err.h>
|
||||
#include <grub/types.h>
|
||||
|
||||
char *grub_terminfo_get_current (void);
|
||||
grub_err_t grub_terminfo_set_current (const char *);
|
||||
|
||||
void grub_terminfo_gotoxy (grub_uint8_t x, grub_uint8_t y);
|
||||
void grub_terminfo_cls (void);
|
||||
void grub_terminfo_reverse_video_on (void);
|
||||
void grub_terminfo_reverse_video_off (void);
|
||||
void grub_terminfo_cursor_on (void);
|
||||
void grub_terminfo_cursor_off (void);
|
||||
|
||||
#endif /* ! GRUB_TERMINFO_HEADER */
|
27
include/grub/tparm.h
Normal file
27
include/grub/tparm.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
/* tparm.h - parameter formatting of terminfo */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2002,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.
|
||||
*/
|
||||
|
||||
#ifndef GRUB_TPARM_HEADER
|
||||
#define GRUB_TPARM_HEADER 1
|
||||
|
||||
/* Function prototypes. */
|
||||
char *grub_terminfo_tparm (const char *string, ...);
|
||||
|
||||
#endif /* ! GRUB_TPARM_HEADER */
|
|
@ -308,7 +308,7 @@ static int
|
|||
complete_arguments (char *command)
|
||||
{
|
||||
grub_command_t cmd;
|
||||
struct grub_arg_option *option;
|
||||
const struct grub_arg_option *option;
|
||||
char shortarg[] = "- ";
|
||||
|
||||
cmd = grub_command_find (command);
|
||||
|
@ -322,7 +322,7 @@ complete_arguments (char *command)
|
|||
/* Add the short arguments. */
|
||||
for (option = cmd->options; option->doc; option++)
|
||||
{
|
||||
if (!option->shortarg)
|
||||
if (! option->shortarg)
|
||||
continue;
|
||||
|
||||
shortarg[1] = option->shortarg;
|
||||
|
|
637
term/i386/pc/serial.c
Normal file
637
term/i386/pc/serial.c
Normal file
|
@ -0,0 +1,637 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2000,2001,2002,2003,2004,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 <grub/machine/serial.h>
|
||||
#include <grub/machine/console.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/normal.h>
|
||||
#include <grub/arg.h>
|
||||
#include <grub/terminfo.h>
|
||||
|
||||
#define TEXT_WIDTH 80
|
||||
#define TEXT_HEIGHT 25
|
||||
|
||||
static unsigned int xpos, ypos;
|
||||
static unsigned int keep_track = 1;
|
||||
static unsigned int registered = 0;
|
||||
|
||||
/* An input buffer. */
|
||||
static char input_buf[8];
|
||||
static unsigned int npending = 0;
|
||||
|
||||
/* Argument options. */
|
||||
static const struct grub_arg_option options[] =
|
||||
{
|
||||
{"unit", 'u', 0, "Set the serial unit", 0, ARG_TYPE_INT},
|
||||
{"port", 'p', 0, "Set the serial port address", 0, ARG_TYPE_STRING},
|
||||
{"speed", 's', 0, "Set the serial port speed", 0, ARG_TYPE_INT},
|
||||
{"word", 'w', 0, "Set the serial port word length", 0, ARG_TYPE_INT},
|
||||
{"parity", 'r', 0, "Set the serial port parity", 0, ARG_TYPE_STRING},
|
||||
{"stop", 't', 0, "Set the serial port stop bits", 0, ARG_TYPE_INT},
|
||||
{0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
/* Serial port settings. */
|
||||
struct serial_port
|
||||
{
|
||||
unsigned short port;
|
||||
unsigned short divisor;
|
||||
unsigned short word_len;
|
||||
unsigned int parity;
|
||||
unsigned short stop_bits;
|
||||
};
|
||||
|
||||
/* Serial port settings. */
|
||||
static struct serial_port serial_settings;
|
||||
|
||||
/* Read a byte from a port. */
|
||||
static inline unsigned char
|
||||
inb (const unsigned short port)
|
||||
{
|
||||
unsigned char value;
|
||||
|
||||
asm volatile ("inb %w1, %0" : "=a" (value) : "Nd" (port));
|
||||
asm volatile ("outb %%al, $0x80" : : );
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* Write a byte to a port. */
|
||||
static inline void
|
||||
outb (const unsigned short port, const unsigned char value)
|
||||
{
|
||||
asm volatile ("outb %b0, %w1" : : "a" (value), "Nd" (port));
|
||||
asm volatile ("outb %%al, $0x80" : : );
|
||||
}
|
||||
|
||||
/* Return the port number for the UNITth serial device. */
|
||||
static inline unsigned short
|
||||
serial_hw_get_port (const unsigned short unit)
|
||||
{
|
||||
/* The BIOS data area. */
|
||||
const unsigned short *addr = (const unsigned short *) 0x0400;
|
||||
return addr[unit];
|
||||
}
|
||||
|
||||
/* Fetch a key. */
|
||||
static int
|
||||
serial_hw_fetch (void)
|
||||
{
|
||||
if (inb (serial_settings.port + UART_LSR) & UART_DATA_READY)
|
||||
return inb (serial_settings.port + UART_RX);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Put a chararacter. */
|
||||
static void
|
||||
serial_hw_put (const int c)
|
||||
{
|
||||
unsigned int timeout = 100000;
|
||||
|
||||
/* Wait until the transmitter holding register is empty. */
|
||||
while ((inb (serial_settings.port + UART_LSR) & UART_EMPTY_TRANSMITTER) == 0)
|
||||
{
|
||||
if (--timeout == 0)
|
||||
/* There is something wrong. But what can I do? */
|
||||
return;
|
||||
}
|
||||
|
||||
outb (serial_settings.port + UART_TX, c);
|
||||
}
|
||||
|
||||
static void
|
||||
serial_translate_key_sequence (void)
|
||||
{
|
||||
static struct
|
||||
{
|
||||
char key;
|
||||
char ascii;
|
||||
}
|
||||
three_code_table[] =
|
||||
{
|
||||
{'A', 16},
|
||||
{'B', 14},
|
||||
{'C', 6},
|
||||
{'D', 2},
|
||||
{'F', 5},
|
||||
{'H', 1},
|
||||
{'4', 4}
|
||||
};
|
||||
|
||||
static struct
|
||||
{
|
||||
short key;
|
||||
char ascii;
|
||||
}
|
||||
four_code_table[] =
|
||||
{
|
||||
{('1' | ('~' << 8)), 1},
|
||||
{('3' | ('~' << 8)), 4},
|
||||
{('5' | ('~' << 8)), 7},
|
||||
{('6' | ('~' << 8)), 3}
|
||||
};
|
||||
|
||||
/* The buffer must start with "ESC [". */
|
||||
if (*((unsigned short *) input_buf) != ('\e' | ('[' << 8)))
|
||||
return;
|
||||
|
||||
if (npending >= 3)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0;
|
||||
i < sizeof (three_code_table) / sizeof (three_code_table[0]);
|
||||
i++)
|
||||
if (three_code_table[i].key == input_buf[2])
|
||||
{
|
||||
input_buf[0] = three_code_table[i].ascii;
|
||||
npending -= 2;
|
||||
grub_memmove (input_buf + 1, input_buf + 3, npending - 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (npending >= 4)
|
||||
{
|
||||
unsigned int i;
|
||||
short key = *((short *) (input_buf + 2));
|
||||
|
||||
for (i = 0;
|
||||
i < sizeof (four_code_table) / sizeof (four_code_table[0]);
|
||||
i++)
|
||||
if (four_code_table[i].key == key)
|
||||
{
|
||||
input_buf[0] = four_code_table[i].ascii;
|
||||
npending -= 3;
|
||||
grub_memmove (input_buf + 1, input_buf + 4, npending - 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
fill_input_buf (const int nowait)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 10000 && npending < sizeof (input_buf); i++)
|
||||
{
|
||||
int c;
|
||||
|
||||
c = serial_hw_fetch ();
|
||||
if (c >= 0)
|
||||
{
|
||||
input_buf[npending++] = c;
|
||||
|
||||
/* Reset the counter to zero, to wait for the same interval. */
|
||||
i = 0;
|
||||
}
|
||||
|
||||
if (nowait)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Translate some key sequences. */
|
||||
serial_translate_key_sequence ();
|
||||
|
||||
return npending;
|
||||
}
|
||||
|
||||
/* Convert speed to divisor. */
|
||||
static unsigned short
|
||||
serial_get_divisor (unsigned int speed)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* The structure for speed vs. divisor. */
|
||||
struct divisor
|
||||
{
|
||||
unsigned int speed;
|
||||
unsigned short div;
|
||||
};
|
||||
|
||||
/* The table which lists common configurations. */
|
||||
/* 1843200 / (speed * 16) */
|
||||
static struct divisor divisor_tab[] =
|
||||
{
|
||||
{ 2400, 0x0030 },
|
||||
{ 4800, 0x0018 },
|
||||
{ 9600, 0x000C },
|
||||
{ 19200, 0x0006 },
|
||||
{ 38400, 0x0003 },
|
||||
{ 57600, 0x0002 },
|
||||
{ 115200, 0x0001 }
|
||||
};
|
||||
|
||||
/* Set the baud rate. */
|
||||
for (i = 0; i < sizeof (divisor_tab) / sizeof (divisor_tab[0]); i++)
|
||||
if (divisor_tab[i].speed == speed)
|
||||
return divisor_tab[i].div;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The serial version of checkkey. */
|
||||
static int
|
||||
grub_serial_checkkey (void)
|
||||
{
|
||||
if (fill_input_buf (1))
|
||||
return input_buf[0];
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* The serial version of getkey. */
|
||||
static int
|
||||
grub_serial_getkey (void)
|
||||
{
|
||||
int c;
|
||||
|
||||
while (! fill_input_buf (0))
|
||||
;
|
||||
|
||||
c = input_buf[0];
|
||||
grub_memmove (input_buf, input_buf + 1, --npending);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Initialize a serial device. PORT is the port number for a serial device.
|
||||
SPEED is a DTE-DTE speed which must be one of these: 2400, 4800, 9600,
|
||||
19200, 38400, 57600 and 115200. WORD_LEN is the word length to be used
|
||||
for the device. Likewise, PARITY is the type of the parity and
|
||||
STOP_BIT_LEN is the length of the stop bit. The possible values for
|
||||
WORD_LEN, PARITY and STOP_BIT_LEN are defined in the header file as
|
||||
macros. */
|
||||
static grub_err_t
|
||||
serial_hw_init (void)
|
||||
{
|
||||
unsigned char status = 0;
|
||||
|
||||
/* Turn off the interupt. */
|
||||
outb (serial_settings.port + UART_IER, 0);
|
||||
|
||||
/* Set DLAB. */
|
||||
outb (serial_settings.port + UART_LCR, UART_DLAB);
|
||||
|
||||
/* Set the baud rate. */
|
||||
outb (serial_settings.port + UART_DLL, serial_settings.divisor & 0xFF);
|
||||
outb (serial_settings.port + UART_DLH, serial_settings.divisor >> 8 );
|
||||
|
||||
/* Set the line status. */
|
||||
status |= (serial_settings.parity
|
||||
| serial_settings.word_len
|
||||
| serial_settings.stop_bits);
|
||||
outb (serial_settings.port + UART_LCR, status);
|
||||
|
||||
/* Enable the FIFO. */
|
||||
outb (serial_settings.port + UART_FCR, UART_ENABLE_FIFO);
|
||||
|
||||
/* Turn on DTR, RTS, and OUT2. */
|
||||
outb (serial_settings.port + UART_MCR, UART_ENABLE_MODEM);
|
||||
|
||||
/* Drain the input buffer. */
|
||||
while (grub_serial_checkkey () != -1)
|
||||
(void) grub_serial_getkey ();
|
||||
|
||||
/* FIXME: should check if the serial terminal was found. */
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
/* The serial version of putchar. */
|
||||
static void
|
||||
grub_serial_putchar (grub_uint32_t c)
|
||||
{
|
||||
/* Keep track of the cursor. */
|
||||
if (keep_track)
|
||||
{
|
||||
/* The serial terminal does not have VGA fonts. */
|
||||
if (c > 0x7F)
|
||||
{
|
||||
/* 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:
|
||||
c = '?';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '\a':
|
||||
break;
|
||||
|
||||
case '\b':
|
||||
case 127:
|
||||
if (xpos > 0)
|
||||
xpos--;
|
||||
break;
|
||||
|
||||
case '\n':
|
||||
if (ypos < TEXT_HEIGHT)
|
||||
ypos++;
|
||||
break;
|
||||
|
||||
case '\r':
|
||||
xpos = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (xpos >= TEXT_WIDTH)
|
||||
{
|
||||
grub_putchar ('\r');
|
||||
grub_putchar ('\n');
|
||||
}
|
||||
xpos++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
serial_hw_put (c);
|
||||
}
|
||||
|
||||
static grub_ssize_t
|
||||
grub_serial_getcharwidth (grub_uint32_t c __attribute__ ((unused)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static grub_uint16_t
|
||||
grub_serial_getwh (void)
|
||||
{
|
||||
return (TEXT_WIDTH << 8) | TEXT_HEIGHT;
|
||||
}
|
||||
|
||||
static grub_uint16_t
|
||||
grub_serial_getxy (void)
|
||||
{
|
||||
return ((xpos << 8) | ypos);
|
||||
}
|
||||
|
||||
static void
|
||||
grub_serial_gotoxy (grub_uint8_t x, grub_uint8_t y)
|
||||
{
|
||||
if (x > TEXT_WIDTH || y > TEXT_HEIGHT)
|
||||
{
|
||||
grub_error (GRUB_ERR_OUT_OF_RANGE, "invalid point (%u,%u)", x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
keep_track = 0;
|
||||
grub_terminfo_gotoxy (x, y);
|
||||
keep_track = 1;
|
||||
|
||||
xpos = x;
|
||||
ypos = y;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
grub_serial_cls (void)
|
||||
{
|
||||
keep_track = 0;
|
||||
grub_terminfo_cls ();
|
||||
keep_track = 1;
|
||||
|
||||
xpos = ypos = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
grub_serial_setcolorstate (const grub_term_color_state state)
|
||||
{
|
||||
keep_track = 0;
|
||||
switch (state)
|
||||
{
|
||||
case GRUB_TERM_COLOR_STANDARD:
|
||||
case GRUB_TERM_COLOR_NORMAL:
|
||||
grub_terminfo_reverse_video_off ();
|
||||
break;
|
||||
case GRUB_TERM_COLOR_HIGHLIGHT:
|
||||
grub_terminfo_reverse_video_on ();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
keep_track = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
grub_serial_setcolor (grub_uint8_t normal_color __attribute__ ((unused)),
|
||||
grub_uint8_t highlight_color __attribute__ ((unused)))
|
||||
{
|
||||
/* FIXME */
|
||||
}
|
||||
|
||||
static void
|
||||
grub_serial_setcursor (const int on)
|
||||
{
|
||||
if (on)
|
||||
grub_terminfo_cursor_on ();
|
||||
else
|
||||
grub_terminfo_cursor_off ();
|
||||
}
|
||||
|
||||
static struct grub_term grub_serial_term =
|
||||
{
|
||||
.name = "serial",
|
||||
.init = 0,
|
||||
.fini = 0,
|
||||
.putchar = grub_serial_putchar,
|
||||
.getcharwidth = grub_serial_getcharwidth,
|
||||
.checkkey = grub_serial_checkkey,
|
||||
.getkey = grub_serial_getkey,
|
||||
.getwh = grub_serial_getwh,
|
||||
.getxy = grub_serial_getxy,
|
||||
.gotoxy = grub_serial_gotoxy,
|
||||
.cls = grub_serial_cls,
|
||||
.setcolorstate = grub_serial_setcolorstate,
|
||||
.setcolor = grub_serial_setcolor,
|
||||
.setcursor = grub_serial_setcursor,
|
||||
.flags = 0,
|
||||
.next = 0
|
||||
};
|
||||
|
||||
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_serial (struct grub_arg_list *state,
|
||||
int argc __attribute__ ((unused)),
|
||||
char **args __attribute__ ((unused)))
|
||||
{
|
||||
struct serial_port backup_settings = serial_settings;
|
||||
grub_err_t hwiniterr;
|
||||
int arg;
|
||||
|
||||
if (state[0].set)
|
||||
{
|
||||
arg = grub_strtoul (state[0].arg, 0, 0);
|
||||
if (arg >= 0 && arg < 4)
|
||||
serial_settings.port = serial_hw_get_port ((int) arg);
|
||||
else
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad unit number.");
|
||||
}
|
||||
|
||||
if (state[1].set)
|
||||
serial_settings.port = (unsigned short) grub_strtoul (state[1].arg, 0, 0);
|
||||
|
||||
if (state[2].set)
|
||||
{
|
||||
unsigned long speed;
|
||||
|
||||
speed = grub_strtoul (state[2].arg, 0, 0);
|
||||
serial_settings.divisor = serial_get_divisor ((unsigned int) speed);
|
||||
if (serial_settings.divisor == 0)
|
||||
{
|
||||
serial_settings = backup_settings;
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad speed");
|
||||
}
|
||||
}
|
||||
|
||||
if (state[3].set)
|
||||
{
|
||||
if (! grub_strcmp (state[3].arg, "5"))
|
||||
serial_settings.word_len = UART_5BITS_WORD;
|
||||
else if (! grub_strcmp (state[3].arg, "6"))
|
||||
serial_settings.word_len = UART_6BITS_WORD;
|
||||
else if (! grub_strcmp (state[3].arg, "7"))
|
||||
serial_settings.word_len = UART_7BITS_WORD;
|
||||
else if (! grub_strcmp (state[3].arg, "8"))
|
||||
serial_settings.word_len = UART_8BITS_WORD;
|
||||
else
|
||||
{
|
||||
serial_settings = backup_settings;
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad word length");
|
||||
}
|
||||
}
|
||||
|
||||
if (state[4].set)
|
||||
{
|
||||
if (! grub_strcmp (state[4].arg, "no"))
|
||||
serial_settings.parity = UART_NO_PARITY;
|
||||
else if (! grub_strcmp (state[4].arg, "odd"))
|
||||
serial_settings.parity = UART_ODD_PARITY;
|
||||
else if (! grub_strcmp (state[4].arg, "even"))
|
||||
serial_settings.parity = UART_EVEN_PARITY;
|
||||
else
|
||||
{
|
||||
serial_settings = backup_settings;
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad parity");
|
||||
}
|
||||
}
|
||||
|
||||
if (state[5].set)
|
||||
{
|
||||
if (! grub_strcmp (state[5].arg, "1"))
|
||||
serial_settings.stop_bits = UART_1_STOP_BIT;
|
||||
else if (! grub_strcmp (state[5].arg, "2"))
|
||||
serial_settings.stop_bits = UART_2_STOP_BITS;
|
||||
else
|
||||
{
|
||||
serial_settings = backup_settings;
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad number of stop bits");
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize with new settings. */
|
||||
hwiniterr = serial_hw_init ();
|
||||
|
||||
if (hwiniterr == GRUB_ERR_NONE)
|
||||
{
|
||||
/* Register terminal if not yet registered. */
|
||||
if (registered == 0)
|
||||
{
|
||||
grub_term_register (&grub_serial_term);
|
||||
registered = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Initialization with new settings failed. */
|
||||
if (registered == 1)
|
||||
{
|
||||
/* If the terminal is registered, attempt to restore previous
|
||||
settings. */
|
||||
serial_settings = backup_settings;
|
||||
if (serial_hw_init () != GRUB_ERR_NONE)
|
||||
{
|
||||
/* If unable to restore settings, unregister terminal. */
|
||||
grub_term_unregister (&grub_serial_term);
|
||||
registered = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hwiniterr;
|
||||
}
|
||||
|
||||
GRUB_MOD_INIT
|
||||
{
|
||||
(void) mod; /* To stop warning. */
|
||||
grub_register_command ("serial", grub_cmd_serial, GRUB_COMMAND_FLAG_BOTH,
|
||||
"serial [OPTIONS...]", "Configure serial port.", options);
|
||||
/* Set default settings. */
|
||||
serial_settings.port = serial_hw_get_port (0);
|
||||
serial_settings.divisor = serial_get_divisor (9600);
|
||||
serial_settings.word_len = UART_8BITS_WORD;
|
||||
serial_settings.parity = UART_NO_PARITY;
|
||||
serial_settings.stop_bits = UART_1_STOP_BIT;
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI
|
||||
{
|
||||
grub_unregister_command ("serial");
|
||||
if (registered == 1) /* Unregister terminal only if registered. */
|
||||
grub_term_unregister (&grub_serial_term);
|
||||
}
|
188
term/terminfo.c
Normal file
188
term/terminfo.c
Normal file
|
@ -0,0 +1,188 @@
|
|||
/* terminfo.c - simple terminfo module */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2003,2004,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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains various functions dealing with different
|
||||
* terminal capabilities. For example, vt52 and vt100.
|
||||
*/
|
||||
|
||||
#include <grub/types.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/normal.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/terminfo.h>
|
||||
#include <grub/tparm.h>
|
||||
|
||||
struct terminfo
|
||||
{
|
||||
char *name;
|
||||
|
||||
char *gotoxy;
|
||||
char *cls;
|
||||
char *reverse_video_on;
|
||||
char *reverse_video_off;
|
||||
char *cursor_on;
|
||||
char *cursor_off;
|
||||
};
|
||||
|
||||
static struct terminfo term;
|
||||
|
||||
/* Get current terminfo name. */
|
||||
char *
|
||||
grub_terminfo_get_current (void)
|
||||
{
|
||||
return term.name;
|
||||
}
|
||||
|
||||
/* Free *PTR and set *PTR to NULL, to prevent double-free. */
|
||||
static void
|
||||
grub_terminfo_free (char **ptr)
|
||||
{
|
||||
grub_free (*ptr);
|
||||
*ptr = 0;
|
||||
}
|
||||
|
||||
/* Set current terminfo type. */
|
||||
grub_err_t
|
||||
grub_terminfo_set_current (const char *str)
|
||||
{
|
||||
/* 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 grub
|
||||
* configuration directory is easier then (b).
|
||||
* d. Your idea here.
|
||||
*/
|
||||
|
||||
/* Free previously allocated memory. */
|
||||
grub_terminfo_free (&term.name);
|
||||
grub_terminfo_free (&term.gotoxy);
|
||||
grub_terminfo_free (&term.cls);
|
||||
grub_terminfo_free (&term.reverse_video_on);
|
||||
grub_terminfo_free (&term.reverse_video_off);
|
||||
grub_terminfo_free (&term.cursor_on);
|
||||
grub_terminfo_free (&term.cursor_off);
|
||||
|
||||
if (grub_strcmp ("vt100", str) == 0)
|
||||
{
|
||||
term.name = grub_strdup ("vt100");
|
||||
term.gotoxy = grub_strdup ("\e[%i%p1%d;%p2%dH");
|
||||
term.cls = grub_strdup ("\e[H\e[J");
|
||||
term.reverse_video_on = grub_strdup ("\e[7m");
|
||||
term.reverse_video_off = grub_strdup ("\e[m");
|
||||
term.cursor_on = grub_strdup ("\e[?25l");
|
||||
term.cursor_off = grub_strdup ("\e[?25h");
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown terminfo type.");
|
||||
}
|
||||
|
||||
/* Wrapper for grub_putchar to write strings. */
|
||||
static void
|
||||
putstr (const char *str)
|
||||
{
|
||||
while (*str)
|
||||
grub_putchar (*str++);
|
||||
}
|
||||
|
||||
/* Move the cursor to the given position starting with "0". */
|
||||
void
|
||||
grub_terminfo_gotoxy (grub_uint8_t x, grub_uint8_t y)
|
||||
{
|
||||
putstr (grub_terminfo_tparm (term.gotoxy, y, x));
|
||||
}
|
||||
|
||||
/* Clear the screen. */
|
||||
void
|
||||
grub_terminfo_cls (void)
|
||||
{
|
||||
putstr (grub_terminfo_tparm (term.cls));
|
||||
}
|
||||
|
||||
/* Set reverse video mode on. */
|
||||
void
|
||||
grub_terminfo_reverse_video_on (void)
|
||||
{
|
||||
putstr (grub_terminfo_tparm (term.reverse_video_on));
|
||||
}
|
||||
|
||||
/* Set reverse video mode off. */
|
||||
void
|
||||
grub_terminfo_reverse_video_off (void)
|
||||
{
|
||||
putstr (grub_terminfo_tparm (term.reverse_video_off));
|
||||
}
|
||||
|
||||
/* Show cursor. */
|
||||
void
|
||||
grub_terminfo_cursor_on (void)
|
||||
{
|
||||
putstr (grub_terminfo_tparm (term.cursor_on));
|
||||
}
|
||||
|
||||
/* Hide cursor. */
|
||||
void
|
||||
grub_terminfo_cursor_off (void)
|
||||
{
|
||||
putstr (grub_terminfo_tparm (term.cursor_off));
|
||||
}
|
||||
|
||||
/* GRUB Command. */
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_terminfo (struct grub_arg_list *state __attribute__ ((unused)),
|
||||
int argc, char **args)
|
||||
{
|
||||
if (argc == 0)
|
||||
{
|
||||
grub_printf ("Current terminfo type: %s\n", grub_terminfo_get_current());
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
else if (argc != 1)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "too many parameters.");
|
||||
else
|
||||
return grub_terminfo_set_current (args[0]);
|
||||
}
|
||||
|
||||
GRUB_MOD_INIT
|
||||
{
|
||||
(void) mod; /* To stop warning. */
|
||||
grub_register_command ("terminfo", grub_cmd_terminfo, GRUB_COMMAND_FLAG_BOTH,
|
||||
"terminfo [TERM]", "Set terminfo type.", 0);
|
||||
grub_terminfo_set_current ("vt100");
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI
|
||||
{
|
||||
grub_unregister_command ("terminfo");
|
||||
}
|
769
term/tparm.c
Normal file
769
term/tparm.c
Normal file
|
@ -0,0 +1,769 @@
|
|||
/****************************************************************************
|
||||
* Copyright (c) 1998-2003,2004,2005 Free Software Foundation, Inc. *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a *
|
||||
* copy of this software and associated documentation files (the *
|
||||
* "Software"), to deal in the Software without restriction, including *
|
||||
* without limitation the rights to use, copy, modify, merge, publish, *
|
||||
* distribute, distribute with modifications, sublicense, and/or sell *
|
||||
* copies of the Software, and to permit persons to whom the Software is *
|
||||
* furnished to do so, subject to the following conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included *
|
||||
* in all copies or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
|
||||
* IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
|
||||
* THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
* *
|
||||
* Except as contained in this notice, the name(s) of the above copyright *
|
||||
* holders shall not be used in advertising or otherwise to promote the *
|
||||
* sale, use or other dealings in this Software without prior written *
|
||||
* authorization. *
|
||||
****************************************************************************/
|
||||
|
||||
/**********************************************************************
|
||||
* This code is a modification of lib_tparm.c found in ncurses-5.2. The
|
||||
* modification are for use in grub by replacing all libc function through
|
||||
* special grub functions. This also meant to delete all dynamic memory
|
||||
* allocation and replace it by a number of fixed buffers.
|
||||
*
|
||||
* Modifications by Tilmann Bubeck <t.bubeck@reinform.de> 2002
|
||||
*
|
||||
* Resync with ncurses-5.4 by Omniflux <omniflux+devel@omniflux.com> 2005
|
||||
**********************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
|
||||
* and: Eric S. Raymond <esr@snark.thyrsus.com> *
|
||||
* and: Thomas E. Dickey, 1996 on *
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* tparm.c
|
||||
*
|
||||
*/
|
||||
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/tparm.h>
|
||||
|
||||
/*
|
||||
* Common/troublesome character definitions
|
||||
*/
|
||||
typedef char grub_bool_t;
|
||||
#ifndef FALSE
|
||||
# define FALSE (0)
|
||||
#endif
|
||||
#ifndef TRUE
|
||||
# define TRUE (!FALSE)
|
||||
#endif
|
||||
|
||||
#define NUM_PARM 9
|
||||
#define NUM_VARS 26
|
||||
#define STACKSIZE 20
|
||||
#define MAX_FORMAT_LEN 256
|
||||
|
||||
#define max(a,b) ((a) > (b) ? (a) : (b))
|
||||
#define isdigit(c) ((c) >= '0' && (c) <= '9')
|
||||
#define isUPPER(c) ((c) >= 'A' && (c) <= 'Z')
|
||||
#define isLOWER(c) ((c) >= 'a' && (c) <= 'z')
|
||||
|
||||
#define UChar(c) ((unsigned char)(c))
|
||||
|
||||
//MODULE_ID("$Id$")
|
||||
|
||||
/*
|
||||
* char *
|
||||
* tparm(string, ...)
|
||||
*
|
||||
* Substitute the given parameters into the given string by the following
|
||||
* rules (taken from terminfo(5)):
|
||||
*
|
||||
* Cursor addressing and other strings requiring parame-
|
||||
* ters in the terminal are described by a parameterized string
|
||||
* capability, with like escapes %x in it. For example, to
|
||||
* address the cursor, the cup capability is given, using two
|
||||
* parameters: the row and column to address to. (Rows and
|
||||
* columns are numbered from zero and refer to the physical
|
||||
* screen visible to the user, not to any unseen memory.) If
|
||||
* the terminal has memory relative cursor addressing, that can
|
||||
* be indicated by
|
||||
*
|
||||
* The parameter mechanism uses a stack and special %
|
||||
* codes to manipulate it. Typically a sequence will push one
|
||||
* of the parameters onto the stack and then print it in some
|
||||
* format. Often more complex operations are necessary.
|
||||
*
|
||||
* The % encodings have the following meanings:
|
||||
*
|
||||
* %% outputs `%'
|
||||
* %c print pop() like %c in printf()
|
||||
* %s print pop() like %s in printf()
|
||||
* %[[:]flags][width[.precision]][doxXs]
|
||||
* as in printf, flags are [-+#] and space
|
||||
* The ':' is used to avoid making %+ or %-
|
||||
* patterns (see below).
|
||||
*
|
||||
* %p[1-9] push ith parm
|
||||
* %P[a-z] set dynamic variable [a-z] to pop()
|
||||
* %g[a-z] get dynamic variable [a-z] and push it
|
||||
* %P[A-Z] set static variable [A-Z] to pop()
|
||||
* %g[A-Z] get static variable [A-Z] and push it
|
||||
* %l push strlen(pop)
|
||||
* %'c' push char constant c
|
||||
* %{nn} push integer constant nn
|
||||
*
|
||||
* %+ %- %* %/ %m
|
||||
* arithmetic (%m is mod): push(pop() op pop())
|
||||
* %& %| %^ bit operations: push(pop() op pop())
|
||||
* %= %> %< logical operations: push(pop() op pop())
|
||||
* %A %O logical and & or operations for conditionals
|
||||
* %! %~ unary operations push(op pop())
|
||||
* %i add 1 to first two parms (for ANSI terminals)
|
||||
*
|
||||
* %? expr %t thenpart %e elsepart %;
|
||||
* if-then-else, %e elsepart is optional.
|
||||
* else-if's are possible ala Algol 68:
|
||||
* %? c1 %t b1 %e c2 %t b2 %e c3 %t b3 %e c4 %t b4 %e b5 %;
|
||||
*
|
||||
* For those of the above operators which are binary and not commutative,
|
||||
* the stack works in the usual way, with
|
||||
* %gx %gy %m
|
||||
* resulting in x mod y, not the reverse.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
int num;
|
||||
char *str;
|
||||
} data;
|
||||
grub_bool_t num_type;
|
||||
} stack_frame;
|
||||
|
||||
static stack_frame stack[STACKSIZE];
|
||||
static int stack_ptr;
|
||||
static const char *tparam_base = "";
|
||||
|
||||
static char *out_buff;
|
||||
static grub_size_t out_size;
|
||||
static grub_size_t out_used;
|
||||
|
||||
static char *fmt_buff;
|
||||
static grub_size_t fmt_size;
|
||||
|
||||
static inline void
|
||||
get_space(grub_size_t need)
|
||||
{
|
||||
need += out_used;
|
||||
if (need > out_size) {
|
||||
out_size = need * 2;
|
||||
out_buff = grub_realloc(out_buff, out_size*sizeof(char));
|
||||
if (out_buff == 0)
|
||||
// FIX ME! OOM, what now?
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
save_text(const char *fmt, const char *s, int len)
|
||||
{
|
||||
grub_size_t s_len = grub_strlen(s);
|
||||
if (len > (int) s_len)
|
||||
s_len = len;
|
||||
|
||||
get_space(s_len + 1);
|
||||
|
||||
(void) grub_sprintf(out_buff + out_used, fmt, s);
|
||||
out_used += grub_strlen(out_buff + out_used);
|
||||
}
|
||||
|
||||
static inline void
|
||||
save_number(const char *fmt, int number, int len)
|
||||
{
|
||||
if (len < 30)
|
||||
len = 30; /* actually log10(MAX_INT)+1 */
|
||||
|
||||
get_space((unsigned) len + 1);
|
||||
|
||||
(void) grub_sprintf(out_buff + out_used, fmt, number);
|
||||
out_used += grub_strlen(out_buff + out_used);
|
||||
}
|
||||
|
||||
static inline void
|
||||
save_char(int c)
|
||||
{
|
||||
if (c == 0)
|
||||
c = 0200;
|
||||
get_space(1);
|
||||
out_buff[out_used++] = c;
|
||||
}
|
||||
|
||||
static inline void
|
||||
npush(int x)
|
||||
{
|
||||
if (stack_ptr < STACKSIZE) {
|
||||
stack[stack_ptr].num_type = TRUE;
|
||||
stack[stack_ptr].data.num = x;
|
||||
stack_ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int
|
||||
npop(void)
|
||||
{
|
||||
int result = 0;
|
||||
if (stack_ptr > 0) {
|
||||
stack_ptr--;
|
||||
if (stack[stack_ptr].num_type)
|
||||
result = stack[stack_ptr].data.num;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void
|
||||
spush(char *x)
|
||||
{
|
||||
if (stack_ptr < STACKSIZE) {
|
||||
stack[stack_ptr].num_type = FALSE;
|
||||
stack[stack_ptr].data.str = x;
|
||||
stack_ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
static inline char *
|
||||
spop(void)
|
||||
{
|
||||
static char dummy[] = ""; /* avoid const-cast */
|
||||
char *result = dummy;
|
||||
if (stack_ptr > 0) {
|
||||
stack_ptr--;
|
||||
if (!stack[stack_ptr].num_type && stack[stack_ptr].data.str != 0)
|
||||
result = stack[stack_ptr].data.str;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline const char *
|
||||
parse_format(const char *s, char *format, int *len)
|
||||
{
|
||||
*len = 0;
|
||||
if (format != 0) {
|
||||
grub_bool_t done = FALSE;
|
||||
grub_bool_t allowminus = FALSE;
|
||||
grub_bool_t dot = FALSE;
|
||||
grub_bool_t err = FALSE;
|
||||
char *fmt = format;
|
||||
int my_width = 0;
|
||||
int my_prec = 0;
|
||||
int value = 0;
|
||||
|
||||
*len = 0;
|
||||
*format++ = '%';
|
||||
while (*s != '\0' && !done) {
|
||||
switch (*s) {
|
||||
case 'c': /* FALLTHRU */
|
||||
case 'd': /* FALLTHRU */
|
||||
case 'o': /* FALLTHRU */
|
||||
case 'x': /* FALLTHRU */
|
||||
case 'X': /* FALLTHRU */
|
||||
case 's':
|
||||
*format++ = *s;
|
||||
done = TRUE;
|
||||
break;
|
||||
case '.':
|
||||
*format++ = *s++;
|
||||
if (dot) {
|
||||
err = TRUE;
|
||||
} else { /* value before '.' is the width */
|
||||
dot = TRUE;
|
||||
my_width = value;
|
||||
}
|
||||
value = 0;
|
||||
break;
|
||||
case '#':
|
||||
*format++ = *s++;
|
||||
break;
|
||||
case ' ':
|
||||
*format++ = *s++;
|
||||
break;
|
||||
case ':':
|
||||
s++;
|
||||
allowminus = TRUE;
|
||||
break;
|
||||
case '-':
|
||||
if (allowminus) {
|
||||
*format++ = *s++;
|
||||
} else {
|
||||
done = TRUE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (isdigit(UChar(*s))) {
|
||||
value = (value * 10) + (*s - '0');
|
||||
if (value > 10000)
|
||||
err = TRUE;
|
||||
*format++ = *s++;
|
||||
} else {
|
||||
done = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we found an error, ignore (and remove) the flags.
|
||||
*/
|
||||
if (err) {
|
||||
my_width = my_prec = value = 0;
|
||||
format = fmt;
|
||||
*format++ = '%';
|
||||
*format++ = *s;
|
||||
}
|
||||
|
||||
/*
|
||||
* Any value after '.' is the precision. If we did not see '.', then
|
||||
* the value is the width.
|
||||
*/
|
||||
if (dot)
|
||||
my_prec = value;
|
||||
else
|
||||
my_width = value;
|
||||
|
||||
*format = '\0';
|
||||
/* return maximum string length in print */
|
||||
*len = (my_width > my_prec) ? my_width : my_prec;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* Analyze the string to see how many parameters we need from the varargs list,
|
||||
* and what their types are. We will only accept string parameters if they
|
||||
* appear as a %l or %s format following an explicit parameter reference (e.g.,
|
||||
* %p2%s). All other parameters are numbers.
|
||||
*
|
||||
* 'number' counts coarsely the number of pop's we see in the string, and
|
||||
* 'popcount' shows the highest parameter number in the string. We would like
|
||||
* to simply use the latter count, but if we are reading termcap strings, there
|
||||
* may be cases that we cannot see the explicit parameter numbers.
|
||||
*/
|
||||
static inline int
|
||||
analyze(const char *string, char *p_is_s[NUM_PARM], int *popcount)
|
||||
{
|
||||
grub_size_t len2;
|
||||
int i;
|
||||
int lastpop = -1;
|
||||
int len;
|
||||
int number = 0;
|
||||
const char *cp = string;
|
||||
static char dummy[] = "";
|
||||
|
||||
if (cp == 0)
|
||||
return 0;
|
||||
|
||||
if ((len2 = grub_strlen(cp)) > fmt_size) {
|
||||
fmt_size = len2 + fmt_size + 2;
|
||||
if ((fmt_buff = grub_realloc(fmt_buff, fmt_size*sizeof(char))) == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
grub_memset(p_is_s, 0, sizeof(p_is_s[0]) * NUM_PARM);
|
||||
*popcount = 0;
|
||||
|
||||
while ((cp - string) < (int) len2) {
|
||||
if (*cp == '%') {
|
||||
cp++;
|
||||
cp = parse_format(cp, fmt_buff, &len);
|
||||
switch (*cp) {
|
||||
default:
|
||||
break;
|
||||
|
||||
case 'd': /* FALLTHRU */
|
||||
case 'o': /* FALLTHRU */
|
||||
case 'x': /* FALLTHRU */
|
||||
case 'X': /* FALLTHRU */
|
||||
case 'c': /* FALLTHRU */
|
||||
if (lastpop <= 0)
|
||||
number++;
|
||||
lastpop = -1;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
case 's':
|
||||
if (lastpop > 0)
|
||||
p_is_s[lastpop - 1] = dummy;
|
||||
++number;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
cp++;
|
||||
i = (UChar(*cp) - '0');
|
||||
if (i >= 0 && i <= NUM_PARM) {
|
||||
lastpop = i;
|
||||
if (lastpop > *popcount)
|
||||
*popcount = lastpop;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
++number;
|
||||
++cp;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
cp++;
|
||||
break;
|
||||
|
||||
case '\'':
|
||||
cp += 2;
|
||||
lastpop = -1;
|
||||
break;
|
||||
|
||||
case '{':
|
||||
cp++;
|
||||
while (isdigit(UChar(*cp))) {
|
||||
cp++;
|
||||
}
|
||||
break;
|
||||
|
||||
case '+':
|
||||
case '-':
|
||||
case '*':
|
||||
case '/':
|
||||
case 'm':
|
||||
case 'A':
|
||||
case 'O':
|
||||
case '&':
|
||||
case '|':
|
||||
case '^':
|
||||
case '=':
|
||||
case '<':
|
||||
case '>':
|
||||
lastpop = -1;
|
||||
number += 2;
|
||||
break;
|
||||
|
||||
case '!':
|
||||
case '~':
|
||||
lastpop = -1;
|
||||
++number;
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
/* will add 1 to first (usually two) parameters */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*cp != '\0')
|
||||
cp++;
|
||||
}
|
||||
|
||||
if (number > NUM_PARM)
|
||||
number = NUM_PARM;
|
||||
return number;
|
||||
}
|
||||
|
||||
static inline char *
|
||||
tparam_internal(const char *string, va_list ap)
|
||||
{
|
||||
char *p_is_s[NUM_PARM];
|
||||
long param[NUM_PARM];
|
||||
int popcount;
|
||||
int number;
|
||||
int len;
|
||||
int level;
|
||||
int x, y;
|
||||
int i;
|
||||
const char *cp = string;
|
||||
grub_size_t len2;
|
||||
static int dynamic_var[NUM_VARS];
|
||||
static int static_vars[NUM_VARS];
|
||||
|
||||
if (cp == 0)
|
||||
return 0;
|
||||
|
||||
out_used = out_size = fmt_size = 0;
|
||||
|
||||
len2 = (int) grub_strlen(cp);
|
||||
|
||||
/*
|
||||
* Find the highest parameter-number referred to in the format string.
|
||||
* Use this value to limit the number of arguments copied from the
|
||||
* variable-length argument list.
|
||||
*/
|
||||
number = analyze(cp, p_is_s, &popcount);
|
||||
if (fmt_buff == 0)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < max(popcount, number); i++) {
|
||||
/*
|
||||
* A few caps (such as plab_norm) have string-valued parms.
|
||||
* We'll have to assume that the caller knows the difference, since
|
||||
* a char* and an int may not be the same size on the stack.
|
||||
*/
|
||||
if (p_is_s[i] != 0) {
|
||||
p_is_s[i] = va_arg(ap, char *);
|
||||
} else {
|
||||
param[i] = va_arg(ap, long int);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a termcap compatibility hack. If there are no explicit pop
|
||||
* operations in the string, load the stack in such a way that
|
||||
* successive pops will grab successive parameters. That will make
|
||||
* the expansion of (for example) \E[%d;%dH work correctly in termcap
|
||||
* style, which means tparam() will expand termcap strings OK.
|
||||
*/
|
||||
stack_ptr = 0;
|
||||
if (popcount == 0) {
|
||||
popcount = number;
|
||||
for (i = number - 1; i >= 0; i--)
|
||||
npush(param[i]);
|
||||
}
|
||||
|
||||
while ((cp - string) < (int) len2) {
|
||||
if (*cp != '%') {
|
||||
save_char(UChar(*cp));
|
||||
} else {
|
||||
tparam_base = cp++;
|
||||
cp = parse_format(cp, fmt_buff, &len);
|
||||
switch (*cp) {
|
||||
default:
|
||||
break;
|
||||
case '%':
|
||||
save_char('%');
|
||||
break;
|
||||
|
||||
case 'd': /* FALLTHRU */
|
||||
case 'o': /* FALLTHRU */
|
||||
case 'x': /* FALLTHRU */
|
||||
case 'X': /* FALLTHRU */
|
||||
save_number(fmt_buff, npop(), len);
|
||||
break;
|
||||
|
||||
case 'c': /* FALLTHRU */
|
||||
save_char(npop());
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
save_number("%d", (int) grub_strlen(spop()), 0);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
save_text(fmt_buff, spop(), len);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
cp++;
|
||||
i = (UChar(*cp) - '1');
|
||||
if (i >= 0 && i < NUM_PARM) {
|
||||
if (p_is_s[i])
|
||||
spush(p_is_s[i]);
|
||||
else
|
||||
npush(param[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
cp++;
|
||||
if (isUPPER(*cp)) {
|
||||
i = (UChar(*cp) - 'A');
|
||||
static_vars[i] = npop();
|
||||
} else if (isLOWER(*cp)) {
|
||||
i = (UChar(*cp) - 'a');
|
||||
dynamic_var[i] = npop();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
cp++;
|
||||
if (isUPPER(*cp)) {
|
||||
i = (UChar(*cp) - 'A');
|
||||
npush(static_vars[i]);
|
||||
} else if (isLOWER(*cp)) {
|
||||
i = (UChar(*cp) - 'a');
|
||||
npush(dynamic_var[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case '\'':
|
||||
cp++;
|
||||
npush(UChar(*cp));
|
||||
cp++;
|
||||
break;
|
||||
|
||||
case '{':
|
||||
number = 0;
|
||||
cp++;
|
||||
while (isdigit(UChar(*cp))) {
|
||||
number = (number * 10) + (UChar(*cp) - '0');
|
||||
cp++;
|
||||
}
|
||||
npush(number);
|
||||
break;
|
||||
|
||||
case '+':
|
||||
npush(npop() + npop());
|
||||
break;
|
||||
|
||||
case '-':
|
||||
y = npop();
|
||||
x = npop();
|
||||
npush(x - y);
|
||||
break;
|
||||
|
||||
case '*':
|
||||
npush(npop() * npop());
|
||||
break;
|
||||
|
||||
case '/':
|
||||
y = npop();
|
||||
x = npop();
|
||||
npush(y ? (x / y) : 0);
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
y = npop();
|
||||
x = npop();
|
||||
npush(y ? (x % y) : 0);
|
||||
break;
|
||||
|
||||
case 'A':
|
||||
npush(npop() && npop());
|
||||
break;
|
||||
|
||||
case 'O':
|
||||
npush(npop() || npop());
|
||||
break;
|
||||
|
||||
case '&':
|
||||
npush(npop() & npop());
|
||||
break;
|
||||
|
||||
case '|':
|
||||
npush(npop() | npop());
|
||||
break;
|
||||
|
||||
case '^':
|
||||
npush(npop() ^ npop());
|
||||
break;
|
||||
|
||||
case '=':
|
||||
y = npop();
|
||||
x = npop();
|
||||
npush(x == y);
|
||||
break;
|
||||
|
||||
case '<':
|
||||
y = npop();
|
||||
x = npop();
|
||||
npush(x < y);
|
||||
break;
|
||||
|
||||
case '>':
|
||||
y = npop();
|
||||
x = npop();
|
||||
npush(x > y);
|
||||
break;
|
||||
|
||||
case '!':
|
||||
npush(!npop());
|
||||
break;
|
||||
|
||||
case '~':
|
||||
npush(~npop());
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
if (p_is_s[0] == 0)
|
||||
param[0]++;
|
||||
if (p_is_s[1] == 0)
|
||||
param[1]++;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
break;
|
||||
|
||||
case 't':
|
||||
x = npop();
|
||||
if (!x) {
|
||||
/* scan forward for %e or %; at level zero */
|
||||
cp++;
|
||||
level = 0;
|
||||
while (*cp) {
|
||||
if (*cp == '%') {
|
||||
cp++;
|
||||
if (*cp == '?')
|
||||
level++;
|
||||
else if (*cp == ';') {
|
||||
if (level > 0)
|
||||
level--;
|
||||
else
|
||||
break;
|
||||
} else if (*cp == 'e' && level == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (*cp)
|
||||
cp++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
/* scan forward for a %; at level zero */
|
||||
cp++;
|
||||
level = 0;
|
||||
while (*cp) {
|
||||
if (*cp == '%') {
|
||||
cp++;
|
||||
if (*cp == '?')
|
||||
level++;
|
||||
else if (*cp == ';') {
|
||||
if (level > 0)
|
||||
level--;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*cp)
|
||||
cp++;
|
||||
}
|
||||
break;
|
||||
|
||||
case ';':
|
||||
break;
|
||||
|
||||
} /* endswitch (*cp) */
|
||||
} /* endelse (*cp == '%') */
|
||||
|
||||
if (*cp == '\0')
|
||||
break;
|
||||
|
||||
cp++;
|
||||
} /* endwhile (*cp) */
|
||||
|
||||
get_space(1);
|
||||
out_buff[out_used] = '\0';
|
||||
|
||||
return (out_buff);
|
||||
}
|
||||
|
||||
char *
|
||||
grub_terminfo_tparm (const char *string, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *result;
|
||||
|
||||
va_start (ap, string);
|
||||
result = tparam_internal (string, ap);
|
||||
va_end (ap);
|
||||
return result;
|
||||
}
|
Loading…
Reference in a new issue