#include "sux.h"
#define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b))
#define DEFAULT(a, b) (a) = (a) ? (a) : (b)
char *key = NULL;
uint8_t key_idx = 0;
uint8_t esc = 0;
uint8_t iscsi = 0;
typedef struct escape escape;
struct escape {
char buf[128];
size_t len;
int arg[16];
int narg;
char mode[2];
};
escape escseq;
static inline char *get_keyseq(int keycode) {
switch (keycode) {
case KEY_BACKSPACE: return "\b";
case KEY_UP : return "\x1B[A";
case KEY_DOWN : return "\x1B[B";
case KEY_RIGHT : return "\x1B[C";
case KEY_LEFT : return "\x1B[D";
case KEY_F( 1) : return "\x1BOP";
case KEY_F( 2) : return "\x1BOQ";
case KEY_F( 3) : return "\x1BOR";
case KEY_F( 4) : return "\x1BOS";
case KEY_F( 5) : return "\x1B[15~";
case KEY_F( 6) : return "\x1B[17~";
case KEY_F( 7) : return "\x1B[18~";
case KEY_F( 8) : return "\x1B[19~";
case KEY_F( 9) : return "\x1B[20~";
case KEY_F(10) : return "\x1B[21~";
case KEY_F(11) : return "\x1B[23~";
case KEY_F(12) : return "\x1B[24~";
default : return NULL;
}
}
int get_key(WINDOW *scr) {
int x, y;
int c;
int keycode = 0;
curs_set(1);
if ((key == NULL) || (key && key[key_idx] == '\0') || !kbd_rdy) {
c = wgetch(scr);
if (c == 19) {
if (kbd_rdy) {
c = wgetch(scr);
}
step = 1;
} else if (c == 0x11) {
end = 1;
}
if (kbd_rdy) {
key_idx = 0;
key = get_keyseq(c);
}
keycode = c;
}
if (kbd_rdy) {
c = (key != NULL) ? key[key_idx++] : c;
}
if (step) {
if (keycode != 19 && keycode != 18 && keycode != 0x11 && !isalnum(keycode)) {
switch (keycode) {
case KEY_F(1):
endwin();
puts("Starting asmmon()");
asmmon("stdin");
puts("Reinitializing screen.");
init_scr();
wrefresh(scr);
break;
}
#if debug && !bench
getyx(scr, y, x);
wmove(scr, getmaxy(scr)-1, 0);
wclrtoeol(scr);
wprintw(scr, "keycode: %i", keycode);
wmove(scr, y, x);
#endif
}
}
if (kbd_rdy) {
switch (c) {
case ERR:
addr[CTRL_ADDR] = 0;
break;
case '\0': break;
default:
if (kbd_rdy && c < 0x100) {
addr[CTRL_ADDR] = 1;
#if debug && !bench
wmove(scr, getmaxy(scr)-1, 0);
wclrtoeol(scr);
wprintw(scr, "c: %i ", c);
wprintw(scr, "key: ");
for (int i = 0; key && key[i] != '\0'; i++) {
wprintw(scr, "$%02X%s", key[i], (key[i+1] != '\0') ? ", " : "");
}
wmove(scr, y, x);
#endif
}
break;
}
} else {
if (step) {
step = !(c == 18);
}
}
addr[STEP_ADDR] = step;
curs_set(0);
return c;
}
void parse_esc() {
char *str = escseq.buf, *nstr;
long int value;
escseq.narg = 0;
escseq.buf[escseq.len] = '\0';
for (;str < escseq.buf + escseq.len; str++) {
nstr = NULL;
value = strtol(str, &nstr, 10);
if (nstr == str) {
value = 0;
}
if (value == LONG_MAX || value == LONG_MIN) {
value = -1;
}
escseq.arg[escseq.narg++] = value;
str = nstr;
if (*str != ';' || escseq.narg == 16) {
break;
}
}
escseq.mode[0] = *str++;
escseq.mode[1] = (str < (escseq.buf + escseq.len)) ? *str : '\0';
}
void handle_esc() {
int x, y;
getyx(scr, y, x);
switch (escseq.mode[0]) {
case 'A':
DEFAULT(escseq.arg[0], 1);
if (y-escseq.arg[0] >= 0) {
y -= escseq.arg[0];
#if !debug
wmove(scr, y, x);
#endif
}
break;
case 'B':
case 'e':
DEFAULT(escseq.arg[0], 1);
if (y+escseq.arg[0] <= getmaxy(scr)) {
y += escseq.arg[0];
#if !debug
wmove(scr, y, x);
#endif
}
break;
case 'C':
case 'a':
DEFAULT(escseq.arg[0], 1);
if (x+escseq.arg[0] <= getmaxx(scr)) {
x += escseq.arg[0];
#if !debug
wmove(scr, y, x);
#endif
}
break;
case 'D':
DEFAULT(escseq.arg[0], 1);
if (x-escseq.arg[0] >= 0) {
x -= escseq.arg[0];
#if !debug
wmove(scr, y, x);
#endif
}
break;
case 'H':
case 'f':
DEFAULT(escseq.arg[0], 1);
DEFAULT(escseq.arg[1], 1);
#if !debug
wmove(scr, escseq.arg[0]-1, escseq.arg[1]-1);
#else
wmove(scr, 31, 0);
wclrtoeol(scr);
wprintw(scr, "escseq.arg[0]: %i, escseq.arg[1]: %i", escseq.arg[0], escseq.arg[1]);
#endif
break;
case 'S':
DEFAULT(escseq.arg[0], 1);
#if !debug
wscrl(scr, -escseq.arg[0]);
#else
#endif
break;
case 'T':
DEFAULT(escseq.arg[0], 1);
#if !debug
wscrl(scr, escseq.arg[0]);
#else
#endif
break;
}
}
void reset_esc() {
memset(&escseq, 0, sizeof(escseq));
}
void handle_ctrlcode(int c) {
int x, y;
uint16_t scr_col = 0;
#if debug
if (!subdbg) {
scr_col = (addr[TX_ADDR] != 0x0C && addr[TX_ADDR] != '\n' && scr_col < 160) ? (addr[1] << 1)-2 : 0;
wmove(scr, 28, scr_col);
}
#endif
getyx(scr, y, x);
switch (c) {
case 0xC:
x=0,y=0;
#if !debug
wclear(scr);
wmove(scr, y, x);
#endif
break;
case CURSES_BACKSPACE:
case '\b':
if (x > 0) {
x--;
#if !debug
wmove(scr, y, x);
#endif
}
#if !debug
wdelch(scr);
#else
if (!subdbg) {
scr_col++;
wmove(scr, 28, scr_col--);
wdelch(scr);
wmove(scr, 28, scr_col);
wdelch(scr);
}
#endif
break;
case '\033': reset_esc(); esc = 1; break;
case '\n':
x = 0;
y+=1;
#if !debug
wmove(scr, y, x);
#endif
break;
default:
#if !debug
waddch(scr, c);
#else
if (!subdbg && scr_col < 160) {
if (c != ' ') {
wprintw(scr, "%02X", c);
} else {
wprintw(scr, " ");
}
}
#endif
x+=1;
break;
}
}
void io(uint64_t address, uint8_t rw) {
switch (address) {
case STEP_ADDR: step = (!rw) ? addr[STEP_ADDR] : step; break;
case CTRL_ADDR:
if (!rw) {
break;
}
kbd_rdy = 1;
wrefresh(scr);
addr[RX_ADDR] = get_key(scr);
kbd_rdy = 0;
break;
case TX_ADDR:
if (rw) {
break;
}
if (esc) {
#if debug
if (!subdbg && addr[RX_ADDR] == '\n') {
wclrtoeol(scr);
}
#endif
int c = addr[TX_ADDR];
if (iscsi) {
escseq.buf[escseq.len++] = c;
if (BETWEEN(c, 0x40, 0x7E) || escseq.len >= sizeof(escseq.buf)-1) {
esc = 0;
iscsi = 0;
parse_esc();
handle_esc();
}
}
if (c == '[') {
iscsi = 1;
}
} else {
handle_ctrlcode(addr[TX_ADDR]);
}
break;
}
}