diff --git a/examples/sixdraw.c b/examples/sixdraw.c
index a7888ac..8da72f2 100644
--- a/examples/sixdraw.c
+++ b/examples/sixdraw.c
@@ -43,7 +43,7 @@
struct sixdraw_ctx {
struct termios termios;
- union ctlseqs_value buffer[10];
+ union ctlseqs_value buffer[64];
char const *prog_name;
struct ctlseqs_matcher *matcher;
struct ctlseqs_reader *reader;
@@ -111,7 +111,6 @@ sixdraw_get_winsize(struct sixdraw_ctx *ctx)
ctx->cols = ws.ws_col;
ctx->ch_width = ws.ws_xpixel / ws.ws_col;
ctx->ch_height = ws.ws_ypixel / ws.ws_row;
- dprintf(ctx->out_fd, "%d %d \n%d %d %d %d\n", ws.ws_xpixel, ws.ws_ypixel, ctx->rows, ctx->cols, ctx->ch_width, ctx->ch_height);
return true;
}
@@ -125,7 +124,7 @@ sixdraw_init(struct sixdraw_ctx *ctx, int argc, char **argv)
.timeout = SIXDRAW_DEFAULT_TIMEOUT_MILLIS,
};
- // Process command line arguments
+ // Process command line arguments.
int opt;
while (-1 != (opt = getopt(argc, argv, "t:"))) {
switch (opt) {
@@ -138,7 +137,7 @@ sixdraw_init(struct sixdraw_ctx *ctx, int argc, char **argv)
}
}
- // Initialize control sequence matcher
+ // Initialize control sequence matcher.
ctx->matcher = ctlseqs_matcher_init();
if (ctx->matcher == NULL) {
sixdraw_print_error(ctx, "failed to initialize matcher");
@@ -157,7 +156,7 @@ sixdraw_init(struct sixdraw_ctx *ctx, int argc, char **argv)
return false;
}
- // Initialize control sequence reader
+ // Initialize control sequence reader.
ctx->reader = ctlseqs_reader_init();
if (ctx->reader == NULL) {
sixdraw_print_error(ctx, "failed to initialize reader");
@@ -166,14 +165,14 @@ sixdraw_init(struct sixdraw_ctx *ctx, int argc, char **argv)
struct ctlseqs_reader_options reader_options = {
.buffer = ctx->buffer,
.fd = ctx->in_fd,
- .maxlen = 32,
+ .maxlen = 4096,
};
if (ctlseqs_reader_config(ctx->reader, &reader_options) != CTLSEQS_OK) {
sixdraw_print_error(ctx, "failed to set reader options");
return false;
}
- // Block SIGWINCH
+ // Block SIGWINCH.
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGWINCH);
@@ -186,13 +185,13 @@ sixdraw_init(struct sixdraw_ctx *ctx, int argc, char **argv)
static bool
sixdraw_prepare(struct sixdraw_ctx *ctx)
{
- // Check whether we're running on a terminal
+ // Check whether we're running on a terminal.
if (!isatty(ctx->in_fd) || !isatty(ctx->out_fd)) {
sixdraw_print_error(ctx, "this program can only run in a terminal");
return false;
}
- // Set terminal to noncanonical mode
+ // Set terminal to noncanonical mode.
if (tcgetattr(ctx->in_fd, &ctx->termios) != 0) {
sixdraw_print_error(ctx, "failed to get terminal attributes");
return false;
@@ -202,12 +201,12 @@ sixdraw_prepare(struct sixdraw_ctx *ctx)
termios.c_cc[VTIME] = 0;
termios.c_lflag &= ~(ICANON | ISIG | ECHO);
if (tcsetattr(ctx->in_fd, TCSANOW, &termios) != 0) {
- sixdraw_print_error(ctx, "failed to get terminal attributes");
+ sixdraw_print_error(ctx, "failed to set terminal attributes");
return false;
}
ctx->has_termios = true;
- // Set STDIN flags to non-blocking
+ // Set STDIN flags to nonblocking.
int flags = fcntl(ctx->in_fd, F_GETFL);
if (flags == -1) {
sixdraw_print_error(ctx, "failed to get file status flags");
@@ -218,18 +217,20 @@ sixdraw_prepare(struct sixdraw_ctx *ctx)
return false;
}
- // Get initial terminal window size
+ // Get initial terminal window size.
if (!sixdraw_get_winsize(ctx)) {
sixdraw_print_error(ctx, "failed to get terminal window size");
return false;
}
- return true;
- // Check terminal support for sixel graphics and DEC locator
+ // Check terminal support for sixel graphics and DEC locator.
dprintf(ctx->out_fd, CTLSEQS_PRIMARY_DA());
- ssize_t result = ctlseqs_read(ctx->reader, ctx->matcher, 500);
+ ssize_t result;
+ do {
+ result = ctlseqs_read(ctx->reader, ctx->matcher, ctx->timeout);
+ } while (result == CTLSEQS_PARTIAL);
if (result != 0) {
- sixdraw_print_error(ctx, "failed to get terminal attributes");
+ sixdraw_print_error(ctx, "failed to get terminal features");
return false;
}
bool has_sixel = false;
@@ -251,9 +252,11 @@ sixdraw_prepare(struct sixdraw_ctx *ctx)
return false;
}
- // Get current cursor status
+ // Get current cursor status.
dprintf(ctx->out_fd, CTLSEQS_DECRQM("25"));
- result = ctlseqs_read(ctx->reader, ctx->matcher, ctx->timeout);
+ do {
+ result = ctlseqs_read(ctx->reader, ctx->matcher, ctx->timeout);
+ } while (result == CTLSEQS_PARTIAL);
if (result != 1) {
sixdraw_print_error(ctx, "failed to get cursor status");
return false;
diff --git a/tests/tcsgrep.c b/tests/tcsgrep.c
index fa71d58..52f8448 100644
--- a/tests/tcsgrep.c
+++ b/tests/tcsgrep.c
@@ -17,7 +17,9 @@
* along with this program. If not, see .
*/
-#include "ctlseqs.h"
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif // HAVE_CONFIG_H
#include
#include
@@ -29,6 +31,8 @@
#include
#include
+#include
+
#define TCSGREP_NINTH_ARG_(a1, a2, a3, a4, a5, a6, a7, a8, a9, ...) a9
#define TCSGREP_COUNT_ARGS_(...) TCSGREP_NINTH_ARG_(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0)
@@ -58,6 +62,8 @@ struct tcsgrep_ctx {
char const *prog_name;
int timeout;
int limit;
+ bool purge_long_seqs;
+ bool verbose;
};
static inline void
@@ -79,7 +85,7 @@ parse_int(char const *str, int *dest)
}
static void
-print_generic_seq(char const *header, union ctlseqs_value *buffer)
+print_generic_seq(char const *header, union ctlseqs_value *buffer, bool newline)
{
size_t length = buffer[0].num;
char const *seq = buffer[1].str;
@@ -96,13 +102,21 @@ print_generic_seq(char const *header, union ctlseqs_value *buffer)
printf(" \\x%02x", ch);
}
}
- printf("\n");
+ if (newline) {
+ printf("\n");
+ }
}
static void
-print_matching_seq(struct tcsgrep_sequence *seq, union ctlseqs_value *buffer)
+print_matching_seq(struct tcsgrep_sequence *seq, union ctlseqs_value *buffer, bool verbose)
{
- printf("OK %s", seq->name);
+ if (verbose) {
+ print_generic_seq("OK", buffer, false);
+ buffer += 2;
+ } else {
+ printf("OK");
+ }
+ printf(" %s", seq->name);
for (int idx = 0; idx < 8; ++idx) {
char placeholder = seq->args[idx];
switch (placeholder) {
@@ -126,13 +140,15 @@ int
main(int argc, char **argv)
{
struct tcsgrep_ctx ctx = {
- .prog_name = argv[0],
- .timeout = -1,
- .limit = 4096,
+ .prog_name = argv[0],
+ .timeout = -1,
+ .limit = 4096,
+ .purge_long_seqs = false,
+ .verbose = false,
};
int opt;
- while (-1 != (opt = getopt(argc, argv, "t:l:"))) {
+ while (-1 != (opt = getopt(argc, argv, "t:l:pv"))) {
switch (opt) {
case 't':
if (!parse_int(optarg, &ctx.timeout)) {
@@ -146,6 +162,12 @@ main(int argc, char **argv)
return 1;
}
break;
+ case 'p':
+ ctx.purge_long_seqs = true;
+ break;
+ case 'v':
+ ctx.verbose = true;
+ break;
case '?':
default:
print_error(&ctx, "invalid arguments");
@@ -183,7 +205,7 @@ main(int argc, char **argv)
TCSGREP_DEFSEQ_NOARGS(DECKPAM),
TCSGREP_DEFSEQ_NOARGS(DECKPNM),
TCSGREP_DEFSEQ_NOARGS(RIS),
- TCSGREP_DEFSEQ(DECUDK, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_NUMS),
+ TCSGREP_DEFSEQ(DECUDK, CTLSEQS_PH_NUM, CTLSEQS_PH_NUM, CTLSEQS_PH_STR),
TCSGREP_DEFSEQ(DECRQSS, CTLSEQS_PH_STR),
TCSGREP_DEFSEQ(DECRSPS, CTLSEQS_PH_NUM, CTLSEQS_PH_STR),
TCSGREP_DEFSEQ(XTGETXRES, CTLSEQS_PH_STR),
@@ -340,11 +362,12 @@ main(int argc, char **argv)
if (reader == NULL) {
print_error(&ctx, "failed to initialize reader");
}
- union ctlseqs_value buffer[16];
+ static union ctlseqs_value buffer[4096];
struct ctlseqs_reader_options reader_options = {
.fd = STDIN_FILENO,
.maxlen = ctx.limit,
- .buffer = buffer
+ .buffer = buffer,
+ .flags = ctx.verbose ? CTLSEQS_READER_SAVE_MATCHED_SEQS : 0,
};
if (ctlseqs_reader_config(reader, &reader_options) != CTLSEQS_OK) {
print_error(&ctx, "reader setopt failed");
@@ -373,17 +396,14 @@ main(int argc, char **argv)
while (true) {
ssize_t result = ctlseqs_read(reader, matcher, ctx.timeout);
switch (result) {
- case CTLSEQS_NOMEM:
- print_error(&ctx, "failed to allocate memory");
- status = 1;
- goto terminate;
case CTLSEQS_ERROR:
print_error(&ctx, "unexpected error");
status = 1;
goto terminate;
case CTLSEQS_TIMEOUT:
printf("TIMEOUT\n");
- break;
+ status = 1;
+ goto terminate;
case CTLSEQS_INTR:
printf("INTR\n");
break;
@@ -391,19 +411,30 @@ main(int argc, char **argv)
printf("EOF\n");
break;
case CTLSEQS_PARTIAL:
- print_generic_seq("PARTIAL", buffer);
+ if (ctx.verbose) {
+ print_generic_seq("PARTIAL", buffer, true);
+ }
break;
case CTLSEQS_NOMATCH:
- print_generic_seq("NOMATCH", buffer);
+ print_generic_seq("NOMATCH", buffer, true);
break;
+ case CTLSEQS_NOMEM:
+ print_generic_seq("NOMEM", buffer, true);
+ if (ctx.purge_long_seqs) {
+ ctlseqs_purge(reader, buffer[0].num);
+ break;
+ } else {
+ status = 1;
+ goto terminate;
+ }
case CTLSEQS_NOSEQ:
- print_generic_seq("NOSEQ", buffer);
+ print_generic_seq("NOSEQ", buffer, true);
if (buffer[1].str[0] == 0x03) {
goto terminate;
}
break;
default:
- print_matching_seq(&seqs[result], buffer);
+ print_matching_seq(&seqs[result], buffer, ctx.verbose);
break;
}
}