1
0
mirror of https://github.com/irssi/irssi.git synced 2024-06-16 06:25:24 +00:00

Added support for using terminfo/termcap instead of curses. By default,

configure chooses to use ncurses if found, of terminfo if only curses was
found. --with-terminfo parameter can be used to specify if you want it or
not.


git-svn-id: http://svn.irssi.org/repos/irssi/trunk@1924 dbcabf3a-b0e7-0310-adc4-f8d773084564
This commit is contained in:
Timo Sirainen 2001-10-28 11:30:26 +00:00 committed by cras
parent 8567481fd0
commit 2ba339a26b
30 changed files with 2662 additions and 268 deletions

View File

@ -23,12 +23,13 @@
#undef SCO_FLAVOR
/* our own curses checks */
#undef USE_CURSES_WINDOWS
#undef HAVE_NCURSES_USE_DEFAULT_COLORS
#undef HAVE_CURSES_IDCOK
#undef HAVE_CURSES_RESIZETERM
#undef HAVE_CURSES_WRESIZE
#undef USE_CURSES_WINDOWS
/* terminfo/termcap */
#undef HAVE_TERMINFO
/* nls */
#undef ENABLE_NLS

View File

@ -90,6 +90,18 @@ AC_ARG_WITH(proxy,
fi,
want_irssiproxy=no)
AC_ARG_WITH(terminfo,
[ --with-terminfo Use terminfo directly instead of curses],
if test x$withval = xyes; then
want_terminfo=yes
else
if test "x$withval" = xno; then
want_terminfo=no
else
want_terminfo=yes
fi
fi,
want_terminfo=auto)
AC_ARG_WITH(modules,
[ --with-modules Specify what modules to build in binary],
@ -173,13 +185,6 @@ AC_ARG_WITH(tests,
TEST_DIR=)
AC_SUBST(TEST_DIR)
AC_ARG_ENABLE(curses-windows,
[ --enable-curses-windows Use curses windows],
if test x$enableval != xno; then
AC_DEFINE(USE_CURSES_WINDOWS)
fi,
AC_DEFINE(USE_CURSES_WINDOWS))
AC_ARG_ENABLE(memdebug,
[ --enable-memdebug Enable memory debugging],
if test x$enableval = xyes; then
@ -213,11 +218,11 @@ dnl **
AC_CHECK_FUNCS(mkfifo fcntl)
AC_CHECK_LIB(socket, socket, [
PROG_LIBS="$PROG_LIBS -lsocket"
LIBS="$LIBS -lsocket"
])
AC_CHECK_LIB(nsl, inet_addr, [
PROG_LIBS="$PROG_LIBS -lnsl"
LIBS="$LIBS -lnsl"
], -lsocket)
dnl * gcc specific options
@ -256,7 +261,7 @@ dnl **
if test "x$want_socks" = "xyes"; then
AC_CHECK_LIB(socks, connect, [
PROG_LIBS="$PROG_LIBS -lsocks"
LIBS="$LIBS -lsocks"
AC_CHECK_HEADER(socks.h, [
AC_DEFINE(HAVE_SOCKS_H)
CFLAGS="$CFLAGS -DSOCKS"
@ -369,7 +374,7 @@ if test -z "$GLIB_DIR"; then
fi
fi
PROG_LIBS="$PROG_LIBS $GLIB_LIBS"
LIBS="$LIBS $GLIB_LIBS"
dnl **
dnl ** check if we can link dynamic libraries to modules
@ -434,35 +439,38 @@ dnl **
if test "x$want_textui" = "xyes"; then
AC_CHECK_CURSES
if test -n "$has_ncurses"; then
AC_CHECK_LIB(ncurses, use_default_colors, [
AC_DEFINE(HAVE_NCURSES_USE_DEFAULT_COLORS)
],, $CURSES_LIBS)
AC_CHECK_LIB(ncurses, idcok, [
AC_DEFINE(HAVE_CURSES_IDCOK)
],, $CURSES_LIBS)
AC_CHECK_LIB(ncurses, resizeterm, [
AC_DEFINE(HAVE_CURSES_RESIZETERM)
],, $CURSES_LIBS)
AC_CHECK_LIB(ncurses, wresize, [
AC_DEFINE(HAVE_CURSES_WRESIZE)
],, $CURSES_LIBS)
elif test "x$has_curses" = "xtrue"; then
AC_CHECK_LIB(curses, idcok, [
AC_DEFINE(HAVE_CURSES_IDCOK)
],, $CURSES_LIBS)
AC_CHECK_LIB(curses, resizeterm, [
AC_DEFINE(HAVE_CURSES_RESIZETERM)
],, $CURSES_LIBS)
AC_CHECK_LIB(curses, wresize, [
AC_DEFINE(HAVE_CURSES_WRESIZE)
],, $CURSES_LIBS)
LIBS="$LIBS $CURSES_LIBS"
if test "x$has_curses" = "xtrue"; then
AC_CHECK_FUNC(use_default_colors, AC_DEFINE(HAVE_NCURSES_USE_DEFAULT_COLORS))
AC_CHECK_FUNC(idcok, AC_DEFINE(HAVE_CURSES_IDCOK))
AC_CHECK_FUNC(resizeterm, AC_DEFINE(HAVE_CURSES_RESIZETERM))
AC_CHECK_FUNC(wresize, AC_DEFINE(HAVE_CURSES_WRESIZE))
if test "x$want_terminfo" = "xauto" -a "x$has_ncurses" != "xtrue"; then
dnl * we'd rather use terminfo/termcap than plain curses
want_terminfo=yes
AC_CHECK_FUNC(setupterm,, want_termcap=yes)
fi
else
want_textui=no
curses_error=yes
AC_CHECK_LIB(tinfo, setupterm, [
LIBS="$LIBS -ltinfo"
want_terminfo=yes
], AC_CHECK_LIB(termlib, tgetent, [
LIBS="$LIBS -ltermlib"
want_termcap=yes
], AC_CHECK_LIB(termcap, tgetent, [
LIBS="$LIBS -ltermcap"
want_termcap=yes
], [
AC_MSG_WARN(Terminfo/termcap not found)
want_textui=no
curses_error=yes
])))
fi
else
has_curses=false
if test "x$want_termcap" = "xyes"; then
AC_CHECK_FUNC(tparm,, need_tparm=yes)
else
AC_DEFINE(HAVE_TERMINFO)
fi
fi
dnl **
@ -642,8 +650,8 @@ AM_CONDITIONAL(BUILD_PLUGINS, test "$want_plugins" = "yes")
AM_CONDITIONAL(BUILD_SERVERTEST, test -n "$TEST_DIR")
AM_CONDITIONAL(HAVE_PERL, test "$want_perl" != "no")
AM_CONDITIONAL(HAVE_STATIC_PERL, test "$want_perl" = "static")
AC_SUBST(PROG_LIBS)
AM_CONDITIONAL(NEED_TPARM, test "$need_tparm" = "yes")
AM_CONDITIONAL(USE_CURSES, test "$want_terminfo" != "yes" -a "$want_termcap" != "yes")
dnl **
dnl ** Keep all the libraries here so each frontend doesn't need to
@ -811,7 +819,16 @@ fi
echo
if test "x$curses_error" != "xyes"; then
echo "Building text frontend ..... : $want_textui"
if test "x$want_textui" = "xno"; then
text=no
elif test "x$want_termcap" = "xyes"; then
text="yes, using termcap"
elif test "x$want_terminfo" = "xyes"; then
text="yes, using terminfo"
else
text="yes, using curses"
fi
echo "Building text frontend ..... : $text"
else
echo "Building text frontend ..... : NO!!"
echo " - Because curses was not found, specify the path to it with"

View File

@ -47,9 +47,9 @@
#############################################################################
# default foreground color (%N) - 0 is the "default terminal color"
default_color = 0;
# default foreground color when "0" can't be used,
# default foreground color (%N) - -1 is the "default terminal color"
default_color = -1;
# default foreground color when -1 can't be used,
# such as with bolds and reverses. white is default.
default_real_color = 7;

View File

@ -990,8 +990,16 @@ void format_send_to_gui(TEXT_DEST_REC *dest, const char *text)
}
}
ptr++;
if (*ptr != FORMAT_COLOR_NOCHANGE)
if (*ptr != FORMAT_COLOR_NOCHANGE) {
bgcolor = *ptr-'0';
if (bgcolor <= 7)
flags &= ~GUI_PRINT_FLAG_BLINK;
else {
/* blink */
bgcolor -= 8;
flags |= GUI_PRINT_FLAG_BLINK;
}
}
}
ptr++;
break;

View File

@ -799,9 +799,11 @@ static int theme_read(THEME_REC *theme, const char *path, const char *data)
}
theme->default_color =
config_get_int(config, NULL, "default_color", 0);
theme->default_real_color =
config_get_int(config, NULL, "default_real_color", 7);
config_get_int(config, NULL, "default_color", -1);
/* FIXME: remove after 0.7.99 */
if (theme->default_color == 0 &&
config_get_int(config, NULL, "default_real_color", -1) != -1)
theme->default_color = -1;
theme_read_replaces(config, theme);
if (data == NULL) {
@ -1141,8 +1143,7 @@ static void themes_read(void)
if (current_theme == NULL) {
fname = g_strdup_printf("%s/default.theme", get_irssi_dir());
current_theme = theme_create(fname, "default");
current_theme->default_color = 0;
current_theme->default_real_color = 7;
current_theme->default_color = -1;
theme_read(current_theme, NULL, default_theme);
g_free(fname);
}

View File

@ -16,11 +16,8 @@ typedef struct {
time_t last_modify;
int default_color; /* default color to use with text with default
background. default is 0 which means the default
color set by terminal */
int default_real_color; /* default color to use with background set.
this shouldn't be 0, unless black is really
wanted. default is 7 (white). */
background. default is -1 which means the
default color set by terminal */
GHashTable *modules;
int replace_keys[256]; /* index to replace_values for each char */

View File

@ -19,9 +19,27 @@ irssi_LDADD = \
@COMMON_LIBS@ \
@PERL_LINK_LIBS@ \
@PERL_FE_LINK_LIBS@ \
@PERL_LINK_FLAGS@ \
$(PROG_LIBS) \
$(CURSES_LIBS)
@PERL_LINK_FLAGS@
tparm_sources = \
tparm.c
terminfo_sources = \
term-terminfo.c \
terminfo-core.c
curses_sources = \
term-curses.c
if NEED_TPARM
use_tparm_sources = $(tparm_sources)
endif
if USE_CURSES
use_term_sources = $(curses_sources)
else
use_term_sources = $(terminfo_sources)
endif
irssi_SOURCES = \
gui-entry.c \
@ -33,10 +51,12 @@ irssi_SOURCES = \
mainwindows.c \
mainwindow-activity.c \
mainwindows-layout.c \
screen.c \
statusbar.c \
statusbar-config.c \
statusbar-items.c \
term.c \
$(use_tparm_sources) \
$(use_term_sources) \
textbuffer.c \
textbuffer-commands.c \
textbuffer-reformat.c \
@ -50,12 +70,18 @@ noinst_HEADERS = \
gui-readline.h \
gui-windows.h \
mainwindows.h \
screen.h \
statusbar.h \
statusbar-config.h \
statusbar-items.h \
term.h \
terminfo-core.h \
textbuffer.h \
textbuffer-view.h \
textbuffer-reformat.h \
module.h \
module-formats.h
EXTRA_DIST = \
$(tparm_sources) \
$(terminfo_sources) \
$(curses_sources)

View File

@ -23,7 +23,7 @@
#include "gui-entry.h"
#include "gui-printtext.h"
#include "screen.h"
#include "term.h"
GUI_ENTRY_REC *active_entry;
@ -76,36 +76,36 @@ static void gui_entry_draw_from(GUI_ENTRY_REC *entry, int pos)
if (xpos > end_xpos)
return;
screen_set_color(screen_root, 0);
screen_move(screen_root, xpos, entry->ypos);
term_set_color(root_window, ATTR_RESET);
term_move(root_window, xpos, entry->ypos);
p = entry->scrstart + pos >= entry->text->len ? "" :
entry->text->str + entry->scrstart + pos;
for (; *p != '\0' && xpos < end_xpos; p++, xpos++) {
if (entry->hidden)
screen_addch(screen_root, ' ');
term_addch(root_window, ' ');
else if ((unsigned char) *p >= 32)
screen_addch(screen_root, (unsigned char) *p);
term_addch(root_window, (unsigned char) *p);
else {
screen_set_color(screen_root, ATTR_REVERSE);
screen_addch(screen_root, *p+'A'-1);
screen_set_color(screen_root, 0);
term_set_color(root_window, ATTR_RESET|ATTR_REVERSE);
term_addch(root_window, *p+'A'-1);
term_set_color(root_window, ATTR_RESET);
}
}
/* clear the rest of the input line */
if (end_xpos == screen_width)
screen_clrtoeol(screen_root);
if (end_xpos == term_width)
term_clrtoeol(root_window);
else {
while (xpos < end_xpos) {
screen_addch(screen_root, ' ');
term_addch(root_window, ' ');
xpos++;
}
}
screen_move_cursor(entry->xpos + entry->scrpos + entry->promptlen,
entry->ypos);
screen_refresh(NULL);
term_move_cursor(entry->xpos + entry->scrpos + entry->promptlen,
entry->ypos);
term_refresh(NULL);
}
static void gui_entry_draw(GUI_ENTRY_REC *entry)
@ -153,9 +153,9 @@ void gui_entry_set_active(GUI_ENTRY_REC *entry)
active_entry = entry;
if (entry != NULL) {
screen_move_cursor(entry->xpos + entry->scrpos +
entry->promptlen, entry->ypos);
screen_refresh(NULL);
term_move_cursor(entry->xpos + entry->scrpos +
entry->promptlen, entry->ypos);
term_refresh(NULL);
}
}

View File

@ -25,14 +25,14 @@
#include "formats.h"
#include "printtext.h"
#include "screen.h"
#include "term.h"
#include "gui-printtext.h"
#include "gui-windows.h"
int mirc_colors[] = { 15, 0, 1, 2, 12, 6, 5, 4, 14, 10, 3, 11, 9, 13, 8, 7 };
static int scrollback_lines, scrollback_hours, scrollback_burst_remove;
static int last_color, last_flags;
static int last_fg, last_bg, last_flags;
static int next_xpos, next_ypos;
static GHashTable *indent_functions;
@ -137,51 +137,51 @@ static void remove_old_lines(TEXT_BUFFER_VIEW_REC *view)
}
}
static void get_colors(int flags, int *fg, int *bg)
static void get_colors(int flags, int *fg, int *bg, int *attr)
{
if (flags & GUI_PRINT_FLAG_MIRC_COLOR) {
/* mirc colors - real range is 0..15, but after 16
colors wrap to 0, 1, ... */
*bg = *bg < 0 ? 0 : mirc_colors[*bg % 16];
if (*fg > 0) *fg = mirc_colors[*fg % 16];
} else {
/* default colors */
*bg = *bg < 0 || *bg > 15 ? 0 : *bg;
if (*fg > 8) *fg &= ~8;
if (*bg >= 0) *bg = mirc_colors[*bg % 16];
if (*fg >= 0) *fg = mirc_colors[*fg % 16];
}
if (*fg < 0 || *fg > 15) {
*fg = *bg == 0 ? current_theme->default_color :
current_theme->default_real_color;
}
if (*fg < 0 || *fg > 15)
*fg = current_theme->default_color;
if (*bg < 0 || *bg > 15)
*bg = -1;
if (flags & GUI_PRINT_FLAG_REVERSE)
*fg |= ATTR_REVERSE;
if (*fg == 8) *fg |= ATTR_COLOR8;
if (flags & GUI_PRINT_FLAG_BOLD) {
if (*fg == 0) *fg = current_theme->default_real_color;
*fg |= 8;
}
if (flags & GUI_PRINT_FLAG_UNDERLINE) *fg |= ATTR_UNDERLINE;
if (flags & GUI_PRINT_FLAG_BLINK) *bg |= 0x08;
*attr = 0;
if (flags & GUI_PRINT_FLAG_REVERSE) *attr |= ATTR_REVERSE;
if (flags & GUI_PRINT_FLAG_BOLD) *attr |= ATTR_BOLD;
if (flags & GUI_PRINT_FLAG_UNDERLINE) *attr |= ATTR_UNDERLINE;
if (flags & GUI_PRINT_FLAG_BLINK) *attr |= ATTR_BLINK;
}
static void line_add_colors(TEXT_BUFFER_REC *buffer, LINE_REC **line,
int fg, int bg, int flags)
{
unsigned char data[20];
int color, pos;
int pos;
/* get the fg & bg command chars */
fg = fg < 0 ? LINE_COLOR_DEFAULT : fg & 0x0f;
bg = LINE_COLOR_BG | (bg < 0 ? LINE_COLOR_DEFAULT : bg & 0x0f);
if (flags & GUI_PRINT_FLAG_BOLD)
fg |= LINE_COLOR_BOLD;
if (flags & GUI_PRINT_FLAG_BLINK)
bg |= LINE_COLOR_BLINK;
/* color should never have last bit on or it would be treated as a
command! */
color = (fg & 0x0f) | ((bg & 0x07) << 4);
pos = 0;
if (((fg & ATTR_COLOR8) == 0 && (fg|(bg << 4)) != last_color) ||
((fg & ATTR_COLOR8) && (fg & 0xf0) != (last_color & 0xf0))) {
if (fg != last_fg) {
last_fg = fg;
data[pos++] = 0;
data[pos++] = color == 0 ? LINE_CMD_COLOR0 : color;
data[pos++] = fg == 0 ? LINE_CMD_COLOR0 : fg;
}
if (bg != last_bg) {
last_bg = bg;
data[pos++] = 0;
data[pos++] = bg;
}
if ((flags & GUI_PRINT_FLAG_UNDERLINE) != (last_flags & GUI_PRINT_FLAG_UNDERLINE)) {
@ -192,14 +192,6 @@ static void line_add_colors(TEXT_BUFFER_REC *buffer, LINE_REC **line,
data[pos++] = 0;
data[pos++] = LINE_CMD_REVERSE;
}
if (fg & ATTR_COLOR8) {
data[pos++] = 0;
data[pos++] = LINE_CMD_COLOR8;
}
if (bg & 0x08) {
data[pos++] = 0;
data[pos++] = LINE_CMD_BLINK;
}
if (flags & GUI_PRINT_FLAG_INDENT) {
data[pos++] = 0;
data[pos++] = LINE_CMD_INDENT;
@ -209,7 +201,6 @@ static void line_add_colors(TEXT_BUFFER_REC *buffer, LINE_REC **line,
*line = textbuffer_insert(buffer, *line, data, pos, NULL);
last_flags = flags;
last_color = fg | (bg << 4);
}
static void line_add_indent_func(TEXT_BUFFER_REC *buffer, LINE_REC **line,
@ -243,24 +234,24 @@ static void sig_gui_print_text(WINDOW_REC *window, void *fgcolor,
TEXT_BUFFER_VIEW_REC *view;
LINE_REC *insert_after;
LINE_INFO_REC lineinfo;
int fg, bg, flags;
int fg, bg, flags, attr;
flags = GPOINTER_TO_INT(pflags);
fg = GPOINTER_TO_INT(fgcolor);
bg = GPOINTER_TO_INT(bgcolor);
get_colors(flags, &fg, &bg);
get_colors(flags, &fg, &bg, &attr);
if (window == NULL) {
g_return_if_fail(next_xpos != -1);
screen_move(screen_root, next_xpos, next_ypos);
if (flags & GUI_PRINT_FLAG_CLRTOEOL) {
screen_set_bg(screen_root, fg | (bg << 4));
screen_clrtoeol(screen_root);
screen_set_bg(screen_root, 0);
}
screen_set_color(screen_root, fg | (bg << 4));
screen_addstr(screen_root, str);
attr |= fg > 0 ? fg : ATTR_RESETFG;
attr |= bg > 0 ? (bg << 4) : ATTR_RESETBG;
term_set_color(root_window, attr);
term_move(root_window, next_xpos, next_ypos);
if (flags & GUI_PRINT_FLAG_CLRTOEOL)
term_clrtoeol(root_window);
term_addstr(root_window, str);
next_xpos += strlen(str);
return;
}
@ -293,7 +284,7 @@ static void sig_gui_printtext_finished(WINDOW_REC *window)
TEXT_BUFFER_VIEW_REC *view;
LINE_REC *insert_after;
last_color = 0;
last_fg = last_bg = -1;
last_flags = 0;
view = WINDOW_GUI(window)->view;

View File

@ -29,7 +29,7 @@
#include "keyboard.h"
#include "translation.h"
#include "screen.h"
#include "term.h"
#include "gui-entry.h"
#include "gui-windows.h"
@ -330,7 +330,7 @@ void readline(void)
int key;
for (;;) {
key = screen_getch();
key = term_getch();
if (key == -1)
break;
@ -485,6 +485,11 @@ static void key_insert_text(const char *data)
g_free(str);
}
static void key_sig_stop(void)
{
term_stop();
}
static void sig_window_auto_changed(void)
{
command_history_next(active_win, gui_entry_get_text(active_entry));
@ -615,9 +620,11 @@ void gui_readline_init(void)
/* inserting special input characters to line.. */
key_bind("insert_text", "Append text to line", NULL, NULL, (SIGNAL_FUNC) key_insert_text);
/* autoreplaces */
key_bind("multi", NULL, "return", "check_replaces;send_line", NULL);
key_bind("multi", NULL, "space", "check_replaces;insert_text ", NULL);
/* moving between windows */
for (n = 0; changekeys[n] != '\0'; n++) {
key = g_strdup_printf("meta-%c", changekeys[n]);
ltoa(data, n+1);
@ -625,6 +632,9 @@ void gui_readline_init(void)
g_free(key);
}
/* misc */
key_bind("stop_irc", "Send SIGSTOP to client", "^Z", NULL, (SIGNAL_FUNC) key_sig_stop);
key_configure_thaw();
signal_add("window changed automatic", (SIGNAL_FUNC) sig_window_auto_changed);
@ -681,6 +691,7 @@ void gui_readline_deinit(void)
key_unbind("insert_text", (SIGNAL_FUNC) key_insert_text);
key_unbind("change_window", (SIGNAL_FUNC) key_change_window);
key_unbind("stop_irc", (SIGNAL_FUNC) key_sig_stop);
keyboard_destroy(keyboard);
key_configure_thaw();

View File

@ -24,7 +24,7 @@
#include "settings.h"
#include "special-vars.h"
#include "screen.h"
#include "term.h"
#include "gui-entry.h"
#include "gui-windows.h"
#include "gui-printtext.h"

View File

@ -32,7 +32,7 @@
#include "fe-common-irc.h"
#include "themes.h"
#include "screen.h"
#include "term.h"
#include "gui-entry.h"
#include "mainwindows.h"
#include "gui-printtext.h"
@ -91,8 +91,8 @@ static void sig_exit(void)
/* redraw irssi's screen.. */
void irssi_redraw(void)
{
screen_clear();
screen_refresh(NULL);
term_clear();
term_refresh(NULL);
/* windows */
mainwindows_redraw();
@ -116,7 +116,7 @@ static void textui_finish_init(void)
{
quitting = FALSE;
screen_refresh_freeze();
term_refresh_freeze();
textbuffer_init();
textbuffer_view_init();
textbuffer_commands_init();
@ -130,7 +130,7 @@ static void textui_finish_init(void)
mainwindows_layout_init();
gui_windows_init();
statusbar_init();
screen_refresh_thaw();
term_refresh_thaw();
settings_check();
module_register("core", "fe-text");
@ -155,7 +155,7 @@ static void textui_deinit(void)
quitting = TRUE;
signal(SIGINT, SIG_DFL);
screen_refresh_freeze();
term_refresh_freeze();
while (modules != NULL)
module_unload(modules->data);
@ -180,8 +180,8 @@ static void textui_deinit(void)
textbuffer_view_deinit();
textbuffer_deinit();
screen_refresh_thaw();
deinit_screen();
term_refresh_thaw();
term_deinit();
theme_unregister();
@ -274,7 +274,7 @@ int main(int argc, char **argv)
textui_init();
args_execute(argc, argv);
if (!init_screen())
if (!term_init())
g_error("Can't initialize screen handling, quitting.\n");
textui_finish_init();

View File

@ -38,7 +38,7 @@ static void window_lastlog_clear(WINDOW_REC *window)
TEXT_BUFFER_VIEW_REC *view;
LINE_REC *line, *next;
screen_refresh_freeze();
term_refresh_freeze();
view = WINDOW_GUI(window)->view;
line = textbuffer_view_get_lines(view);
@ -50,7 +50,7 @@ static void window_lastlog_clear(WINDOW_REC *window)
line = next;
}
textbuffer_view_redraw(view);
screen_refresh_thaw();
term_refresh_thaw();
}
/* Only unknown keys in `optlist' should be levels.

View File

@ -123,7 +123,7 @@ static void sig_layout_restore(void)
windows_count = g_slist_length(sorted_config);
/* calculate the saved terminal height */
avail_height = screen_height -
avail_height = term_height -
screen_reserved_top - screen_reserved_bottom;
height = 0;
heights = g_new0(int, windows_count);

View File

@ -27,7 +27,7 @@
#include "settings.h"
#include "printtext.h"
#include "screen.h"
#include "term.h"
#include "gui-windows.h"
#define NEW_WINDOW_SIZE (WINDOW_MIN_SIZE + 1)
@ -39,16 +39,16 @@ int screen_reserved_top, screen_reserved_bottom;
static int old_screen_width, old_screen_height;
#define mainwindow_create_screen(window) \
screen_window_create(0, \
(window)->first_line + (window)->statusbar_lines_top, \
(window)->width, \
(window)->height + (window)->statusbar_lines)
#define mainwindow_set_screen_size(window) \
screen_window_move((window)->screen_win, 0, \
term_window_create(0, \
(window)->first_line + (window)->statusbar_lines_top, \
(window)->width, \
(window)->height - (window)->statusbar_lines);
(window)->height + (window)->statusbar_lines)
#define mainwindow_set_screen_size(window) \
term_window_move((window)->screen_win, 0, \
(window)->first_line + (window)->statusbar_lines_top, \
(window)->width, \
(window)->height - (window)->statusbar_lines);
static MAIN_WINDOW_REC *find_window_with_room(void)
@ -176,13 +176,13 @@ MAIN_WINDOW_REC *mainwindow_create(void)
int space;
rec = g_new0(MAIN_WINDOW_REC, 1);
rec->width = screen_width;
rec->width = term_width;
if (mainwindows == NULL) {
active_mainwin = rec;
rec->first_line = screen_reserved_top;
rec->last_line = screen_height-1 - screen_reserved_bottom;
rec->last_line = term_height-1 - screen_reserved_bottom;
rec->height = rec->last_line-rec->first_line+1;
} else {
parent = WINDOW_MAIN(active_win);
@ -204,7 +204,7 @@ MAIN_WINDOW_REC *mainwindow_create(void)
}
rec->screen_win = mainwindow_create_screen(rec);
screen_refresh(NULL);
term_refresh(NULL);
mainwindows = g_slist_append(mainwindows, rec);
signal_emit("mainwindow created", 1, rec);
@ -290,7 +290,7 @@ void mainwindow_destroy(MAIN_WINDOW_REC *window)
mainwindows = g_slist_remove(mainwindows, window);
signal_emit("mainwindow destroyed", 1, window);
screen_window_destroy(window->screen_win);
term_window_destroy(window->screen_win);
if (!quitting && mainwindows != NULL) {
gui_windows_remove_parent(window);
@ -308,13 +308,13 @@ void mainwindows_redraw(void)
{
GSList *tmp;
screen_refresh_freeze();
term_refresh_freeze();
for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) {
MAIN_WINDOW_REC *rec = tmp->data;
gui_window_redraw(rec->active);
}
screen_refresh_thaw();
term_refresh_thaw();
}
static int mainwindows_compare(MAIN_WINDOW_REC *w1, MAIN_WINDOW_REC *w2)
@ -453,7 +453,7 @@ void mainwindows_resize(int width, int height)
old_screen_width = width;
old_screen_height = height;
screen_refresh_freeze();
term_refresh_freeze();
if (ydiff < 0)
mainwindows_resize_smaller(xdiff, ydiff);
else if (ydiff > 0)
@ -462,7 +462,7 @@ void mainwindows_resize(int width, int height)
mainwindows_resize_horiz(xdiff);
signal_emit("terminal resized", 0);
screen_refresh_thaw();
term_refresh_thaw();
irssi_redraw();
}
@ -492,7 +492,7 @@ int mainwindows_reserve_lines(int top, int bottom)
ret = screen_reserved_bottom;
screen_reserved_bottom += bottom;
window = mainwindows_find_upper(screen_height);
window = mainwindows_find_upper(term_height);
if (window != NULL) {
window->last_line -= bottom;
mainwindow_resize(window, 0, -bottom);
@ -706,7 +706,7 @@ static void cmd_window_balance(void)
windows = g_slist_length(mainwindows);
if (windows == 1) return;
avail_size = screen_height - screen_reserved_top-screen_reserved_bottom;
avail_size = term_height - screen_reserved_top-screen_reserved_bottom;
unit_size = avail_size/windows;
bigger_units = avail_size%windows;
@ -1033,8 +1033,8 @@ static void sig_window_print_info(WINDOW_REC *win)
void mainwindows_init(void)
{
old_screen_width = screen_width;
old_screen_height = screen_height;
old_screen_width = term_width;
old_screen_height = term_height;
mainwindows = NULL;
active_mainwin = NULL;

View File

@ -2,7 +2,7 @@
#define __MAINWINDOWS_H
#include "fe-windows.h"
#include "screen.h"
#include "term.h"
#define WINDOW_MIN_SIZE 2
@ -12,7 +12,7 @@
typedef struct {
WINDOW_REC *active;
SCREEN_WINDOW *screen_win;
TERM_WINDOW *screen_win;
int sticky_windows; /* number of sticky windows */
int first_line, last_line; /* first/last line used by this window (0..x) (includes statusbars) */

View File

@ -277,8 +277,8 @@ static void item_input(SBAR_ITEM_REC *item, int get_size_only)
GUI_ENTRY_REC *rec;
if (get_size_only) {
item->min_size = 2+screen_width/10;
item->max_size = screen_width;
item->min_size = 2+term_width/10;
item->max_size = term_width;
return;
}

View File

@ -235,7 +235,7 @@ static void statusbar_redraw_items(STATUSBAR_REC *bar)
if (bar->parent_window != NULL)
active_win = bar->parent_window->active;
statusbar_resize_items(bar, screen_width);
statusbar_resize_items(bar, term_width);
xpos = 0;
for (tmp = bar->items; tmp != NULL; tmp = tmp->next) {
@ -248,7 +248,7 @@ static void statusbar_redraw_items(STATUSBAR_REC *bar)
}
}
rxpos = screen_width;
rxpos = term_width;
for (tmp = bar->items; tmp != NULL; tmp = tmp->next) {
SBAR_ITEM_REC *rec = tmp->data;
@ -282,10 +282,10 @@ void statusbar_redraw(STATUSBAR_REC *bar)
if (bar == NULL) {
if (active_statusbar_group != NULL) {
screen_refresh_freeze();
term_refresh_freeze();
g_slist_foreach(active_statusbar_group->bars,
(GFunc) statusbar_redraw, NULL);
screen_refresh_thaw();
term_refresh_thaw();
}
return;
}
@ -295,7 +295,7 @@ void statusbar_redraw(STATUSBAR_REC *bar)
g_free(str);
statusbar_redraw_items(bar);
screen_refresh(NULL);
term_refresh(NULL);
}
void statusbar_item_redraw(SBAR_ITEM_REC *item)
@ -317,7 +317,7 @@ void statusbar_item_redraw(SBAR_ITEM_REC *item)
} else {
/*FIXME:fprintf(stderr, "%s redrawing", item->config->name);*/
item->func(item, FALSE);
screen_refresh(NULL);
term_refresh(NULL);
}
active_win = old_active_win;
@ -360,7 +360,7 @@ static void statusbars_recalc_ypos(STATUSBAR_REC *bar)
/* get the Y-position for the first statusbar */
if (bar->config->type == STATUSBAR_TYPE_ROOT) {
ypos = bar->config->placement == STATUSBAR_TOP ? 0 :
screen_height - g_slist_length(bar_group);
term_height - g_slist_length(bar_group);
} else {
ypos = bar->config->placement == STATUSBAR_TOP ?
bar->parent_window->first_line :

368
src/fe-text/term-curses.c Normal file
View File

@ -0,0 +1,368 @@
/*
term-curses.c : irssi
Copyright (C) 1999-2001 Timo Sirainen
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "module.h"
#include "settings.h"
#include "term.h"
#include "mainwindows.h"
#if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
# include <ncurses.h>
#else
# include <curses.h>
#endif
#include <termios.h>
#include <signal.h>
#ifndef COLOR_PAIRS
# define COLOR_PAIRS 64
#endif
#if defined (TIOCGWINSZ) && defined (HAVE_CURSES_RESIZETERM)
# define USE_RESIZE_TERM
#endif
#ifndef _POSIX_VDISABLE
# define _POSIX_VDISABLE 0
#endif
struct _TERM_WINDOW {
int x, y;
int width, height;
WINDOW *win;
};
TERM_WINDOW *root_window;
int term_width, term_height;
static int curs_x, curs_y;
static int freeze_refresh;
static struct termios old_tio;
static int init_curses(void)
{
char ansi_tab[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
int num;
struct termios tio;
if (!initscr())
return FALSE;
cbreak(); noecho(); idlok(stdscr, 1);
#ifdef HAVE_CURSES_IDCOK
/*idcok(stdscr, 1); - disabled currently, causes redrawing problems with NetBSD */
#endif
intrflush(stdscr, FALSE); nodelay(stdscr, TRUE);
/* Disable INTR, QUIT, VDSUSP and SUSP keys */
if (tcgetattr(0, &old_tio) == 0) {
memcpy(&tio, &old_tio, sizeof(tio));
tio.c_cc[VINTR] = _POSIX_VDISABLE;
tio.c_cc[VQUIT] = _POSIX_VDISABLE;
#ifdef VDSUSP
tio.c_cc[VDSUSP] = _POSIX_VDISABLE;
#endif
#ifdef VSUSP
tio.c_cc[VSUSP] = _POSIX_VDISABLE;
#endif
tcsetattr(0, 0, &tio);
}
if (has_colors())
start_color();
else if (term_use_colors)
term_use_colors = FALSE;
#ifdef HAVE_NCURSES_USE_DEFAULT_COLORS
/* this lets us to use the "default" background color for colors <= 7 so
background pixmaps etc. show up right */
use_default_colors();
for (num = 1; num < COLOR_PAIRS; num++)
init_pair(num, ansi_tab[num & 7], num <= 7 ? -1 : ansi_tab[num >> 3]);
init_pair(63, 0, -1); /* hm.. not THAT good idea, but probably more
people want dark grey than white on white.. */
#else
for (num = 1; num < COLOR_PAIRS; num++)
init_pair(num, ansi_tab[num & 7], ansi_tab[num >> 3]);
init_pair(63, 0, 0);
#endif
clear();
return TRUE;
}
static int term_init_int(void)
{
int ret;
ret = init_curses();
if (!ret) return 0;
curs_x = curs_y = 0;
freeze_refresh = 0;
root_window = g_new0(TERM_WINDOW, 1);
root_window->win = stdscr;
term_width = COLS;
term_height = LINES;
return ret;
}
static void term_deinit_int(void)
{
tcsetattr(0, 0, &old_tio);
endwin();
g_free_and_null(root_window);
}
int term_init(void)
{
if (!term_init_int())
return FALSE;
settings_add_int("lookandfeel", "default_color", 7);
term_common_init();
return TRUE;
}
void term_deinit(void)
{
term_common_deinit();
term_deinit_int();
}
/* Resize terminal - if width or height is negative,
the new size is unknown and should be figured out somehow */
void term_resize(int width, int height)
{
#ifdef HAVE_CURSES_RESIZETERM
if (width < 0 || height < 0) {
#endif
term_deinit_int();
term_init_int();
mainwindows_recreate();
#ifdef HAVE_CURSES_RESIZETERM
} else if (term_width != width || term_height != height) {
term_width = width;
term_height = height;
resizeterm(term_height, term_width);
}
#endif
}
/* Returns TRUE if terminal has colors */
int term_has_colors(void)
{
return has_colors();
}
/* Force the colors on any way you can */
void term_force_colors(int set)
{
/* don't do anything with curses */
}
/* Clear screen */
void term_clear(void)
{
clear();
}
/* Beep */
void term_beep(void)
{
beep();
}
/* Create a new window in terminal */
TERM_WINDOW *term_window_create(int x, int y, int width, int height)
{
TERM_WINDOW *window;
window = g_new0(TERM_WINDOW, 1);
window->x = x; window->y = y;
window->width = width; window->height = height;
window->win = newwin(height, width, y, x);
idlok(window->win, 1);
return window;
}
/* Destroy a terminal window */
void term_window_destroy(TERM_WINDOW *window)
{
delwin(window->win);
g_free(window);
}
/* Move/resize a window */
void term_window_move(TERM_WINDOW *window, int x, int y,
int width, int height)
{
/* some checks to make sure the window is visible in screen,
otherwise curses could get nasty and not show our window anymore. */
if (width < 1) width = 1;
if (height < 1) height = 1;
if (x+width > term_width) x = term_width-width;
if (y+height > term_height) y = term_height-height;
#ifdef HAVE_CURSES_WRESIZE
if (window->width != width || window->height != height)
wresize(window->win, height, width);
if (window->x != x || window->y != y)
mvwin(window->win, y, x);
#else
if (window->width != width || window->height != height ||
window->x != x || window->y != y) {
delwin(window->win);
window->win = newwin(height, width, y, x);
idlok(window->win, 1);
}
#endif
window->x = x; window->y = y;
window->width = width; window->height = height;
}
/* Clear window */
void term_window_clear(TERM_WINDOW *window)
{
werase(window->win);
}
/* Scroll window up/down */
void term_window_scroll(TERM_WINDOW *window, int count)
{
scrollok(window->win, TRUE);
wscrl(window->win, count);
scrollok(window->win, FALSE);
}
static int get_attr(int color)
{
int attr;
if (!term_use_colors)
attr = (color & 0x70) ? A_REVERSE : 0;
else if (((color & 0x0f) == 8) && (color & ATTR_BOLD) == 0)
attr = (A_DIM | COLOR_PAIR(63));
else if ((color & 0x77) == 0)
attr = A_NORMAL;
else {
if (color & ATTR_RESETFG) {
color &= ~0x0f;
color |= settings_get_int("default_color");
}
attr = (COLOR_PAIR((color&7) + (color&0x70)/2));
}
if ((color & 0x08) || (color & ATTR_BOLD)) attr |= A_BOLD;
if (color & ATTR_BLINK) attr |= A_BLINK;
if (color & ATTR_UNDERLINE) attr |= A_UNDERLINE;
if (color & ATTR_REVERSE) attr |= A_REVERSE;
return attr;
}
/* Change active color */
void term_set_color(TERM_WINDOW *window, int col)
{
wattrset(window->win, get_attr(col));
wbkgdset(window->win, ' ' | get_attr(col));
}
void term_move(TERM_WINDOW *window, int x, int y)
{
wmove(window->win, y, x);
}
void term_addch(TERM_WINDOW *window, int chr)
{
waddch(window->win, chr);
}
void term_addstr(TERM_WINDOW *window, char *str)
{
waddstr(window->win, str);
}
void term_clrtoeol(TERM_WINDOW *window)
{
wclrtoeol(window->win);
}
void term_move_cursor(int x, int y)
{
curs_x = x;
curs_y = y;
}
void term_refresh_freeze(void)
{
freeze_refresh++;
}
void term_refresh_thaw(void)
{
if (freeze_refresh > 0) {
freeze_refresh--;
if (freeze_refresh == 0) term_refresh(NULL);
}
}
void term_refresh(TERM_WINDOW *window)
{
if (window != NULL)
wnoutrefresh(window->win);
if (freeze_refresh == 0) {
move(curs_y, curs_x);
wnoutrefresh(stdscr);
doupdate();
}
}
void term_stop(void)
{
term_deinit_int();
kill(getpid(), SIGSTOP);
term_init_int();
irssi_redraw();
}
int term_getch(void)
{
int key;
key = getch();
if (key == ERR)
return -1;
#ifdef KEY_RESIZE
if (key == KEY_RESIZE)
return -1;
#endif
return key;
}

296
src/fe-text/term-terminfo.c Normal file
View File

@ -0,0 +1,296 @@
/*
term-terminfo.c : irssi
Copyright (C) 2001 Timo Sirainen
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "module.h"
#include "signals.h"
#include "term.h"
#include "terminfo-core.h"
#include <signal.h>
struct _TERM_WINDOW {
/* Terminal to use for window */
TERM_REC *term;
/* Area for window in terminal */
int x, y;
int width, height;
};
TERM_WINDOW *root_window;
int term_width, term_height;
static int curs_x, curs_y;
static int last_fg, last_bg, last_attrs;
static int redraw_needed, redraw_tag;
/* SIGCONT handler */
static void sig_cont(int p)
{
redraw_needed = TRUE;
terminfo_cont(current_term);
}
static int redraw_timeout(void)
{
if (redraw_needed) {
irssi_redraw();
redraw_needed = FALSE;
}
return 1;
}
int term_init(void)
{
struct sigaction act;
last_fg = last_bg = -1;
last_attrs = 0;
current_term = terminfo_core_init(stdin, stdout);
if (current_term == NULL)
return FALSE;
/* grab CONT signal */
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
act.sa_handler = sig_cont;
sigaction(SIGCONT, &act, NULL);
redraw_tag = g_timeout_add(500, (GSourceFunc) redraw_timeout, NULL);
curs_x = curs_y = 0;
term_width = current_term->width;
term_height = current_term->height;
root_window = term_window_create(0, 0, term_width, term_height);
term_common_init();
return TRUE;
}
void term_deinit(void)
{
g_source_remove(redraw_tag);
term_common_deinit();
terminfo_core_deinit(current_term);
}
/* Resize terminal - if width or height is negative,
the new size is unknown and should be figured out somehow */
void term_resize(int width, int height)
{
if (width < 0 || height < 0) {
terminfo_resize(current_term);
width = current_term->width;
height = current_term->height;
}
if (term_width != width || term_height != height) {
term_width = current_term->width = width;
term_height = current_term->height = height;
term_window_move(root_window, 0, 0, term_width, term_height);
}
}
/* Returns TRUE if terminal has colors */
int term_has_colors(void)
{
return terminfo_has_colors(current_term);
}
/* Force the colors on any way you can */
void term_force_colors(int set)
{
terminfo_setup_colors(current_term, set);
}
/* Clear screen */
void term_clear(void)
{
terminfo_clear();
}
/* Beep */
void term_beep(void)
{
/* FIXME */
}
/* Create a new window in terminal */
TERM_WINDOW *term_window_create(int x, int y, int width, int height)
{
TERM_WINDOW *window;
window = g_new0(TERM_WINDOW, 1);
window->term = current_term;
window->x = x; window->y = y;
window->width = width; window->height = height;
return window;
}
/* Destroy a terminal window */
void term_window_destroy(TERM_WINDOW *window)
{
g_free(window);
}
/* Move/resize a window */
void term_window_move(TERM_WINDOW *window, int x, int y,
int width, int height)
{
window->x = x;
window->y = y;
window->width = width;
window->height = height;
}
/* Clear window */
void term_window_clear(TERM_WINDOW *window)
{
int y;
terminfo_set_normal();
for (y = 0; y < window->height; y++) {
terminfo_move(0, window->y+y);
terminfo_clrtoeol();
}
}
/* Scroll window up/down */
void term_window_scroll(TERM_WINDOW *window, int count)
{
terminfo_scroll(window->y, window->y+window->height-1, count);
}
/* Change active color */
void term_set_color(TERM_WINDOW *window, int col)
{
int set_normal;
set_normal = ((col & ATTR_RESETFG) && last_fg != -1) ||
((col & ATTR_RESETBG) && last_bg != -1);
if (((last_attrs & ATTR_BOLD) && (col & ATTR_BOLD) == 0) ||
((last_attrs & ATTR_BLINK) && (col & ATTR_BLINK) == 0)) {
/* we'll need to get rid of bold/blink - this can only be
done with setting the default color */
set_normal = TRUE;
}
if (set_normal) {
last_fg = last_bg = -1;
last_attrs = 0;
terminfo_set_normal();
}
/* reversed text (use standout) */
if (col & ATTR_REVERSE) {
if ((last_attrs & ATTR_REVERSE) == 0)
terminfo_set_standout(TRUE);
} else if (last_attrs & ATTR_REVERSE)
terminfo_set_standout(FALSE);
/* set foreground color */
if ((col & 0x0f) != last_fg &&
((col & 0x0f) != 0 || (col & ATTR_RESETFG) == 0)) {
last_fg = col & 0x0f;
terminfo_set_fg(last_fg);
}
/* set background color */
if (col & ATTR_BLINK)
col |= 0x80;
else if (col & 0x80)
col |= ATTR_BLINK;
if ((col & 0xf0) >> 4 != last_bg &&
((col & 0xf0) != 0 || (col & ATTR_RESETBG) == 0)) {
last_bg = (col & 0xf0) >> 4;
terminfo_set_bg(last_bg);
}
/* bold */
if (col & 0x08)
col |= ATTR_BOLD;
else if (col & ATTR_BOLD)
terminfo_set_bold();
/* underline */
if (col & ATTR_UNDERLINE) {
if ((last_attrs & ATTR_UNDERLINE) == 0)
terminfo_set_uline(TRUE);
} else if (last_attrs & ATTR_UNDERLINE)
terminfo_set_uline(FALSE);
last_attrs = col & ~0xff;
}
void term_move(TERM_WINDOW *window, int x, int y)
{
terminfo_move(x+window->x, y+window->y);
}
void term_addch(TERM_WINDOW *window, int chr)
{
putc(chr, window->term->out);
}
void term_addstr(TERM_WINDOW *window, char *str)
{
fputs(str, window->term->out);
}
void term_clrtoeol(TERM_WINDOW *window)
{
terminfo_clrtoeol();
}
void term_move_cursor(int x, int y)
{
curs_x = x;
curs_y = y;
}
void term_refresh(TERM_WINDOW *window)
{
terminfo_move(curs_x, curs_y);
fflush(window != NULL ? window->term->out : current_term->out);
}
void term_refresh_freeze(void)
{
}
void term_refresh_thaw(void)
{
}
void term_stop(void)
{
terminfo_stop(current_term);
kill(getpid(), SIGSTOP);
terminfo_cont(current_term);
irssi_redraw();
}
int term_getch(void)
{
return fgetc(current_term->in);
}

140
src/fe-text/term.c Normal file
View File

@ -0,0 +1,140 @@
/*
term.c : irssi
Copyright (C) 2001 Timo Sirainen
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "module.h"
#include "signals.h"
#include "commands.h"
#include "settings.h"
#include "term.h"
#include "mainwindows.h"
#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#endif
#include <signal.h>
#include <termios.h>
#define RESIZE_TIMEOUT 500 /* how often to check if the terminal has been resized */
#define MIN_SCREEN_WIDTH 20
int term_use_colors;
#ifdef SIGWINCH
static int resize_timeout_tag;
#endif
static int resize_needed;
static int resize_timeout(void)
{
#ifdef TIOCGWINSZ
struct winsize ws;
#endif
if (!resize_needed)
return TRUE;
resize_needed = FALSE;
#ifdef TIOCGWINSZ
/* Get new window size */
if (ioctl(0, TIOCGWINSZ, &ws) < 0)
return TRUE;
if (ws.ws_row == term_height && ws.ws_col == term_width) {
/* Same size, abort. */
return TRUE;
}
if (ws.ws_col < MIN_SCREEN_WIDTH)
ws.ws_col = MIN_SCREEN_WIDTH;
term_resize(ws.ws_col, ws.ws_row);
#else
term_resize(-1, -1);
#endif
mainwindows_resize(term_width, term_height);
return TRUE;
}
#ifdef SIGWINCH
static void sig_winch(int p)
{
resize_needed = TRUE;
}
#endif
static void cmd_resize(void)
{
resize_needed = TRUE;
resize_timeout();
}
static void read_settings(void)
{
int old_colors = term_use_colors;
if (settings_get_bool("force_colors"))
term_use_colors = TRUE;
else {
term_use_colors = settings_get_bool("colors");
if (term_use_colors && !term_has_colors())
term_use_colors = FALSE;
}
if (term_use_colors != old_colors)
irssi_redraw();
}
void term_common_init(void)
{
#ifdef SIGWINCH
struct sigaction act;
#endif
settings_add_bool("lookandfeel", "colors", TRUE);
settings_add_bool("lookandfeel", "force_colors", FALSE);
term_use_colors = settings_get_bool("colors");
signal_add("beep", (SIGNAL_FUNC) term_beep);
signal_add("setup changed", (SIGNAL_FUNC) read_settings);
command_bind("resize", NULL, (SIGNAL_FUNC) cmd_resize);
#ifdef SIGWINCH
sigemptyset (&act.sa_mask);
act.sa_flags = 0;
act.sa_handler = sig_winch;
sigaction(SIGWINCH, &act, NULL);
resize_timeout_tag = g_timeout_add(RESIZE_TIMEOUT,
(GSourceFunc) resize_timeout, NULL);
#endif
}
void term_common_deinit(void)
{
#ifdef SIGWINCH
g_source_remove(resize_timeout_tag);
#endif
command_unbind("resize", (SIGNAL_FUNC) cmd_resize);
signal_remove("beep", (SIGNAL_FUNC) term_beep);
signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
}

81
src/fe-text/term.h Normal file
View File

@ -0,0 +1,81 @@
#ifndef __TERM_H
#define __TERM_H
typedef struct _TERM_WINDOW TERM_WINDOW;
#define ATTR_RESETFG 0x0100
#define ATTR_RESETBG 0x0200
#define ATTR_BOLD 0x0400
#define ATTR_BLINK 0x0800
#define ATTR_UNDERLINE 0x1000
#define ATTR_REVERSE 0x2000
#define ATTR_RESET (ATTR_RESETFG|ATTR_RESETBG)
#define ATTR_NOCOLORS (ATTR_UNDERLINE|ATTR_REVERSE)
#ifdef WANT_BIG5
/* XXX I didn't check the encoding range of big5+. This is standard big5. */
# define is_big5_los(lo) (((char)0x40<=lo)&&(lo<=(char)0x7E)) /* standard */
# define is_big5_lox(lo) (((char)0x80<=lo)&&(lo<=(char)0xFE)) /* extended */
# define is_big5_hi(hi) (((char)0x81<=hi)&&(hi<=(char)0xFE))
# define is_big5(hi,lo) is_big5_hi(hi) && (is_big5_los(lo) || is_big5_lox(lo))
#endif
extern TERM_WINDOW *root_window;
extern int term_width, term_height, term_use_colors;
/* Initialize / deinitialize terminal */
int term_init(void);
void term_deinit(void);
/* Resize terminal - if width or height is negative,
the new size is unknown and should be figured out somehow */
void term_resize(int width, int height);
/* Returns TRUE if terminal has colors */
int term_has_colors(void);
/* Force the colors on any way you can */
void term_force_colors(int set);
/* Clear screen */
void term_clear(void);
/* Beep */
void term_beep(void);
/* Create a new window in terminal */
TERM_WINDOW *term_window_create(int x, int y, int width, int height);
/* Destroy a terminal window */
void term_window_destroy(TERM_WINDOW *window);
/* Move/resize window */
void term_window_move(TERM_WINDOW *window, int x, int y,
int width, int height);
/* Clear window */
void term_window_clear(TERM_WINDOW *window);
/* Scroll window up/down */
void term_window_scroll(TERM_WINDOW *window, int count);
void term_set_color(TERM_WINDOW *window, int col);
void term_move(TERM_WINDOW *window, int x, int y);
void term_addch(TERM_WINDOW *window, int chr);
void term_addstr(TERM_WINDOW *window, char *str);
void term_clrtoeol(TERM_WINDOW *window);
void term_move_cursor(int x, int y);
void term_refresh_freeze(void);
void term_refresh_thaw(void);
void term_refresh(TERM_WINDOW *window);
void term_stop(void);
int term_getch(void);
/* internal */
void term_common_init(void);
void term_common_deinit(void);
void term_force_resize(void);
#endif

584
src/fe-text/terminfo-core.c Normal file
View File

@ -0,0 +1,584 @@
#include "module.h"
#include "signals.h"
#include "terminfo-core.h"
#ifndef _POSIX_VDISABLE
# define _POSIX_VDISABLE 0
#endif
#define tput(s) tputs(s, 0, term_putchar)
inline static int term_putchar(int c)
{
return fputc(c, current_term->out);
}
/* Don't bother including curses.h because of these -
they might not even be defined there */
char *tparm();
int tputs();
#ifdef HAVE_TERMINFO
int setupterm();
char *tigetstr();
int tigetnum();
int tigetflag();
#define term_getstr(x, buffer) tigetstr(x.ti_name)
#define term_getnum(x) tigetnum(x.ti_name);
#define term_getflag(x) tigetflag(x.ti_name);
#else
int tgetent();
char *tgetstr();
int tgetnum();
int tgetflag();
#define term_getstr(x, buffer) tgetstr(x.tc_name, &buffer)
#define term_getnum(x) tgetnum(x.tc_name)
#define term_getflag(x) tgetflag(x.tc_name)
#endif
#define CAP_TYPE_FLAG 0
#define CAP_TYPE_INT 1
#define CAP_TYPE_STR 2
typedef struct {
const char *ti_name; /* terminfo name */
const char *tc_name; /* termcap name */
int type;
void *ptr;
} TERMINFO_REC;
TERM_REC *current_term;
static TERM_REC temp_term; /* not really used for anything */
/* Define only what we might need */
static TERMINFO_REC tcaps[] = {
/* Terminal size */
{ "cols", "co", CAP_TYPE_INT, &temp_term.width },
{ "lines", "li", CAP_TYPE_INT, &temp_term.height },
/* Cursor movement */
{ "smcup", "ti", CAP_TYPE_STR, &temp_term.TI_smcup },
{ "rmcup", "te", CAP_TYPE_STR, &temp_term.TI_rmcup },
{ "cup", "cm", CAP_TYPE_STR, &temp_term.TI_cup },
{ "hpa", "ch", CAP_TYPE_STR, &temp_term.TI_hpa },
{ "vpa", "vh", CAP_TYPE_STR, &temp_term.TI_vpa },
{ "xvpa", "YD", CAP_TYPE_FLAG, &temp_term.TI_xvpa },
{ "hvpa", "YA", CAP_TYPE_FLAG, &temp_term.TI_xhpa },
/* Scrolling */
{ "csr", "cs", CAP_TYPE_STR, &temp_term.TI_csr },
{ "wind", "wi", CAP_TYPE_STR, &temp_term.TI_wind },
{ "ri", "sr", CAP_TYPE_STR, &temp_term.TI_ri },
{ "rin", "SR", CAP_TYPE_STR, &temp_term.TI_rin },
{ "ind", "sf", CAP_TYPE_STR, &temp_term.TI_ind },
{ "indn", "SF", CAP_TYPE_STR, &temp_term.TI_indn },
{ "il", "AL", CAP_TYPE_STR, &temp_term.TI_il },
{ "il1", "al", CAP_TYPE_STR, &temp_term.TI_il1 },
{ "dl", "DL", CAP_TYPE_STR, &temp_term.TI_dl },
{ "dl1", "dl", CAP_TYPE_STR, &temp_term.TI_dl1 },
/* Clearing screen */
{ "clear", "cl", CAP_TYPE_STR, &temp_term.TI_clear },
{ "ed", "cd", CAP_TYPE_STR, &temp_term.TI_ed },
/* Clearing to end of line */
{ "el", "ce", CAP_TYPE_STR, &temp_term.TI_el },
/* Colors */
{ "sgr0", "me", CAP_TYPE_STR, &temp_term.TI_sgr0 },
{ "smul", "us", CAP_TYPE_STR, &temp_term.TI_smul },
{ "rmul", "ue", CAP_TYPE_STR, &temp_term.TI_rmul },
{ "smso", "so", CAP_TYPE_STR, &temp_term.TI_smso },
{ "rmso", "se", CAP_TYPE_STR, &temp_term.TI_rmso },
{ "bold", "md", CAP_TYPE_STR, &temp_term.TI_bold },
{ "blink", "mb", CAP_TYPE_STR, &temp_term.TI_blink },
{ "setaf", "AF", CAP_TYPE_STR, &temp_term.TI_setaf },
{ "setab", "AB", CAP_TYPE_STR, &temp_term.TI_setab },
{ "setf", "Sf", CAP_TYPE_STR, &temp_term.TI_setf },
{ "setb", "Sb", CAP_TYPE_STR, &temp_term.TI_setb },
/* Beep */
{ "bel", "bl", CAP_TYPE_STR, &temp_term.TI_bel },
};
/* Move cursor (cursor_address / cup) */
static void _move_cup(TERM_REC *term, int x, int y)
{
tput(tparm(term->TI_cup, y, x));
}
/* Move cursor (column_address+row_address / hpa+vpa) */
static void _move_pa(TERM_REC *term, int x, int y)
{
tput(tparm(term->TI_hpa, x));
tput(tparm(term->TI_vpa, y));
}
#define scroll_region_setup(term, y1, y2) \
if ((term)->TI_csr != NULL) \
tput(tparm((term)->TI_csr, y1, y2)); \
else \
tput(tparm((term)->TI_wind, y1, y2, 0, (term)->width-1));
/* Scroll (change_scroll_region+parm_rindex+parm_index / csr+rin+indn) */
static void _scroll_region(TERM_REC *term, int y1, int y2, int count)
{
/* setup the scrolling region to wanted area */
scroll_region_setup(term, y1, y2);
term->move(term, 0, y1);
if (count > 0) {
term->move(term, 0, y2);
tput(tparm(term->TI_indn, count, count));
} else if (count < 0) {
term->move(term, 0, y1);
tput(tparm(term->TI_rin, -count, -count));
}
/* reset the scrolling region to full screen */
scroll_region_setup(term, 0, term->height-1);
}
/* Scroll (change_scroll_region+scroll_reverse+scroll_forward / csr+ri+ind) */
static void _scroll_region_1(TERM_REC *term, int y1, int y2, int count)
{
int i;
/* setup the scrolling region to wanted area */
scroll_region_setup(term, y1, y2);
if (count > 0) {
term->move(term, 0, y2);
for (i = 0; i < count; i++)
tput(tparm(term->TI_ind));
} else if (count < 0) {
term->move(term, 0, y1);
for (i = count; i < 0; i++)
tput(tparm(term->TI_ri));
tput(tparm(term->TI_rin, -count, -count));
}
/* reset the scrolling region to full screen */
scroll_region_setup(term, 0, term->height-1);
}
/* Scroll (parm_insert_line+parm_delete_line / il+dl) */
static void _scroll_line(TERM_REC *term, int y1, int y2, int count)
{
if (count > 0) {
term->move(term, 0, y1);
tput(tparm(term->TI_dl, count, count));
term->move(term, 0, y2-count+1);
tput(tparm(term->TI_il, count, count));
} else if (count < 0) {
term->move(term, 0, y2+count+1);
tput(tparm(term->TI_dl, -count, -count));
term->move(term, 0, y1);
tput(tparm(term->TI_il, -count, -count));
}
}
/* Scroll (insert_line+delete_line / il1+dl1) */
static void _scroll_line_1(TERM_REC *term, int y1, int y2, int count)
{
int i;
if (count > 0) {
term->move(term, 0, y1);
for (i = 0; i < count; i++)
tput(tparm(term->TI_dl1));
term->move(term, 0, y2-count+1);
for (i = 0; i < count; i++)
tput(tparm(term->TI_il1));
} else if (count < 0) {
term->move(term, 0, y2+count+1);
for (i = count; i < 0; i++)
tput(tparm(term->TI_dl1));
term->move(term, 0, y1);
for (i = count; i < 0; i++)
tput(tparm(term->TI_il1));
}
}
/* Clear screen (clear_screen / clear) */
static void _clear_screen(TERM_REC *term)
{
tput(tparm(term->TI_clear));
}
/* Clear screen (clr_eos / ed) */
static void _clear_eos(TERM_REC *term)
{
term->move(term, 0, 0);
tput(tparm(term->TI_ed));
}
/* Clear screen (parm_delete_line / dl) */
static void _clear_del(TERM_REC *term)
{
term->move(term, 0, 0);
tput(tparm(term->TI_dl, term->height, term->height));
}
/* Clear screen (delete_line / dl1) */
static void _clear_del_1(TERM_REC *term)
{
int i;
term->move(term, 0, 0);
for (i = 0; i < term->height; i++)
tput(tparm(term->TI_dl1));
}
/* Clear to end of line (clr_eol / el) */
static void _clrtoeol(TERM_REC *term)
{
tput(tparm(term->TI_el));
}
/* Reset all terminal attributes */
static void _set_normal(TERM_REC *term)
{
tput(tparm(term->TI_normal));
}
/* Bold on */
static void _set_bold(TERM_REC *term)
{
tput(tparm(term->TI_bold));
}
/* Underline on/off */
static void _set_uline(TERM_REC *term, int set)
{
tput(tparm(set ? term->TI_smul : term->TI_rmul));
}
/* Standout on/off */
static void _set_standout(TERM_REC *term, int set)
{
tput(tparm(set ? term->TI_smso : term->TI_rmso));
}
/* Change foreground color */
static void _set_fg(TERM_REC *term, int color)
{
tput(tparm(term->TI_fg[color & 0x0f]));
}
/* Change background color */
static void _set_bg(TERM_REC *term, int color)
{
tput(tparm(term->TI_bg[color & 0x0f]));
}
/* Beep */
static void _beep(TERM_REC *term)
{
tput(tparm(term->TI_bel));
}
static void _ignore(TERM_REC *term)
{
}
static void _ignore_parm(TERM_REC *term, int param)
{
}
static void term_fill_capabilities(TERM_REC *term)
{
int i, ival;
char *sval;
void *ptr;
#ifndef HAVE_TERMINFO
char *tptr = term->buffer2;
#endif
for (i = 0; i < sizeof(tcaps)/sizeof(tcaps[0]); i++) {
ptr = (char *) term + (int) ((char *) tcaps[i].ptr - (char *) &temp_term);
switch (tcaps[i].type) {
case CAP_TYPE_FLAG:
ival = term_getflag(tcaps[i]);
*(int *)ptr = ival;
break;
case CAP_TYPE_INT:
ival = term_getnum(tcaps[i]);
*(int *)ptr = ival;
break;
case CAP_TYPE_STR:
sval = term_getstr(tcaps[i], tptr);
if (sval == (char *) -1)
*(char **)ptr = NULL;
else
*(char **)ptr = sval;
break;
}
}
}
/* Terminal was resized - ask the width/height from terminfo again */
void terminfo_resize(TERM_REC *term)
{
/* easiest way to do this is just to refill everything, and since
termcap needs that buffer this is probably also the safest way */
/* FIXME: leaks memory? does this even work? */
term_fill_capabilities(term);
}
static void terminfo_colors_deinit(TERM_REC *term)
{
int i;
if (terminfo_has_colors(term)) {
for (i = 0; i < 16; i++) {
g_free(term->TI_fg[i]);
g_free(term->TI_bg[i]);
}
memset(term->TI_fg, 0, sizeof(term->TI_fg));
memset(term->TI_bg, 0, sizeof(term->TI_fg));
}
}
/* Setup colors - if force is set, use ANSI-style colors if
terminal capabilities don't contain color codes */
void terminfo_setup_colors(TERM_REC *term, int force)
{
static char ansitab[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
const char *bold, *blink;
int i;
terminfo_colors_deinit(term);
if (term->TI_setf) {
for (i = 0; i < 8; i++)
term->TI_fg[i] = g_strdup(tparm(term->TI_setf, i, 0));
} else if (term->TI_setaf) {
for (i = 0; i < 8; i++)
term->TI_fg[i] = g_strdup(tparm(term->TI_setaf, ansitab[i], 0));
} else if (force) {
for (i = 0; i < 8; i++)
term->TI_fg[i] = g_strdup_printf("\033[%dm", 30+ansitab[i]);
}
if (term->TI_setb) {
for (i = 0; i < 8; i++)
term->TI_bg[i] = g_strdup(tparm(term->TI_setb, i, 0));
} else if (term->TI_setab) {
for (i = 0; i < 8; i++)
term->TI_bg[i] = g_strdup(tparm(term->TI_setab, ansitab[i], 0));
} else if (force) {
for (i = 0; i < 8; i++)
term->TI_bg[i] = g_strdup_printf("\033[%dm", 40+ansitab[i]);
}
if (term->TI_setf || term->TI_setaf || force) {
term->set_fg = _set_fg;
term->set_bg = _set_bg;
/* bold fg, blink bg */
bold = term->TI_bold ? term->TI_bold : "";
for (i = 0; i < 8; i++)
term->TI_fg[i+8] = g_strconcat(bold, term->TI_fg[i], NULL);
blink = term->TI_blink ? term->TI_blink : "";
for (i = 0; i < 8; i++)
term->TI_bg[i+8] = g_strconcat(blink, term->TI_bg[i], NULL);
} else {
/* no colors */
term->set_fg = term->set_bg = _ignore_parm;
}
}
static void terminfo_input_init(TERM_REC *term)
{
tcgetattr(fileno(term->in), &term->old_tio);
memcpy(&term->tio, &term->old_tio, sizeof(term->tio));
term->tio.c_lflag &= ~(ICANON | ECHO); /* CBREAK, no ECHO */
term->tio.c_cc[VMIN] = 0; /* non-blocking read */
term->tio.c_cc[VTIME] = 0; /* No timer */
/* Disable INTR, QUIT, VDSUSP and SUSP keys */
term->tio.c_cc[VINTR] = _POSIX_VDISABLE;
term->tio.c_cc[VQUIT] = _POSIX_VDISABLE;
#ifdef VDSUSP
term->tio.c_cc[VDSUSP] = _POSIX_VDISABLE;
#endif
#ifdef VSUSP
term->tio.c_cc[VSUSP] = _POSIX_VDISABLE;
#endif
tcsetattr(fileno(term->in), 0, &term->tio);
}
static void terminfo_input_deinit(TERM_REC *term)
{
tcsetattr(fileno(term->in), 0, &term->old_tio);
}
void terminfo_cont(TERM_REC *term)
{
if (term->TI_smcup)
tput(tparm(term->TI_smcup));
terminfo_input_init(term);
}
void terminfo_stop(TERM_REC *term)
{
/* reset colors */
terminfo_set_normal();
/* move cursor to bottom of the screen */
terminfo_move(0, term->height-1);
/* stop cup-mode */
if (term->TI_rmcup)
tput(tparm(term->TI_rmcup));
/* reset input settings */
terminfo_input_deinit(term);
fflush(term->out);
}
static int term_setup(TERM_REC *term)
{
GString *str;
#ifdef HAVE_TERMINFO
int err;
#endif
char *term_env;
term_env = getenv("TERM");
if (term_env == NULL) {
fprintf(term->out, "TERM environment not set\n");
return 0;
}
#ifdef HAVE_TERMINFO
if (setupterm(term_env, 1, &err) != 0) {
fprintf(term->out, "setupterm() failed for TERM=%s: %d\n", term_env, err);
return 0;
}
#else
if (tgetent(term->buffer1, term_env) < 1)
{
fprintf(term->out, "Termcap not found for TERM=%s\n", term_env);
return -1;
}
#endif
term_fill_capabilities(term);
/* Cursor movement */
if (term->TI_cup)
term->move = _move_cup;
else if (term->TI_hpa && term->TI_vpa &&
!term->TI_xhpa && !term->TI_xvpa)
term->move = _move_pa;
else {
fprintf(term->out, "Terminal doesn't support cursor movement\n");
return 0;
}
/* Scrolling */
if ((term->TI_csr || term->TI_wind) && term->TI_rin && term->TI_indn)
term->scroll = _scroll_region;
else if ((term->TI_csr || term->TI_wind) && term->TI_ri && term->TI_ind)
term->scroll = _scroll_region_1;
else if (term->TI_il && term->TI_dl)
term->scroll = _scroll_line;
else if (term->TI_il1 && term->TI_dl1)
term->scroll = _scroll_line_1;
else {
fprintf(term->out, "Terminal doesn't support scrolling\n");
return 0;
}
/* Clearing screen */
if (term->TI_clear)
term->clear = _clear_screen;
else if (term->TI_ed)
term->clear = _clear_eos;
else if (term->TI_dl)
term->clear = _clear_del;
else if (term->TI_dl1)
term->clear = _clear_del_1;
else {
/* we could do this by line inserts as well, but don't
bother - if some terminal has insert line it most probably
has delete line as well, if not a regular clear screen */
fprintf(term->out, "Terminal doesn't support clearing screen\n");
return 0;
}
/* Clearing to end of line */
if (term->TI_el)
term->clrtoeol = _clrtoeol;
else {
fprintf(term->out, "Terminal doesn't support clearing to end of line\n");
return 0;
}
/* Bold, underline, standout */
term->set_bold = term->TI_bold ? _set_bold : _ignore;
term->set_uline = term->TI_smul && term->TI_rmul ?
_set_uline : _ignore_parm;
term->set_standout = term->TI_smso && term->TI_rmso ?
_set_standout : _ignore_parm;
/* Create a string to set all attributes off */
str = g_string_new(NULL);
if (term->TI_sgr0)
g_string_append(str, term->TI_sgr0);
if (term->TI_rmul && (term->TI_sgr0 == NULL || strcmp(term->TI_rmul, term->TI_sgr0) != 0))
g_string_append(str, term->TI_rmul);
if (term->TI_rmso && (term->TI_sgr0 == NULL || strcmp(term->TI_rmso, term->TI_sgr0) != 0))
g_string_append(str, term->TI_rmso);
term->TI_normal = str->str;
g_string_free(str, FALSE);
term->set_normal = _set_normal;
term->beep = term->TI_bel ? _beep : _ignore;
terminfo_setup_colors(term, FALSE);
terminfo_cont(term);
return 1;
}
TERM_REC *terminfo_core_init(FILE *in, FILE *out)
{
TERM_REC *old_term, *term;
old_term = current_term;
current_term = term = g_new0(TERM_REC, 1);
term->in = in;
term->out = out;
if (!term_setup(term)) {
g_free(term);
term = NULL;
}
current_term = old_term;
return term;
}
void terminfo_core_deinit(TERM_REC *term)
{
TERM_REC *old_term;
old_term = current_term;
current_term = term;
term->set_normal(term);
current_term = old_term;
terminfo_stop(term);
g_free(term->TI_normal);
terminfo_colors_deinit(term);
g_free(term);
}

View File

@ -0,0 +1,91 @@
#ifndef __TERMINFO_CORE_H
#define __TERMINFO_CORE_H
#include <termios.h>
#define terminfo_move(x, y) current_term->move(current_term, x, y)
#define terminfo_scroll(y1, y2, count) current_term->scroll(current_term, y1, y2, count)
#define terminfo_clear() current_term->clear(current_term)
#define terminfo_clrtoeol() current_term->clrtoeol(current_term)
#define terminfo_set_fg(color) current_term->set_fg(current_term, color)
#define terminfo_set_bg(color) current_term->set_bg(current_term, color)
#define terminfo_set_normal() current_term->set_normal(current_term)
#define terminfo_set_bold() current_term->set_bold(current_term)
#define terminfo_set_uline(set) current_term->set_uline(current_term, set)
#define terminfo_set_standout(set) current_term->set_standout(current_term, set)
#define terminfo_has_colors(term) (term->TI_fg[0] != NULL)
typedef struct _TERM_REC TERM_REC;
struct _TERM_REC {
/* Functions */
void (*move)(TERM_REC *term, int x, int y);
void (*scroll)(TERM_REC *term, int y1, int y2, int count);
void (*clear)(TERM_REC *term);
void (*clrtoeol)(TERM_REC *term);
void (*set_fg)(TERM_REC *term, int color);
void (*set_bg)(TERM_REC *term, int color);
void (*set_normal)(TERM_REC *term);
void (*set_bold)(TERM_REC *term);
void (*set_uline)(TERM_REC *term, int set);
void (*set_standout)(TERM_REC *term, int set);
void (*beep)(TERM_REC *term);
#ifndef HAVE_TERMINFO
char buffer1[1024], buffer2[1024];
#endif
FILE *in, *out;
struct termios tio, old_tio;
/* Terminal size */
int width, height;
/* Cursor movement */
const char *TI_smcup, *TI_rmcup, *TI_cup;
const char *TI_hpa, *TI_vpa;
int TI_xhpa, TI_xvpa;
/* Scrolling */
const char *TI_csr, *TI_wind;
const char *TI_ri, *TI_rin, *TI_ind, *TI_indn;
const char *TI_il, *TI_il1, *TI_dl, *TI_dl1;
/* Clearing screen */
const char *TI_clear, *TI_ed; /* + *TI_dl, *TI_dl1; */
/* Clearing to end of line */
const char *TI_el;
/* Colors */
const char *TI_sgr0; /* turn off all attributes */
const char *TI_smul, *TI_rmul; /* underline on/off */
const char *TI_smso, *TI_rmso; /* standout on/off */
const char *TI_bold, *TI_blink;
const char *TI_setaf, *TI_setab, *TI_setf, *TI_setb;
/* Colors - generated and dynamically allocated */
char *TI_fg[16], *TI_bg[16], *TI_normal;
/* Beep */
char *TI_bel;
};
extern TERM_REC *current_term;
TERM_REC *terminfo_core_init(FILE *in, FILE *out);
void terminfo_core_deinit(TERM_REC *term);
/* Setup colors - if force is set, use ANSI-style colors if
terminal capabilities don't contain color codes */
void terminfo_setup_colors(TERM_REC *term, int force);
/* Terminal was resized - ask the width/height from terminfo again */
void terminfo_resize(TERM_REC *term);
void terminfo_cont(TERM_REC *term);
void terminfo_stop(TERM_REC *term);
#endif

View File

@ -239,7 +239,7 @@ static void cmd_scrollback_redraw(void)
gui = WINDOW_GUI(active_win);
screen_refresh_freeze();
term_refresh_freeze();
line = textbuffer_view_get_lines(gui->view);
while (line != NULL) {
next = line->next;
@ -248,7 +248,7 @@ static void cmd_scrollback_redraw(void)
}
gui_window_redraw(active_win);
screen_refresh_thaw();
term_refresh_thaw();
}
static void cmd_scrollback_status(void)

View File

@ -20,7 +20,6 @@
#include "module.h"
#include "textbuffer-view.h"
#include "screen.h"
typedef struct {
char *name;
@ -102,6 +101,46 @@ static void textbuffer_cache_unref(TEXT_BUFFER_CACHE_REC *cache)
textbuffer_cache_destroy(cache);
}
#define FGATTR (ATTR_NOCOLORS | ATTR_RESETBG | ATTR_BLINK | 0xf0)
#define BGATTR (ATTR_NOCOLORS | ATTR_RESETFG | ATTR_BOLD | 0x0f)
static void update_cmd_color(unsigned char cmd, int *color)
{
if ((cmd & 0x80) == 0) {
if (cmd & LINE_COLOR_BG) {
/* set background color */
*color &= BGATTR;
if ((cmd & LINE_COLOR_DEFAULT) == 0)
*color |= (cmd & 0x0f) << 4;
else {
*color |= ATTR_RESETBG;
if (cmd & LINE_COLOR_BLINK)
*color |= ATTR_BLINK;
}
} else {
/* set foreground color */
*color &= FGATTR;
if ((cmd & LINE_COLOR_DEFAULT) == 0)
*color |= cmd & 0x0f;
else {
*color |= ATTR_RESETFG;
if (cmd & LINE_COLOR_BOLD)
*color |= ATTR_BOLD;
}
}
} else switch (cmd) {
case LINE_CMD_UNDERLINE:
*color ^= ATTR_UNDERLINE;
break;
case LINE_CMD_REVERSE:
*color ^= ATTR_REVERSE;
break;
case LINE_CMD_COLOR0:
*color &= BGATTR;
break;
}
}
static LINE_CACHE_REC *
view_update_line_cache(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line)
{
@ -115,7 +154,8 @@ view_update_line_cache(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line)
g_return_val_if_fail(line->text != NULL, NULL);
xpos = 0; color = 0; indent_pos = view->default_indent;
color = ATTR_RESETFG | ATTR_RESETBG;
xpos = 0; indent_pos = view->default_indent;
last_space = last_color = 0; last_space_ptr = NULL; sub = NULL;
indent_func = view->default_indent_func;
@ -139,38 +179,17 @@ view_update_line_cache(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line)
continue;
}
if ((cmd & 0x80) == 0) {
/* set color */
color = (color & ATTR_NOCOLORS) | cmd;
} else switch (cmd) {
case LINE_CMD_UNDERLINE:
color ^= ATTR_UNDERLINE;
break;
case LINE_CMD_REVERSE:
color ^= ATTR_REVERSE;
break;
case LINE_CMD_COLOR0:
color = color & ATTR_NOCOLORS;
break;
case LINE_CMD_COLOR8:
color &= 0xfff0;
color |= 8|ATTR_COLOR8;
break;
case LINE_CMD_BLINK:
color |= 0x80;
break;
case LINE_CMD_INDENT:
if (cmd == LINE_CMD_INDENT) {
/* set indentation position here - don't do
it if we're too close to right border */
if (xpos < view->width-5) indent_pos = xpos;
break;
case LINE_CMD_INDENT_FUNC:
} else if (cmd == LINE_CMD_INDENT_FUNC) {
memcpy(&indent_func, ptr, sizeof(INDENT_FUNC));
ptr += sizeof(INDENT_FUNC);
if (indent_func == NULL)
indent_func = view->default_indent_func;
break;
}
} else
update_cmd_color(cmd, &color);
continue;
}
@ -306,9 +325,9 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line,
}
/* first clear the line */
screen_set_color(view->window, 0);
screen_move(view->window, 0, ypos);
screen_clrtoeol(view->window);
term_set_color(view->window, ATTR_RESET);
term_move(view->window, 0, ypos);
term_clrtoeol(view->window);
if (subline > 0) {
indent_func = cache->lines[subline-1].indent_func;
@ -318,8 +337,8 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line,
color = cache->lines[subline-1].color;
}
screen_move(view->window, xpos, ypos);
screen_set_color(view->window, color);
term_move(view->window, xpos, ypos);
term_set_color(view->window, color);
/* get the beginning of the next subline */
text_newline = subline == cache->count-1 ? NULL :
@ -335,47 +354,28 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line,
if (*text == LINE_CMD_EOL || *text == LINE_CMD_FORMAT)
break;
if ((*text & 0x80) == 0) {
/* set color */
color = (color & ATTR_NOCOLORS) | *text;
} else if (*text == LINE_CMD_CONTINUE) {
if (*text == LINE_CMD_CONTINUE) {
/* jump to next block */
memcpy(&tmp, text+1, sizeof(unsigned char *));
text = tmp;
continue;
} else switch (*text) {
case LINE_CMD_UNDERLINE:
color ^= ATTR_UNDERLINE;
break;
case LINE_CMD_REVERSE:
color ^= ATTR_REVERSE;
break;
case LINE_CMD_COLOR0:
color = color & ATTR_NOCOLORS;
break;
case LINE_CMD_COLOR8:
color &= 0xfff0;
color |= 8|ATTR_COLOR8;
break;
case LINE_CMD_BLINK:
color |= 0x80;
break;
case LINE_CMD_INDENT_FUNC:
text += sizeof(INDENT_FUNC);
break;
} else if (*text == LINE_CMD_INDENT_FUNC) {
text += sizeof(INDENT_FUNC);
} else {
update_cmd_color(*text, &color);
term_set_color(view->window, color);
}
screen_set_color(view->window, color);
text++;
continue;
}
if ((*text & 127) >= 32)
screen_addch(view->window, *text);
term_addch(view->window, *text);
else {
/* low-ascii */
screen_set_color(view->window, ATTR_REVERSE);
screen_addch(view->window, (*text & 127)+'A'-1);
screen_set_color(view->window, color);
term_set_color(view->window, ATTR_RESET|ATTR_REVERSE);
term_addch(view->window, (*text & 127)+'A'-1);
term_set_color(view->window, color);
}
text++;
}
@ -594,9 +594,10 @@ static void view_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line,
}
/* clear the rest of the view */
term_set_color(view->window, ATTR_RESET);
while (lines > 0) {
screen_move(view->window, 0, ypos);
screen_clrtoeol(view->window);
term_move(view->window, 0, ypos);
term_clrtoeol(view->window);
ypos++; lines--;
}
}
@ -682,7 +683,7 @@ static int view_scroll(TEXT_BUFFER_VIEW_REC *view, LINE_REC **lines,
whole view */
textbuffer_view_redraw(view);
} else {
screen_window_scroll(view->window, realcount);
term_window_scroll(view->window, realcount);
if (draw_nonclean) {
if (realcount < 0)
@ -691,7 +692,7 @@ static int view_scroll(TEXT_BUFFER_VIEW_REC *view, LINE_REC **lines,
view_draw_bottom(view, realcount);
}
screen_refresh(view->window);
term_refresh(view->window);
}
}
@ -792,7 +793,7 @@ void textbuffer_view_scroll(TEXT_BUFFER_VIEW_REC *view, int lines)
view->bottom = view_is_bottom(view);
if (view->window != NULL)
screen_refresh(view->window);
term_refresh(view->window);
}
/* Scroll to specified line */
@ -888,7 +889,7 @@ static void view_insert_line(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line)
}
if (view->window != NULL)
screen_refresh(view->window);
term_refresh(view->window);
}
/* Update some line in the buffer which has been modified using
@ -1051,7 +1052,7 @@ static void view_remove_line(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line,
view->bottom = view_is_bottom(view);
if (view->window != NULL)
screen_refresh(view->window);
term_refresh(view->window);
}
/* Remove one line from buffer. */
@ -1147,7 +1148,7 @@ LINE_REC *textbuffer_view_get_bookmark(TEXT_BUFFER_VIEW_REC *view,
/* Specify window where the changes in view should be drawn,
NULL disables it. */
void textbuffer_view_set_window(TEXT_BUFFER_VIEW_REC *view,
SCREEN_WINDOW *window)
TERM_WINDOW *window)
{
g_return_if_fail(view != NULL);
@ -1164,9 +1165,9 @@ void textbuffer_view_redraw(TEXT_BUFFER_VIEW_REC *view)
g_return_if_fail(view != NULL);
if (view->window != NULL) {
screen_window_clear(view->window);
term_window_clear(view->window);
view_draw_top(view, view->height);
screen_refresh(view->window);
term_refresh(view->window);
}
}

