1/* extendbuf.c -- manage a dynamically-allocated buffer 2 3 Copyright 2004, 2005 Free Software Foundation, Inc. 4 5 This program is free software: you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation, either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. 17*/ 18/* Written by James Yougnman <jay@gnu.org>. */ 19 20#if HAVE_CONFIG_H 21# include <config.h> 22#endif 23 24#include <stddef.h> 25#include <stdlib.h> 26#include <assert.h> 27#include <errno.h> 28 29#include "xalloc.h" 30#include "extendbuf.h" 31 32 33/* We initially use a small default size to ensure that this code 34 * gets exercised. 35 */ 36#ifndef SIZE_DEFAULT 37# define SIZE_DEFAULT 16 38#endif 39 40static size_t 41decide_size(size_t current, size_t wanted) 42{ 43 size_t newsize; 44 45 if (0 == current) 46 newsize = SIZE_DEFAULT; 47 else 48 newsize = current; 49 50 while (newsize < wanted) 51 { 52 if (2 * newsize < newsize) 53 xalloc_die (); 54 newsize *= 2; 55 } 56 return newsize; 57} 58 59 60void * 61extendbuf(void* existing, size_t wanted, size_t *allocated) 62{ 63 int saved_errno; 64 size_t newsize; 65 void *result; /* leave uninitialised to allow static code checkers to identify bugs */ 66 67 saved_errno = errno; 68 69 assert(wanted > 0u); 70 newsize = decide_size(*allocated, wanted); 71 72 if ( (*allocated) == 0 ) 73 { 74 /* Sanity check: If there is no existing allocation size, there 75 * must be no existing allocated buffer. 76 */ 77 assert(NULL == existing); 78 79 (*allocated) = newsize; 80 result = xmalloc(newsize); 81 } 82 else 83 { 84 if (newsize != (*allocated) ) 85 { 86 (*allocated) = newsize; 87 result = xrealloc (existing, newsize); 88 89 } 90 else 91 { 92 result = existing; 93 } 94 } 95 96 if (result) 97 { 98 /* xmalloc() or xrealloc() may have changed errno, but in the 99 success case we want to preserve the previous value. 100 */ 101 errno = saved_errno; 102 } 103 return result; 104} 105