Skip to content

Commit 316a386

Browse files
ninjaljtcanabrava
authored andcommitted
Support colon-separated sub-params in CSI and DCS
This adds supports for sub-parameters in control sequences. For now, it supports the colon-separated variants of SGR 38 and SGR 48 for RGB and indexed colours: CSI 38 : 2 : <id> : <red> : <green> : <blue> [ : ... ] m CSI 38 : 2 : <red> : <green> : <blue> m CSI 38 : 5 : <index8> m and likewise for SGR 48. <id> is ignored (it's supposed to be a colour space id, to support different kinds of RGB).
1 parent 497f9af commit 316a386

2 files changed

Lines changed: 82 additions & 44 deletions

File tree

‎src/Vt102Emulation.cpp‎

Lines changed: 68 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -270,28 +270,44 @@ const int MAX_ARGUMENT = 40960;
270270
/* The tokenizer's state
271271
272272
The state is represented by the buffer (tokenBuffer, tokenBufferPos),
273-
and accompanied by decoded arguments kept in (argv,argc).
273+
and accompanied by decoded arguments kept in params.
274274
Note that they are kept internal in the tokenizer.
275275
*/
276276

277277
void Vt102Emulation::resetTokenizer()
278278
{
279279
tokenBufferPos = 0;
280-
argc = 0;
281-
argv[0] = 0;
282-
argv[1] = 0;
280+
params.count = 0;
281+
params.value[0] = 0;
282+
params.value[1] = 0;
283+
params.sub[0].value[0] = 0;
284+
params.sub[0].count = 0;
283285
tokenState = -1;
284286
}
285287

286288
void Vt102Emulation::addDigit(int digit)
287289
{
288-
argv[argc] = qMin(10 * argv[argc] + digit, MAX_ARGUMENT);
290+
if (params.sub[params.count].count == 0) {
291+
params.value[params.count] = qMin(10 * params.value[params.count] + digit, MAX_ARGUMENT);
292+
} else {
293+
struct subParam *sub = &params.sub[params.count];
294+
sub->value[sub->count] = qMin(10 * sub->value[sub->count] + digit, MAX_ARGUMENT);
295+
}
289296
}
290297

291298
void Vt102Emulation::addArgument()
292299
{
293-
argc = qMin(argc + 1, MAXARGS - 1);
294-
argv[argc] = 0;
300+
params.count = qMin(params.count + 1, MAXARGS - 1);
301+
params.value[params.count] = 0;
302+
params.sub[params.count].value[0] = 0;
303+
params.sub[params.count].count = 0;
304+
}
305+
306+
void Vt102Emulation::addSub()
307+
{
308+
struct subParam *sub = &params.sub[params.count];
309+
sub->count = qMin(sub->count + 1, MAXARGS - 1);
310+
sub->value[sub->count] = 0;
295311
}
296312

297313
void Vt102Emulation::addToCurrentToken(uint cc)
@@ -439,11 +455,7 @@ void Vt102Emulation::clear()
439455
{
440456
_nIntermediate = 0;
441457
_ignore = false;
442-
tokenBufferPos = 0;
443-
tokenState = -1;
444-
argc = 0;
445-
argv[0] = 0;
446-
argv[1] = 0;
458+
resetTokenizer();
447459
}
448460

449461
#define MAX_INTERMEDIATES 1
@@ -466,7 +478,7 @@ void Vt102Emulation::param(const uint cc)
466478
} else if (cc == ';') {
467479
addArgument();
468480
} else if (cc == ':') {
469-
_ignore = true;
481+
addSub();
470482
}
471483
}
472484