View File

@ -2,7 +2,7 @@
#define __TEXTBUFFER_VIEW_H
#include "textbuffer.h"
#include "screen.h"
#include "term.h"
typedef struct _TEXT_BUFFER_VIEW_REC TEXT_BUFFER_VIEW_REC;
@ -48,7 +48,7 @@ struct _TEXT_BUFFER_VIEW_REC {
TEXT_BUFFER_REC *buffer;
GSList *siblings; /* other views that use the same buffer */
SCREEN_WINDOW *window;
TERM_WINDOW *window;
int width, height;
int default_indent;
@ -134,7 +134,7 @@ LINE_REC *textbuffer_view_get_bookmark(TEXT_BUFFER_VIEW_REC *view,
/* Specify window where the changes in view should be drawn,
NULL disables it. */
void textbuffer_view_set_window(TEXT_BUFFER_VIEW_REC *view,
SCREEN_WINDOW *window);
TERM_WINDOW *window);
/* Redraw the view */
void textbuffer_view_redraw(TEXT_BUFFER_VIEW_REC *view);

View File

@ -340,16 +340,55 @@ void textbuffer_remove_all_lines(TEXT_BUFFER_REC *buffer)
buffer->last_eol = TRUE;
}
static void set_color(GString *str, int cmd, int *last_fg, int *last_bg)
{
if (cmd & LINE_COLOR_DEFAULT) {
g_string_sprintfa(str, "\004%c", FORMAT_STYLE_DEFAULTS);
/* need to reset the fg/bg color */
if (cmd & LINE_COLOR_BG) {
*last_bg = -1;
if (*last_fg != -1) {
g_string_sprintfa(str, "\004%c%c",
*last_fg,
FORMAT_COLOR_NOCHANGE);
}
} else {
*last_fg = -1;
if (*last_bg != -1) {
g_string_sprintfa(str, "\004%c%c",
FORMAT_COLOR_NOCHANGE,
*last_bg);
}
}
return;
}
if ((cmd & LINE_COLOR_BG) == 0) {
/* change foreground color */
*last_fg = (cmd & 0x0f)+'0';
g_string_sprintfa(str, "\004%c%c", *last_fg,
FORMAT_COLOR_NOCHANGE);
} else {
/* change background color */
*last_bg = (cmd & 0x0f)+'0';
g_string_sprintfa(str, "\004%c%c",
FORMAT_COLOR_NOCHANGE, *last_bg);
}
}
void textbuffer_line2text(LINE_REC *line, int coloring, GString *str)
{
unsigned char cmd;
char *ptr, *tmp;
int last_fg, last_bg;
g_return_if_fail(line != NULL);
g_return_if_fail(str != NULL);
g_string_truncate(str, 0);
last_fg = last_bg = -1;
for (ptr = line->text;;) {
if (*ptr != 0) {
g_string_append_c(str, *ptr);
@ -380,9 +419,7 @@ void textbuffer_line2text(LINE_REC *line, int coloring, GString *str)
if ((cmd & 0x80) == 0) {
/* set color */
g_string_sprintfa(str, "\004%c%c",
(cmd & 0x0f)+'0',
((cmd & 0xf0) >> 4)+'0');
set_color(str, cmd, &last_fg, &last_bg);
} else switch (cmd) {
case LINE_CMD_UNDERLINE:
g_string_append_c(str, 31);
@ -394,13 +431,6 @@ void textbuffer_line2text(LINE_REC *line, int coloring, GString *str)
g_string_sprintfa(str, "\004%c%c",
'0', FORMAT_COLOR_NOCHANGE);
break;
case LINE_CMD_COLOR8:
g_string_sprintfa(str, "\004%c%c",
'8', FORMAT_COLOR_NOCHANGE);
break;
case LINE_CMD_BLINK:
g_string_sprintfa(str, "\004%c", FORMAT_STYLE_BLINK);
break;
case LINE_CMD_INDENT:
break;
case LINE_CMD_INDENT_FUNC:

View File

@ -3,16 +3,19 @@
#define LINE_TEXT_CHUNK_SIZE 16384
#define LINE_COLOR_BG 0x20
#define LINE_COLOR_DEFAULT 0x10
#define LINE_COLOR_BOLD 0x08
#define LINE_COLOR_BLINK 0x08
enum {
LINE_CMD_EOL=0x80, /* line ends here */
LINE_CMD_CONTINUE, /* line continues in next block */
LINE_CMD_COLOR0, /* change to black, would be same as \0\0 but it breaks things.. */
LINE_CMD_COLOR8, /* change to dark grey, normally 8 = bold black */
LINE_CMD_UNDERLINE, /* enable/disable underlining */
LINE_CMD_REVERSE, /* enable/disable reversed text */
LINE_CMD_INDENT, /* if line is split, indent it at this position */
LINE_CMD_INDENT_FUNC, /* if line is split, use the specified indentation function */
LINE_CMD_BLINK, /* blinking background */
LINE_CMD_FORMAT, /* end of line, but next will come the format that was used to create the
text in format <module><format_name><arg><arg2...> - fields are separated
with \0<format> and last argument ends with \0<eol>. \0<continue> is allowed
@ -26,9 +29,17 @@ typedef struct {
} LINE_INFO_REC;
typedef struct _LINE_REC {
/* text in the line. \0 means that the next char will be a
color or command. <= 127 = color or if 8. bit is set, the
first 7 bits are the command. See LINE_CMD_xxxx.
/* Text in the line. \0 means that the next char will be a
color or command.
If the 8th bit is set, the first 7 bits are the command
(see LINE_CMD_xxxx). Otherwise they specify a color change:
Bit:
5 - Setting a background color
4 - Use "default terminal color"
3 - Bold (fg) / blink (bg) - can be used with 4th bit
0-2 - Color
DO NOT ADD BLACK WITH \0\0 - this will break things. Use
LINE_CMD_COLOR0 instead. */

740
src/fe-text/tparm.c Normal file
View File

@ -0,0 +1,740 @@
/*
* tparm.c
*
* By Ross Ridge
* Public Domain
* 92/02/01 07:30:36
*
*/
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#ifndef MAX_PUSHED
#define MAX_PUSHED 32
#endif
#define ARG 1
#define NUM 2
#define INTEGER 1
#define STRING 2
#define MAX_LINE 640
typedef void* anyptr;
typedef struct stack_str {
int type;
int argnum;
int value;
} stack;
static stack S[MAX_PUSHED];
static stack vars['z'-'a'+1];
static int pos = 0;
static struct arg_str {
int type;
int integer;
char *string;
} arg_list[10];
static int argcnt;
static va_list tparm_args;
static int pusharg(int arg)
{
if (pos == MAX_PUSHED)
return 1;
S[pos].type = ARG;
S[pos++].argnum = arg;
return 0;
}
static int pushnum(int num)
{
if (pos == MAX_PUSHED)
return 1;
S[pos].type = NUM;
S[pos++].value = num;
return 0;
}
/* VARARGS2 */
static int getarg(int argnum, int type, anyptr p)
{
while (argcnt < argnum) {
arg_list[argcnt].type = INTEGER;
arg_list[argcnt++].integer = (int) va_arg(tparm_args, int);
}
if (argcnt > argnum) {
if (arg_list[argnum].type != type)
return 1;
else if (type == STRING)
*(char **)p = arg_list[argnum].string;
else
*(int *)p = arg_list[argnum].integer;
} else {
arg_list[argcnt].type = type;
if (type == STRING)
*(char **)p = arg_list[argcnt++].string
= (char *) va_arg(tparm_args, char *);
else
*(int *)p = arg_list[argcnt++].integer = (int) va_arg(tparm_args, int);
}
return 0;
}
static int popstring(char **str)
{
if (pos-- == 0)
return 1;
if (S[pos].type != ARG)
return 1;
return(getarg(S[pos].argnum, STRING, (anyptr) str));
}
static int popnum(int *num)
{
if (pos-- == 0)
return 1;
switch (S[pos].type) {
case ARG:
return (getarg(S[pos].argnum, INTEGER, (anyptr) num));
case NUM:
*num = S[pos].value;
return 0;
}
return 1;
}
static int cvtchar(char *sp, char *c)
{
switch(*sp) {
case '\\':
switch(*++sp) {
case '\'':
case '$':
case '\\':
case '%':
*c = *sp;
return 2;
case '\0':
*c = '\\';
return 1;
case '0':
if (sp[1] == '0' && sp[2] == '0') {
*c = '\0';
return 4;
}
*c = '\200'; /* '\0' ???? */
return 2;
default:
*c = *sp;
return 2;
}
default:
*c = *sp;
return 1;
}
}
static int termcap;
/* sigh... this has got to be the ugliest code I've ever written.
Trying to handle everything has its cost, I guess.
It actually isn't to hard to figure out if a given % code is supposed
to be interpeted with its termcap or terminfo meaning since almost
all terminfo codes are invalid unless something has been pushed on
the stack and termcap strings will never push things on the stack
(%p isn't used by termcap). So where we have a choice we make the
decision by wether or not somthing has been pushed on the stack.
The static variable termcap keeps track of this; it starts out set
to 1 and is incremented as each argument processed by a termcap % code,
however if something is pushed on the stack it's set to 0 and the
rest of the % codes are interpeted as terminfo % codes. Another way
of putting it is that if termcap equals one we haven't decided either
way yet, if it equals zero we're looking for terminfo codes, and if
its greater than 1 we're looking for termcap codes.
Terminfo % codes:
%% output a '%'
%[[:][-+# ][width][.precision]][doxXs]
output pop according to the printf format
%c output pop as a char
%'c' push character constant c.
%{n} push decimal constant n.
%p[1-9] push paramter [1-9]
%g[a-z] push variable [a-z]
%P[a-z] put pop in variable [a-z]
%l push the length of pop (a string)
%+ add pop to pop and push the result
%- subtract pop from pop and push the result
%* multiply pop and pop and push the result
%& bitwise and pop and pop and push the result
%| bitwise or pop and pop and push the result
%^ bitwise xor pop and pop and push the result
%~ push the bitwise not of pop
%= compare if pop and pop are equal and push the result
%> compare if pop is less than pop and push the result
%< compare if pop is greater than pop and push the result
%A logical and pop and pop and push the result
%O logical or pop and pop and push the result
%! push the logical not of pop
%? condition %t if_true [%e if_false] %;
if condtion evaulates as true then evaluate if_true,
else evaluate if_false. elseif's can be done:
%? cond %t true [%e cond2 %t true2] ... [%e condN %t trueN] [%e false] %;
%i add one to parameters 1 and 2. (ANSI)
Termcap Codes:
%% output a %
%. output parameter as a character
%d output parameter as a decimal number
%2 output parameter in printf format %02d
%3 output parameter in printf format %03d
%+x add the character x to parameter and output it as a character
(UW) %-x subtract parameter FROM the character x and output it as a char
(UW) %ax add the character x to parameter
(GNU) %a[+*-/=][cp]x
GNU arithmetic.
(UW) %sx subtract parameter FROM the character x
%>xy if parameter > character x then add character y to parameter
%B convert to BCD (parameter = (parameter/10)*16 + parameter%16)
%D Delta Data encode (parameter = parameter - 2*(paramter%16))
%i increment the first two parameters by one
%n xor the first two parameters by 0140
(GNU) %m xor the first two parameters by 0177
%r swap the first two parameters
(GNU) %b backup to previous parameter
(GNU) %f skip this parameter
Note the two definitions of %a, the GNU defintion is used if the characters
after the 'a' are valid, otherwise the UW definition is used.
(GNU) used by GNU Emacs termcap libraries
(UW) used by the University of Waterloo (MFCF) termcap libraries
*/
char *tparm(const char *str, ...) {
static char OOPS[] = "OOPS";
static char buf[MAX_LINE];
register const char *sp;
register char *dp;
register char *fmt;
char conv_char;
char scan_for;
int scan_depth = 0, if_depth;
static int i, j;
static char *s, c;
char fmt_buf[MAX_LINE];
char sbuf[MAX_LINE];
va_start(tparm_args, str);
sp = str;
dp = buf;
scan_for = 0;
if_depth = 0;
argcnt = 0;
pos = 0;
termcap = 1;
while (*sp != '\0') {
switch(*sp) {
case '\\':
if (scan_for) {
if (*++sp != '\0')
sp++;
break;
}
*dp++ = *sp++;
if (*sp != '\0')
*dp++ = *sp++;
break;
case '%':
sp++;
if (scan_for) {
if (*sp == scan_for && if_depth == scan_depth) {
if (scan_for == ';')
if_depth--;
scan_for = 0;
} else if (*sp == '?')
if_depth++;
else if (*sp == ';') {
if (if_depth == 0)
return OOPS;
else
if_depth--;
}
sp++;
break;
}
fmt = NULL;
switch(*sp) {
case '%':
*dp++ = *sp++;
break;
case '+':
if (!termcap) {
if (popnum(&j) || popnum(&i))
return OOPS;
i += j;
if (pushnum(i))
return OOPS;
sp++;
break;
}
;/* FALLTHROUGH */
case 'C':
if (*sp == 'C') {
if (getarg(termcap - 1, INTEGER, &i))
return OOPS;
if (i >= 96) {
i /= 96;
if (i == '$')
*dp++ = '\\';
*dp++ = i;
}
}
fmt = "%c";
/* FALLTHROUGH */
case 'a':
if (!termcap)
return OOPS;
if (getarg(termcap - 1, INTEGER, (anyptr) &i))
return OOPS;
if (*++sp == '\0')
return OOPS;
if ((sp[1] == 'p' || sp[1] == 'c')
&& sp[2] != '\0' && fmt == NULL) {
/* GNU aritmitic parameter, what they
realy need is terminfo. */
int val, lc;
if (sp[1] == 'p'
&& getarg(termcap - 1 + sp[2] - '@',
INTEGER, (anyptr) &val))
return OOPS;
if (sp[1] == 'c') {
lc = cvtchar(sp + 2, &c) + 2;
/* Mask out 8th bit so \200 can be
used for \0 as per GNU doc's */
val = c & 0177;
} else
lc = 2;
switch(sp[0]) {
case '=':
break;
case '+':
val = i + val;
break;
case '-':
val = i - val;
break;
case '*':
val = i * val;
break;
case '/':
val = i / val;
break;
default:
/* Not really GNU's %a after all... */
lc = cvtchar(sp, &c);
val = c + i;
break;
}
arg_list[termcap - 1].integer = val;
sp += lc;
break;
}
sp += cvtchar(sp, &c);
arg_list[termcap - 1].integer = c + i;
if (fmt == NULL)
break;
sp--;
/* FALLTHROUGH */
case '-':
if (!termcap) {
if (popnum(&j) || popnum(&i))
return OOPS;
i -= j;
if (pushnum(i))
return OOPS;
sp++;
break;
}
fmt = "%c";
/* FALLTHROUGH */
case 's':
if (termcap && (fmt == NULL || *sp == '-')) {
if (getarg(termcap - 1, INTEGER, &i))
return OOPS;
if (*++sp == '\0')
return OOPS;
sp += cvtchar(sp, &c);
arg_list[termcap - 1].integer = c - i;
if (fmt == NULL)
break;
sp--;
}
if (!termcap)
return OOPS;
;/* FALLTHROUGH */
case '.':
if (termcap && fmt == NULL)
fmt = "%c";
;/* FALLTHROUGH */
case 'd':
if (termcap && fmt == NULL)
fmt = "%d";
;/* FALLTHROUGH */
case '2':
if (termcap && fmt == NULL)
fmt = "%02d";
;/* FALLTHROUGH */
case '3':
if (termcap && fmt == NULL)
fmt = "%03d";
;/* FALLTHROUGH */
case ':': case ' ': case '#': case 'u':
case 'x': case 'X': case 'o': case 'c':
case '0': case '1': case '4': case '5':
case '6': case '7': case '8': case '9':
if (fmt == NULL) {
if (termcap)
return OOPS;
if (*sp == ':')
sp++;
fmt = fmt_buf;
*fmt++ = '%';
while(*sp != 's' && *sp != 'x' && *sp != 'X' && *sp != 'd' && *sp != 'o' && *sp != 'c' && *sp != 'u') {
if (*sp == '\0')
return OOPS;
*fmt++ = *sp++;
}
*fmt++ = *sp;
*fmt = '\0';
fmt = fmt_buf;
}
conv_char = fmt[strlen(fmt) - 1];
if (conv_char == 's') {
if (popstring(&s))
return OOPS;
sprintf(sbuf, fmt, s);
} else {
if (termcap) {
if (getarg(termcap++ - 1,
INTEGER, &i))
return OOPS;
} else
if (popnum(&i))
return OOPS;
if (i == 0 && conv_char == 'c')
*sbuf = 0;
else
sprintf(sbuf, fmt, i);
}
sp++;
fmt = sbuf;
while(*fmt != '\0') {
if (*fmt == '$')
*dp++ = '\\';
*dp++ = *fmt++;
}
break;
case 'r':
if (!termcap || getarg(1, INTEGER, &i))
return OOPS;
arg_list[1].integer = arg_list[0].integer;
arg_list[0].integer = i;
sp++;
break;
case 'i':
if (getarg(1, INTEGER, &i)
|| arg_list[0].type != INTEGER)
return OOPS;
arg_list[1].integer++;
arg_list[0].integer++;
sp++;
break;
case 'n':
if (!termcap || getarg(1, INTEGER, &i))
return OOPS;
arg_list[0].integer ^= 0140;
arg_list[1].integer ^= 0140;
sp++;
break;
case '>':
if (!termcap) {
if (popnum(&j) || popnum(&i))
return OOPS;
i = (i > j);
if (pushnum(i))
return OOPS;
sp++;
break;
}
if (getarg(termcap-1, INTEGER, &i))
return OOPS;
sp += cvtchar(sp, &c);
if (i > c) {
sp += cvtchar(sp, &c);
arg_list[termcap-1].integer += c;
} else
sp += cvtchar(sp, &c);
sp++;
break;
case 'B':
if (!termcap || getarg(termcap-1, INTEGER, &i))
return OOPS;
arg_list[termcap-1].integer = 16*(i/10)+i%10;
sp++;
break;
case 'D':
if (!termcap || getarg(termcap-1, INTEGER, &i))
return OOPS;
arg_list[termcap-1].integer = i - 2 * (i % 16);
sp++;
break;
case 'p':
if (termcap > 1)
return OOPS;
if (*++sp == '\0')
return OOPS;
if (*sp == '0')
i = 9;
else
i = *sp - '1';
if (i < 0 || i > 9)
return OOPS;
if (pusharg(i))
return OOPS;
termcap = 0;
sp++;
break;
case 'P':
if (termcap || *++sp == '\0')
return OOPS;
i = *sp++ - 'a';
if (i < 0 || i > 25)
return OOPS;
if (pos-- == 0)
return OOPS;
switch(vars[i].type = S[pos].type) {
case ARG:
vars[i].argnum = S[pos].argnum;
break;
case NUM:
vars[i].value = S[pos].value;
break;
}
break;
case 'g':
if (termcap || *++sp == '\0')
return OOPS;
i = *sp++ - 'a';
if (i < 0 || i > 25)
return OOPS;
switch(vars[i].type) {
case ARG:
if (pusharg(vars[i].argnum))
return OOPS;
break;
case NUM:
if (pushnum(vars[i].value))
return OOPS;
break;
}
break;
case '\'':
if (termcap > 1)
return OOPS;
if (*++sp == '\0')
return OOPS;
sp += cvtchar(sp, &c);
if (pushnum(c) || *sp++ != '\'')
return OOPS;
termcap = 0;
break;
case '{':
if (termcap > 1)
return OOPS;
i = 0;
sp++;
while(isdigit(*sp))
i = 10 * i + *sp++ - '0';
if (*sp++ != '}' || pushnum(i))
return OOPS;
termcap = 0;
break;
case 'l':
if (termcap || popstring(&s))
return OOPS;
i = strlen(s);
if (pushnum(i))
return OOPS;
sp++;
break;
case '*':
if (termcap || popnum(&j) || popnum(&i))
return OOPS;
i *= j;
if (pushnum(i))
return OOPS;
sp++;
break;
case '/':
if (termcap || popnum(&j) || popnum(&i))
return OOPS;
i /= j;
if (pushnum(i))
return OOPS;
sp++;
break;
case 'm':
if (termcap) {
if (getarg(1, INTEGER, &i))
return OOPS;
arg_list[0].integer ^= 0177;
arg_list[1].integer ^= 0177;
sp++;
break;
}
if (popnum(&j) || popnum(&i))
return OOPS;
i %= j;
if (pushnum(i))
return OOPS;
sp++;
break;
case '&':
if (popnum(&j) || popnum(&i))
return OOPS;
i &= j;
if (pushnum(i))
return OOPS;
sp++;
break;
case '|':
if (popnum(&j) || popnum(&i))
return OOPS;
i |= j;
if (pushnum(i))
return OOPS;
sp++;
break;
case '^':
if (popnum(&j) || popnum(&i))
return OOPS;
i ^= j;
if (pushnum(i))
return OOPS;
sp++;
break;
case '=':
if (popnum(&j) || popnum(&i))
return OOPS;
i = (i == j);
if (pushnum(i))
return OOPS;
sp++;
break;
case '<':
if (popnum(&j) || popnum(&i))
return OOPS;
i = (i < j);
if (pushnum(i))
return OOPS;
sp++;
break;
case 'A':
if (popnum(&j) || popnum(&i))
return OOPS;
i = (i && j);
if (pushnum(i))
return OOPS;
sp++;
break;
case 'O':
if (popnum(&j) || popnum(&i))
return OOPS;
i = (i || j);
if (pushnum(i))
return OOPS;
sp++;
break;
case '!':
if (popnum(&i))
return OOPS;
i = !i;
if (pushnum(i))
return OOPS;
sp++;
break;
case '~':
if (popnum(&i))
return OOPS;
i = ~i;
if (pushnum(i))
return OOPS;
sp++;
break;
case '?':
if (termcap > 1)
return OOPS;
termcap = 0;
if_depth++;
sp++;
break;
case 't':
if (popnum(&i) || if_depth == 0)
return OOPS;
if (!i) {
scan_for = 'e';
scan_depth = if_depth;
}
sp++;
break;
case 'e':
if (if_depth == 0)
return OOPS;
scan_for = ';';
scan_depth = if_depth;
sp++;
break;
case ';':
if (if_depth-- == 0)
return OOPS;
sp++;
break;
case 'b':
if (--termcap < 1)
return OOPS;
sp++;
break;
case 'f':
if (!termcap++)
return OOPS;
sp++;
break;
}
break;
default:
if (scan_for)
sp++;
else
*dp++ = *sp++;
break;
}
}
va_end(tparm_args);
*dp = '\0';
return buf;
}