summaryrefslogtreecommitdiff
path: root/src/fe-text
diff options
context:
space:
mode:
Diffstat (limited to 'src/fe-text')
-rw-r--r--src/fe-text/Makefile.am36
-rw-r--r--src/fe-text/gui-entry.c34
-rw-r--r--src/fe-text/gui-printtext.c93
-rw-r--r--src/fe-text/gui-readline.c15
-rw-r--r--src/fe-text/gui-windows.c2
-rw-r--r--src/fe-text/irssi.c18
-rw-r--r--src/fe-text/lastlog.c4
-rw-r--r--src/fe-text/mainwindows-layout.c2
-rw-r--r--src/fe-text/mainwindows.c42
-rw-r--r--src/fe-text/mainwindows.h4
-rw-r--r--src/fe-text/statusbar-items.c4
-rw-r--r--src/fe-text/statusbar.c14
-rw-r--r--src/fe-text/term-curses.c368
-rw-r--r--src/fe-text/term-terminfo.c296
-rw-r--r--src/fe-text/term.c140
-rw-r--r--src/fe-text/term.h81
-rw-r--r--src/fe-text/terminfo-core.c584
-rw-r--r--src/fe-text/terminfo-core.h91
-rw-r--r--src/fe-text/textbuffer-commands.c4
-rw-r--r--src/fe-text/textbuffer-view.c143
-rw-r--r--src/fe-text/textbuffer-view.h6
-rw-r--r--src/fe-text/textbuffer.c50
-rw-r--r--src/fe-text/textbuffer.h21
-rw-r--r--src/fe-text/tparm.c740
24 files changed, 2581 insertions, 211 deletions
diff --git a/src/fe-text/Makefile.am b/src/fe-text/Makefile.am
index 00e0f856..faf1494f 100644
--- a/src/fe-text/Makefile.am
+++ b/src/fe-text/Makefile.am
@@ -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)
diff --git a/src/fe-text/gui-entry.c b/src/fe-text/gui-entry.c
index bff316e8..f3f2463e 100644
--- a/src/fe-text/gui-entry.c
+++ b/src/fe-text/gui-entry.c
@@ -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);
}
}
diff --git a/src/fe-text/gui-printtext.c b/src/fe-text/gui-printtext.c
index 79f86674..5c882dc4 100644
--- a/src/fe-text/gui-printtext.c
+++ b/src/fe-text/gui-printtext.c
@@ -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 (*fg < 0 || *fg > 15) {
- *fg = *bg == 0 ? current_theme->default_color :
- current_theme->default_real_color;
+ if (*bg >= 0) *bg = mirc_colors[*bg % 16];
+ if (*fg >= 0) *fg = mirc_colors[*fg % 16];
}
- if (flags & GUI_PRINT_FLAG_REVERSE)
- *fg |= ATTR_REVERSE;
+ if (*fg < 0 || *fg > 15)
+ *fg = current_theme->default_color;
+ if (*bg < 0 || *bg > 15)
+ *bg = -1;
- 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;
- /* color should never have last bit on or it would be treated as a
- command! */
- color = (fg & 0x0f) | ((bg & 0x07) << 4);
- pos = 0;
+ /* 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;
- if (((fg & ATTR_COLOR8) == 0 && (fg|(bg << 4)) != last_color) ||
- ((fg & ATTR_COLOR8) && (fg & 0xf0) != (last_color & 0xf0))) {
+ pos = 0;
+ if (fg != last_fg) {
+ last_fg = fg;
+ data[pos++] = 0;
+ data[pos++] = fg == 0 ? LINE_CMD_COLOR0 : fg;
+ }
+ if (bg != last_bg) {
+ last_bg = bg;
data[pos++] = 0;
- data[pos++] = color == 0 ? LINE_CMD_COLOR0 : color;
+ 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;
diff --git a/src/fe-text/gui-readline.c b/src/fe-text/gui-readline.c
index a9417de7..8008d6d6 100644
--- a/src/fe-text/gui-readline.c
+++ b/src/fe-text/gui-readline.c
@@ -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();
diff --git a/src/fe-text/gui-windows.c b/src/fe-text/gui-windows.c
index f3266828..5c6f00e5 100644
--- a/src/fe-text/gui-windows.c
+++ b/src/fe-text/gui-windows.c
@@ -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"
diff --git a/src/fe-text/irssi.c b/src/fe-text/irssi.c
index 543972fc..e625e595 100644
--- a/src/fe-text/irssi.c
+++ b/src/fe-text/irssi.c
@@ -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();
diff --git a/src/fe-text/lastlog.c b/src/fe-text/lastlog.c
index 1602fdad..e4155611 100644
--- a/src/fe-text/lastlog.c
+++ b/src/fe-text/lastlog.c
@@ -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.
diff --git a/src/fe-text/mainwindows-layout.c b/src/fe-text/mainwindows-layout.c
index 0e6af783..d3df6b86 100644
--- a/src/fe-text/mainwindows-layout.c
+++ b/src/fe-text/mainwindows-layout.c
@@ -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);
diff --git a/src/fe-text/mainwindows.c b/src/fe-text/mainwindows.c
index 32ceeeb9..0d1c3f19 100644
--- a/src/fe-text/mainwindows.c
+++ b/src/fe-text/mainwindows.c
@@ -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;
diff --git a/src/fe-text/mainwindows.h b/src/fe-text/mainwindows.h
index 4021b8f1..6306758f 100644
--- a/src/fe-text/mainwindows.h
+++ b/src/fe-text/mainwindows.h
@@ -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) */
diff --git a/src/fe-text/statusbar-items.c b/src/fe-text/statusbar-items.c
index 6ef22dbc..70547daf 100644
--- a/src/fe-text/statusbar-items.c
+++ b/src/fe-text/statusbar-items.c
@@ -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;
}
diff --git a/src/fe-text/statusbar.c b/src/fe-text/statusbar.c
index ed9a8ea1..0ed75fed 100644
--- a/src/fe-text/statusbar.c
+++ b/src/fe-text/statusbar.c
@@ -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 :
diff --git a/src/fe-text/term-curses.c b/src/fe-text/term-curses.c
new file mode 100644
index 00000000..02ac826b
--- /dev/null
+++ b/src/fe-text/term-curses.c
@@ -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;
+}
diff --git a/src/fe-text/term-terminfo.c b/src/fe-text/term-terminfo.c
new file mode 100644
index 00000000..1f0e8974
--- /dev/null
+++ b/src/fe-text/term-terminfo.c
@@ -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);
+}
diff --git a/src/fe-text/term.c b/src/fe-text/term.c
new file mode 100644
index 00000000..97764ac1
--- /dev/null
+++ b/src/fe-text/term.c
@@ -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);
+}
diff --git a/src/fe-text/term.h b/src/fe-text/term.h
new file mode 100644
index 00000000..5aa89e59
--- /dev/null
+++ b/src/fe-text/term.h
@@ -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
diff --git a/src/fe-text/terminfo-core.c b/src/fe-text/terminfo-core.c
new file mode 100644
index 00000000..08c76d10
--- /dev/null
+++ b/src/fe-text/terminfo-core.c
@@ -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);
+}
diff --git a/src/fe-text/terminfo-core.h b/src/fe-text/terminfo-core.h
new file mode 100644
index 00000000..480e80c1
--- /dev/null
+++ b/src/fe-text/terminfo-core.h
@@ -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
diff --git a/src/fe-text/textbuffer-commands.c b/src/fe-text/textbuffer-commands.c
index 502b3881..348e9d06 100644
--- a/src/fe-text/textbuffer-commands.c
+++ b/src/fe-text/textbuffer-commands.c
@@ -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)
diff --git a/src/fe-text/textbuffer-view.c b/src/fe-text/textbuffer-view.c
index adb9a320..cc33f715 100644
--- a/src/fe-text/textbuffer-view.c
+++ b/src/fe-text/textbuffer-view.c
@@ -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);
}
}
diff --git a/src/fe-text/textbuffer-view.h b/src/fe-text/textbuffer-view.h
index c5fc7ba2..e8b1262d 100644
--- a/src/fe-text/textbuffer-view.h
+++ b/src/fe-text/textbuffer-view.h
@@ -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);
diff --git a/src/fe-text/textbuffer.c b/src/fe-text/textbuffer.c
index f99aacca..b08e6fec 100644
--- a/src/fe-text/textbuffer.c
+++ b/src/fe-text/textbuffer.c
@@ -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:
diff --git a/src/fe-text/textbuffer.h b/src/fe-text/textbuffer.h
index 8256309f..87e950fa 100644
--- a/src/fe-text/textbuffer.h
+++ b/src/fe-text/textbuffer.h
@@ -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. */
diff --git a/src/fe-text/tparm.c b/src/fe-text/tparm.c
new file mode 100644
index 00000000..5ec5c936
--- /dev/null
+++ b/src/fe-text/tparm.c
@@ -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;
+}