Synchronet now requires the libarchive development package (e.g. libarchive-dev on Debian-based Linux distros, libarchive.org for more info) to build successfully.

Commit a3ddb26e authored by deuce's avatar deuce

Support macros... currently, only 64 are supported, but that could

be expanded if people like it... this can be used to store and replay data,
making sprites a lot easier to implement client-side.
parent 959c4903
......@@ -1768,6 +1768,201 @@ all_done:
FREE_AND_NULL(cterm->sx_mask);
}
static int
is_hex(char ch)
{
if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'))
return 1;
return 0;
}
static int
get_hexstrlen(char *str, char *end)
{
int ret = 0;
for (;str <= end; str++) {
if (is_hex(*str)) {
if (str == end)
return -1;
if (!is_hex(*(str+1)))
return -1;
ret++;
str++;
}
else
return ret;
}
return ret;
}
static int
nibble_val(char ch)
{
if (ch >= '0' && ch <= '9')
return ch - '0';
if (ch >= 'a' && ch <= 'f')
return (ch - 'a') + 10;
if (ch >= 'A' && ch <= 'F')
return (ch - 'A') + 10;
return -1;
}
static void
get_hexstr(char *str, char *end, char *out)
{
for (;str <= end; str++) {
if (is_hex(*str)) {
if (str == end)
return;
if (!is_hex(*(str+1)))
return;
*(out++) = nibble_val(*str) << 4 | nibble_val(*(str + 1));
str++;
}
else
return;
}
}
static void parse_macro_string(struct cterminal *cterm, bool finish)
{
char *p = cterm->strbuf;
char *end;
int i;
if (cterm->strbuflen == 0) {
if (finish)
goto all_done;
return;
}
end = p+cterm->strbuflen-1;
if (*end >= '\x08' && *end <= '\x0d') {
cterm->strbuflen--;
if (finish)
goto all_done;
return;
}
if (cterm->macro_encoding == MACRO_ENCODING_ASCII) {
if ((*end >= ' ' && *end <= '\x7e') || (*end >= '\xa0' && *end <= '\xff')) {
if (finish)
goto all_done;
return;
}
}
if (cterm->macro_encoding == MACRO_ENCODING_HEX &&
(is_hex(*end) || (*end == '!') || (*end == ';'))) {
if (finish)
goto all_done;
return;
}
cterm->macro = MACRO_INACTIVE;
return;
all_done:
if (cterm->macro_del == MACRO_DELETE_ALL) {
for (i = 0; i < (sizeof(cterm->macros) / sizeof(cterm->macros[0])); i++) {
FREE_AND_NULL(cterm->macros[i]);
cterm->macro_lens[i] = 0;
}
}
else {
FREE_AND_NULL(cterm->macros[cterm->macro_num]);
cterm->macro_lens[cterm->macro_num] = 0;
}
if (cterm->strbuflen == 0)
return;
if (cterm->macro_encoding == MACRO_ENCODING_ASCII) {
cterm->macros[cterm->macro_num] = malloc(cterm->strbuflen + 1);
if (cterm->macros[cterm->macro_num]) {
cterm->macro_lens[cterm->macro_num] = cterm->strbuflen;
memcpy(cterm->macros[cterm->macro_num], cterm->strbuf, cterm->strbuflen);
cterm->macros[cterm->macro_num][cterm->strbuflen] = 0;
}
}
else {
// Hex string...
int plen;
unsigned long ul;
size_t mlen = 0;
char *out;
// First, calculate the required length...
for (p = cterm->strbuf; p <= end;) {
if (*p == '!') {
if (p == end)
return;
p++;
if (p == end)
return;
if (*p == ';')
ul = 1;
else {
if (memchr(p, ';', cterm->strbuflen - (p - cterm->strbuf)) == NULL)
return;
ul = strtoul(p, &p, 10);
if (*p != ';')
return;
if (ul == ULONG_MAX)
return;
p++;
}
plen = get_hexstrlen(p, end);
p += plen * 2;
if (plen == -1)
return;
mlen += ul * plen;
if (p <= end) {
if (*p == ';')
p++;
else
return;
}
}
else {
plen = get_hexstrlen(p, end);
if (plen == -1)
return;
p += plen * 2;
mlen += plen;
}
}
cterm->macros[cterm->macro_num] = malloc(mlen + 1);
if (cterm->macros[cterm->macro_num] == NULL)
return;
cterm->macro_lens[cterm->macro_num] = mlen;
out = cterm->macros[cterm->macro_num];
for (p = cterm->strbuf; p <= end;) {
if (*p == '!') {
p++;
if (*p == ';')
ul = 1;
else {
ul = strtoul(p, &p, 10);
p++;
}
plen = get_hexstrlen(p, end);
for (i = 0; i < ul; i++) {
get_hexstr(p, end, out);
out += plen;
}
p += plen * 2;
if (p <= end && *p == ';')
p++;
}
else {
plen = get_hexstrlen(p, end);
get_hexstr(p, end, out);
out += plen;
p += plen * 2;
}
}
}
}
static void save_extended_colour_seq(struct cterminal *cterm, int fg, struct esc_seq *seq, int seqoff, int count)
{
char **str = fg ? &cterm->fg_tc_str : &cterm->bg_tc_str;
......@@ -2189,6 +2384,12 @@ static void do_ansi(struct cterminal *cterm, char *retbuf, size_t retsize, int *
sprintf(tmp, "\x1b[=3;%u;%un", vparams[vmode].charheight, vparams[vmode].charwidth);
break;
}
case 62: /* Query macro space available */
{
// Just fake it as int16_max
strcpy(tmp, "\x1b[32767*{");
break;
}
}
if(*tmp && strlen(retbuf) + strlen(tmp) < retsize)
strcat(retbuf, tmp);
......@@ -2759,6 +2960,19 @@ static void do_ansi(struct cterminal *cterm, char *retbuf, size_t retsize, int *
if(newspeed >= 0)
*speed = newspeed;
}
else if (strcmp(seq->ctrl_func, "*z") == 0) {
if (seq->param_int[0] >= 0 && seq->param_int[0] <= 63) {
if (cterm->macros[seq->param_int[0]]) {
if ((cterm->in_macro & (1<<seq->param_int[0])) == 0) {
cterm->escbuf[0]=0;
cterm->sequence=0;
cterm->in_macro |= (1<<seq->param_int[0]);
cterm_write(cterm, cterm->macros[seq->param_int[0]], cterm->macro_lens[seq->param_int[0]], retbuf + strlen(retbuf), retsize - strlen(retbuf), speed);
cterm->in_macro &= ~(1<<seq->param_int[0]);
}
}
}
}
}
else {
switch(seq->final_byte) {
......@@ -3414,6 +3628,7 @@ static void do_ansi(struct cterminal *cterm, char *retbuf, size_t retsize, int *
case 'P': // Device Control String - DCS
cterm->string = CTERM_STRING_DCS;
cterm->sixel = SIXEL_POSSIBLE;
cterm->macro = MACRO_POSSIBLE;
FREE_AND_NULL(cterm->strbuf);
cterm->strbuf = malloc(1024);
cterm->strbufsize = 1024;
......@@ -3453,6 +3668,8 @@ static void do_ansi(struct cterminal *cterm, char *retbuf, size_t retsize, int *
case CTERM_STRING_DCS:
if (cterm->sixel == SIXEL_STARTED)
parse_sixel_string(cterm, true);
else if (cterm->macro == MACRO_STARTED)
parse_macro_string(cterm, true);
else {
if (strncmp(cterm->strbuf, "CTerm:Font:", 11) == 0) {
cterm->font_slot = strtoul(cterm->strbuf+11, &p, 10);
......@@ -3771,6 +3988,10 @@ cterm_reset(struct cterminal *cterm)
cterm->sx_width = 0;
cterm->sx_height = 0;
FREE_AND_NULL(cterm->sx_mask);
for (i = 0; i < (sizeof(cterm->macros) / sizeof(cterm->macros[0])); i++) {
FREE_AND_NULL(cterm->macros[i]);
cterm->macro_lens[i] = 0;
}
wx = TERM_MINX;
wy = TERM_MINY;
ww = TERM_MAXX;
......@@ -3789,6 +4010,7 @@ cterm_reset(struct cterminal *cterm)
/* Set up a shadow palette */
for (i=0; i < sizeof(dac_default)/sizeof(struct dac_colors); i++)
setpalette(i+16, dac_default[i].red << 8 | dac_default[i].red, dac_default[i].green << 8 | dac_default[i].green, dac_default[i].blue << 8 | dac_default[i].blue);
}
struct cterminal* CIOLIBCALL cterm_init(int height, int width, int xpos, int ypos, int backlines, struct vmem_cell *scrollback, int emulation)
......@@ -4088,6 +4310,68 @@ static void parse_sixel_intro(struct cterminal *cterm)
cterm->sixel = SIXEL_INACTIVE;
}
static void parse_macro_intro(struct cterminal *cterm)
{
size_t i;
if (cterm->macro != MACRO_POSSIBLE)
return;
i = strspn(cterm->strbuf, "0123456789;");
if (i >= cterm->strbuflen)
return;
if (cterm->strbuf[i] != '!') {
cterm->macro = MACRO_INACTIVE;
return;
}
i++;
if (i >= cterm->strbuflen)
return;
if (cterm->strbuf[i] == 'z') {
char *p;
unsigned long res;
// Parse parameters...
cterm->macro_num = -1;
cterm->macro_del = MACRO_DELETE_OLD;
cterm->macro_encoding = MACRO_ENCODING_ASCII;
res = strtoul(cterm->strbuf, &p, 10);
if (res != ULONG_MAX)
cterm->macro_num = res;
if (*p == ';') {
p++;
res = strtoul(p, &p, 10);
if (res != ULONG_MAX)
cterm->macro_del = res;
else
cterm->macro_del = -1;
}
if (*p == ';') {
p++;
res = strtoul(p, &p, 10);
if (res != ULONG_MAX)
cterm->macro_encoding = res;
else
cterm->macro_encoding = -1;
}
if (cterm->macro_num < 0 || cterm->macro_num > 63)
cterm->macro = MACRO_INACTIVE;
else if (cterm->macro_del < 0 || cterm->macro_del > 1)
cterm->macro = MACRO_INACTIVE;
else if (cterm->macro_encoding < 0 || cterm->macro_encoding > 1)
cterm->macro = MACRO_INACTIVE;
else {
cterm->macro = MACRO_STARTED;
cterm->strbuflen = 0;
}
}
else if (cterm->strbuf[i] != 'z')
cterm->macro = MACRO_INACTIVE;
}
#define ustrlen(s) strlen((const char *)s)
#define uctputs(c, p) ctputs(c, (char *)p)
#define ustrcat(b, s) strcat((char *)b, (const char *)s)
......@@ -4097,7 +4381,7 @@ CIOLIBEXPORT char* CIOLIBCALL cterm_write(struct cterminal * cterm, const void *
const unsigned char *buf = (unsigned char *)vbuf;
unsigned char ch[2];
unsigned char prn[BUFSIZE];
int i, j, k, l, x, y, mx, my;
int i, j, k, x, y, mx, my;
int sx, sy, ex, ey;
struct text_info ti;
int olddmc;
......@@ -4203,6 +4487,14 @@ CIOLIBEXPORT char* CIOLIBCALL cterm_write(struct cterminal * cterm, const void *
parse_sixel_intro(cterm);
break;
}
switch(cterm->macro) {
case MACRO_STARTED:
parse_macro_string(cterm, false);
break;
case MACRO_POSSIBLE:
parse_macro_intro(cterm);
break;
}
if (cterm->strbuflen == cterm->strbufsize) {
char *p;
......
......@@ -198,6 +198,22 @@ struct cterminal {
int (*mouse_state_query)(int parameter, void *cbdata);
void *mouse_state_query_cbdata;
/* Macros */
char *macros[64];
size_t macro_lens[64];
uint64_t in_macro;
int macro;
#define MACRO_INACTIVE 0
#define MACRO_POSSIBLE 1
#define MACRO_STARTED 2
int macro_num;
int macro_del;
#define MACRO_DELETE_OLD 0
#define MACRO_DELETE_ALL 1
int macro_encoding;
#define MACRO_ENCODING_ASCII 0
#define MACRO_ENCODING_HEX 1
/* conio function pointers */
#ifdef CTERM_WITHOUT_CONIO
void (*ciolib_gotoxy) (struct cterminal *,int,int);
......
......@@ -89,6 +89,7 @@ ESC P Device Control String
deduced from the size of the data. This replaces the now
deprecated CSI = Ps1 ; Ps2 {
[ p1 [ ; p2 ] ] q
Defaults: p1 = 0 p2 = 0
Indicates the string is a sixel sequence.
......@@ -153,6 +154,7 @@ ESC P Device Control String
Moves the active position to the left border of the
next sixel row.
$ q pt
Request Status String (DECRQSS)
......@@ -177,6 +179,30 @@ ESC P Device Control String
$| Request width in columns
*| Request height in lines
p1 [ ; p2 [ ; p3 ] ! z
Define Macro (DECDMAC)
Defaults: p2 = 0 p3 = 0
Sets a macro to be replayed using CSI Pn * z
p1 is the macro number to set, and make be between 0 and
63 inclusive.
If p2 is zero, the macro numbered p1 will be deleted. If
p2 is one, all macros are deleted.
If p3 is zero, the macro is defined using ASCII characters
(0x20 - 0x7e and 0xa0 - 0xff only) if p3 is one, the macro
is defined using hex pairs.
When the macro is defined using hex pairs, a repeat
sequence may be included in the format of ! Pn ; D..D ;
Pn specifies the number of repeats (default of one instance)
D..D is the sequence of pairs to send Pn times. The
terminating ; may be left out if the sequence to be
repeated ends at the end of the string.
ESC ^ Privacy Message
Begins a string consisting of the characters 0x08 - 0x0d and
0x20-0x7e, terminated by a String Terminator (ST)
......@@ -968,6 +994,13 @@ CSI = Ps n
Where pH is the height of a character cell in pixels, and pW is
the width of a character cell in pixels.
When Ps is 62, CTerm will respond with a Mode Report of the form
CSI 32767 * {
This indicates that 524,272 bytes are available for macro storage.
This is not actually true, SyncTERM will use all available memory
for macro storage, but some software checks this value, and some
parsers don't allow more than INT16_MAX parameter values.
SOURCE: CTerm only.
CSI Pn1 ; Pn2 r
......@@ -1078,6 +1111,12 @@ CSI 2 $ w
SOURCE: VT320
CSI Pn * z
Invoke Macro (DECINVM)
Invokes a macro.
Pn specifies the macro number. If Pn is not 0..63, no action is
taken.
CSI = Ps1 ; Ps2 {
NON-STANDARD EXTENSION (Deprecated)
Defaults: Ps1 = 255 Ps2 = 0
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment