memalloc.c revision 111025
1/*- 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Kenneth Almquist. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37#ifndef lint 38#if 0 39static char sccsid[] = "@(#)memalloc.c 8.3 (Berkeley) 5/4/95"; 40#endif 41#endif /* not lint */ 42#include <sys/cdefs.h> 43__FBSDID("$FreeBSD: head/bin/sh/memalloc.c 111025 2003-02-17 03:51:44Z tjr $"); 44 45#include <sys/param.h> 46 47#include "shell.h" 48#include "output.h" 49#include "memalloc.h" 50#include "error.h" 51#include "mystring.h" 52#include "expand.h" 53#include <stdlib.h> 54#include <unistd.h> 55 56/* 57 * Like malloc, but returns an error when out of space. 58 */ 59 60pointer 61ckmalloc(int nbytes) 62{ 63 pointer p; 64 65 if ((p = malloc(nbytes)) == NULL) 66 error("Out of space"); 67 return p; 68} 69 70 71/* 72 * Same for realloc. 73 */ 74 75pointer 76ckrealloc(pointer p, int nbytes) 77{ 78 if ((p = realloc(p, nbytes)) == NULL) 79 error("Out of space"); 80 return p; 81} 82 83 84/* 85 * Make a copy of a string in safe storage. 86 */ 87 88char * 89savestr(char *s) 90{ 91 char *p; 92 93 p = ckmalloc(strlen(s) + 1); 94 scopy(s, p); 95 return p; 96} 97 98 99/* 100 * Parse trees for commands are allocated in lifo order, so we use a stack 101 * to make this more efficient, and also to avoid all sorts of exception 102 * handling code to handle interrupts in the middle of a parse. 103 * 104 * The size 504 was chosen because the Ultrix malloc handles that size 105 * well. 106 */ 107 108#define MINSIZE 504 /* minimum size of a block */ 109 110 111struct stack_block { 112 struct stack_block *prev; 113 char space[MINSIZE]; 114}; 115 116struct stack_block stackbase; 117struct stack_block *stackp = &stackbase; 118struct stackmark *markp; 119char *stacknxt = stackbase.space; 120int stacknleft = MINSIZE; 121int sstrnleft; 122int herefd = -1; 123 124 125 126pointer 127stalloc(int nbytes) 128{ 129 char *p; 130 131 nbytes = ALIGN(nbytes); 132 if (nbytes > stacknleft) { 133 int blocksize; 134 struct stack_block *sp; 135 136 blocksize = nbytes; 137 if (blocksize < MINSIZE) 138 blocksize = MINSIZE; 139 INTOFF; 140 sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + 141 blocksize); 142 sp->prev = stackp; 143 stacknxt = (char *)ALIGN(sp->space); 144 stacknleft = blocksize - (stacknxt - sp->space); 145 stackp = sp; 146 INTON; 147 } 148 p = stacknxt; 149 stacknxt += nbytes; 150 stacknleft -= nbytes; 151 return p; 152} 153 154 155void 156stunalloc(pointer p) 157{ 158 if (p == NULL) { /*DEBUG */ 159 write(STDERR_FILENO, "stunalloc\n", 10); 160 abort(); 161 } 162 stacknleft += stacknxt - (char *)p; 163 stacknxt = p; 164} 165 166 167 168void 169setstackmark(struct stackmark *mark) 170{ 171 mark->stackp = stackp; 172 mark->stacknxt = stacknxt; 173 mark->stacknleft = stacknleft; 174 mark->marknext = markp; 175 markp = mark; 176} 177 178 179void 180popstackmark(struct stackmark *mark) 181{ 182 struct stack_block *sp; 183 184 INTOFF; 185 markp = mark->marknext; 186 while (stackp != mark->stackp) { 187 sp = stackp; 188 stackp = sp->prev; 189 ckfree(sp); 190 } 191 stacknxt = mark->stacknxt; 192 stacknleft = mark->stacknleft; 193 INTON; 194} 195 196 197/* 198 * When the parser reads in a string, it wants to stick the string on the 199 * stack and only adjust the stack pointer when it knows how big the 200 * string is. Stackblock (defined in stack.h) returns a pointer to a block 201 * of space on top of the stack and stackblocklen returns the length of 202 * this block. Growstackblock will grow this space by at least one byte, 203 * possibly moving it (like realloc). Grabstackblock actually allocates the 204 * part of the block that has been used. 205 */ 206 207void 208growstackblock(void) 209{ 210 char *p; 211 int newlen; 212 char *oldspace; 213 int oldlen; 214 struct stack_block *sp; 215 struct stack_block *oldstackp; 216 217 newlen = ALIGN(stacknleft * 2 + 100); 218 oldspace = stacknxt; 219 oldlen = stacknleft; 220 221 if (stacknxt == stackp->space && stackp != &stackbase) { 222 INTOFF; 223 oldstackp = stackp; 224 sp = stackp; 225 stackp = sp->prev; 226 sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - 227 MINSIZE + newlen); 228 sp->prev = stackp; 229 stackp = sp; 230 stacknxt = sp->space; 231 stacknleft = newlen; 232 { 233 /* Stack marks pointing to the start of the old block 234 * must be relocated to point to the new block 235 */ 236 struct stackmark *xmark; 237 xmark = markp; 238 while (xmark != NULL && xmark->stackp == oldstackp) { 239 xmark->stackp = stackp; 240 xmark->stacknxt = stacknxt; 241 xmark->stacknleft = stacknleft; 242 xmark = xmark->marknext; 243 } 244 } 245 INTON; 246 } else { 247 p = stalloc(newlen); 248 memcpy(p, oldspace, oldlen); 249 stacknxt = p; /* free the space */ 250 stacknleft += newlen; /* we just allocated */ 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