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