diff --git a/src/core/ebuffer.c b/src/core/ebuffer.c new file mode 100644 index 00000000..5abfca74 --- /dev/null +++ b/src/core/ebuffer.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2007 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/** + * @file + * + * Automatically expanding buffers + * + */ + +#include +#include +#include +#include + +/** + * Expand expandable buffer + * + * @v buffer Buffer descriptor + * @v new_len Required new size + * @ret rc Return status code + */ +static int ebuffer_expand ( struct buffer *buffer, size_t new_len ) { + size_t actual_len = 1; + userptr_t new_addr; + + /* Round new_len up to the nearest power of two, to reduce + * total number of reallocations required. + */ + while ( actual_len < new_len ) + actual_len <<= 1; + + /* Reallocate buffer */ + new_addr = erealloc ( buffer->addr, actual_len ); + if ( ! new_addr ) + return -ENOMEM; + + buffer->addr = new_addr; + buffer->len = actual_len; + return 0; +} + +/** + * Allocate expandable buffer + * + * @v buffer Buffer descriptor + * @v len Initial length (may be zero) + * @ret rc Return status code + * + * Allocates space for the buffer and stores it in @c buffer->addr. + * The space must eventually be freed by calling efree(buffer->addr). + */ +int ebuffer_alloc ( struct buffer *buffer, size_t len ) { + memset ( buffer, 0, sizeof ( *buffer ) ); + buffer->expand = ebuffer_expand; + return ebuffer_expand ( buffer, len ); +} diff --git a/src/include/gpxe/ebuffer.h b/src/include/gpxe/ebuffer.h new file mode 100644 index 00000000..38f18df2 --- /dev/null +++ b/src/include/gpxe/ebuffer.h @@ -0,0 +1,13 @@ +#ifndef _GPXE_EBUFFER_H +#define _GPXE_EBUFFER_H + +/** + * @file + * + * Automatically expanding buffers + * + */ + +extern int ebuffer_alloc ( struct buffer *buffer, size_t len ); + +#endif /* _GPXE_EBUFFER_H */