Allow negative numbers in CSI codes
This commit is contained in:
parent
7cea233de3
commit
f9844ba3b0
@ -47,7 +47,7 @@ cursor_reset_display_attrs(Cursor *self) {
|
|||||||
|
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
parse_color(unsigned int *params, unsigned int *i, unsigned int count, uint32_t *result) {
|
parse_color(int *params, unsigned int *i, unsigned int count, uint32_t *result) {
|
||||||
unsigned int attr;
|
unsigned int attr;
|
||||||
uint8_t r, g, b;
|
uint8_t r, g, b;
|
||||||
if (*i < count) {
|
if (*i < count) {
|
||||||
@ -73,7 +73,7 @@ parse_color(unsigned int *params, unsigned int *i, unsigned int count, uint32_t
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
cursor_from_sgr(Cursor *self, unsigned int *params, unsigned int count) {
|
cursor_from_sgr(Cursor *self, int *params, unsigned int count) {
|
||||||
#define SET_COLOR(which) { parse_color(params, &i, count, &self->which); } break;
|
#define SET_COLOR(which) { parse_color(params, &i, count, &self->which); } break;
|
||||||
START_ALLOW_CASE_RANGE
|
START_ALLOW_CASE_RANGE
|
||||||
unsigned int i = 0, attr;
|
unsigned int i = 0, attr;
|
||||||
@ -90,7 +90,7 @@ START_ALLOW_CASE_RANGE
|
|||||||
case 3:
|
case 3:
|
||||||
self->italic = true; break;
|
self->italic = true; break;
|
||||||
case 4:
|
case 4:
|
||||||
if (i < count) { self->decoration = MIN(3u, params[i]); i++; }
|
if (i < count) { self->decoration = MIN(3, params[i]); i++; }
|
||||||
else self->decoration = 1;
|
else self->decoration = 1;
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
@ -136,7 +136,7 @@ END_ALLOW_CASE_RANGE
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
apply_sgr_to_cells(GPUCell *first_cell, unsigned int cell_count, unsigned int *params, unsigned int count) {
|
apply_sgr_to_cells(GPUCell *first_cell, unsigned int cell_count, int *params, unsigned int count) {
|
||||||
#define RANGE for(unsigned c = 0; c < cell_count; c++, cell++)
|
#define RANGE for(unsigned c = 0; c < cell_count; c++, cell++)
|
||||||
#define SET(shift) RANGE { cell->attrs |= (1 << shift); } break;
|
#define SET(shift) RANGE { cell->attrs |= (1 << shift); } break;
|
||||||
#define RESET(shift) RANGE { cell->attrs &= ~(1 << shift); } break;
|
#define RESET(shift) RANGE { cell->attrs &= ~(1 << shift); } break;
|
||||||
@ -161,7 +161,7 @@ apply_sgr_to_cells(GPUCell *first_cell, unsigned int cell_count, unsigned int *p
|
|||||||
case 3:
|
case 3:
|
||||||
SET(ITALIC_SHIFT);
|
SET(ITALIC_SHIFT);
|
||||||
case 4:
|
case 4:
|
||||||
if (i < count) { uint8_t val = MIN(3u, params[i]); i++; SETM(val, DECORATION_MASK, DECORATION_SHIFT); }
|
if (i < count) { uint8_t val = MIN(3, params[i]); i++; SETM(val, DECORATION_MASK, DECORATION_SHIFT); }
|
||||||
else { SETM(1, DECORATION_MASK, DECORATION_SHIFT); }
|
else { SETM(1, DECORATION_MASK, DECORATION_SHIFT); }
|
||||||
case 7:
|
case 7:
|
||||||
SET(REVERSE_SHIFT);
|
SET(REVERSE_SHIFT);
|
||||||
|
|||||||
@ -299,8 +299,8 @@ void cursor_reset(Cursor*);
|
|||||||
Cursor* cursor_copy(Cursor*);
|
Cursor* cursor_copy(Cursor*);
|
||||||
void cursor_copy_to(Cursor *src, Cursor *dest);
|
void cursor_copy_to(Cursor *src, Cursor *dest);
|
||||||
void cursor_reset_display_attrs(Cursor*);
|
void cursor_reset_display_attrs(Cursor*);
|
||||||
void cursor_from_sgr(Cursor *self, unsigned int *params, unsigned int count);
|
void cursor_from_sgr(Cursor *self, int *params, unsigned int count);
|
||||||
void apply_sgr_to_cells(GPUCell *first_cell, unsigned int cell_count, unsigned int *params, unsigned int count);
|
void apply_sgr_to_cells(GPUCell *first_cell, unsigned int cell_count, int *params, unsigned int count);
|
||||||
const char* cell_as_sgr(const GPUCell *, const GPUCell *);
|
const char* cell_as_sgr(const GPUCell *, const GPUCell *);
|
||||||
const char* cursor_as_sgr(const Cursor *);
|
const char* cursor_as_sgr(const Cursor *);
|
||||||
|
|
||||||
|
|||||||
@ -22,10 +22,14 @@ static uint64_t pow10_array[] = {
|
|||||||
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000
|
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline uint64_t
|
static inline int64_t
|
||||||
utoi(uint32_t *buf, unsigned int sz) {
|
utoi(const uint32_t *buf, unsigned int sz) {
|
||||||
uint64_t ans = 0;
|
int64_t ans = 0;
|
||||||
uint32_t *p = buf;
|
const uint32_t *p = buf;
|
||||||
|
int mult = 1;
|
||||||
|
if (sz && *p == '-') {
|
||||||
|
mult = -1; p++; sz--;
|
||||||
|
}
|
||||||
// Ignore leading zeros
|
// Ignore leading zeros
|
||||||
while(sz > 0) {
|
while(sz > 0) {
|
||||||
if (*p == '0') { p++; sz--; }
|
if (*p == '0') { p++; sz--; }
|
||||||
@ -36,7 +40,7 @@ utoi(uint32_t *buf, unsigned int sz) {
|
|||||||
ans += (p[i] - '0') * pow10_array[j];
|
ans += (p[i] - '0') * pow10_array[j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ans;
|
return ans * mult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -79,12 +83,12 @@ _report_error(PyObject *dump_callback, const char *fmt, ...) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_report_params(PyObject *dump_callback, const char *name, unsigned int *params, unsigned int count, Region *r) {
|
_report_params(PyObject *dump_callback, const char *name, int *params, unsigned int count, Region *r) {
|
||||||
static char buf[MAX_PARAMS*3] = {0};
|
static char buf[MAX_PARAMS*3] = {0};
|
||||||
unsigned int i, p=0;
|
unsigned int i, p=0;
|
||||||
if (r) p += snprintf(buf + p, sizeof(buf) - 2, "%u %u %u %u ", r->top, r->left, r->bottom, r->right);
|
if (r) p += snprintf(buf + p, sizeof(buf) - 2, "%u %u %u %u ", r->top, r->left, r->bottom, r->right);
|
||||||
for(i = 0; i < count && p < MAX_PARAMS*3-20; i++) {
|
for(i = 0; i < count && p < MAX_PARAMS*3-20; i++) {
|
||||||
int n = snprintf(buf + p, MAX_PARAMS*3 - p, "%u ", params[i]);
|
int n = snprintf(buf + p, MAX_PARAMS*3 - p, "%i ", params[i]);
|
||||||
if (n < 0) break;
|
if (n < 0) break;
|
||||||
p += n;
|
p += n;
|
||||||
}
|
}
|
||||||
@ -360,7 +364,8 @@ dispatch_osc(Screen *screen, PyObject DUMP_UNUSED *dump_callback) {
|
|||||||
#define END_DISPATCH Py_CLEAR(string); } PyErr_Clear(); break; }
|
#define END_DISPATCH Py_CLEAR(string); } PyErr_Clear(); break; }
|
||||||
|
|
||||||
const unsigned int limit = screen->parser_buf_pos;
|
const unsigned int limit = screen->parser_buf_pos;
|
||||||
unsigned int code=0, i;
|
int code=0;
|
||||||
|
unsigned int i;
|
||||||
for (i = 0; i < MIN(limit, 5u); i++) {
|
for (i = 0; i < MIN(limit, 5u); i++) {
|
||||||
if (screen->parser_buf[i] < '0' || screen->parser_buf[i] > '9') break;
|
if (screen->parser_buf[i] < '0' || screen->parser_buf[i] > '9') break;
|
||||||
}
|
}
|
||||||
@ -460,12 +465,12 @@ static inline void
|
|||||||
screen_tabn(Screen *s, unsigned int count) { for (index_type i=0; i < MAX(1u, count); i++) screen_tab(s); }
|
screen_tabn(Screen *s, unsigned int count) { for (index_type i=0; i < MAX(1u, count); i++) screen_tab(s); }
|
||||||
|
|
||||||
static inline const char*
|
static inline const char*
|
||||||
repr_csi_params(unsigned int *params, unsigned int num_params) {
|
repr_csi_params(int *params, unsigned int num_params) {
|
||||||
if (!num_params) return "";
|
if (!num_params) return "";
|
||||||
static char buf[256];
|
static char buf[256];
|
||||||
unsigned int pos = 0, i = 0;
|
unsigned int pos = 0, i = 0;
|
||||||
while (pos < 200 && i++ < num_params && sizeof(buf) > pos + 1) {
|
while (pos < 200 && i++ < num_params && sizeof(buf) > pos + 1) {
|
||||||
const char *fmt = i < num_params ? "%u, " : "%u";
|
const char *fmt = i < num_params ? "%i, " : "%i";
|
||||||
int ret = snprintf(buf + pos, sizeof(buf) - pos - 1, fmt, params[i-1]);
|
int ret = snprintf(buf + pos, sizeof(buf) - pos - 1, fmt, params[i-1]);
|
||||||
if (ret < 0) return "An error occurred formatting the params array";
|
if (ret < 0) return "An error occurred formatting the params array";
|
||||||
pos += ret;
|
pos += ret;
|
||||||
@ -478,7 +483,7 @@ repr_csi_params(unsigned int *params, unsigned int num_params) {
|
|||||||
static
|
static
|
||||||
#endif
|
#endif
|
||||||
void
|
void
|
||||||
parse_sgr(Screen *screen, uint32_t *buf, unsigned int num, unsigned int *params, PyObject DUMP_UNUSED *dump_callback, const char *report_name DUMP_UNUSED, Region *region) {
|
parse_sgr(Screen *screen, uint32_t *buf, unsigned int num, int *params, PyObject DUMP_UNUSED *dump_callback, const char *report_name DUMP_UNUSED, Region *region) {
|
||||||
enum State { START, NORMAL, MULTIPLE, COLOR, COLOR1, COLOR3 };
|
enum State { START, NORMAL, MULTIPLE, COLOR, COLOR1, COLOR3 };
|
||||||
enum State state = START;
|
enum State state = START;
|
||||||
unsigned int num_params, num_start, i;
|
unsigned int num_params, num_start, i;
|
||||||
@ -606,7 +611,8 @@ parse_sgr(Screen *screen, uint32_t *buf, unsigned int num, unsigned int *params,
|
|||||||
|
|
||||||
static inline unsigned int
|
static inline unsigned int
|
||||||
parse_region(Region *r, uint32_t *buf, unsigned int num) {
|
parse_region(Region *r, uint32_t *buf, unsigned int num) {
|
||||||
unsigned int i, start, params[8] = {0}, num_params=0;
|
unsigned int i, start, num_params = 0;
|
||||||
|
int params[8] = {0};
|
||||||
for (i=0, start=0; i < num && num_params < 4; i++) {
|
for (i=0, start=0; i < num && num_params < 4; i++) {
|
||||||
switch(buf[i]) {
|
switch(buf[i]) {
|
||||||
IS_DIGIT
|
IS_DIGIT
|
||||||
@ -646,10 +652,17 @@ dispatch_csi(Screen *screen, PyObject DUMP_UNUSED *dump_callback) {
|
|||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
#define NON_NEGATIVE_PARAM(x) { \
|
||||||
|
if (x < 0) { \
|
||||||
|
REPORT_ERROR("CSI code 0x%x is not allowed to have negative parameter (%d)", code, x); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
#define CALL_CSI_HANDLER1(name, defval) \
|
#define CALL_CSI_HANDLER1(name, defval) \
|
||||||
AT_MOST_ONE_PARAMETER; \
|
AT_MOST_ONE_PARAMETER; \
|
||||||
p1 = num_params > 0 ? params[0] : defval; \
|
p1 = num_params > 0 ? params[0] : defval; \
|
||||||
|
NON_NEGATIVE_PARAM(p1); \
|
||||||
REPORT_COMMAND(name, p1); \
|
REPORT_COMMAND(name, p1); \
|
||||||
name(screen, p1); \
|
name(screen, p1); \
|
||||||
break;
|
break;
|
||||||
@ -657,6 +670,7 @@ dispatch_csi(Screen *screen, PyObject DUMP_UNUSED *dump_callback) {
|
|||||||
#define CALL_CSI_HANDLER1P(name, defval, qch) \
|
#define CALL_CSI_HANDLER1P(name, defval, qch) \
|
||||||
AT_MOST_ONE_PARAMETER; \
|
AT_MOST_ONE_PARAMETER; \
|
||||||
p1 = num_params > 0 ? params[0] : defval; \
|
p1 = num_params > 0 ? params[0] : defval; \
|
||||||
|
NON_NEGATIVE_PARAM(p1); \
|
||||||
private = start_modifier == qch; \
|
private = start_modifier == qch; \
|
||||||
REPORT_COMMAND(name, p1, private); \
|
REPORT_COMMAND(name, p1, private); \
|
||||||
name(screen, p1, private); \
|
name(screen, p1, private); \
|
||||||
@ -665,6 +679,7 @@ dispatch_csi(Screen *screen, PyObject DUMP_UNUSED *dump_callback) {
|
|||||||
#define CALL_CSI_HANDLER1S(name, defval) \
|
#define CALL_CSI_HANDLER1S(name, defval) \
|
||||||
AT_MOST_ONE_PARAMETER; \
|
AT_MOST_ONE_PARAMETER; \
|
||||||
p1 = num_params > 0 ? params[0] : defval; \
|
p1 = num_params > 0 ? params[0] : defval; \
|
||||||
|
NON_NEGATIVE_PARAM(p1); \
|
||||||
REPORT_COMMAND(name, p1, start_modifier); \
|
REPORT_COMMAND(name, p1, start_modifier); \
|
||||||
name(screen, p1, start_modifier); \
|
name(screen, p1, start_modifier); \
|
||||||
break;
|
break;
|
||||||
@ -672,13 +687,20 @@ dispatch_csi(Screen *screen, PyObject DUMP_UNUSED *dump_callback) {
|
|||||||
#define CALL_CSI_HANDLER1M(name, defval) \
|
#define CALL_CSI_HANDLER1M(name, defval) \
|
||||||
AT_MOST_ONE_PARAMETER; \
|
AT_MOST_ONE_PARAMETER; \
|
||||||
p1 = num_params > 0 ? params[0] : defval; \
|
p1 = num_params > 0 ? params[0] : defval; \
|
||||||
|
NON_NEGATIVE_PARAM(p1); \
|
||||||
REPORT_COMMAND(name, p1, end_modifier); \
|
REPORT_COMMAND(name, p1, end_modifier); \
|
||||||
name(screen, p1, end_modifier); \
|
name(screen, p1, end_modifier); \
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#define CALL_CSI_HANDLER2(name, defval1, defval2) \
|
#define CALL_CSI_HANDLER2(name, defval1, defval2) \
|
||||||
|
if (num_params > 2) { \
|
||||||
|
REPORT_ERROR("CSI code 0x%x has %u > 2 parameters", code, num_params); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
p1 = num_params > 0 ? params[0] : defval1; \
|
p1 = num_params > 0 ? params[0] : defval1; \
|
||||||
p2 = num_params > 1 ? params[1] : defval2; \
|
p2 = num_params > 1 ? params[1] : defval2; \
|
||||||
|
NON_NEGATIVE_PARAM(p1); \
|
||||||
|
NON_NEGATIVE_PARAM(p2); \
|
||||||
REPORT_COMMAND(name, p1, p2); \
|
REPORT_COMMAND(name, p1, p2); \
|
||||||
name(screen, p1, p2); \
|
name(screen, p1, p2); \
|
||||||
break;
|
break;
|
||||||
@ -701,8 +723,8 @@ dispatch_csi(Screen *screen, PyObject DUMP_UNUSED *dump_callback) {
|
|||||||
|
|
||||||
char start_modifier = 0, end_modifier = 0;
|
char start_modifier = 0, end_modifier = 0;
|
||||||
uint32_t *buf = screen->parser_buf, code = screen->parser_buf[screen->parser_buf_pos];
|
uint32_t *buf = screen->parser_buf, code = screen->parser_buf[screen->parser_buf_pos];
|
||||||
unsigned int num = screen->parser_buf_pos, start, i, num_params=0, p1, p2;
|
unsigned int num = screen->parser_buf_pos, start, i, num_params=0;
|
||||||
static unsigned int params[MAX_PARAMS] = {0};
|
static int params[MAX_PARAMS] = {0}, p1, p2;
|
||||||
bool private;
|
bool private;
|
||||||
if (buf[0] == '>' || buf[0] == '<' || buf[0] == '?' || buf[0] == '!' || buf[0] == '=') {
|
if (buf[0] == '>' || buf[0] == '<' || buf[0] == '?' || buf[0] == '!' || buf[0] == '=') {
|
||||||
start_modifier = (char)screen->parser_buf[0];
|
start_modifier = (char)screen->parser_buf[0];
|
||||||
@ -732,6 +754,12 @@ dispatch_csi(Screen *screen, PyObject DUMP_UNUSED *dump_callback) {
|
|||||||
switch(buf[i]) {
|
switch(buf[i]) {
|
||||||
IS_DIGIT
|
IS_DIGIT
|
||||||
break;
|
break;
|
||||||
|
case '-':
|
||||||
|
if (i > start) {
|
||||||
|
REPORT_ERROR("CSI code can contain hyphens only at the start of numbers");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
if (i > start) params[num_params++] = utoi(buf + start, i - start);
|
if (i > start) params[num_params++] = utoi(buf + start, i - start);
|
||||||
else if (i == start && buf[i] == ';') params[num_params++] = 0;
|
else if (i == start && buf[i] == ';') params[num_params++] = 0;
|
||||||
|
|||||||
@ -609,7 +609,7 @@ screen_alignment_display(Screen *self) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
select_graphic_rendition(Screen *self, unsigned int *params, unsigned int count, Region *region_) {
|
select_graphic_rendition(Screen *self, int *params, unsigned int count, Region *region_) {
|
||||||
if (region_) {
|
if (region_) {
|
||||||
Region region = *region_;
|
Region region = *region_;
|
||||||
if (!region.top) region.top = 1;
|
if (!region.top) region.top = 1;
|
||||||
@ -2214,8 +2214,8 @@ reset_mode(Screen *self, PyObject *args) {
|
|||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
_select_graphic_rendition(Screen *self, PyObject *args) {
|
_select_graphic_rendition(Screen *self, PyObject *args) {
|
||||||
unsigned int params[256] = {0};
|
int params[256] = {0};
|
||||||
for (int i = 0; i < PyTuple_GET_SIZE(args); i++) { params[i] = PyLong_AsUnsignedLong(PyTuple_GET_ITEM(args, i)); }
|
for (int i = 0; i < PyTuple_GET_SIZE(args); i++) { params[i] = PyLong_AsLong(PyTuple_GET_ITEM(args, i)); }
|
||||||
select_graphic_rendition(self, params, PyTuple_GET_SIZE(args), NULL);
|
select_graphic_rendition(self, params, PyTuple_GET_SIZE(args), NULL);
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -197,7 +197,7 @@ uint32_t* translation_table(uint32_t which);
|
|||||||
void screen_request_capabilities(Screen *, char, PyObject *);
|
void screen_request_capabilities(Screen *, char, PyObject *);
|
||||||
void screen_set_8bit_controls(Screen *, bool);
|
void screen_set_8bit_controls(Screen *, bool);
|
||||||
void report_device_attributes(Screen *self, unsigned int UNUSED mode, char start_modifier);
|
void report_device_attributes(Screen *self, unsigned int UNUSED mode, char start_modifier);
|
||||||
void select_graphic_rendition(Screen *self, unsigned int *params, unsigned int count, Region*);
|
void select_graphic_rendition(Screen *self, int *params, unsigned int count, Region*);
|
||||||
void report_device_status(Screen *self, unsigned int which, bool UNUSED);
|
void report_device_status(Screen *self, unsigned int which, bool UNUSED);
|
||||||
void report_mode_status(Screen *self, unsigned int which, bool);
|
void report_mode_status(Screen *self, unsigned int which, bool);
|
||||||
void screen_apply_selection(Screen *self, void *address, size_t size);
|
void screen_apply_selection(Screen *self, void *address, size_t size);
|
||||||
|
|||||||
@ -101,6 +101,9 @@ class TestParser(BaseTest):
|
|||||||
pb('x\033[2@y', 'x', ('screen_insert_characters', 2), 'y')
|
pb('x\033[2@y', 'x', ('screen_insert_characters', 2), 'y')
|
||||||
self.ae(str(s.line(0)), 'xy bc')
|
self.ae(str(s.line(0)), 'xy bc')
|
||||||
pb('x\033[2;7@y', 'x', ('CSI code 0x40 has 2 > 1 parameters',), 'y')
|
pb('x\033[2;7@y', 'x', ('CSI code 0x40 has 2 > 1 parameters',), 'y')
|
||||||
|
pb('x\033[2;-7@y', 'x', ('CSI code 0x40 has 2 > 1 parameters',), 'y')
|
||||||
|
pb('x\033[-2@y', 'x', ('CSI code 0x40 is not allowed to have negative parameter (-2)',), 'y')
|
||||||
|
pb('x\033[2-3@y', 'x', ('CSI code can contain hyphens only at the start of numbers',), 'y')
|
||||||
pb('x\033[@y', 'x', ('screen_insert_characters', 1), 'y')
|
pb('x\033[@y', 'x', ('screen_insert_characters', 1), 'y')
|
||||||
pb('x\033[345@y', 'x', ('screen_insert_characters', 345), 'y')
|
pb('x\033[345@y', 'x', ('screen_insert_characters', 345), 'y')
|
||||||
pb('x\033[345;@y', 'x', ('screen_insert_characters', 345), 'y')
|
pb('x\033[345;@y', 'x', ('screen_insert_characters', 345), 'y')
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user