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