Fix bugs. Properly handle partial match.
This commit is contained in:
parent
a47c6f78eb
commit
342ff4d8f0
|
@ -120,13 +120,6 @@ before
|
|||
You may want this option enabled if
|
||||
.I fd
|
||||
is maintained in an event loop.
|
||||
.TP
|
||||
.B CTLSEQS_READER_RETAIN_PARTIAL
|
||||
When
|
||||
.BR ctlseqs_read ()
|
||||
returns
|
||||
.BR CTLSEQS_PARTIAL ,
|
||||
preserve the partially matched sequence in the internal buffer for future calls.
|
||||
.
|
||||
.SH RETURN VALUE
|
||||
.TP
|
||||
|
@ -135,14 +128,11 @@ Success.
|
|||
.TP
|
||||
.B CTLSEQS_NOMEM
|
||||
Fails to allocate sufficient memory.
|
||||
.SH BUGS
|
||||
After a successful
|
||||
.BR ctlseqs_read ()
|
||||
call, changing
|
||||
.TP
|
||||
.B CTLSEQS_ERROR
|
||||
Attempts to change
|
||||
.I maxlen
|
||||
to a smaller value on the same
|
||||
.I reader
|
||||
may result in data loss due to truncation of the internal read buffer.
|
||||
value, but data in the internal read buffer will be lost due to truncation, if done so.
|
||||
.
|
||||
.SH SEE ALSO
|
||||
.BR ctlseqs_read (3)
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
@ -136,15 +135,15 @@ struct ctlseqs_reader {
|
|||
union ctlseqs_value *buffer;
|
||||
size_t readlen;
|
||||
struct pollfd pollfd;
|
||||
bool no_poll;
|
||||
bool retain_partial;
|
||||
char *rbuf;
|
||||
size_t buf_start;
|
||||
size_t buf_end;
|
||||
size_t last_idx;
|
||||
enum ctlseqs_state state;
|
||||
bool no_poll;
|
||||
};
|
||||
|
||||
CTLSEQS_HOT static int
|
||||
CTLSEQS_HOT static inline int
|
||||
ctlseqs_poll(struct pollfd *pollfd, int timeout)
|
||||
{
|
||||
int nevents = poll(pollfd, 1, timeout);
|
||||
|
@ -160,10 +159,11 @@ ctlseqs_poll(struct pollfd *pollfd, int timeout)
|
|||
return pollfd->revents & POLLHUP ? CTLSEQS_EOF : CTLSEQS_ERROR;
|
||||
}
|
||||
|
||||
CTLSEQS_HOT static int
|
||||
CTLSEQS_HOT static inline int
|
||||
ctlseqs_do_read(struct ctlseqs_reader *reader)
|
||||
{
|
||||
ssize_t nbytes = read(reader->pollfd.fd, reader->rbuf + reader->buf_start, reader->readlen - reader->buf_start);
|
||||
char *buf = reader->rbuf + reader->buf_start + reader->last_idx;
|
||||
ssize_t nbytes = read(reader->pollfd.fd, buf, reader->readlen - reader->buf_start);
|
||||
if (CTLSEQS_UNLIKELY(nbytes == -1)) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
return CTLSEQS_TIMEOUT;
|
||||
|
@ -231,7 +231,7 @@ ctlseqs_state_transition(enum ctlseqs_state state, char ch)
|
|||
}
|
||||
}
|
||||
|
||||
CTLSEQS_HOT bool
|
||||
CTLSEQS_HOT static bool
|
||||
ctlseqs_fetch(char **seq, int type, union ctlseqs_value *buf, size_t *buf_offset)
|
||||
{
|
||||
unsigned long cnt, num;
|
||||
|
@ -322,13 +322,13 @@ ctlseqs_match_pattern(struct ctlseqs_reader *reader, struct ctlseqs_matcher cons
|
|||
}
|
||||
|
||||
CTLSEQS_HOT static ssize_t
|
||||
ctlseqs_match(struct ctlseqs_reader *reader, struct ctlseqs_matcher const *matcher, bool retain_partial)
|
||||
ctlseqs_match(struct ctlseqs_reader *reader, struct ctlseqs_matcher const *matcher)
|
||||
{
|
||||
ssize_t retval = CTLSEQS_PARTIAL;
|
||||
char const *buf = reader->rbuf + reader->buf_start;
|
||||
size_t idx, len = reader->buf_end - reader->buf_start;
|
||||
enum ctlseqs_state state = reader->state;
|
||||
for (idx = 0; idx < len; ++idx) {
|
||||
for (idx = reader->last_idx; idx < len; ++idx) {
|
||||
state = ctlseqs_state_transition(state, buf[idx]);
|
||||
if (state == ctlseqs_state_err) {
|
||||
for (; idx < len; ++idx) {
|
||||
|
@ -344,13 +344,16 @@ ctlseqs_match(struct ctlseqs_reader *reader, struct ctlseqs_matcher const *match
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (retval == CTLSEQS_PARTIAL || retval == CTLSEQS_NOSEQ) {
|
||||
reader->state = state >= ctlseqs_state_done ? ctlseqs_state_none : state;
|
||||
if (retval == CTLSEQS_NOMATCH || retval == CTLSEQS_PARTIAL || retval == CTLSEQS_NOSEQ) {
|
||||
reader->buffer[0].num = idx;
|
||||
reader->buffer[1].str = buf;
|
||||
}
|
||||
reader->state = state;
|
||||
if (!retain_partial || retval != CTLSEQS_PARTIAL) {
|
||||
if (retval == CTLSEQS_PARTIAL) {
|
||||
reader->last_idx = idx;
|
||||
} else {
|
||||
reader->buf_start += idx;
|
||||
reader->last_idx = 0;
|
||||
}
|
||||
if (reader->buf_start == reader->buf_end) {
|
||||
reader->buf_start = 0;
|
||||
|
@ -443,7 +446,9 @@ ctlseqs_reader_init()
|
|||
{
|
||||
struct ctlseqs_reader *reader = malloc(sizeof(struct ctlseqs_reader));
|
||||
if (CTLSEQS_LIKELY(reader != NULL)) {
|
||||
*reader = (struct ctlseqs_reader) { 0 };
|
||||
*reader = (struct ctlseqs_reader) {
|
||||
.pollfd.events = POLLIN,
|
||||
};
|
||||
}
|
||||
return reader;
|
||||
}
|
||||
|
@ -451,13 +456,15 @@ ctlseqs_reader_init()
|
|||
int
|
||||
ctlseqs_reader_setopt(struct ctlseqs_reader *reader, struct ctlseqs_reader_opts const *options)
|
||||
{
|
||||
reader->buffer = options->buffer;
|
||||
size_t readlen = options->maxlen;
|
||||
if (reader->readlen != readlen) {
|
||||
char *rbuf;
|
||||
if (reader->rbuf == NULL) {
|
||||
rbuf = malloc(readlen);
|
||||
} else {
|
||||
if (readlen < reader->buf_end) {
|
||||
return CTLSEQS_ERROR;
|
||||
}
|
||||
rbuf = realloc(reader->rbuf, readlen);
|
||||
}
|
||||
if (rbuf == NULL) {
|
||||
|
@ -469,39 +476,34 @@ ctlseqs_reader_setopt(struct ctlseqs_reader *reader, struct ctlseqs_reader_opts
|
|||
reader->buf_end = reader->readlen;
|
||||
}
|
||||
}
|
||||
reader->pollfd = (struct pollfd) { .fd = options->fd, .events = POLLIN };
|
||||
reader->buffer = options->buffer;
|
||||
reader->pollfd.fd = options->fd;
|
||||
reader->no_poll = options->flags & CTLSEQS_READER_NO_POLL;
|
||||
reader->retain_partial = options->flags & CTLSEQS_READER_RETAIN_PARTIAL;
|
||||
return CTLSEQS_OK;
|
||||
}
|
||||
|
||||
CTLSEQS_HOT ssize_t
|
||||
ctlseqs_read(struct ctlseqs_reader *reader, struct ctlseqs_matcher const *matcher, int timeout)
|
||||
{
|
||||
ssize_t match_result;
|
||||
if (reader->buf_start != 0) {
|
||||
match_result = ctlseqs_match(reader, matcher, true);
|
||||
if (match_result != CTLSEQS_PARTIAL) {
|
||||
goto terminate;
|
||||
ssize_t result;
|
||||
// Whether we have read more than we could match in the preview call.
|
||||
if (reader->state == ctlseqs_state_none && reader->buf_start != 0) {
|
||||
result = ctlseqs_match(reader, matcher);
|
||||
if (result != CTLSEQS_PARTIAL) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (!reader->no_poll) {
|
||||
match_result = ctlseqs_poll(&reader->pollfd, timeout);
|
||||
if (match_result < 0) {
|
||||
goto terminate;
|
||||
result = ctlseqs_poll(&reader->pollfd, timeout);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
match_result = ctlseqs_do_read(reader);
|
||||
if (CTLSEQS_UNLIKELY(match_result < 0)) {
|
||||
if (match_result == CTLSEQS_TIMEOUT && reader->state != ctlseqs_state_none) {
|
||||
match_result = CTLSEQS_PARTIAL;
|
||||
}
|
||||
goto terminate;
|
||||
result = ctlseqs_do_read(reader);
|
||||
if (CTLSEQS_UNLIKELY(result < 0)) {
|
||||
return reader->state == ctlseqs_state_none ? result : CTLSEQS_PARTIAL;
|
||||
}
|
||||
match_result = ctlseqs_match(reader, matcher, reader->retain_partial);
|
||||
terminate:
|
||||
reader->state = ctlseqs_state_none;
|
||||
return match_result;
|
||||
return ctlseqs_match(reader, matcher);
|
||||
}
|
||||
|
||||
CTLSEQS_COLD void
|
||||
|
|
|
@ -349,8 +349,7 @@
|
|||
|
||||
/* Reader option flags */
|
||||
|
||||
#define CTLSEQS_READER_NO_POLL (1 << 0) // Do not poll() before read()
|
||||
#define CTLSEQS_READER_RETAIN_PARTIAL (1 << 1) // Retain data after a partial match
|
||||
#define CTLSEQS_READER_NO_POLL (1 << 0) // Do not poll() before read()
|
||||
|
||||
/* Function return status codes */
|
||||
|
||||
|
|
|
@ -389,6 +389,9 @@ main(int argc, char **argv)
|
|||
case CTLSEQS_PARTIAL:
|
||||
print_generic_seq("PARTIAL", buffer);
|
||||
break;
|
||||
case CTLSEQS_NOMATCH:
|
||||
print_generic_seq("NOMATCH", buffer);
|
||||
break;
|
||||
case CTLSEQS_NOSEQ:
|
||||
print_generic_seq("NOSEQ", buffer);
|
||||
if (buffer[1].str[0] == 0x03) {
|
||||
|
|
Loading…
Reference in New Issue