#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
-#include <pty.h>
+#include <langinfo.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <termios.h>
#include <wchar.h>
-
+#ifdef __linux__
+# include <pty.h>
+#elif defined(__FreeBSD__)
+# include <libutil.h>
+#elif defined(__OpenBSD__) || defined(__NetBSD__)
+# include <util.h>
+#endif
#include "madtty.h"
+#ifndef NCURSES_ATTR_SHIFT
+# define NCURSES_ATTR_SHIFT 8
+#endif
+
#define IS_CONTROL(ch) !((ch) & 0xffffff60UL)
-static int has_default = 0;
+static int has_default, is_utf8;
enum {
C0_NUL = 0x00,
char rbuf[BUFSIZ];
char ebuf[BUFSIZ];
int rlen, elen;
+ madtty_handler_t handler;
+ void *data;
};
typedef struct t_row_t {
[KEY_PPAGE] = "\e[5~",
[KEY_NPAGE] = "\e[6~",
[KEY_SUSPEND] = "\x1A", /* Ctrl+Z gets mapped to this */
- [KEY_F(1)] = "\e[[A",
- [KEY_F(2)] = "\e[[B",
- [KEY_F(3)] = "\e[[C",
- [KEY_F(4)] = "\e[[D",
- [KEY_F(5)] = "\e[[E",
+ [KEY_F(1)] = "\e[11~",
+ [KEY_F(2)] = "\e[12~",
+ [KEY_F(3)] = "\e[13~",
+ [KEY_F(4)] = "\e[14~",
+ [KEY_F(5)] = "\e[15~",
[KEY_F(6)] = "\e[17~",
[KEY_F(7)] = "\e[18~",
[KEY_F(8)] = "\e[19~",
[KEY_F(9)] = "\e[20~",
[KEY_F(10)] = "\e[21~",
+ [KEY_F(11)] = "\e[23~",
+ [KEY_F(12)] = "\e[24~",
+ [KEY_F(13)] = "\e[25~",
+ [KEY_F(14)] = "\e[26~",
+ [KEY_F(15)] = "\e[28~",
+ [KEY_F(16)] = "\e[29~",
+ [KEY_F(17)] = "\e[31~",
+ [KEY_F(18)] = "\e[32~",
+ [KEY_F(19)] = "\e[33~",
+ [KEY_F(20)] = "\e[34~",
};
static void t_row_set(t_row_t *row, int start, int len, uint16_t attr)
static void try_interpret_escape_seq(madtty_t *t)
{
char lastchar = t->ebuf[t->elen-1];
-
+ if(!*t->ebuf)
+ return;
+ if(t->handler){
+ switch((*(t->handler))(t, t->ebuf)){
+ case MADTTY_HANDLER_OK:
+ goto cancel;
+ case MADTTY_HANDLER_NOTYET:
+ return;
+ }
+ }
switch (*t->ebuf) {
- case '\0':
- return;
-
case 'M':
interpret_csi_SR(t);
cancel_escape_sequence(t);
if (t->elen + 1 >= (int)sizeof(t->ebuf)) {
cancel:
+#ifndef NDEBUG
+ fprintf(stderr, "cancelled: \\033");
+ for (int i = 0; i < (int)t->elen; i++) {
+ if (isprint(t->ebuf[i])) {
+ fputc(t->ebuf[i], stderr);
+ } else {
+ fprintf(stderr, "\\%03o", t->ebuf[i]);
+ }
+ }
+ fputc('\n', stderr);
+#endif
cancel_escape_sequence(t);
}
}
}
}
+static void is_utf8_locale(void)
+{
+ const char *cset = nl_langinfo(CODESET) ?: "ANSI_X3.4-1968";
+ is_utf8 = !strcmp(cset, "UTF-8");
+}
+
// vt100 special graphics and line drawing
// 5f-7e standard vt100
// 40-5e rxvt extension for extra curses acs chars
-static uint16_t const vt100_0[62] = { // 41 .. 7e
+static uint16_t const vt100_utf8[62] = { // 41 .. 7e
0x2191, 0x2193, 0x2192, 0x2190, 0x2588, 0x259a, 0x2603, // 41-47 hi mr. snowman!
0, 0, 0, 0, 0, 0, 0, 0, // 48-4f
0, 0, 0, 0, 0, 0, 0, 0, // 50-57
0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, // 78-7e
};
-void madtty_putc(madtty_t *t, wchar_t wc)
+static uint32_t vt100[62];
+
+void madtty_init_vt100_graphics(void)
+{
+ vt100['l' - 0x41] = ACS_ULCORNER;
+ vt100['m' - 0x41] = ACS_LLCORNER;
+ vt100['k' - 0x41] = ACS_URCORNER;
+ vt100['j' - 0x41] = ACS_LRCORNER;
+ vt100['u' - 0x41] = ACS_RTEE;
+ vt100['t' - 0x41] = ACS_LTEE;
+ vt100['v' - 0x41] = ACS_TTEE;
+ vt100['w' - 0x41] = ACS_BTEE;
+ vt100['q' - 0x41] = ACS_HLINE;
+ vt100['x' - 0x41] = ACS_VLINE;
+ vt100['n' - 0x41] = ACS_PLUS;
+ vt100['o' - 0x41] = ACS_S1;
+ vt100['s' - 0x41] = ACS_S9;
+ vt100['`' - 0x41] = ACS_DIAMOND;
+ vt100['a' - 0x41] = ACS_CKBOARD;
+ vt100['f' - 0x41] = ACS_DEGREE;
+ vt100['g' - 0x41] = ACS_PLMINUS;
+ vt100['~' - 0x41] = ACS_BULLET;
+#if 0 /* out of bounds */
+ vt100[',' - 0x41] = ACS_LARROW;
+ vt100['+' - 0x41] = ACS_RARROW;
+ vt100['.' - 0x41] = ACS_DARROW;
+ vt100['-' - 0x41] = ACS_UARROW;
+ vt100['0' - 0x41] = ACS_BLOCK;
+#endif
+ vt100['h' - 0x41] = ACS_BOARD;
+ vt100['i' - 0x41] = ACS_LANTERN;
+ /* these defaults were invented for ncurses */
+ vt100['p' - 0x41] = ACS_S3;
+ vt100['r' - 0x41] = ACS_S7;
+ vt100['y' - 0x41] = ACS_LEQUAL;
+ vt100['z' - 0x41] = ACS_GEQUAL;
+ vt100['{' - 0x41] = ACS_PI;
+ vt100['|' - 0x41] = ACS_NEQUAL;
+ vt100['}' - 0x41] = ACS_STERLING;
+ is_utf8_locale();
+}
+
+static void madtty_putc(madtty_t *t, wchar_t wc)
{
int width = 0;
t_row_t *tmp;
if (t->graphmode) {
- if (wc >= 0x41 && wc <= 0x7e && vt100_0[wc - 0x41]) {
- wc = vt100_0[wc - 0x41];
+ if (wc >= 0x41 && wc <= 0x7e) {
+ wchar_t gc = is_utf8 ? vt100_utf8[wc - 0x41] : vt100[wc - 0x41];
+ if (gc)
+ wc = gc;
}
width = 1;
} else {
lines[row].attr = realloc(lines[row].attr, sizeof(uint16_t) * cols);
if (t->cols < cols)
t_row_set(lines + row, t->cols, cols - t->cols, 0);
+ else
+ lines[row].dirty = true;
}
t->cols = cols;
}
while (t->rows < rows) {
lines[t->rows].text = (wchar_t *)calloc(sizeof(wchar_t), cols);
lines[t->rows].attr = (uint16_t *)calloc(sizeof(uint16_t), cols);
+ t_row_set(lines + t->rows, 0, t->cols, 0);
t->rows++;
}
t->curs_row += lines - t->lines;
- t->scroll_top += lines - t->lines;
- t->scroll_bot += lines - t->lines;
- if (t->scroll_bot > lines + t->rows)
- t->scroll_bot = lines + t->rows;
+ t->scroll_top = lines;
+ t->scroll_bot = lines + rows;
t->lines = lines;
clamp_cursor_to_bounds(t);
ioctl(t->pty, TIOCSWINSZ, &ws);
void madtty_init_colors(void)
{
- if (COLORS > 8) {
+ if (COLOR_PAIRS > 64) {
use_default_colors();
- assume_default_colors(-1, -1);
has_default = 1;
for (int bg = -1; bg < 8; bg++) {
}
}
} else {
+ int use_default = use_default_colors() == OK;
for (int bg = 0; bg < 8; bg++) {
for (int fg = 0; fg < 8; fg++) {
- init_pair((7 - fg) * 8 + bg, fg, bg);
+ if (use_default) {
+ init_pair((7 - fg) * 8 + bg,
+ fg == COLOR_WHITE ? -1 : fg,
+ bg == COLOR_BLACK ? -1 : bg);
+ } else {
+ init_pair((7 - fg) * 8 + bg, fg, bg);
+ }
}
}
}
int madtty_color_pair(int fg, int bg)
{
- return has_default ? (fg + 1) * 16 + bg + 1 : (7 - fg) * 8 + bg;
+ if (has_default) {
+ if (fg < -1)
+ fg = -1;
+ if (bg < -1)
+ bg = -1;
+ return COLOR_PAIR((fg + 1) * 16 + bg + 1);
+ }
+ if (fg < 0)
+ fg = COLOR_WHITE;
+ if (bg < 0)
+ bg = COLOR_BLACK;
+ return COLOR_PAIR((7 - fg) * 8 + bg);
+}
+
+void madtty_set_handler(madtty_t *t, madtty_handler_t handler)
+{
+ t->handler = handler;
+}
+
+void madtty_set_data(madtty_t *t, void *data)
+{
+ t->data = data;
+}
+
+void *madtty_get_data(madtty_t *t)
+{
+ return t->data;
}