memalloc.c revision 213811
11556Srgrimes/*- 21556Srgrimes * Copyright (c) 1991, 1993 31556Srgrimes * The Regents of the University of California. All rights reserved. 41556Srgrimes * 51556Srgrimes * This code is derived from software contributed to Berkeley by 61556Srgrimes * Kenneth Almquist. 71556Srgrimes * 81556Srgrimes * Redistribution and use in source and binary forms, with or without 91556Srgrimes * modification, are permitted provided that the following conditions 101556Srgrimes * are met: 111556Srgrimes * 1. Redistributions of source code must retain the above copyright 121556Srgrimes * notice, this list of conditions and the following disclaimer. 131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141556Srgrimes * notice, this list of conditions and the following disclaimer in the 151556Srgrimes * documentation and/or other materials provided with the distribution. 161556Srgrimes * 4. Neither the name of the University nor the names of its contributors 171556Srgrimes * may be used to endorse or promote products derived from this software 181556Srgrimes * without specific prior written permission. 191556Srgrimes * 201556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301556Srgrimes * SUCH DAMAGE. 311556Srgrimes */ 321556Srgrimes 331556Srgrimes#ifndef lint 341556Srgrimes#if 0 351556Srgrimesstatic char sccsid[] = "@(#)memalloc.c 8.3 (Berkeley) 5/4/95"; 361556Srgrimes#endif 371556Srgrimes#endif /* not lint */ 3836150Scharnier#include <sys/cdefs.h> 3936150Scharnier__FBSDID("$FreeBSD: head/bin/sh/memalloc.c 213811 2010-10-13 22:18:03Z obrien $"); 4036150Scharnier 4136150Scharnier#include <sys/param.h> 4250471Speter#include "shell.h" 431556Srgrimes#include "output.h" 441556Srgrimes#include "memalloc.h" 451556Srgrimes#include "error.h" 461556Srgrimes#include "mystring.h" 471556Srgrimes#include "expand.h" 481556Srgrimes#include <stdlib.h> 491556Srgrimes#include <unistd.h> 501556Srgrimes 5139049Scracauer/* 5217987Speter * Like malloc, but returns an error when out of space. 5317987Speter */ 541556Srgrimes 551556Srgrimespointer 561556Srgrimesckmalloc(size_t nbytes) 571556Srgrimes{ 581556Srgrimes pointer p; 591556Srgrimes 6090111Simp INTOFF; 6117987Speter p = malloc(nbytes); 6225222Ssteve INTON; 631556Srgrimes if (p == NULL) 641556Srgrimes error("Out of space"); 651556Srgrimes return p; 661556Srgrimes} 671556Srgrimes 681556Srgrimes 691556Srgrimes/* 701556Srgrimes * Same for realloc. 711556Srgrimes */ 721556Srgrimes 731556Srgrimespointer 741556Srgrimesckrealloc(pointer p, int nbytes) 7590111Simp{ 7617987Speter INTOFF; 771556Srgrimes p = realloc(p, nbytes); 781556Srgrimes INTON; 791556Srgrimes if (p == NULL) 801556Srgrimes error("Out of space"); 811556Srgrimes return p; 821556Srgrimes} 831556Srgrimes 841556Srgrimesvoid 851556Srgrimesckfree(pointer p) 861556Srgrimes{ 871556Srgrimes INTOFF; 8890111Simp free(p); 8945618Scracauer INTON; 9025222Ssteve} 911556Srgrimes 921556Srgrimes 931556Srgrimes/* 941556Srgrimes * Make a copy of a string in safe storage. 951556Srgrimes */ 961556Srgrimes 971556Srgrimeschar * 981556Srgrimessavestr(const char *s) 991556Srgrimes{ 1001556Srgrimes char *p; 1011556Srgrimes 1021556Srgrimes p = ckmalloc(strlen(s) + 1); 1031556Srgrimes scopy(s, p); 1041556Srgrimes return p; 1051556Srgrimes} 1061556Srgrimes 1071556Srgrimes 1081556Srgrimes/* 1091556Srgrimes * Parse trees for commands are allocated in lifo order, so we use a stack 1101556Srgrimes * to make this more efficient, and also to avoid all sorts of exception 1111556Srgrimes * handling code to handle interrupts in the middle of a parse. 1121556Srgrimes * 1131556Srgrimes * The size 496 was chosen because with 16-byte alignment the total size 1141556Srgrimes * for the allocated block is 512. 1151556Srgrimes */ 1161556Srgrimes 11764702Scracauer#define MINSIZE 496 /* minimum size of a block. */ 1181556Srgrimes 1191556Srgrimes 1201556Srgrimesstruct stack_block { 1211556Srgrimes struct stack_block *prev; 1221556Srgrimes /* Data follows */ 1231556Srgrimes}; 1241556Srgrimes#define SPACE(sp) ((char*)(sp) + ALIGN(sizeof(struct stack_block))) 1251556Srgrimes 12690111Simpstatic struct stack_block *stackp; 12717987Speterstatic struct stackmark *markp; 12825222Sstevechar *stacknxt; 1291556Srgrimesint stacknleft; 1301556Srgrimesint sstrnleft; 1311556Srgrimesint herefd = -1; 1321556Srgrimes 1331556Srgrimes 1341556Srgrimesstatic void 1351556Srgrimesstnewblock(int nbytes) 1361556Srgrimes{ 1371556Srgrimes struct stack_block *sp; 1381556Srgrimes int allocsize; 13945618Scracauer 14045618Scracauer if (nbytes < MINSIZE) 1411556Srgrimes nbytes = MINSIZE; 1421556Srgrimes 1431556Srgrimes allocsize = ALIGN(sizeof(struct stack_block)) + ALIGN(nbytes); 1441556Srgrimes 1451556Srgrimes INTOFF; 1461556Srgrimes sp = ckmalloc(allocsize); 1471556Srgrimes sp->prev = stackp; 1481556Srgrimes stacknxt = SPACE(sp); 1491556Srgrimes stacknleft = allocsize - (stacknxt - (char*)sp); 1501556Srgrimes stackp = sp; 1511556Srgrimes INTON; 1521556Srgrimes} 1531556Srgrimes 1541556Srgrimes 15590111Simppointer 15645618Scracauerstalloc(int nbytes) 1571556Srgrimes{ 15880381Ssheldonh char *p; 1591556Srgrimes 1601556Srgrimes nbytes = ALIGN(nbytes); 1611556Srgrimes if (nbytes > stacknleft) 1621556Srgrimes stnewblock(nbytes); 1631556Srgrimes p = stacknxt; 1641556Srgrimes stacknxt += nbytes; 1651556Srgrimes stacknleft -= nbytes; 1661556Srgrimes return p; 1671556Srgrimes} 16890111Simp 16945618Scracauer 1701556Srgrimesvoid 1711556Srgrimesstunalloc(pointer p) 1721556Srgrimes{ 17364702Scracauer if (p == NULL) { /*DEBUG */ 17464702Scracauer write(STDERR_FILENO, "stunalloc\n", 10); 1751556Srgrimes abort(); 1761556Srgrimes } 1771556Srgrimes stacknleft += stacknxt - (char *)p; 1781556Srgrimes stacknxt = p; 17990111Simp} 18045618Scracauer 1811556Srgrimes 1821556Srgrimes 1831556Srgrimesvoid 18464702Scracauersetstackmark(struct stackmark *mark) 1851556Srgrimes{ 1861556Srgrimes mark->stackp = stackp; 1871556Srgrimes mark->stacknxt = stacknxt; 1881556Srgrimes mark->stacknleft = stacknleft; 1891556Srgrimes mark->marknext = markp; 1901556Srgrimes markp = mark; 1911556Srgrimes} 1921556Srgrimes 1931556Srgrimes 1941556Srgrimesvoid 1951556Srgrimespopstackmark(struct stackmark *mark) 1961556Srgrimes{ 1971556Srgrimes struct stack_block *sp; 1981556Srgrimes 1991556Srgrimes INTOFF; 2001556Srgrimes markp = mark->marknext; 2011556Srgrimes while (stackp != mark->stackp) { 2021556Srgrimes sp = stackp; 2031556Srgrimes stackp = sp->prev; 2041556Srgrimes ckfree(sp); 2051556Srgrimes } 2061556Srgrimes stacknxt = mark->stacknxt; 20790111Simp stacknleft = mark->stacknleft; 20845618Scracauer INTON; 2091556Srgrimes} 21045618Scracauer 21145618Scracauer 21245618Scracauer/* 2131556Srgrimes * When the parser reads in a string, it wants to stick the string on the 21464702Scracauer * stack and only adjust the stack pointer when it knows how big the 2151556Srgrimes * string is. Stackblock (defined in stack.h) returns a pointer to a block 21645618Scracauer * of space on top of the stack and stackblocklen returns the length of 21745618Scracauer * this block. Growstackblock will grow this space by at least one byte, 21845618Scracauer * possibly moving it (like realloc). Grabstackblock actually allocates the 21945618Scracauer * part of the block that has been used. 2201556Srgrimes */ 2211556Srgrimes 22264702Scracauervoid 2231556Srgrimesgrowstackblock(void) 2241556Srgrimes{ 22545618Scracauer char *p; 22645618Scracauer int newlen; 2271556Srgrimes char *oldspace; 2281556Srgrimes int oldlen; 2291556Srgrimes struct stack_block *sp; 2301556Srgrimes struct stack_block *oldstackp; 23164702Scracauer struct stackmark *xmark; 23264702Scracauer 23364702Scracauer newlen = (stacknleft == 0) ? MINSIZE : stacknleft * 2 + 100; 23464702Scracauer newlen = ALIGN(newlen); 23564702Scracauer oldspace = stacknxt; 23664702Scracauer oldlen = stacknleft; 23764702Scracauer 23864702Scracauer if (stackp != NULL && stacknxt == SPACE(stackp)) { 23964702Scracauer INTOFF; 24064702Scracauer oldstackp = stackp; 24164702Scracauer stackp = oldstackp->prev; 24264702Scracauer sp = ckrealloc((pointer)oldstackp, newlen); 24364702Scracauer sp->prev = stackp; 2441556Srgrimes stackp = sp; 2451556Srgrimes stacknxt = SPACE(sp); 2461556Srgrimes stacknleft = newlen - (stacknxt - (char*)sp); 24717987Speter 2481556Srgrimes /* 24918018Speter * Stack marks pointing to the start of the old block 2501556Srgrimes * must be relocated to point to the new block 2511556Srgrimes */ 2521556Srgrimes xmark = markp; 2531556Srgrimes while (xmark != NULL && xmark->stackp == oldstackp) { 2541556Srgrimes xmark->stackp = stackp; 2551556Srgrimes xmark->stacknxt = stacknxt; 25690111Simp xmark->stacknleft = stacknleft; 25717987Speter xmark = xmark->marknext; 2581556Srgrimes } 2591556Srgrimes INTON; 2601556Srgrimes } else { 2611556Srgrimes p = stalloc(newlen); 2621556Srgrimes if (oldlen != 0) 2631556Srgrimes memcpy(p, oldspace, oldlen); 2641556Srgrimes stunalloc(p); 2651556Srgrimes } 2661556Srgrimes} 2671556Srgrimes 2681556Srgrimes 2691556Srgrimes 2701556Srgrimesvoid 2711556Srgrimesgrabstackblock(int len) 2721556Srgrimes{ 2731556Srgrimes len = ALIGN(len); 2741556Srgrimes stacknxt += len; 2751556Srgrimes stacknleft -= len; 2761556Srgrimes} 2771556Srgrimes 2781556Srgrimes 2791556Srgrimes 2801556Srgrimes/* 2811556Srgrimes * The following routines are somewhat easier to use that the above. 2821556Srgrimes * The user declares a variable of type STACKSTR, which may be declared 2831556Srgrimes * to be a register. The macro STARTSTACKSTR initializes things. Then 2841556Srgrimes * the user uses the macro STPUTC to add characters to the string. In 28590111Simp * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is 28645618Scracauer * grown as necessary. When the user is done, she can just leave the 28745618Scracauer * string there and refer to it using stackblock(). Or she can allocate 28845618Scracauer * the space for it using grabstackstr(). If it is necessary to allow 28945618Scracauer * someone else to use the stack temporarily and then continue to grow 2901556Srgrimes * the string, the user should use grabstack to allocate the space, and 29139137Stegge * then call ungrabstr(p) to return to the previous mode of operation. 2921556Srgrimes * 2931556Srgrimes * USTPUTC is like STPUTC except that it doesn't check for overflow. 2941556Srgrimes * CHECKSTACKSPACE can be called before USTPUTC to ensure that there 2951556Srgrimes * is space for at least one character. 2961556Srgrimes */ 2971556Srgrimes 2981556Srgrimes 2991556Srgrimeschar * 3001556Srgrimesgrowstackstr(void) 3011556Srgrimes{ 3021556Srgrimes int len; 3031556Srgrimes 3041556Srgrimes len = stackblocksize(); 3051556Srgrimes if (herefd >= 0 && len >= 1024) { 30690111Simp xwrite(herefd, stackblock(), len); 30745618Scracauer sstrnleft = len - 1; 30845618Scracauer return stackblock(); 30945618Scracauer } 31045618Scracauer growstackblock(); 3111556Srgrimes sstrnleft = stackblocksize() - len - 1; 3121556Srgrimes return stackblock() + len; 3131556Srgrimes} 3141556Srgrimes 3151556Srgrimes 3161556Srgrimes/* 3171556Srgrimes * Called from CHECKSTRSPACE. 3181556Srgrimes */ 31990111Simp 32045618Scracauerchar * 3211556Srgrimesmakestrspace(void) 3221556Srgrimes{ 3231556Srgrimes int len; 3241556Srgrimes 325 len = stackblocksize() - sstrnleft; 326 growstackblock(); 327 sstrnleft = stackblocksize() - len; 328 return stackblock() + len; 329} 330 331 332 333void 334ungrabstackstr(char *s, char *p) 335{ 336 stacknleft += stacknxt - s; 337 stacknxt = s; 338 sstrnleft = stacknleft - (p - s); 339} 340