memalloc.c revision 216387
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 * 4. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * 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 216387 2010-12-12 00:07:27Z jilles $"); 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(size_t nbytes) 57{ 58 pointer p; 59 60 INTOFF; 61 p = malloc(nbytes); 62 INTON; 63 if (p == NULL) 64 error("Out of space"); 65 return p; 66} 67 68 69/* 70 * Same for realloc. 71 */ 72 73pointer 74ckrealloc(pointer p, int nbytes) 75{ 76 INTOFF; 77 p = realloc(p, nbytes); 78 INTON; 79 if (p == NULL) 80 error("Out of space"); 81 return p; 82} 83 84void 85ckfree(pointer p) 86{ 87 INTOFF; 88 free(p); 89 INTON; 90} 91 92 93/* 94 * Make a copy of a string in safe storage. 95 */ 96 97char * 98savestr(const char *s) 99{ 100 char *p; 101 102 p = ckmalloc(strlen(s) + 1); 103 scopy(s, p); 104 return p; 105} 106 107 108/* 109 * Parse trees for commands are allocated in lifo order, so we use a stack 110 * to make this more efficient, and also to avoid all sorts of exception 111 * handling code to handle interrupts in the middle of a parse. 112 * 113 * The size 496 was chosen because with 16-byte alignment the total size 114 * for the allocated block is 512. 115 */ 116 117#define MINSIZE 496 /* minimum size of a block. */ 118 119 120struct stack_block { 121 struct stack_block *prev; 122 /* Data follows */ 123}; 124#define SPACE(sp) ((char*)(sp) + ALIGN(sizeof(struct stack_block))) 125 126static struct stack_block *stackp; 127static struct stackmark *markp; 128char *stacknxt; 129int stacknleft; 130int sstrnleft; 131 132 133static void 134stnewblock(int nbytes) 135{ 136 struct stack_block *sp; 137 int allocsize; 138 139 if (nbytes < MINSIZE) 140 nbytes = MINSIZE; 141 142 allocsize = ALIGN(sizeof(struct stack_block)) + ALIGN(nbytes); 143 144 INTOFF; 145 sp = ckmalloc(allocsize); 146 sp->prev = stackp; 147 stacknxt = SPACE(sp); 148 stacknleft = allocsize - (stacknxt - (char*)sp); 149 stackp = sp; 150 INTON; 151} 152 153 154pointer 155stalloc(int nbytes) 156{ 157 char *p; 158 159 nbytes = ALIGN(nbytes); 160 if (nbytes > stacknleft) 161 stnewblock(nbytes); 162 p = stacknxt; 163 stacknxt += nbytes; 164 stacknleft -= nbytes; 165 return p; 166} 167 168 169void 170stunalloc(pointer p) 171{ 172 if (p == NULL) { /*DEBUG */ 173 write(STDERR_FILENO, "stunalloc\n", 10); 174 abort(); 175 } 176 stacknleft += stacknxt - (char *)p; 177 stacknxt = p; 178} 179 180 181 182void 183setstackmark(struct stackmark *mark) 184{ 185 mark->stackp = stackp; 186 mark->stacknxt = stacknxt; 187 mark->stacknleft = stacknleft; 188 mark->marknext = markp; 189 markp = mark; 190} 191 192 193void 194popstackmark(struct stackmark *mark) 195{ 196 struct stack_block *sp; 197 198 INTOFF; 199 markp = mark->marknext; 200 while (stackp != mark->stackp) { 201 sp = stackp; 202 stackp = sp->prev; 203 ckfree(sp); 204 } 205 stacknxt = mark->stacknxt; 206 stacknleft = mark->stacknleft; 207 INTON; 208} 209 210 211/* 212 * When the parser reads in a string, it wants to stick the string on the 213 * stack and only adjust the stack pointer when it knows how big the 214 * string is. Stackblock (defined in stack.h) returns a pointer to a block 215 * of space on top of the stack and stackblocklen returns the length of 216 * this block. Growstackblock will grow this space by at least one byte, 217 * possibly moving it (like realloc). Grabstackblock actually allocates the 218 * part of the block that has been used. 219 */ 220 221void 222growstackblock(void) 223{ 224 char *p; 225 int newlen; 226 char *oldspace; 227 int oldlen; 228 struct stack_block *sp; 229 struct stack_block *oldstackp; 230 struct stackmark *xmark; 231 232 newlen = (stacknleft == 0) ? MINSIZE : stacknleft * 2 + 100; 233 newlen = ALIGN(newlen); 234 oldspace = stacknxt; 235 oldlen = stacknleft; 236 237 if (stackp != NULL && stacknxt == SPACE(stackp)) { 238 INTOFF; 239 oldstackp = stackp; 240 stackp = oldstackp->prev; 241 sp = ckrealloc((pointer)oldstackp, newlen); 242 sp->prev = stackp; 243 stackp = sp; 244 stacknxt = SPACE(sp); 245 stacknleft = newlen - (stacknxt - (char*)sp); 246 247 /* 248 * Stack marks pointing to the start of the old block 249 * must be relocated to point to the new block 250 */ 251 xmark = markp; 252 while (xmark != NULL && xmark->stackp == oldstackp) { 253 xmark->stackp = stackp; 254 xmark->stacknxt = stacknxt; 255 xmark->stacknleft = stacknleft; 256 xmark = xmark->marknext; 257 } 258 INTON; 259 } else { 260 p = stalloc(newlen); 261 if (oldlen != 0) 262 memcpy(p, oldspace, oldlen); 263 stunalloc(p); 264 } 265} 266 267 268 269void 270grabstackblock(int len) 271{ 272 len = ALIGN(len); 273 stacknxt += len; 274 stacknleft -= len; 275} 276 277 278 279/* 280 * The following routines are somewhat easier to use that the above. 281 * The user declares a variable of type STACKSTR, which may be declared 282 * to be a register. The macro STARTSTACKSTR initializes things. Then 283 * the user uses the macro STPUTC to add characters to the string. In 284 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is 285 * grown as necessary. When the user is done, she can just leave the 286 * string there and refer to it using stackblock(). Or she can allocate 287 * the space for it using grabstackstr(). If it is necessary to allow 288 * someone else to use the stack temporarily and then continue to grow 289 * the string, the user should use grabstack to allocate the space, and 290 * then call ungrabstr(p) to return to the previous mode of operation. 291 * 292 * USTPUTC is like STPUTC except that it doesn't check for overflow. 293 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there 294 * is space for at least one character. 295 */ 296 297static char * 298growstrstackblock(int n) 299{ 300 growstackblock(); 301 sstrnleft = stackblocksize() - n; 302 return stackblock() + n; 303} 304 305char * 306growstackstr(void) 307{ 308 int len; 309 310 len = stackblocksize(); 311 return growstrstackblock(len); 312} 313 314 315/* 316 * Called from CHECKSTRSPACE. 317 */ 318 319char * 320makestrspace(void) 321{ 322 int len; 323 324 len = stackblocksize() - sstrnleft; 325 return growstrstackblock(len); 326} 327 328 329 330void 331ungrabstackstr(char *s, char *p) 332{ 333 stacknleft += stacknxt - s; 334 stacknxt = s; 335 sstrnleft = stacknleft - (p - s); 336} 337 338 339char * 340stputbin(const char *data, int len, char *p) 341{ 342 int i; 343 344 for (i = 0; i < len; i++) 345 STPUTC(data[i], p); 346 return (p); 347} 348 349char * 350stputs(const char *data, char *p) 351{ 352 return (stputbin(data, strlen(data), p)); 353} 354