@@ -476,39 +488,54 @@ void Vt102Emulation::csi_dispatch(const uint cc)
476488
return;
477489
if ((tokenBufferPos == 0 || (tokenBuffer[0] != '?' && tokenBuffer[0] != '!' && tokenBuffer[0] != '=' && tokenBuffer[0] != '>')) && cc < 256
478490
&& (charClass[cc] & CPN) == CPN && _nIntermediate == 0) {
479-
processToken(token_csi_pn(cc), argv[0], argv[1]);
491+
processToken(token_csi_pn(cc), params.value[0], params.value[1]);
480492
} else if ((tokenBufferPos == 0 || (tokenBuffer[0] != '?' && tokenBuffer[0] != '!' && tokenBuffer[0] != '=' && tokenBuffer[0] != '>')) && cc < 256
481493
&& (charClass[cc] & CPS) == CPS && _nIntermediate == 0) {
482-
processToken(token_csi_ps(cc, argv[0]), argv[1], argv[2]);
494+
processToken(token_csi_ps(cc, params.value[0]), params.value[1], params.value[2]);
483495
} else if (tokenBufferPos != 0 && tokenBuffer[0] == '!') {
484496
processToken(token_csi_pe(cc), 0, 0);
485497
} else if (_nIntermediate == 1 && _intermediate[0] == ' ') {
486498
if (tokenBufferPos == 1) {
487499
processToken(token_csi_sp(cc), 0, 0);
488500
} else {
489-
processToken(token_csi_psp(cc, argv[0]), 0, 0);
501+
processToken(token_csi_psp(cc, params.value[0]), 0, 0);
490502
}
491503
} else if (cc == 'y' && _nIntermediate == 1 && _intermediate[0] == '*') {
492-
processChecksumRequest(argc, argv);
504+
processChecksumRequest(params.count, params.value);
493505
} else {
494-
for (int i = 0; i <= argc; i++) {
506+
for (int i = 0; i <= params.count; i++) {
495507
if (tokenBufferPos != 0 && tokenBuffer[0] == '?') {
496-
processToken(token_csi_pr(cc, argv[i]), i, 0);
508+
processToken(token_csi_pr(cc, params.value[i]), i, 0);
497509
} else if (tokenBufferPos != 0 && tokenBuffer[0] == '=') {
498510
processToken(token_csi_pq(cc), 0, 0);
499511
} else if (tokenBufferPos != 0 && tokenBuffer[0] == '>') {
500512
processToken(token_csi_pg(cc), 0, 0);
501-
} else if (cc == 'm' && argc - i >= 4 && (argv[i] == 38 || argv[i] == 48) && argv[i + 1] == 2) {
513+
} else if (cc == 'm' && params.count - i >= 4 && (params.value[i] == 38 || params.value[i] == 48) && params.value[i + 1] == 2) {
502514
// ESC[ ... 48;2;<red>;<green>;<blue> ... m -or- ESC[ ... 38;2;<red>;<green>;<blue> ... m
503515
i += 2;
504-
processToken(token_csi_ps(cc, argv[i - 2]), COLOR_SPACE_RGB, (argv[i] << 16) | (argv[i + 1] << 8) | argv[i + 2]);
516+
processToken(token_csi_ps(cc, params.value[i - 2]),
517+
COLOR_SPACE_RGB,
518+
(params.value[i] << 16) | (params.value[i + 1] << 8) | params.value[i + 2]);
505519
i += 2;
506-
} else if (cc == 'm' && argc - i >= 2 && (argv[i] == 38 || argv[i] == 48) && argv[i + 1] == 5) {
520+
} else if (cc == 'm' && params.sub[i].count >= 5 && (params.value[i] == 38 || params.value[i] == 48) && params.sub[i].value[1] == 2) {
521+
// ESC[ ... 48:2:<id>:<red>:<green>:<blue> ... m -or- ESC[ ... 38:2:<id>:<red>:<green>:<blue> ... m
522+
processToken(token_csi_ps(cc, params.value[i]),
523+
COLOR_SPACE_RGB,
524+
(params.sub[i].value[3] << 16) | (params.sub[i].value[4] << 8) | params.sub[i].value[5]);
525+
} else if (cc == 'm' && params.sub[i].count == 4 && (params.value[i] == 38 || params.value[i] == 48) && params.sub[i].value[1] == 2) {
526+
// ESC[ ... 48:2:<red>:<green>:<blue> ... m -or- ESC[ ... 38:2:<red>:<green>:<blue> ... m
527+
processToken(token_csi_ps(cc, params.value[i]),
528+
COLOR_SPACE_RGB,
529+
(params.sub[i].value[2] << 16) | (params.sub[i].value[3] << 8) | params.sub[i].value[4]);
530+
} else if (cc == 'm' && params.count - i >= 2 && (params.value[i] == 38 || params.value[i] == 48) && params.value[i + 1] == 5) {
507531
// ESC[ ... 48;5;<index> ... m -or- ESC[ ... 38;5;<index> ... m
508532
i += 2;
509-
processToken(token_csi_ps(cc, argv[i - 2]), COLOR_SPACE_256, argv[i]);
533+
processToken(token_csi_ps(cc, params.value[i - 2]), COLOR_SPACE_256, params.value[i]);
534+
} else if (cc == 'm' && params.sub[i].count >= 2 && (params.value[i] == 38 || params.value[i] == 48) && params.sub[i].value[1] == 5) {
535+
// ESC[ ... 48:5:<index> ... m -or- ESC[ ... 38:5:<index> ... m
536+
processToken(token_csi_ps(cc, params.value[i]), COLOR_SPACE_256, params.sub[i].value[2]);
510537
} else if (_nIntermediate == 0) {
511-
processToken(token_csi_ps(cc, argv[i]), 0, 0);
538+
processToken(token_csi_ps(cc, params.value[i]), 0, 0);
512539
}
513540
}
514541
}
@@ -2640,13 +2667,13 @@ void Vt102Emulation::sixelQuery(int q)
26402667
{
26412668
char tmp[30];
26422669
if (q == 1) {
2643-
if (argv[1] == 1 || argv[1] == 4) {
2670+
if (params.value[1] == 1 || params.value[1] == 4) {
26442671
snprintf(tmp, sizeof(tmp), "\033[?1;0;%dS", MAX_SIXEL_COLORS);
26452672
sendString(tmp);
26462673
}
26472674
}
26482675
if (q == 2) {
2649-
if (argv[1] == 1 || argv[1] == 4) {
2676+
if (params.value[1] == 1 || params.value[1] == 4) {
26502677
snprintf(tmp, sizeof(tmp), "\033[?2;0;%d;%dS", MAX_IMAGE_DIM, MAX_IMAGE_DIM);
26512678
sendString(tmp);
26522679
}
@@ -2937,19 +2964,19 @@ bool Vt102Emulation::processSixel(uint cc)
29372964
}
29382965
addArgument();
29392966

2940-
if (argc == 4) {
2967+
if (params.count == 4) {
29412968
// We just ignore the pixel aspect ratio, it's dumb
2942-
// const int pixelWidth = argv[0];
2943-
// const int pixelHeight = argv[1];
2969+
// const int pixelWidth = params.value[0];
2970+
// const int pixelHeight = params.value[1];
29442971

29452972
if (!m_SixelStarted) {
2946-
if (argv[1] == 0 || argv[0] == 0) {
2973+
if (params.value[1] == 0 || params.value[0] == 0) {
29472974
m_aspect = qMakePair(1, 1);
29482975
} else {
2949-
m_aspect = qMakePair(argv[0], argv[1]);
2976+
m_aspect = qMakePair(params.value[0], params.value[1]);
29502977
}
2951-
const int width = argv[2];
2952-
const int height = argv[3];
2978+
const int width = params.value[2];
2979+
const int height = params.value[3];
29532980
SixelModeEnable(width, height);
29542981
}
29552982
resetTokenizer();
@@ -2969,7 +2996,7 @@ bool Vt102Emulation::processSixel(uint cc)
29692996
return true;
29702997
}
29712998

2972-
SixelCharacterAdd(cc, argv[0]);
2999+
SixelCharacterAdd(cc, params.value[0]);
29733000
resetTokenizer();
29743001
return true;
29753002
}
@@ -2979,24 +3006,24 @@ bool Vt102Emulation::processSixel(uint cc)
29793006
return true;
29803007
}
29813008
addArgument();
2982-
if (argc < 1) {
3009+
if (params.count < 1) {
29833010
return false;
29843011
}
2985-
const int index = argv[0];
2986-
if (argc == 5) {
2987-
const int colorspace = argv[1];
3012+
const int index = params.value[0];
3013+
if (params.count == 5) {
3014+
const int colorspace = params.value[1];
29883015
switch (colorspace) {
29893016
case 1:
29903017
// Confusingly it is in HLS order...
2991-
SixelColorChangeHSL(index, argv[2], argv[4], argv[3]);
3018+
SixelColorChangeHSL(index, params.value[2], params.value[4], params.value[3]);
29923019
break;
29933020
case 2:
2994-
SixelColorChangeRGB(index, argv[2], argv[3], argv[4]);
3021+
SixelColorChangeRGB(index, params.value[2], params.value[3], params.value[4]);
29953022
break;
29963023
default:
29973024
return false;
29983025
}
2999-
} else if (argc == 1 && index >= 0) { // Negative index is an error. Too large index is ignored
3026+
} else if (params.count == 1 && index >= 0) { // Negative index is an error. Too large index is ignored
30003027
if (index < MAX_SIXEL_COLORS) {
30013028
m_currentColor = index;
30023029
}

‎src/Vt102Emulation.h‎

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,22 @@ private Q_SLOTS:
129129
uint tokenBuffer[MAX_TOKEN_LENGTH]; // FIXME: overflow?
130130

131131
private:
132-
#define MAXARGS 15
132+
#define MAXARGS 16
133133
void addDigit(int dig);
134134
void addArgument();
135-
int argv[MAXARGS] = {};
136-
int argc;
135+
void addSub();
136+
137+
struct subParam {
138+
int value[MAXARGS];
139+
int count;
140+
};
141+
142+
struct {
143+
int value[MAXARGS];
144+
struct subParam sub[MAXARGS];
145+
int count;
146+
} params = {};
147+
137148
void initTokenizer();
138149

139150
enum ParserStates {

0 commit comments

Comments
 (0)