mirror of
https://github.com/cuberite/libevent.git
synced 2025-09-10 13:04:23 -04:00
Refactor evbuffer_readln() into a search-for-eol function and an extract-line function.
svn:r1404
This commit is contained in:
parent
a26d2d1b87
commit
d41347722a
@ -10,6 +10,7 @@ Changes in 2.0.3-alpha:
|
|||||||
o Fix a bug in bufferevent_socket_connect() when the connection succeeds too quickly.
|
o Fix a bug in bufferevent_socket_connect() when the connection succeeds too quickly.
|
||||||
o Export an evutil_sockaddr_cmp() to compare to sockaddr objects for equality.
|
o Export an evutil_sockaddr_cmp() to compare to sockaddr objects for equality.
|
||||||
o Add a bufferevent_get_enabled() to tell what a bufferevent has been configured to do.
|
o Add a bufferevent_get_enabled() to tell what a bufferevent has been configured to do.
|
||||||
|
o Add an evbuffer_search_eol() function to locate the end of a line nondestructively.
|
||||||
|
|
||||||
|
|
||||||
Changes in 2.0.2-alpha:
|
Changes in 2.0.2-alpha:
|
||||||
|
138
buffer.c
138
buffer.c
@ -139,6 +139,8 @@ static int use_mmap = 1;
|
|||||||
|
|
||||||
static void evbuffer_chain_align(struct evbuffer_chain *chain);
|
static void evbuffer_chain_align(struct evbuffer_chain *chain);
|
||||||
static void evbuffer_deferred_callback(struct deferred_cb *cb, void *arg);
|
static void evbuffer_deferred_callback(struct deferred_cb *cb, void *arg);
|
||||||
|
static int evbuffer_ptr_memcmp(const struct evbuffer *buf,
|
||||||
|
const struct evbuffer_ptr *pos, const char *mem, size_t len);
|
||||||
|
|
||||||
static struct evbuffer_chain *
|
static struct evbuffer_chain *
|
||||||
evbuffer_chain_new(size_t size)
|
evbuffer_chain_new(size_t size)
|
||||||
@ -1070,14 +1072,88 @@ evbuffer_getchr(struct evbuffer_ptr *it)
|
|||||||
return chain->buffer[chain->misalign + off];
|
return chain->buffer[chain->misalign + off];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct evbuffer_ptr
|
||||||
|
evbuffer_search_eol(struct evbuffer *buffer,
|
||||||
|
struct evbuffer_ptr *start, size_t *eol_len_out,
|
||||||
|
enum evbuffer_eol_style eol_style)
|
||||||
|
{
|
||||||
|
struct evbuffer_ptr it, it2;
|
||||||
|
size_t extra_drain = 0;
|
||||||
|
int ok = 0;
|
||||||
|
|
||||||
|
EVBUFFER_LOCK(buffer, EVTHREAD_READ);
|
||||||
|
|
||||||
|
if (start) {
|
||||||
|
memcpy(&it, start, sizeof(it));
|
||||||
|
} else {
|
||||||
|
it.pos = 0;
|
||||||
|
it._internal.chain = buffer->first;
|
||||||
|
it._internal.pos_in_chain = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the eol_style determines our first stop character and how many
|
||||||
|
* characters we are going to drain afterwards. */
|
||||||
|
switch (eol_style) {
|
||||||
|
case EVBUFFER_EOL_ANY:
|
||||||
|
if (evbuffer_strpbrk(&it, "\r\n") < 0)
|
||||||
|
goto done;
|
||||||
|
memcpy(&it2, &it, sizeof(it));
|
||||||
|
extra_drain = evbuffer_strspn(&it2, "\r\n");
|
||||||
|
break;
|
||||||
|
case EVBUFFER_EOL_CRLF_STRICT: {
|
||||||
|
it = evbuffer_search(buffer, "\r\n", 2, &it);
|
||||||
|
if (it.pos < 0)
|
||||||
|
goto done;
|
||||||
|
extra_drain = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EVBUFFER_EOL_CRLF:
|
||||||
|
while (1) {
|
||||||
|
if (evbuffer_strpbrk(&it, "\r\n") < 0)
|
||||||
|
goto done;
|
||||||
|
if (evbuffer_getchr(&it) == '\n') {
|
||||||
|
extra_drain = 1;
|
||||||
|
break;
|
||||||
|
} else if (!evbuffer_ptr_memcmp(
|
||||||
|
buffer, &it, "\r\n", 2)) {
|
||||||
|
extra_drain = 2;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (evbuffer_ptr_set(buffer, &it, 1,
|
||||||
|
EVBUFFER_PTR_ADD)<0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EVBUFFER_EOL_LF:
|
||||||
|
if (evbuffer_strchr(&it, '\n') < 0)
|
||||||
|
goto done;
|
||||||
|
extra_drain = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = 1;
|
||||||
|
done:
|
||||||
|
EVBUFFER_UNLOCK(buffer, EVTHREAD_READ);
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
it.pos = -1;
|
||||||
|
}
|
||||||
|
if (eol_len_out)
|
||||||
|
*eol_len_out = extra_drain;
|
||||||
|
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
evbuffer_readln(struct evbuffer *buffer, size_t *n_read_out,
|
evbuffer_readln(struct evbuffer *buffer, size_t *n_read_out,
|
||||||
enum evbuffer_eol_style eol_style)
|
enum evbuffer_eol_style eol_style)
|
||||||
{
|
{
|
||||||
struct evbuffer_ptr it;
|
struct evbuffer_ptr it;
|
||||||
char *line, chr;
|
char *line;
|
||||||
unsigned int n_to_copy, extra_drain;
|
size_t n_to_copy=0, extra_drain=0;
|
||||||
int count = 0;
|
|
||||||
char *result = NULL;
|
char *result = NULL;
|
||||||
|
|
||||||
EVBUFFER_LOCK(buffer, EVTHREAD_WRITE);
|
EVBUFFER_LOCK(buffer, EVTHREAD_WRITE);
|
||||||
@ -1086,50 +1162,10 @@ evbuffer_readln(struct evbuffer *buffer, size_t *n_read_out,
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (evbuffer_ptr_set(buffer, &it, 0, EVBUFFER_PTR_SET) < 0)
|
it = evbuffer_search_eol(buffer, NULL, &extra_drain, eol_style);
|
||||||
|
if (it.pos < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
n_to_copy = it.pos;
|
||||||
/* the eol_style determines our first stop character and how many
|
|
||||||
* characters we are going to drain afterwards. */
|
|
||||||
switch (eol_style) {
|
|
||||||
case EVBUFFER_EOL_ANY:
|
|
||||||
count = evbuffer_strpbrk(&it, "\r\n");
|
|
||||||
if (count == -1)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
n_to_copy = count;
|
|
||||||
extra_drain = evbuffer_strspn(&it, "\r\n");
|
|
||||||
break;
|
|
||||||
case EVBUFFER_EOL_CRLF_STRICT: {
|
|
||||||
int tmp;
|
|
||||||
while ((tmp = evbuffer_strchr(&it, '\r')) != -1) {
|
|
||||||
count += tmp;
|
|
||||||
if (evbuffer_ptr_set(buffer, &it, 1, EVBUFFER_PTR_ADD)
|
|
||||||
< 0)
|
|
||||||
goto done;
|
|
||||||
chr = evbuffer_getchr(&it);
|
|
||||||
if (chr == '\n') {
|
|
||||||
n_to_copy = count;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++count;
|
|
||||||
}
|
|
||||||
if (tmp == -1)
|
|
||||||
goto done;
|
|
||||||
extra_drain = 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case EVBUFFER_EOL_CRLF:
|
|
||||||
/* we might strip a preceding '\r' */
|
|
||||||
case EVBUFFER_EOL_LF:
|
|
||||||
if ((count = evbuffer_strchr(&it, '\n')) == -1)
|
|
||||||
goto done;
|
|
||||||
n_to_copy = count;
|
|
||||||
extra_drain = 1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((line = mm_malloc(n_to_copy+1)) == NULL) {
|
if ((line = mm_malloc(n_to_copy+1)) == NULL) {
|
||||||
event_warn("%s: out of memory\n", __func__);
|
event_warn("%s: out of memory\n", __func__);
|
||||||
@ -1138,18 +1174,16 @@ evbuffer_readln(struct evbuffer *buffer, size_t *n_read_out,
|
|||||||
}
|
}
|
||||||
|
|
||||||
evbuffer_remove(buffer, line, n_to_copy);
|
evbuffer_remove(buffer, line, n_to_copy);
|
||||||
if (eol_style == EVBUFFER_EOL_CRLF &&
|
|
||||||
n_to_copy && line[n_to_copy-1] == '\r')
|
|
||||||
--n_to_copy;
|
|
||||||
line[n_to_copy] = '\0';
|
line[n_to_copy] = '\0';
|
||||||
|
|
||||||
evbuffer_drain(buffer, extra_drain);
|
evbuffer_drain(buffer, extra_drain);
|
||||||
if (n_read_out)
|
|
||||||
*n_read_out = (size_t)n_to_copy;
|
|
||||||
|
|
||||||
result = line;
|
result = line;
|
||||||
done:
|
done:
|
||||||
EVBUFFER_UNLOCK(buffer, EVTHREAD_WRITE);
|
EVBUFFER_UNLOCK(buffer, EVTHREAD_WRITE);
|
||||||
|
|
||||||
|
if (n_read_out)
|
||||||
|
*n_read_out = result ? n_to_copy : 0;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -480,6 +480,24 @@ int
|
|||||||
evbuffer_ptr_set(struct evbuffer *buffer, struct evbuffer_ptr *pos,
|
evbuffer_ptr_set(struct evbuffer *buffer, struct evbuffer_ptr *pos,
|
||||||
size_t position, enum evbuffer_ptr_how how);
|
size_t position, enum evbuffer_ptr_how how);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Search for an end-of-line string within an evbuffer.
|
||||||
|
|
||||||
|
@param buffer the evbuffer to be searched
|
||||||
|
@param start NULL or a pointer to a valid struct evbuffer_ptr to start
|
||||||
|
searching at.
|
||||||
|
@param eol_len_out If non-NULL, the pointed-to value will be set to
|
||||||
|
the length of the end-of-line string.
|
||||||
|
@param eol_style The kind of EOL to look for; see evbuffer_readln() for
|
||||||
|
more information
|
||||||
|
@return a struct evbuffer_ptr whose 'pos' field has the offset of the
|
||||||
|
first occurrence EOL in the buffer after 'start'. The 'pos'
|
||||||
|
field of the result is -1 if the string was not found.
|
||||||
|
*/
|
||||||
|
struct evbuffer_ptr evbuffer_search_eol(struct evbuffer *buffer,
|
||||||
|
struct evbuffer_ptr *start, size_t *eol_len_out,
|
||||||
|
enum evbuffer_eol_style eol_style);
|
||||||
|
|
||||||
/** Structure passed to an evbuffer callback */
|
/** Structure passed to an evbuffer callback */
|
||||||
struct evbuffer_cb_info {
|
struct evbuffer_cb_info {
|
||||||
/** The size of */
|
/** The size of */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user