memalloc.c revision 39049
150476Speter/*-
215903Swosch * Copyright (c) 1991, 1993
315903Swosch *	The Regents of the University of California.  All rights reserved.
431074Swosch *
515903Swosch * This code is derived from software contributed to Berkeley by
615903Swosch * Kenneth Almquist.
715903Swosch *
815903Swosch * Redistribution and use in source and binary forms, with or without
915903Swosch * modification, are permitted provided that the following conditions
1015903Swosch * are met:
1115903Swosch * 1. Redistributions of source code must retain the above copyright
1215903Swosch *    notice, this list of conditions and the following disclaimer.
1315903Swosch * 2. Redistributions in binary form must reproduce the above copyright
1415903Swosch *    notice, this list of conditions and the following disclaimer in the
1515903Swosch *    documentation and/or other materials provided with the distribution.
1615903Swosch * 3. All advertising materials mentioning features or use of this software
1715903Swosch *    must display the following acknowledgement:
1815903Swosch *	This product includes software developed by the University of
1915903Swosch *	California, Berkeley and its contributors.
2015903Swosch * 4. Neither the name of the University nor the names of its contributors
2115903Swosch *    may be used to endorse or promote products derived from this software
2274806Sru *    without specific prior written permission.
2315903Swosch *
2415903Swosch * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2523546Swosch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2623546Swosch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2715903Swosch * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2815903Swosch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2915903Swosch * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3015903Swosch * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3115903Swosch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3215903Swosch * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3315903Swosch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3415903Swosch * SUCH DAMAGE.
3515903Swosch */
3620935Swosch
3720935Swosch#ifndef lint
3860749Shoek#if 0
3917511Speterstatic char sccsid[] = "@(#)memalloc.c	8.3 (Berkeley) 5/4/95";
4015903Swosch#endif
4127659Spststatic const char rcsid[] =
4227659Spst	"$Id: memalloc.c,v 1.10 1998/09/06 21:13:09 tegge Exp $";
4327659Spst#endif /* not lint */
4427659Spst
4527659Spst#include "shell.h"
4615903Swosch#include "output.h"
4715903Swosch#include "memalloc.h"
4815903Swosch#include "error.h"
4915903Swosch#include "machdep.h"
5015903Swosch#include "mystring.h"
511638Srgrimes#include "expand.h"
5211468Sbde#include <stdlib.h>
531638Srgrimes#include <unistd.h>
5427659Spst
5527659Spst/*
5672942Sru * Like malloc, but returns an error when out of space.
5727659Spst */
5823546Swosch
5923546Swoschpointer
6011468Sbdeckmalloc(nbytes)
6138898Sjb	int nbytes;
6211468Sbde{
6311623Sbde	pointer p;
6474806Sru
6574806Sru	if ((p = malloc(nbytes)) == NULL)
6674806Sru		error("Out of space");
6711623Sbde	return p;
6874806Sru}
6911623Sbde
7074806Sru
7111623Sbde/*
7211623Sbde * Same for realloc.
7374806Sru */
7411468Sbde
7511468Sbdepointer
7611468Sbdeckrealloc(p, nbytes)
7711623Sbde	pointer p;
7818314Speter	int nbytes;
7918314Speter{
8018314Speter
8118314Speter	if ((p = realloc(p, nbytes)) == NULL)
8218314Speter		error("Out of space");
8318314Speter	return p;
8418314Speter}
8518314Speter
8618314Speter
871844Swollman/*
881638Srgrimes * Make a copy of a string in safe storage.
8917511Speter */
9074806Sru
9174806Sruchar *
9274806Srusavestr(s)
9374806Sru	char *s;
9418314Speter	{
9517511Speter	char *p;
9617511Speter
9717831Speter	p = ckmalloc(strlen(s) + 1);
9817511Speter	scopy(s, p);
9927673Sbde	return p;
10027659Spst}
10127659Spst
10227659Spst
10327659Spst/*
10417511Speter * Parse trees for commands are allocated in lifo order, so we use a stack
10517511Speter * to make this more efficient, and also to avoid all sorts of exception
10617511Speter * handling code to handle interrupts in the middle of a parse.
10717511Speter *
10827659Spst * The size 504 was chosen because the Ultrix malloc handles that size
10974806Sru * well.
11074806Sru */
11127673Sbde
11274806Sru#define MINSIZE 504		/* minimum size of a block */
11327659Spst
11427659Spst
11527659Spststruct stack_block {
11627659Spst	struct stack_block *prev;
11727659Spst	char space[MINSIZE];
11827659Spst};
11927659Spst
12027659Spststruct stack_block stackbase;
12127659Spststruct stack_block *stackp = &stackbase;
12217511Speterchar *stacknxt = stackbase.space;
12311468Sbdeint stacknleft = MINSIZE;
1241844Swollmanint sstrnleft;
12523546Swoschint herefd = -1;
12611136Swollman
12774806Sru
12874806Sru
12974806Srupointer
13074806Srustalloc(nbytes)
13123546Swosch	int nbytes;
13211468Sbde{
13311468Sbde	char *p;
13417831Speter
13523546Swosch	nbytes = ALIGN(nbytes);
13617511Speter	if (nbytes > stacknleft) {
13723546Swosch		int blocksize;
13817511Speter		struct stack_block *sp;
13911136Swollman
14027673Sbde		blocksize = nbytes;
14127659Spst		if (blocksize < MINSIZE)
14227659Spst			blocksize = MINSIZE;
14327659Spst		INTOFF;
14427659Spst		sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
14527659Spst		sp->prev = stackp;
14627659Spst		stacknxt = sp->space;
14727659Spst		stacknleft = blocksize;
14827659Spst		stackp = sp;
14911136Swollman		INTON;
15011468Sbde	}
15111136Swollman	p = stacknxt;
15227659Spst	stacknxt += nbytes;
15311136Swollman	stacknleft -= nbytes;
1541638Srgrimes	return p;
1551844Swollman}
15611623Sbde
15774806Sru
15874806Sruvoid
15911136Swollmanstunalloc(p)
16018314Speter	pointer p;
16174806Sru	{
16227659Spst	if (p == NULL) {		/*DEBUG */
16374806Sru		write(2, "stunalloc\n", 10);
16427673Sbde		abort();
16527659Spst	}
16674806Sru	stacknleft += stacknxt - (char *)p;
16727659Spst	stacknxt = p;
16818314Speter}
16918314Speter
17074806Sru
17174806Sru
17274806Sruvoid
17374806Srusetstackmark(mark)
17474806Sru	struct stackmark *mark;
17574806Sru	{
17674806Sru	mark->stackp = stackp;
17774806Sru	mark->stacknxt = stacknxt;
17874806Sru	mark->stacknleft = stacknleft;
17974806Sru}
18074806Sru
18127673Sbde
18274806Sruvoid
18327659Spstpopstackmark(mark)
18474806Sru	struct stackmark *mark;
18527659Spst	{
18618314Speter	struct stack_block *sp;
18727659Spst
1881844Swollman	INTOFF;
18974806Sru	while (stackp != mark->stackp) {
19074806Sru		sp = stackp;
19174806Sru		stackp = sp->prev;
19227673Sbde		ckfree(sp);
19327659Spst	}
19474806Sru	stacknxt = mark->stacknxt;
19574806Sru	stacknleft = mark->stacknleft;
19627659Spst	INTON;
1971844Swollman}
1981844Swollman
19911468Sbde
20020935Swosch/*
20115902Swosch * When the parser reads in a string, it wants to stick the string on the
20215902Swosch * stack and only adjust the stack pointer when it knows how big the
20315902Swosch * string is.  Stackblock (defined in stack.h) returns a pointer to a block
20415902Swosch * of space on top of the stack and stackblocklen returns the length of
20515902Swosch * this block.  Growstackblock will grow this space by at least one byte,
20615902Swosch * possibly moving it (like realloc).  Grabstackblock actually allocates the
20715902Swosch * part of the block that has been used.
20815902Swosch */
20915902Swosch
21015902Swoschvoid
2112353Sbdegrowstackblock() {
21223546Swosch	char *p;
2131844Swollman	int newlen = ALIGN(stacknleft * 2 + 100);
21415902Swosch	char *oldspace = stacknxt;
21527673Sbde	int oldlen = stacknleft;
21627659Spst	struct stack_block *sp;
21727659Spst
21827659Spst	if (stacknxt == stackp->space && stackp != &stackbase) {
21927659Spst		INTOFF;
22027659Spst		sp = stackp;
22127659Spst		stackp = sp->prev;
22227659Spst		sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
22327659Spst		sp->prev = stackp;
22427659Spst		stackp = sp;
22527659Spst		stacknxt = sp->space;
22627659Spst		stacknleft = newlen;
22727659Spst		INTON;
22827659Spst	} else {
22927659Spst		p = stalloc(newlen);
2301638Srgrimes		memcpy(p, oldspace, oldlen);
23127659Spst		stacknxt = p;			/* free the space */
232		stacknleft += newlen;		/* we just allocated */
233	}
234}
235
236
237
238void
239grabstackblock(len)
240	int len;
241{
242	len = ALIGN(len);
243	stacknxt += len;
244	stacknleft -= len;
245}
246
247
248
249/*
250 * The following routines are somewhat easier to use that the above.
251 * The user declares a variable of type STACKSTR, which may be declared
252 * to be a register.  The macro STARTSTACKSTR initializes things.  Then
253 * the user uses the macro STPUTC to add characters to the string.  In
254 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
255 * grown as necessary.  When the user is done, she can just leave the
256 * string there and refer to it using stackblock().  Or she can allocate
257 * the space for it using grabstackstr().  If it is necessary to allow
258 * someone else to use the stack temporarily and then continue to grow
259 * the string, the user should use grabstack to allocate the space, and
260 * then call ungrabstr(p) to return to the previous mode of operation.
261 *
262 * USTPUTC is like STPUTC except that it doesn't check for overflow.
263 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
264 * is space for at least one character.
265 */
266
267
268char *
269growstackstr() {
270	int len = stackblocksize();
271	if (herefd >= 0 && len >= 1024) {
272		xwrite(herefd, stackblock(), rmquotes(stackblock(), len));
273		sstrnleft = len - 1;
274		return stackblock();
275	}
276	growstackblock();
277	sstrnleft = stackblocksize() - len - 1;
278	return stackblock() + len;
279}
280
281
282/*
283 * Called from CHECKSTRSPACE.
284 */
285
286char *
287makestrspace() {
288	int len = stackblocksize() - sstrnleft;
289	growstackblock();
290	sstrnleft = stackblocksize() - len;
291	return stackblock() + len;
292}
293
294
295
296void
297ungrabstackstr(s, p)
298	char *s;
299	char *p;
300	{
301	stacknleft += stacknxt - s;
302	stacknxt = s;
303	sstrnleft = stacknleft - (p - s);
304}
305