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