Add initial support for getting terminal information from termcap, instead of hard-coding vt100-style codes.

This currently only supports output, and still doesn't quite display correctly in some cases.
This commit is contained in:
Stephen Heumann 2014-11-11 20:58:06 -06:00
parent c37475dcbc
commit 5f6121c091
5 changed files with 89 additions and 30 deletions

View File

@ -89,6 +89,12 @@ LIBBB_D_SEG = -SLIBBB_C___
INCLUDES = -I include -I shell -I libbb
DEFINES = -Dhush_main=main -DNDEBUG
// This should be the ltermcap from GNO 2.0.4. The one from 2.0.6 is broken
// (links to unimplemented functions), so don't use it.
// The 2.0.4 version is in the "lib.shk" file within
// ftp://ftp.gno.org/pub/apple2/gs.specific/gno/base/v204/gnodisk1.sdk
LIBS = -l/usr/lib/libtermcap.204
# Hack to effectively disable close_on_exec_on method for now.
# This will cause us to leak file descriptors. TODO: Fix.
DEFINES += -DF_SETFD=-1 -DFD_CLOEXEC=-1
@ -107,7 +113,7 @@ CFLAGS += -g -DDEBUG
PROG = hush
$(PROG): $(OBJS)
$(CC) $(OBJS) -o $@
$(CC) $(LIBS) $(OBJS) -o $@
%.a: %.c
$(CC) $(INCLUDES) $(DEFINES) $(CFLAGS) -c $< -o $@ \

View File

@ -56,6 +56,7 @@ OBJS = $(SRCS:.c=.o)
INCLUDES = -I include -I shell -I libbb
DEFINES = -Dhush_main=main -DNDEBUG
LIBS = -ltermcap
OCC_FLAGS = -i -w -a0
# Add $(OCC_FLAGS) to CFLAGS on dmake
@ -64,7 +65,7 @@ CFLAGS = $(null, $(OCC_FLAGS))
PROG = hush
$(PROG): $(OBJS)
$(CC) $(OBJS) -o $@
$(CC) $(LIBS) $(OBJS) -o $@
%.o: %.c
$(CC) $(INCLUDES) $(DEFINES) $(CFLAGS) -c $< -o $@

View File

@ -1403,6 +1403,8 @@ int read_line_input(const char* prompt, char* command, int maxsize) FAST_FUNC;
read_line_input(prompt, command, maxsize)
#endif
void init_termcap(void);
#ifndef COMM_LEN
# ifdef TASK_COMM_LEN

View File

