summaryrefslogtreecommitdiffstats
path: root/src/core/linebuf.c
diff options
context:
space:
mode:
authorMichael Brown2015-07-28 17:59:11 +0200
committerMichael Brown2015-07-28 17:59:11 +0200
commit1e4ff872be639e93e8df3918a965bb08675dcc77 (patch)
tree77aed8f6f542ebe09cd66f0871ef4a184b160756 /src/core/linebuf.c
parent[pool] Add a generic concept of a pooled connection (diff)
downloadipxe-1e4ff872be639e93e8df3918a965bb08675dcc77.tar.gz
ipxe-1e4ff872be639e93e8df3918a965bb08675dcc77.tar.xz
ipxe-1e4ff872be639e93e8df3918a965bb08675dcc77.zip
[linebuf] Support buffering of multiple lines
Allow line buffer to accumulate multiple lines, with buffered_line() returning each freshly-completed line as it is encountered. This allows buffered lines to be subsequently processed as a group. Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/core/linebuf.c')
-rw-r--r--src/core/linebuf.c53
1 files changed, 40 insertions, 13 deletions
diff --git a/src/core/linebuf.c b/src/core/linebuf.c
index 7930d19a..c197e383 100644
--- a/src/core/linebuf.c
+++ b/src/core/linebuf.c
@@ -43,7 +43,18 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* @ret line Buffered line, or NULL if no line ready to read
*/
char * buffered_line ( struct line_buffer *linebuf ) {
- return ( linebuf->ready ? linebuf->data : NULL );
+ char *line = &linebuf->data[ linebuf->len ];
+
+ /* Fail unless we have a newly completed line to retrieve */
+ if ( ( linebuf->len == 0 ) || ( linebuf->consumed == 0 ) ||
+ ( *(--line) != '\0' ) )
+ return NULL;
+
+ /* Identify start of line */
+ while ( ( line > linebuf->data ) && ( line[-1] != '\0' ) )
+ line--;
+
+ return line;
}
/**
@@ -52,10 +63,11 @@ char * buffered_line ( struct line_buffer *linebuf ) {
* @v linebuf Line buffer
*/
void empty_line_buffer ( struct line_buffer *linebuf ) {
+
free ( linebuf->data );
linebuf->data = NULL;
linebuf->len = 0;
- linebuf->ready = 0;
+ linebuf->consumed = 0;
}
/**
@@ -76,16 +88,13 @@ void empty_line_buffer ( struct line_buffer *linebuf ) {
* should call empty_line_buffer() before freeing a @c struct @c
* line_buffer.
*/
-ssize_t line_buffer ( struct line_buffer *linebuf,
- const char *data, size_t len ) {
+int line_buffer ( struct line_buffer *linebuf, const char *data, size_t len ) {
const char *eol;
size_t consume;
size_t new_len;
char *new_data;
-
- /* Free any completed line from previous iteration */
- if ( linebuf->ready )
- empty_line_buffer ( linebuf );
+ char *lf;
+ char *cr;
/* Search for line terminator */
if ( ( eol = memchr ( data, '\n', len ) ) ) {
@@ -94,6 +103,10 @@ ssize_t line_buffer ( struct line_buffer *linebuf,
consume = len;
}
+ /* Reject any embedded NULs within the data to be consumed */
+ if ( memchr ( data, '\0', consume ) )
+ return -EINVAL;
+
/* Reallocate data buffer and copy in new data */
new_len = ( linebuf->len + consume );
new_data = realloc ( linebuf->data, ( new_len + 1 ) );
@@ -104,13 +117,27 @@ ssize_t line_buffer ( struct line_buffer *linebuf,
linebuf->data = new_data;
linebuf->len = new_len;
- /* If we have reached end of line, trim the line and mark as ready */
+ /* If we have reached end of line, terminate the line */
if ( eol ) {
- linebuf->data[--linebuf->len] = '\0'; /* trim NL */
- if ( linebuf->data[linebuf->len - 1] == '\r' )
- linebuf->data[--linebuf->len] = '\0'; /* trim CR */
- linebuf->ready = 1;
+
+ /* Overwrite trailing LF (which must exist at this point) */
+ assert ( linebuf->len > 0 );
+ lf = &linebuf->data[ linebuf->len - 1 ];
+ assert ( *lf == '\n' );
+ *lf = '\0';
+
+ /* Trim (and overwrite) trailing CR, if present */
+ if ( linebuf->len > 1 ) {
+ cr = ( lf - 1 );
+ if ( *cr == '\r' ) {
+ linebuf->len--;
+ *cr = '\0';
+ }
+ }
}
+ /* Record consumed length */
+ linebuf->consumed = consume;
+
return consume;
}