+ switch (wc) {
+ case C0_ESC:
+ new_escape_sequence(rt);
+ break;
+
+ case C0_BEL:
+ /* do nothing for now... maybe a visual bell would be nice? */
+ break;
+
+ case C0_BS:
+ if (rt->curs_col > 0)
+ rt->curs_col--;
+ break;
+
+ case C0_HT: /* tab */
+ rt->curs_col = (rt->curs_col + 8) & ~7;
+ if (rt->curs_col >= rt->cols)
+ rt->curs_col = rt->cols - 1;
+ break;
+
+ case C0_CR:
+ rt->curs_col = 0;
+ break;
+
+ case C0_VT:
+ case C0_FF:
+ case C0_LF:
+ cursor_line_down(rt);
+ break;
+
+ case C0_SO: /* shift out - acs */
+ rt->graphmode = true;
+ break;
+ case C0_SI: /* shift in - acs */
+ rt->graphmode = false;
+ break;
+ }
+}
+
+void madtty_putc(madtty_t *rt, wchar_t wc)
+{
+ int width = 0;
+
+ if (!rt->seen_input) {
+ rt->seen_input = 1;
+ kill(-rt->childpid, SIGWINCH);
+ }
+
+#if 0
+ if (wc == '\n' || (wc >= ' ' && isprint(wc))) {
+ fputc(wc, stderr);
+ } else {
+ fprintf(stderr, "\\%03o", wc);
+ }
+#endif
+
+ if (rt->escaped) {
+ assert (rt->elen + 1 < (int)sizeof(rt->ebuf));
+ rt->ebuf[rt->elen] = wc;
+ rt->ebuf[++rt->elen] = '\0';
+ try_interpret_escape_seq(rt);
+ } else if (IS_CONTROL(wc)) {
+ madtty_process_nonprinting(rt, wc);
+ } else {
+ mtty_row_t *tmp;
+
+ if (rt->graphmode) {
+ // vt100 special graphics and line drawing
+ // 5f-7e standard vt100
+ // 40-5e rxvt extension for extra curses acs chars
+ static uint16_t vt100_0[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
+ 0, 0, 0, 0, 0, 0, 0, 0x0020, // 58-5f
+ 0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1, // 60-67
+ 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba, // 68-6f
+ 0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c, // 70-77
+ 0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, // 78-7e
+ };
+
+ if (wc >= 0x41 && wc <= 0x7e && vt100_0[wc - 0x41]) {
+ wc = vt100_0[wc - 0x41];
+ }
+ width = 1;
+ } else {
+ width = wcwidth(wc) ?: 1;
+ }
+
+ if (width == 2 && rt->curs_col == rt->cols - 1) {
+ tmp = rt->curs_row;
+ tmp->dirty = true;
+ tmp->text[rt->curs_col] = 0;
+ tmp->attr[rt->curs_col] = build_attrs(rt->curattrs);
+ rt->curs_col++;
+ }
+
+ if (rt->curs_col >= rt->cols) {
+ rt->curs_col = 0;
+ cursor_line_down(rt);
+ }
+
+ tmp = rt->curs_row;
+ tmp->dirty = true;
+
+ if (rt->insert) {
+ wmemmove(tmp->text + rt->curs_col + width, tmp->text + rt->curs_col,
+ (rt->cols - rt->curs_col - width));
+ memmove(tmp->attr + rt->curs_col + width, tmp->attr + rt->curs_col,
+ (rt->cols - rt->curs_col - width) * sizeof(tmp->attr[0]));
+ }
+
+ tmp->text[rt->curs_col] = wc;
+ tmp->attr[rt->curs_col] = build_attrs(rt->curattrs);
+ rt->curs_col++;
+ if (width == 2) {
+ tmp->text[rt->curs_col] = 0;
+ tmp->attr[rt->curs_col] = build_attrs(rt->curattrs);
+ rt->curs_col++;
+ }
+ }
+}
+
+int madtty_process(madtty_t *rt)
+{
+ int res, pos = 0;
+
+ if (rt->pty < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ res = read(rt->pty, rt->rbuf + rt->rlen, sizeof(rt->rbuf) - rt->rlen);
+ if (res < 0)
+ return -1;
+
+ rt->rlen += res;
+ while (pos < rt->rlen) {
+ wchar_t wc;
+ ssize_t len;
+
+ len = (ssize_t)mbrtowc(&wc, rt->rbuf + pos, rt->rlen - pos, &rt->ps);
+ if (len == -2) {
+ rt->rlen -= pos;
+ memmove(rt->rbuf, rt->rbuf + pos, rt->rlen);
+ return 0;
+ }
+
+ if (len == -1) {
+ len = 1;
+ wc = rt->rbuf[pos];
+ }
+
+ pos += len ? len : 1;
+ madtty_putc(rt, wc);
+ }
+
+ rt->rlen -= pos;
+ memmove(rt->rbuf, rt->rbuf + pos, rt->rlen);
+ return 0;
+}
+
+madtty_t *madtty_create(int rows, int cols)
+{
+ madtty_t *rt;