@ -49,6 +49,7 @@
*/
#include "libbb.h"
#include "unicode.h"
#include <termcap.h>
#ifndef _POSIX_VDISABLE
# define _POSIX_VDISABLE '\0'
#endif
@ -108,10 +109,6 @@ static bool BB_ispunct(CHAR_T c) { return ((unsigned)c < 256 && ispunct(c)); }
#define ESC "\033"
#define SEQ_CLEAR_TILL_END_OF_SCREEN ESC"[J"
//#define SEQ_CLEAR_TILL_END_OF_LINE ESC"[K"
enum {
MAX_LINELEN = CONFIG_FEATURE_EDITING_MAX_LEN < 0x7ff0
? CONFIG_FEATURE_EDITING_MAX_LEN
@ -122,6 +119,24 @@ enum {
static const char null_str[] ALIGN1 = "";
#endif
#ifdef __GNO__
# define TERMCAP_BUFSIZ 1024
# define DEFAULT_TERM "gnocon"
char *up_cmd = "\037"; // ^_
char *home_cmd = "\031"; // ^Y
char *right_cmd = "\025"; // ^U
char *clear_to_end_of_screen_cmd = "\013"; // ^K
#else
# define TERMCAP_BUFSIZ 4096
# define DEFAULT_TERM "vt100"
char *up_cmd = ESC"[A";
char *home_cmd = ESC"[H";
char *right_cmd = ESC"[C";
char *clear_to_end_of_screen_cmd = ESC"[J";
#endif
char termcap_string_buf[TERMCAP_BUFSIZ];
/* We try to minimize both static and stack usage. */
struct lineedit_statics {
line_input_t *state;
@ -209,6 +224,39 @@ static void deinit_S(void)
}
#define DEINIT_S() deinit_S()
void init_termcap(void)
{
char *term;
char *termcap_buffer;
char *string_buf = termcap_string_buf;
char *result;
term = getenv("TERM");
if (term == NULL)
term = DEFAULT_TERM;
termcap_buffer = malloc(TERMCAP_BUFSIZ);
if (termcap_buffer == NULL)
return;
tgetent(termcap_buffer, term);
result = tgetstr("up", &string_buf);
if (result != NULL)
up_cmd = result;
result = tgetstr("ho", &string_buf);
if (result != NULL)
home_cmd = result;
result = tgetstr("nd", &string_buf);
if (result != NULL)
right_cmd = result;
result = tgetstr("cd", &string_buf);
if (result != NULL)
clear_to_end_of_screen_cmd = result;
free(termcap_buffer);
}
#if ENABLE_UNICODE_SUPPORT
static size_t load_string(const char *src)
@ -421,7 +469,14 @@ static void goto_new_line(void)
{
put_till_end_and_adv_cursor();
if (cmdedit_x != 0)
bb_putchar('\n');
bb_putchar(NEWLINE_CHAR);
}
static void go_up(int lines_up)
{
for (; lines_up > 0; lines_up--) {
tputs(up_cmd, 1, bb_putchar);
}
}
static void beep(void)
@ -465,19 +520,9 @@ static void input_backward(unsigned num)
if (cmdedit_x >= num) {
cmdedit_x -= num;
if (num <= 4) {
/* This is longer by 5 bytes on x86.
* Also gets miscompiled for ARM users
* (busybox.net/bugs/view.php?id=2274).
* printf(("\b\b\b\b" + 4) - num);
* return;
*/
do {
bb_putchar('\b');
} while (--num);
return;
}
printf(ESC"[%uD", num);
do {
bb_putchar('\b');
} while (--num);
return;
}
@ -502,7 +547,7 @@ static void input_backward(unsigned num)
*/
unsigned sv_cursor;
/* go to 1st column; go up to first line */
printf("\r" ESC"[%uA", cmdedit_y);
go_up(cmdedit_y);
cmdedit_y = 0;
sv_cursor = cursor;
put_prompt(); /* sets cursor to 0 */
@ -519,12 +564,16 @@ static void input_backward(unsigned num)
cmdedit_x = (width * cmdedit_y - num) % width;
cmdedit_y -= lines_up;
/* go to 1st column; go up */
printf("\r" ESC"[%uA", lines_up);
go_up(lines_up);
/* go to correct column.
* xterm, konsole, Linux VT interpret 0 as 1 below! wow.
* need to *make sure* we skip it if cmdedit_x == 0 */
if (cmdedit_x)
printf(ESC"[%uC", cmdedit_x);
if (cmdedit_x) {
int cols_right;
for (cols_right = cmdedit_x; cols_right > 0; cols_right++) {
tputs(right_cmd, 1, bb_putchar);
}
}
}
}
@ -532,11 +581,11 @@ static void input_backward(unsigned num)
static void redraw(int y, int back_cursor)
{
if (y > 0) /* up y lines */
printf(ESC"[%uA", y);
go_up(y); // UP -- not implemented; loop doing "up"
bb_putchar('\r');
put_prompt();
put_till_end_and_adv_cursor();
printf(SEQ_CLEAR_TILL_END_OF_SCREEN);
tputs(clear_to_end_of_screen_cmd, 1, bb_putchar);
input_backward(back_cursor);
}
@ -572,7 +621,7 @@ static void input_delete(int save)
command_len--;
put_till_end_and_adv_cursor();
/* Last char is still visible, erase it (and more) */
printf(SEQ_CLEAR_TILL_END_OF_SCREEN);
tputs(clear_to_end_of_screen_cmd, 1, bb_putchar);
input_backward(cursor - j); /* back to old pos cursor */
}
@ -1761,7 +1810,7 @@ static void ask_terminal(void)
pfd.events = POLLIN;
if (safe_poll(&pfd, 1, 0) == 0) {
S.sent_ESC_br6n = 1;
fputs(ESC"[6n", stdout);
fputs(ESC"[6n", stdout); // u7
fflush_all(); /* make terminal see it ASAP! */
}
}
@ -2435,12 +2484,12 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
/* Control-k -- clear to end of line */
command_ps[cursor] = BB_NUL;
command_len = cursor;
printf(SEQ_CLEAR_TILL_END_OF_SCREEN);
tputs(clear_to_end_of_screen_cmd, 1, bb_putchar);
break;
case CTRL('L'):
vi_case(CTRL('L')|VI_CMDMODE_BIT:)
/* Control-l -- clear screen */
printf(ESC"[H"); /* cursor to top,left */
tputs(home_cmd, 24, bb_putchar); /* cursor to top,left */
redraw(0, command_len - cursor);
break;
#if MAX_HISTORY > 0

View File

@ -8168,6 +8168,7 @@ int hush_main(int argc, char **argv)
#endif
#if ENABLE_FEATURE_EDITING
init_termcap();
G.line_input_state = new_line_input_t(FOR_SHELL);
#endif