Start work on CSI parser
Also cleaup error reporting and command dumping macros
This commit is contained in:
+106
-32
@@ -5,6 +5,7 @@
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "data-types.h"
|
||||
#include "control-codes.h"
|
||||
|
||||
@@ -14,17 +15,63 @@
|
||||
#define OSC_STATE 3
|
||||
#define DCS_STATE 4
|
||||
|
||||
#define IS_DIGIT \
|
||||
case '0': \
|
||||
case '1': \
|
||||
case '2': \
|
||||
case '3': \
|
||||
case '4': \
|
||||
case '5': \
|
||||
case '6': \
|
||||
case '7': \
|
||||
case '8': \
|
||||
case '9':
|
||||
|
||||
#ifdef DUMP_COMMANDS
|
||||
static void _report_error(PyObject *dump_callback, const char *fmt, ...) {
|
||||
va_list argptr;
|
||||
va_start(argptr, fmt);
|
||||
PyObject *temp = PyUnicode_FromFormatV(fmt, argptr);
|
||||
va_end(argptr);
|
||||
if (temp != NULL) {
|
||||
Py_XDECREF(PyObject_CallFunctionObjArgs(dump_callback, temp, NULL)); PyErr_Clear();
|
||||
Py_CLEAR(temp);
|
||||
}
|
||||
}
|
||||
|
||||
#define REPORT_ERROR(...) _report_error(dump_callback, __VA_ARGS__);
|
||||
|
||||
#define REPORT_COMMAND0(name) \
|
||||
Py_XDECREF(PyObject_CallFunction(dump_callback, "s", #name)); PyErr_Clear();
|
||||
|
||||
#define REPORT_COMMAND1(name, x) \
|
||||
Py_XDECREF(PyObject_CallFunction(dump_callback, "si", #name, (int)x)); PyErr_Clear();
|
||||
|
||||
#define REPORT_COMMAND2(name, x, y) \
|
||||
Py_XDECREF(PyObject_CallFunction(dump_callback, "sii", #name, (int)x, (int)y)); PyErr_Clear();
|
||||
|
||||
#define HANDLER(name) \
|
||||
static inline void read_##name(Screen *screen, uint8_t UNUSED *buf, unsigned int UNUSED buflen, unsigned int UNUSED *pos, PyObject UNUSED *dump_callback)
|
||||
|
||||
#else
|
||||
|
||||
#define REPORT_ERROR(...) fprintf(stderr, "[PARSE ERROR] "); fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n");
|
||||
|
||||
#define REPORT_COMMAND0(name)
|
||||
#define REPORT_COMMAND1(name, x)
|
||||
#define REPORT_COMMAND2(name, x, y)
|
||||
|
||||
#define HANDLER(name) \
|
||||
static inline void read_##name(Screen *screen, uint8_t UNUSED *buf, unsigned int UNUSED buflen, unsigned int UNUSED *pos)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define SET_STATE(state) screen->parser_state = state; screen->parser_buf_pos = 0;
|
||||
|
||||
// Parse text {{{
|
||||
|
||||
|
||||
HANDLER(text) {
|
||||
uint8_t ch;
|
||||
|
||||
@@ -37,16 +84,9 @@ HANDLER(text) {
|
||||
screen->parser_text_start = 0; \
|
||||
}
|
||||
|
||||
#ifdef DUMP_COMMANDS
|
||||
#define CALL_SCREEN_HANDLER(name) \
|
||||
DRAW_TEXT; \
|
||||
Py_XDECREF(PyObject_CallFunction(dump_callback, "sC", #name, (int)ch)); PyErr_Clear(); \
|
||||
DRAW_TEXT; REPORT_COMMAND1(name, ch); \
|
||||
name(screen, ch); break;
|
||||
#else
|
||||
#define CALL_SCREEN_HANDLER(name) \
|
||||
DRAW_TEXT; \
|
||||
name(screen, ch); break;
|
||||
#endif
|
||||
|
||||
switch(ch) {
|
||||
case BEL:
|
||||
@@ -83,6 +123,7 @@ HANDLER(text) {
|
||||
}
|
||||
DRAW_TEXT;
|
||||
}
|
||||
#define moo 1
|
||||
// }}}
|
||||
|
||||
// Parse ESC {{{
|
||||
@@ -90,13 +131,7 @@ HANDLER(text) {
|
||||
static inline void screen_linefeed2(Screen *screen) { screen_linefeed(screen, '\n'); }
|
||||
|
||||
static inline void escape_dispatch(Screen *screen, uint8_t ch, PyObject UNUSED *dump_callback) {
|
||||
#ifdef DUMP_COMMANDS
|
||||
#define CALL_ED(name) \
|
||||
Py_XDECREF(PyObject_CallFunction(dump_callback, "s", #name)); PyErr_Clear(); \
|
||||
name(screen); break;
|
||||
#else
|
||||
#define CALL_ED(name) name(screen); break;
|
||||
#endif
|
||||
#define CALL_ED(name) REPORT_COMMAND0(name); name(screen); break;
|
||||
switch (ch) {
|
||||
case RIS:
|
||||
CALL_ED(screen_reset);
|
||||
@@ -116,36 +151,24 @@ static inline void escape_dispatch(Screen *screen, uint8_t ch, PyObject UNUSED *
|
||||
CALL_ED(screen_normal_keypad_mode);
|
||||
case DECPAM:
|
||||
CALL_ED(screen_alternate_keypad_mode);
|
||||
#ifdef DUMP_COMMANDS
|
||||
default:
|
||||
Py_XDECREF(PyObject_CallFunction(dump_callback, "sB", "Unknown char in escape_dispatch: ", ch)); PyErr_Clear();
|
||||
#endif
|
||||
REPORT_ERROR("%s%d", "Unknown char in escape_dispatch: ", ch);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void sharp_dispatch(Screen *screen, uint8_t ch, PyObject UNUSED *dump_callback) {
|
||||
switch(ch) {
|
||||
case DECALN:
|
||||
#ifdef DUMP_COMMANDS
|
||||
Py_XDECREF(PyObject_CallFunction(dump_callback, "s", "screen_alignment_display")); PyErr_Clear();
|
||||
#endif
|
||||
REPORT_COMMAND0(screen_alignment_display);
|
||||
screen_alignment_display(screen);
|
||||
break;
|
||||
#ifdef DUMP_COMMANDS
|
||||
default:
|
||||
Py_XDECREF(PyObject_CallFunction(dump_callback, "sB", "Unknown char in sharp_dispatch: ", ch)); PyErr_Clear();
|
||||
#endif
|
||||
REPORT_ERROR("%s%d", "Unknown char in sharp_dispatch: ", ch);
|
||||
}
|
||||
}
|
||||
|
||||
HANDLER(esc) {
|
||||
#ifdef DUMP_COMMANDS
|
||||
#define ESC_DISPATCH(which, extra) which(screen, ch, extra); SET_STATE(NORMAL_STATE); \
|
||||
Py_XDECREF(PyObject_CallFunction(dump_callback, "sCC", #which, (int)ch, (int)(extra))); PyErr_Clear(); \
|
||||
return;
|
||||
#else
|
||||
#define ESC_DISPATCH(which, extra) which(screen, ch, extra); SET_STATE(NORMAL_STATE); return;
|
||||
#endif
|
||||
#define ESC_DISPATCH(which, extra) REPORT_COMMAND2(which, ch, extra); which(screen, ch, extra); SET_STATE(NORMAL_STATE); return;
|
||||
#ifdef DUMP_COMMANDS
|
||||
#define ESC_DELEGATE(which) which(screen, ch, dump_callback); SET_STATE(NORMAL_STATE); return;
|
||||
#else
|
||||
@@ -188,7 +211,58 @@ HANDLER(esc) {
|
||||
|
||||
// Parse CSI {{{
|
||||
HANDLER(csi) {
|
||||
screen->parser_state = NORMAL_STATE;
|
||||
#define CALL_BASIC_HANDLER(name) REPORT_COMMAND1(screen, ch); name(screen, ch); break;
|
||||
#define HANDLE_BASIC_CH \
|
||||
case BEL: \
|
||||
CALL_BASIC_HANDLER(screen_bell); \
|
||||
case BS: \
|
||||
CALL_BASIC_HANDLER(screen_backspace); \
|
||||
case HT: \
|
||||
CALL_BASIC_HANDLER(screen_tab); \
|
||||
case LF: \
|
||||
case VT: \
|
||||
case FF: \
|
||||
CALL_BASIC_HANDLER(screen_linefeed); \
|
||||
case CR: \
|
||||
CALL_BASIC_HANDLER(screen_carriage_return); \
|
||||
case NUL: \
|
||||
case DEL: \
|
||||
break; // no-op
|
||||
|
||||
uint8_t ch = buf[(*pos)++];
|
||||
switch(screen->parser_buf_pos) {
|
||||
case 0: // CSI starting
|
||||
screen->parser_buf[0] = 0;
|
||||
screen->parser_buf[1] = 0;
|
||||
switch(ch) {
|
||||
IS_DIGIT
|
||||
screen->parser_buf_pos = 2;
|
||||
screen->parser_buf[1] = ch;
|
||||
break;
|
||||
case '?':
|
||||
case '>':
|
||||
case '!':
|
||||
screen->parser_buf[0] = ch; screen->parser_buf_pos = 1;
|
||||
break;
|
||||
HANDLE_BASIC_CH
|
||||
default:
|
||||
REPORT_ERROR("%s%d", "Invalid first character for CSI: ", (int)ch);
|
||||
SET_STATE(NORMAL_STATE);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default: // CSI started
|
||||
switch(ch) {
|
||||
IS_DIGIT
|
||||
case ';':
|
||||
if (screen->parser_buf_pos >= PARSER_BUF_SZ - 1) {
|
||||
REPORT_ERROR("%s", "CSI sequence too long, ignoring.");
|
||||
SET_STATE(NORMAL_STATE);
|
||||
} else screen->parser_buf[screen->parser_buf_pos++] = ch;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// }}}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user