Update documentation. Fix bugs.
This commit is contained in:
parent
342ff4d8f0
commit
808c6d5033
|
@ -18,7 +18,7 @@
|
||||||
The ctlseqs library provides low-level C API for manipulating terminal
|
The ctlseqs library provides low-level C API for manipulating terminal
|
||||||
emulators with control sequences.
|
emulators with control sequences.
|
||||||
|
|
||||||
This library is free software. you can redistribute it and/or modify it
|
Ctlseqs is free software. you can redistribute it and/or modify it
|
||||||
under the terms of the GNU General Public License as published by the
|
under the terms of the GNU General Public License as published by the
|
||||||
Free Software Foundation, either version 3 of the License, or (at your
|
Free Software Foundation, either version 3 of the License, or (at your
|
||||||
option) any later version.
|
option) any later version.
|
||||||
|
|
|
@ -41,8 +41,6 @@ AC_TYPE_SIZE_T
|
||||||
AC_TYPE_SSIZE_T
|
AC_TYPE_SSIZE_T
|
||||||
|
|
||||||
# Checks for library functions.
|
# Checks for library functions.
|
||||||
AC_FUNC_MALLOC
|
|
||||||
AC_FUNC_REALLOC
|
|
||||||
AC_CHECK_FUNCS([dprintf memset strtoul])
|
AC_CHECK_FUNCS([dprintf memset strtoul])
|
||||||
|
|
||||||
AC_CONFIG_FILES([Makefile man/Makefile src/Makefile tests/Makefile examples/Makefile])
|
AC_CONFIG_FILES([Makefile man/Makefile src/Makefile tests/Makefile examples/Makefile])
|
||||||
|
|
|
@ -51,6 +51,7 @@ A control sequence is successfully read, but fails to match any pattern in
|
||||||
.TP
|
.TP
|
||||||
.B CTLSEQS_PARTIAL
|
.B CTLSEQS_PARTIAL
|
||||||
Data is read successfully and can be recognized as part of a control sequence, but is not yet terminated.
|
Data is read successfully and can be recognized as part of a control sequence, but is not yet terminated.
|
||||||
|
Partial sequence is not consumed from the read buffer.
|
||||||
.TP
|
.TP
|
||||||
.B CTLSEQS_NOSEQ
|
.B CTLSEQS_NOSEQ
|
||||||
Data is read successfully, but cannot be recognized as a valid control sequence.
|
Data is read successfully, but cannot be recognized as a valid control sequence.
|
||||||
|
@ -60,6 +61,11 @@ The specified
|
||||||
.I timeout
|
.I timeout
|
||||||
has expired, and no data is read.
|
has expired, and no data is read.
|
||||||
.TP
|
.TP
|
||||||
|
.B CTLSEQS_NOMEM
|
||||||
|
Like
|
||||||
|
.BR CTLSEQS_PARTIAL ,
|
||||||
|
but the internal read buffer is full, and no data can be further read.
|
||||||
|
.TP
|
||||||
.B CTLSEQS_EOF
|
.B CTLSEQS_EOF
|
||||||
End-of-file is encountered, and no data is read.
|
End-of-file is encountered, and no data is read.
|
||||||
.TP
|
.TP
|
||||||
|
|
|
@ -162,8 +162,8 @@ ctlseqs_poll(struct pollfd *pollfd, int timeout)
|
||||||
CTLSEQS_HOT static inline int
|
CTLSEQS_HOT static inline int
|
||||||
ctlseqs_do_read(struct ctlseqs_reader *reader)
|
ctlseqs_do_read(struct ctlseqs_reader *reader)
|
||||||
{
|
{
|
||||||
char *buf = reader->rbuf + reader->buf_start + reader->last_idx;
|
size_t offset = reader->buf_start + reader->last_idx;
|
||||||
ssize_t nbytes = read(reader->pollfd.fd, buf, reader->readlen - reader->buf_start);
|
ssize_t nbytes = read(reader->pollfd.fd, reader->rbuf + offset, reader->readlen - offset);
|
||||||
if (CTLSEQS_UNLIKELY(nbytes == -1)) {
|
if (CTLSEQS_UNLIKELY(nbytes == -1)) {
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||||
return CTLSEQS_TIMEOUT;
|
return CTLSEQS_TIMEOUT;
|
||||||
|
@ -331,6 +331,7 @@ ctlseqs_match(struct ctlseqs_reader *reader, struct ctlseqs_matcher const *match
|
||||||
for (idx = reader->last_idx; idx < len; ++idx) {
|
for (idx = reader->last_idx; idx < len; ++idx) {
|
||||||
state = ctlseqs_state_transition(state, buf[idx]);
|
state = ctlseqs_state_transition(state, buf[idx]);
|
||||||
if (state == ctlseqs_state_err) {
|
if (state == ctlseqs_state_err) {
|
||||||
|
// Anything before next ESC is definitely not a control sequence.
|
||||||
for (; idx < len; ++idx) {
|
for (; idx < len; ++idx) {
|
||||||
if (buf[idx] == 0x1b) {
|
if (buf[idx] == 0x1b) {
|
||||||
break;
|
break;
|
||||||
|
@ -341,24 +342,39 @@ ctlseqs_match(struct ctlseqs_reader *reader, struct ctlseqs_matcher const *match
|
||||||
}
|
}
|
||||||
if (state == ctlseqs_state_done) {
|
if (state == ctlseqs_state_done) {
|
||||||
retval = ctlseqs_match_pattern(reader, matcher);
|
retval = ctlseqs_match_pattern(reader, matcher);
|
||||||
|
++idx;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
reader->state = state >= ctlseqs_state_done ? ctlseqs_state_none : state;
|
if (retval < 0) {
|
||||||
if (retval == CTLSEQS_NOMATCH || retval == CTLSEQS_PARTIAL || retval == CTLSEQS_NOSEQ) {
|
|
||||||
reader->buffer[0].num = idx;
|
reader->buffer[0].num = idx;
|
||||||
reader->buffer[1].str = buf;
|
reader->buffer[1].str = buf;
|
||||||
}
|
}
|
||||||
if (retval == CTLSEQS_PARTIAL) {
|
if (retval == CTLSEQS_PARTIAL) {
|
||||||
reader->last_idx = idx;
|
reader->last_idx = idx;
|
||||||
|
if (CTLSEQS_UNLIKELY(reader->buf_start + idx == reader->readlen)) {
|
||||||
|
// Buffer is full but a match is still pending.
|
||||||
|
// This may happen when the reader's maxlen option is not large enough to hold a sequence,
|
||||||
|
// or when the the sequences are produced faster than consumed.
|
||||||
|
if (reader->buf_start > reader->readlen / 2) {
|
||||||
|
memcpy(reader->rbuf, reader->rbuf + reader->buf_start, idx);
|
||||||
|
reader->buf_start = 0;
|
||||||
|
reader->buf_end = idx;
|
||||||
|
} else {
|
||||||
|
// We could memmove() here, but having a buffer no larger than twice the size of a sequence
|
||||||
|
// is hardly what a normal program would desire.
|
||||||
|
retval = CTLSEQS_NOMEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
reader->buf_start += idx;
|
reader->buf_start += idx;
|
||||||
reader->last_idx = 0;
|
reader->last_idx = 0;
|
||||||
|
if (reader->buf_start == reader->buf_end) {
|
||||||
|
reader->buf_start = 0;
|
||||||
|
reader->buf_end = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (reader->buf_start == reader->buf_end) {
|
reader->state = state >= ctlseqs_state_done ? ctlseqs_state_none : state;
|
||||||
reader->buf_start = 0;
|
|
||||||
reader->buf_end = 0;
|
|
||||||
}
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -459,14 +475,10 @@ ctlseqs_reader_setopt(struct ctlseqs_reader *reader, struct ctlseqs_reader_opts
|
||||||
size_t readlen = options->maxlen;
|
size_t readlen = options->maxlen;
|
||||||
if (reader->readlen != readlen) {
|
if (reader->readlen != readlen) {
|
||||||
char *rbuf;
|
char *rbuf;
|
||||||
if (reader->rbuf == NULL) {
|
if (readlen < reader->buf_end) {
|
||||||
rbuf = malloc(readlen);
|
return CTLSEQS_ERROR;
|
||||||
} else {
|
|
||||||
if (readlen < reader->buf_end) {
|
|
||||||
return CTLSEQS_ERROR;
|
|
||||||
}
|
|
||||||
rbuf = realloc(reader->rbuf, readlen);
|
|
||||||
}
|
}
|
||||||
|
rbuf = realloc(reader->rbuf, readlen);
|
||||||
if (rbuf == NULL) {
|
if (rbuf == NULL) {
|
||||||
return CTLSEQS_NOMEM;
|
return CTLSEQS_NOMEM;
|
||||||
}
|
}
|
||||||
|
|
|
@ -381,7 +381,7 @@ main(int argc, char **argv)
|
||||||
printf("TIMEOUT\n");
|
printf("TIMEOUT\n");
|
||||||
break;
|
break;
|
||||||
case CTLSEQS_INTR:
|
case CTLSEQS_INTR:
|
||||||
printf("INTERRUPTED\n");
|
printf("INTR\n");
|
||||||
break;
|
break;
|
||||||
case CTLSEQS_EOF:
|
case CTLSEQS_EOF:
|
||||||
printf("EOF\n");
|
printf("EOF\n");
|
||||||
|
|
Loading…
Reference in New Issue