16d49a12e83a942dc47dee62df7719b4f660e65a
[people/xl0/gpxe.git] / src / core / ebuffer.c
1 /*
2  * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 /**
20  * @file
21  *
22  * Automatically expanding buffers
23  *
24  */
25
26 #include <errno.h>
27 #include <gpxe/buffer.h>
28 #include <gpxe/umalloc.h>
29 #include <gpxe/ebuffer.h>
30
31 /**
32  * Expand expandable buffer
33  *
34  * @v buffer            Buffer descriptor
35  * @v new_len           Required new size
36  * @ret rc              Return status code
37  */
38 static int ebuffer_expand ( struct buffer *buffer, size_t new_len ) {
39         size_t actual_len = 1;
40         userptr_t new_addr;
41
42         /* Round new_len up to the nearest power of two, to reduce
43          * total number of reallocations required.
44          */
45         while ( actual_len < new_len )
46                 actual_len <<= 1;
47
48         /* Reallocate buffer */
49         new_addr = urealloc ( buffer->addr, actual_len );
50         if ( ! new_addr )
51                 return -ENOMEM;
52
53         buffer->addr = new_addr;
54         buffer->len = actual_len;
55         return 0;
56 }
57
58 /**
59  * Allocate expandable buffer
60  *
61  * @v buffer            Buffer descriptor
62  * @v len               Initial length (may be zero)
63  * @ret rc              Return status code
64  *
65  * Allocates space for the buffer and stores it in @c buffer->addr.
66  * The space must eventually be freed by calling ufree(buffer->addr).
67  */
68 int ebuffer_alloc ( struct buffer *buffer, size_t len ) {
69         memset ( buffer, 0, sizeof ( *buffer ) );
70         buffer->expand = ebuffer_expand;
71         return ebuffer_expand ( buffer, len );
72 }