Update tcsgrep.
This commit is contained in:
parent
d5f5bad6f6
commit
e00c42a9b9
|
@ -331,13 +331,6 @@ ctlseqs_match(struct ctlseqs_reader *reader, struct ctlseqs_matcher const *match
|
||||||
state = ctlseqs_state_transit(state, buf[idx]);
|
state = ctlseqs_state_transit(state, buf[idx]);
|
||||||
if (state == ctlseqs_state_err) {
|
if (state == ctlseqs_state_err) {
|
||||||
retval = CTLSEQS_NOSEQ;
|
retval = CTLSEQS_NOSEQ;
|
||||||
for (; idx < len; ++idx) {
|
|
||||||
if (buf[idx] == 0x1b) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
reader->buffer[0].num = idx;
|
|
||||||
reader->buffer[1].str = buf;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (state == ctlseqs_state_done) {
|
if (state == ctlseqs_state_done) {
|
||||||
|
@ -345,6 +338,15 @@ ctlseqs_match(struct ctlseqs_reader *reader, struct ctlseqs_matcher const *match
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (retval == CTLSEQS_PARTIAL || retval == CTLSEQS_NOSEQ) {
|
||||||
|
for (; idx < len; ++idx) {
|
||||||
|
if (buf[idx] == 0x1b) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reader->buffer[0].num = idx;
|
||||||
|
reader->buffer[1].str = buf;
|
||||||
|
}
|
||||||
reader->state = state;
|
reader->state = state;
|
||||||
if (!reader->retain_partial || retval != CTLSEQS_PARTIAL) {
|
if (!reader->retain_partial || retval != CTLSEQS_PARTIAL) {
|
||||||
reader->buf_start += idx;
|
reader->buf_start += idx;
|
||||||
|
|
197
tests/tcsgrep.c
197
tests/tcsgrep.c
|
@ -19,11 +19,14 @@
|
||||||
|
|
||||||
#include "ctlseqs.h"
|
#include "ctlseqs.h"
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <limits.h>
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <termios.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#define TCSGREP_NINTH_ARG_(a1, a2, a3, a4, a5, a6, a7, a8, a9, ...) a9
|
#define TCSGREP_NINTH_ARG_(a1, a2, a3, a4, a5, a6, a7, a8, a9, ...) a9
|
||||||
|
@ -64,44 +67,105 @@ print_error(struct tcsgrep_ctx const *ctx, char const *msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
parse_int(char const *str, int *dest) {
|
parse_int(char const *str, int *dest)
|
||||||
|
{
|
||||||
errno = 0;
|
errno = 0;
|
||||||
long result = strtol(str, NULL, 10);
|
unsigned long result = strtoul(str, NULL, 10);
|
||||||
if (errno || result < -1 || result > INT_MAX) {
|
if (errno || result > 4096) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*dest = result;
|
*dest = result;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static void
|
||||||
parse_options(struct tcsgrep_ctx *ctx, int argc, char **argv) {
|
print_generic_seq(char const *header, union ctlseqs_value *buffer)
|
||||||
while (true) {
|
{
|
||||||
int result = getopt(argc, argv, "t:l:");
|
size_t length = buffer[0].num;
|
||||||
switch (result) {
|
char const *seq = buffer[1].str;
|
||||||
case 't':
|
printf("%s %zu", header, length);
|
||||||
if (!parse_int(optarg, &ctx->timeout)) {
|
for (size_t idx = 0; idx < length; ++idx) {
|
||||||
print_error(ctx, "invalid timeout option");
|
char ch = seq[idx];
|
||||||
return false;
|
if (isprint(ch)) {
|
||||||
}
|
printf(" %c", ch);
|
||||||
break;
|
} else if (ch == 0x1b) {
|
||||||
case 'l':
|
printf(" ESC");
|
||||||
if (!parse_int(optarg, &ctx->limit)) {
|
} else {
|
||||||
print_error(ctx, "invalid limit option");
|
printf(" \\x%02x", ch);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '?':
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_matching_seq(struct tcsgrep_sequence *seq, union ctlseqs_value *buffer)
|
||||||
|
{
|
||||||
|
printf("OK %s", seq->name);
|
||||||
|
for (int idx = 0; idx < 8; ++idx) {
|
||||||
|
char placeholder = seq->pattern[idx];
|
||||||
|
switch (placeholder) {
|
||||||
|
case 0x0e: // CTLSEQS_PH_NUM
|
||||||
|
printf(" %lu", buffer[idx].num);
|
||||||
|
break;
|
||||||
|
case 0x10: // CTLSEQS_PH_STR
|
||||||
|
printf(" %.*s", (int)buffer[idx].num, buffer[idx + 1].str);
|
||||||
|
break;
|
||||||
|
case 0x0f: // CTLSEQS_PH_NUMS
|
||||||
|
for (size_t i = 1; i <= buffer[idx].num; ++i) {
|
||||||
|
printf(" %lu", buffer[idx + i].num);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
struct tcsgrep_ctx ctx = {
|
||||||
|
.prog_name = argv[0],
|
||||||
|
.timeout = -1,
|
||||||
|
.limit = 4096,
|
||||||
|
};
|
||||||
|
|
||||||
|
int opt;
|
||||||
|
while (-1 != (opt = getopt(argc, argv, "t:l:"))) {
|
||||||
|
switch (opt) {
|
||||||
|
case 't':
|
||||||
|
if (!parse_int(optarg, &ctx.timeout)) {
|
||||||
|
print_error(&ctx, "invalid timeout option");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
if (!parse_int(optarg, &ctx.limit)) {
|
||||||
|
print_error(&ctx, "invalid limit option");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '?':
|
||||||
|
default:
|
||||||
|
print_error(&ctx, "invalid arguments");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int flags = fcntl(STDIN_FILENO, F_GETFL);
|
||||||
|
if (flags == -1) {
|
||||||
|
print_error(&ctx, "failed to get file status flags");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK) == -1) {
|
||||||
|
print_error(&ctx, "failed to set file status flags");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ctlseqs_matcher *matcher = ctlseqs_matcher_init();
|
||||||
|
if (matcher == NULL) {
|
||||||
|
print_error(&ctx, "failed to initialize matcher");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
static struct tcsgrep_sequence seqs[] = {
|
static struct tcsgrep_sequence seqs[] = {
|
||||||
TCSGREP_DEFSEQ_NOARGS(S7C1T),
|
TCSGREP_DEFSEQ_NOARGS(S7C1T),
|
||||||
TCSGREP_DEFSEQ_NOARGS(S8C1T),
|
TCSGREP_DEFSEQ_NOARGS(S8C1T),
|
||||||
|
@ -252,19 +316,6 @@ main(int argc, char **argv)
|
||||||
TCSGREP_DEFSEQ_NOARGS(KEY_F11),
|
TCSGREP_DEFSEQ_NOARGS(KEY_F11),
|
||||||
TCSGREP_DEFSEQ_NOARGS(KEY_F12),
|
TCSGREP_DEFSEQ_NOARGS(KEY_F12),
|
||||||
};
|
};
|
||||||
struct tcsgrep_ctx ctx = {
|
|
||||||
.prog_name = argv[0],
|
|
||||||
.timeout = -1,
|
|
||||||
.limit = -1,
|
|
||||||
};
|
|
||||||
if (!parse_options(&ctx, argc, argv)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
struct ctlseqs_matcher *matcher = ctlseqs_matcher_init();
|
|
||||||
if (matcher == NULL) {
|
|
||||||
print_error(&ctx, "failed to initialize matcher");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
size_t npatterns = sizeof(seqs) / sizeof(struct tcsgrep_sequence);
|
size_t npatterns = sizeof(seqs) / sizeof(struct tcsgrep_sequence);
|
||||||
char const **patterns = malloc(sizeof(char const *) * npatterns);
|
char const **patterns = malloc(sizeof(char const *) * npatterns);
|
||||||
if (patterns == NULL) {
|
if (patterns == NULL) {
|
||||||
|
@ -278,13 +329,79 @@ main(int argc, char **argv)
|
||||||
.patterns = patterns,
|
.patterns = patterns,
|
||||||
.npatterns = npatterns,
|
.npatterns = npatterns,
|
||||||
};
|
};
|
||||||
if (!ctlseqs_matcher_setopt(matcher, &matcher_opts)) {
|
if (ctlseqs_matcher_setopt(matcher, &matcher_opts) != CTLSEQS_OK) {
|
||||||
print_error(&ctx, "matcher setopt failed");
|
print_error(&ctx, "matcher setopt failed");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ctlseqs_reader *reader = ctlseqs_reader_init();
|
struct ctlseqs_reader *reader = ctlseqs_reader_init();
|
||||||
if (reader == NULL) {
|
if (reader == NULL) {
|
||||||
print_error(&ctx, "failed to initialize reader");
|
print_error(&ctx, "failed to initialize reader");
|
||||||
}
|
}
|
||||||
return 0;
|
union ctlseqs_value buffer[16];
|
||||||
|
struct ctlseqs_reader_opts reader_opts = {
|
||||||
|
.fd = STDIN_FILENO,
|
||||||
|
.maxlen = ctx.limit,
|
||||||
|
.buffer = buffer
|
||||||
|
};
|
||||||
|
if (ctlseqs_reader_setopt(reader, &reader_opts) != CTLSEQS_OK) {
|
||||||
|
print_error(&ctx, "reader setopt failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO)) {
|
||||||
|
print_error(&ctx, "not a tty");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
struct termios old_termios;
|
||||||
|
if (tcgetattr(STDIN_FILENO, &old_termios) != 0) {
|
||||||
|
print_error(&ctx, "failed to get terminal attributes");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
struct termios new_termios = old_termios;
|
||||||
|
new_termios.c_lflag &= ~(ICANON | ISIG | ECHO);
|
||||||
|
if (tcsetattr(STDIN_FILENO, TCSANOW, &new_termios) != 0) {
|
||||||
|
print_error(&ctx, "failed to set terminal attributes");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int status = 0;
|
||||||
|
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;
|
||||||
|
case CTLSEQS_INTR:
|
||||||
|
printf("INTERRUPTED\n");
|
||||||
|
break;
|
||||||
|
case CTLSEQS_EOF:
|
||||||
|
printf("EOF\n");
|
||||||
|
break;
|
||||||
|
case CTLSEQS_PARTIAL:
|
||||||
|
print_generic_seq("PARTIAL", buffer);
|
||||||
|
break;
|
||||||
|
case CTLSEQS_NOSEQ:
|
||||||
|
print_generic_seq("NOSEQ", buffer);
|
||||||
|
if (buffer[1].str[0] == 0x03) {
|
||||||
|
goto terminate;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
print_matching_seq(&seqs[result], buffer);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
terminate:
|
||||||
|
tcsetattr(STDIN_FILENO, TCSANOW, &old_termios);
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue