memalloc.c revision 127958
1251886Speter/*- 2251886Speter * Copyright (c) 1991, 1993 3251886Speter * The Regents of the University of California. All rights reserved. 4251886Speter * 5251886Speter * This code is derived from software contributed to Berkeley by 6251886Speter * Kenneth Almquist. 7251886Speter * 8251886Speter * Redistribution and use in source and binary forms, with or without 9251886Speter * modification, are permitted provided that the following conditions 10362181Sdim * are met: 11362181Sdim * 1. Redistributions of source code must retain the above copyright 12362181Sdim * notice, this list of conditions and the following disclaimer. 13362181Sdim * 2. Redistributions in binary form must reproduce the above copyright 14251886Speter * notice, this list of conditions and the following disclaimer in the 15362181Sdim * documentation and/or other materials provided with the distribution. 16362181Sdim * 4. Neither the name of the University nor the names of its contributors 17362181Sdim * may be used to endorse or promote products derived from this software 18251886Speter * without specific prior written permission. 19251886Speter * 20251886Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21251886Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22251886Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23251886Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24251886Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25251886Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33#ifndef lint 34#if 0 35static char sccsid[] = "@(#)memalloc.c 8.3 (Berkeley) 5/4/95"; 36#endif 37#endif /* not lint */ 38#include <sys/cdefs.h> 39__FBSDID("$FreeBSD: head/bin/sh/memalloc.c 127958 2004-04-06 20:06:54Z markm $"); 40 41#include <sys/param.h> 42#include "shell.h" 43#include "output.h" 44#include "memalloc.h" 45#include "error.h" 46#include "mystring.h" 47#include "expand.h" 48#include <stdlib.h> 49#include <unistd.h> 50 51/* 52 * Like malloc, but returns an error when out of space. 53 */ 54 55pointer 56ckmalloc(int nbytes) 57{ 58 pointer p; 59 60 if ((p = malloc(nbytes)) == NULL) 61 error("Out of space"); 62 return p; 63} 64 65 66/* 67 * Same for realloc. 68 */ 69 70pointer 71ckrealloc(pointer p, int nbytes) 72{ 73 if ((p = realloc(p, nbytes)) == NULL) 74 error("Out of space"); 75 return p; 76} 77 78 79/* 80 * Make a copy of a string in safe storage. 81 */ 82 83char * 84savestr(char *s) 85{ 86 char *p; 87 88 p = ckmalloc(strlen(s) + 1); 89 scopy(s, p); 90 return p; 91} 92 93 94/* 95 * Parse trees for commands are allocated in lifo order, so we use a stack 96 * to make this more efficient, and also to avoid all sorts of exception 97 * handling code to handle interrupts in the middle of a parse. 98 * 99 * The size 496 was chosen because with 16-byte alignment the total size 100 * for the allocated block is 512. 101 */ 102 103#define MINSIZE 496 /* minimum size of a block. */ 104 105 106struct stack_block { 107 struct stack_block *prev; 108 /* Data follows */ 109}; 110#define SPACE(sp) ((char*)(sp) + ALIGN(sizeof(struct stack_block))) 111 112STATIC struct stack_block *stackp; 113STATIC struct stackmark *markp; 114char *stacknxt; 115int stacknleft; 116int sstrnleft; 117int herefd = -1; 118 119 120static void 121stnewblock(int nbytes) 122{ 123 struct stack_block *sp; 124 int allocsize; 125 126 if (nbytes < MINSIZE) 127 nbytes = MINSIZE; 128 129 allocsize = ALIGN(sizeof(struct stack_block)) + ALIGN(nbytes); 130 131 INTOFF; 132 sp = ckmalloc(allocsize); 133 sp->prev = stackp; 134 stacknxt = SPACE(sp); 135 stacknleft = allocsize - (stacknxt - (char*)sp); 136 stackp = sp; 137 INTON; 138} 139 140 141pointer 142stalloc(int nbytes) 143{ 144 char *p; 145 146 nbytes = ALIGN(nbytes); 147 if (nbytes > stacknleft) 148 stnewblock(nbytes); 149 p = stacknxt; 150 stacknxt += nbytes; 151 stacknleft -= nbytes; 152 return p; 153} 154 155 156void 157stunalloc(pointer p) 158{ 159 if (p == NULL) { /*DEBUG */ 160 write(STDERR_FILENO, "stunalloc\n", 10); 161 abort(); 162 } 163 stacknleft += stacknxt - (char *)p; 164 stacknxt = p; 165} 166 167 168 169void 170setstackmark(struct stackmark *mark) 171{ 172 mark->stackp = stackp; 173 mark->stacknxt = stacknxt; 174 mark->stacknleft = stacknleft; 175 mark->marknext = markp; 176 markp = mark; 177} 178 179 180void 181popstackmark(struct stackmark *mark) 182{ 183 struct stack_block *sp; 184 185 INTOFF; 186 markp = mark->marknext; 187 while (stackp != mark->stackp) { 188 sp = stackp; 189 stackp = sp->prev; 190 ckfree(sp); 191 } 192 stacknxt = mark->stacknxt; 193 stacknleft = mark->stacknleft; 194 INTON; 195} 196 197 198/* 199 * When the parser reads in a string, it wants to stick the string on the 200 * stack and only adjust the stack pointer when it knows how big the 201 * string is. Stackblock (defined in stack.h) returns a pointer to a block 202 * of space on top of the stack and stackblocklen returns the length of 203 * this block. Growstackblock will grow this space by at least one byte, 204 * possibly moving it (like realloc). Grabstackblock actually allocates the 205 * part of the block that has been used. 206 */ 207 208void 209growstackblock(void) 210{ 211 char *p; 212 int newlen; 213 char *oldspace; 214 int oldlen; 215 struct stack_block *sp; 216 struct stack_block *oldstackp; 217 struct stackmark *xmark; 218 219 newlen = (stacknleft == 0) ? MINSIZE : stacknleft * 2 + 100; 220 newlen = ALIGN(newlen); 221 oldspace = stacknxt; 222 oldlen = stacknleft; 223 224 if (stackp != NULL && stacknxt == SPACE(stackp)) { 225 INTOFF; 226 oldstackp = stackp; 227 stackp = oldstackp->prev; 228 sp = ckrealloc((pointer)oldstackp, newlen); 229 sp->prev = stackp; 230 stackp = sp; 231 stacknxt = SPACE(sp); 232 stacknleft = newlen - (stacknxt - (char*)sp); 233 234 /* 235 * Stack marks pointing to the start of the old block 236 * must be relocated to point to the new block 237 */ 238 xmark = markp; 239 while (xmark != NULL && xmark->stackp == oldstackp) { 240 xmark->stackp = stackp; 241 xmark->stacknxt = stacknxt; 242 xmark->stacknleft = stacknleft; 243 xmark = xmark->marknext; 244 } 245 INTON; 246 } else { 247 p = stalloc(newlen); 248 if (oldlen != 0) 249 memcpy(p, oldspace, oldlen); 250 stunalloc(p); 251 } 252} 253 254 255 256void 257grabstackblock(int len) 258{ 259 len = ALIGN(len); 260 stacknxt += len; 261 stacknleft -= len; 262} 263 264 265 266/* 267 * The following routines are somewhat easier to use that the above. 268 * The user declares a variable of type STACKSTR, which may be declared 269 * to be a register. The macro STARTSTACKSTR initializes things. Then 270 * the user uses the macro STPUTC to add characters to the string. In 271 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is 272 * grown as necessary. When the user is done, she can just leave the 273 * string there and refer to it using stackblock(). Or she can allocate 274 * the space for it using grabstackstr(). If it is necessary to allow 275 * someone else to use the stack temporarily and then continue to grow 276 * the string, the user should use grabstack to allocate the space, and 277 * then call ungrabstr(p) to return to the previous mode of operation. 278 * 279 * USTPUTC is like STPUTC except that it doesn't check for overflow. 280 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there 281 * is space for at least one character. 282 */ 283 284 285char * 286growstackstr(void) 287{ 288 int len; 289 290 len = stackblocksize(); 291 if (herefd >= 0 && len >= 1024) { 292 xwrite(herefd, stackblock(), len); 293 sstrnleft = len - 1; 294 return stackblock(); 295 } 296 growstackblock(); 297 sstrnleft = stackblocksize() - len - 1; 298 return stackblock() + len; 299} 300 301 302/* 303 * Called from CHECKSTRSPACE. 304 */ 305 306char * 307makestrspace(void) 308{ 309 int len; 310 311 len = stackblocksize() - sstrnleft; 312 growstackblock(); 313 sstrnleft = stackblocksize() - len; 314 return stackblock() + len; 315} 316 317 318 319void 320ungrabstackstr(char *s, char *p) 321{ 322 stacknleft += stacknxt - s; 323 stacknxt = s; 324 sstrnleft = stacknleft - (p - s); 325} 326