Update documentation. Fix bugs.

This commit is contained in:
CismonX 2020-12-09 17:48:19 +08:00
parent 342ff4d8f0
commit 808c6d5033
Signed by: cismonx
GPG Key ID: 3094873E29A482FB
5 changed files with 35 additions and 19 deletions

View File

@ -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.

View File

@ -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])

View File

@ -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

View File

@ -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;
} }

View File

@ -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");