xref: /csrg-svn/bin/sh/memalloc.c (revision 69272)
147127Sbostic /*-
260698Sbostic  * Copyright (c) 1991, 1993
360698Sbostic  *	The Regents of the University of California.  All rights reserved.
447127Sbostic  *
547127Sbostic  * This code is derived from software contributed to Berkeley by
647127Sbostic  * Kenneth Almquist.
747127Sbostic  *
847127Sbostic  * %sccs.include.redist.c%
947127Sbostic  */
1047127Sbostic 
1147127Sbostic #ifndef lint
12*69272Schristos static char sccsid[] = "@(#)memalloc.c	8.3 (Berkeley) 05/04/95";
1347127Sbostic #endif /* not lint */
1447127Sbostic 
1547127Sbostic #include "shell.h"
1647127Sbostic #include "output.h"
1747127Sbostic #include "memalloc.h"
1847127Sbostic #include "error.h"
1947127Sbostic #include "machdep.h"
2047127Sbostic #include "mystring.h"
21*69272Schristos #include <stdlib.h>
22*69272Schristos #include <unistd.h>
2347127Sbostic 
2447127Sbostic /*
2547127Sbostic  * Like malloc, but returns an error when out of space.
2647127Sbostic  */
2747127Sbostic 
2847127Sbostic pointer
ckmalloc(nbytes)29*69272Schristos ckmalloc(nbytes)
30*69272Schristos 	int nbytes;
31*69272Schristos {
3247127Sbostic 	register pointer p;
3347127Sbostic 
3447127Sbostic 	if ((p = malloc(nbytes)) == NULL)
3547127Sbostic 		error("Out of space");
3647127Sbostic 	return p;
3747127Sbostic }
3847127Sbostic 
3947127Sbostic 
4047127Sbostic /*
4147127Sbostic  * Same for realloc.
4247127Sbostic  */
4347127Sbostic 
4447127Sbostic pointer
ckrealloc(p,nbytes)4547127Sbostic ckrealloc(p, nbytes)
4647127Sbostic 	register pointer p;
47*69272Schristos 	int nbytes;
48*69272Schristos {
4947127Sbostic 
5047127Sbostic 	if ((p = realloc(p, nbytes)) == NULL)
5147127Sbostic 		error("Out of space");
5247127Sbostic 	return p;
5347127Sbostic }
5447127Sbostic 
5547127Sbostic 
5647127Sbostic /*
5747127Sbostic  * Make a copy of a string in safe storage.
5847127Sbostic  */
5947127Sbostic 
6047127Sbostic char *
savestr(s)6147127Sbostic savestr(s)
6247127Sbostic 	char *s;
6347127Sbostic 	{
6447127Sbostic 	register char *p;
6547127Sbostic 
6647127Sbostic 	p = ckmalloc(strlen(s) + 1);
6747127Sbostic 	scopy(s, p);
6847127Sbostic 	return p;
6947127Sbostic }
7047127Sbostic 
7147127Sbostic 
7247127Sbostic /*
7347127Sbostic  * Parse trees for commands are allocated in lifo order, so we use a stack
7447127Sbostic  * to make this more efficient, and also to avoid all sorts of exception
7547127Sbostic  * handling code to handle interrupts in the middle of a parse.
7647127Sbostic  *
7747127Sbostic  * The size 504 was chosen because the Ultrix malloc handles that size
7847127Sbostic  * well.
7947127Sbostic  */
8047127Sbostic 
8147127Sbostic #define MINSIZE 504		/* minimum size of a block */
8247127Sbostic 
8347127Sbostic 
8447127Sbostic struct stack_block {
8547127Sbostic 	struct stack_block *prev;
8647127Sbostic 	char space[MINSIZE];
8747127Sbostic };
8847127Sbostic 
8947127Sbostic struct stack_block stackbase;
9047127Sbostic struct stack_block *stackp = &stackbase;
9147127Sbostic char *stacknxt = stackbase.space;
9247127Sbostic int stacknleft = MINSIZE;
9347127Sbostic int sstrnleft;
9447127Sbostic int herefd = -1;
9547127Sbostic 
9647127Sbostic 
9747127Sbostic 
9847127Sbostic pointer
stalloc(nbytes)99*69272Schristos stalloc(nbytes)
100*69272Schristos 	int nbytes;
101*69272Schristos {
10247127Sbostic 	register char *p;
10347127Sbostic 
10447127Sbostic 	nbytes = ALIGN(nbytes);
10547127Sbostic 	if (nbytes > stacknleft) {
10647127Sbostic 		int blocksize;
10747127Sbostic 		struct stack_block *sp;
10847127Sbostic 
10947127Sbostic 		blocksize = nbytes;
11047127Sbostic 		if (blocksize < MINSIZE)
11147127Sbostic 			blocksize = MINSIZE;
11247127Sbostic 		INTOFF;
11347127Sbostic 		sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
11447127Sbostic 		sp->prev = stackp;
11547127Sbostic 		stacknxt = sp->space;
11647127Sbostic 		stacknleft = blocksize;
11747127Sbostic 		stackp = sp;
11847127Sbostic 		INTON;
11947127Sbostic 	}
12047127Sbostic 	p = stacknxt;
12147127Sbostic 	stacknxt += nbytes;
12247127Sbostic 	stacknleft -= nbytes;
12347127Sbostic 	return p;
12447127Sbostic }
12547127Sbostic 
12647127Sbostic 
12747127Sbostic void
stunalloc(p)12847127Sbostic stunalloc(p)
12947127Sbostic 	pointer p;
13047127Sbostic 	{
13147127Sbostic 	if (p == NULL) {		/*DEBUG */
13247127Sbostic 		write(2, "stunalloc\n", 10);
13347127Sbostic 		abort();
13447127Sbostic 	}
13547127Sbostic 	stacknleft += stacknxt - (char *)p;
13647127Sbostic 	stacknxt = p;
13747127Sbostic }
13847127Sbostic 
13947127Sbostic 
14047127Sbostic 
14147127Sbostic void
setstackmark(mark)14247127Sbostic setstackmark(mark)
14347127Sbostic 	struct stackmark *mark;
14447127Sbostic 	{
14547127Sbostic 	mark->stackp = stackp;
14647127Sbostic 	mark->stacknxt = stacknxt;
14747127Sbostic 	mark->stacknleft = stacknleft;
14847127Sbostic }
14947127Sbostic 
15047127Sbostic 
15147127Sbostic void
popstackmark(mark)15247127Sbostic popstackmark(mark)
15347127Sbostic 	struct stackmark *mark;
15447127Sbostic 	{
15547127Sbostic 	struct stack_block *sp;
15647127Sbostic 
15747127Sbostic 	INTOFF;
15847127Sbostic 	while (stackp != mark->stackp) {
15947127Sbostic 		sp = stackp;
16047127Sbostic 		stackp = sp->prev;
16147127Sbostic 		ckfree(sp);
16247127Sbostic 	}
16347127Sbostic 	stacknxt = mark->stacknxt;
16447127Sbostic 	stacknleft = mark->stacknleft;
16547127Sbostic 	INTON;
16647127Sbostic }
16747127Sbostic 
16847127Sbostic 
16947127Sbostic /*
17047127Sbostic  * When the parser reads in a string, it wants to stick the string on the
17147127Sbostic  * stack and only adjust the stack pointer when it knows how big the
17247127Sbostic  * string is.  Stackblock (defined in stack.h) returns a pointer to a block
17347127Sbostic  * of space on top of the stack and stackblocklen returns the length of
17447127Sbostic  * this block.  Growstackblock will grow this space by at least one byte,
17547127Sbostic  * possibly moving it (like realloc).  Grabstackblock actually allocates the
17647127Sbostic  * part of the block that has been used.
17747127Sbostic  */
17847127Sbostic 
17947127Sbostic void
growstackblock()18047127Sbostic growstackblock() {
18147127Sbostic 	char *p;
18247127Sbostic 	int newlen = stacknleft * 2 + 100;
18347127Sbostic 	char *oldspace = stacknxt;
18447127Sbostic 	int oldlen = stacknleft;
18547127Sbostic 	struct stack_block *sp;
18647127Sbostic 
18747296Smarc 	if (stacknxt == stackp->space && stackp != &stackbase) {
18847127Sbostic 		INTOFF;
18947127Sbostic 		sp = stackp;
19047127Sbostic 		stackp = sp->prev;
19147127Sbostic 		sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
19247127Sbostic 		sp->prev = stackp;
19347127Sbostic 		stackp = sp;
19447127Sbostic 		stacknxt = sp->space;
19547127Sbostic 		stacknleft = newlen;
19647127Sbostic 		INTON;
19747127Sbostic 	} else {
19847127Sbostic 		p = stalloc(newlen);
199*69272Schristos 		memcpy(p, oldspace, oldlen);
20047127Sbostic 		stacknxt = p;			/* free the space */
201*69272Schristos 		stacknleft += ALIGN(newlen);	/* we just allocated */
20247127Sbostic 	}
20347127Sbostic }
20447127Sbostic 
20547127Sbostic 
20647127Sbostic 
20747127Sbostic void
grabstackblock(len)208*69272Schristos grabstackblock(len)
209*69272Schristos 	int len;
210*69272Schristos {
21147127Sbostic 	len = ALIGN(len);
21247127Sbostic 	stacknxt += len;
21347127Sbostic 	stacknleft -= len;
21447127Sbostic }
21547127Sbostic 
21647127Sbostic 
21747127Sbostic 
21847127Sbostic /*
21947127Sbostic  * The following routines are somewhat easier to use that the above.
22047127Sbostic  * The user declares a variable of type STACKSTR, which may be declared
22147127Sbostic  * to be a register.  The macro STARTSTACKSTR initializes things.  Then
22247127Sbostic  * the user uses the macro STPUTC to add characters to the string.  In
22347127Sbostic  * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
22447127Sbostic  * grown as necessary.  When the user is done, she can just leave the
22547127Sbostic  * string there and refer to it using stackblock().  Or she can allocate
22647127Sbostic  * the space for it using grabstackstr().  If it is necessary to allow
22747127Sbostic  * someone else to use the stack temporarily and then continue to grow
22847127Sbostic  * the string, the user should use grabstack to allocate the space, and
22947127Sbostic  * then call ungrabstr(p) to return to the previous mode of operation.
23047127Sbostic  *
23147127Sbostic  * USTPUTC is like STPUTC except that it doesn't check for overflow.
23247127Sbostic  * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
23347127Sbostic  * is space for at least one character.
23447127Sbostic  */
23547127Sbostic 
23647127Sbostic 
23747127Sbostic char *
growstackstr()23847127Sbostic growstackstr() {
23947127Sbostic 	int len = stackblocksize();
24047296Smarc 	if (herefd >= 0 && len >= 1024) {
24147127Sbostic 		xwrite(herefd, stackblock(), len);
24247127Sbostic 		sstrnleft = len - 1;
24347127Sbostic 		return stackblock();
24447127Sbostic 	}
24547127Sbostic 	growstackblock();
24647127Sbostic 	sstrnleft = stackblocksize() - len - 1;
24747127Sbostic 	return stackblock() + len;
24847127Sbostic }
24947127Sbostic 
25047127Sbostic 
25147127Sbostic /*
25247127Sbostic  * Called from CHECKSTRSPACE.
25347127Sbostic  */
25447127Sbostic 
25547127Sbostic char *
makestrspace()25647127Sbostic makestrspace() {
25747127Sbostic 	int len = stackblocksize() - sstrnleft;
25847127Sbostic 	growstackblock();
25947127Sbostic 	sstrnleft = stackblocksize() - len;
26047127Sbostic 	return stackblock() + len;
26147127Sbostic }
26247127Sbostic 
26347127Sbostic 
26447127Sbostic 
26547127Sbostic void
ungrabstackstr(s,p)26647127Sbostic ungrabstackstr(s, p)
26747127Sbostic 	char *s;
26847127Sbostic 	char *p;
26947127Sbostic 	{
27047127Sbostic 	stacknleft += stacknxt - s;
27147127Sbostic 	stacknxt = s;
27247127Sbostic 	sstrnleft = stacknleft - (p - s);
27347127Sbostic }
274