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