memalloc.c revision 1556
11556Srgrimes/*-
21556Srgrimes * Copyright (c) 1991, 1993
31556Srgrimes *	The Regents of the University of California.  All rights reserved.
41556Srgrimes *
51556Srgrimes * This code is derived from software contributed to Berkeley by
61556Srgrimes * Kenneth Almquist.
71556Srgrimes *
81556Srgrimes * Redistribution and use in source and binary forms, with or without
91556Srgrimes * modification, are permitted provided that the following conditions
101556Srgrimes * are met:
111556Srgrimes * 1. Redistributions of source code must retain the above copyright
121556Srgrimes *    notice, this list of conditions and the following disclaimer.
131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141556Srgrimes *    notice, this list of conditions and the following disclaimer in the
151556Srgrimes *    documentation and/or other materials provided with the distribution.
161556Srgrimes * 3. All advertising materials mentioning features or use of this software
171556Srgrimes *    must display the following acknowledgement:
181556Srgrimes *	This product includes software developed by the University of
191556Srgrimes *	California, Berkeley and its contributors.
201556Srgrimes * 4. Neither the name of the University nor the names of its contributors
211556Srgrimes *    may be used to endorse or promote products derived from this software
221556Srgrimes *    without specific prior written permission.
231556Srgrimes *
241556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341556Srgrimes * SUCH DAMAGE.
351556Srgrimes */
361556Srgrimes
371556Srgrimes#ifndef lint
381556Srgrimesstatic char sccsid[] = "@(#)memalloc.c	8.1 (Berkeley) 5/31/93";
391556Srgrimes#endif /* not lint */
401556Srgrimes
411556Srgrimes#include "shell.h"
421556Srgrimes#include "output.h"
431556Srgrimes#include "memalloc.h"
441556Srgrimes#include "error.h"
451556Srgrimes#include "machdep.h"
461556Srgrimes#include "mystring.h"
471556Srgrimes
481556Srgrimes/*
491556Srgrimes * Like malloc, but returns an error when out of space.
501556Srgrimes */
511556Srgrimes
521556Srgrimespointer
531556Srgrimesckmalloc(nbytes) {
541556Srgrimes	register pointer p;
551556Srgrimes	pointer malloc();
561556Srgrimes
571556Srgrimes	if ((p = malloc(nbytes)) == NULL)
581556Srgrimes		error("Out of space");
591556Srgrimes	return p;
601556Srgrimes}
611556Srgrimes
621556Srgrimes
631556Srgrimes/*
641556Srgrimes * Same for realloc.
651556Srgrimes */
661556Srgrimes
671556Srgrimespointer
681556Srgrimesckrealloc(p, nbytes)
691556Srgrimes	register pointer p;
701556Srgrimes	{
711556Srgrimes	pointer realloc();
721556Srgrimes
731556Srgrimes	if ((p = realloc(p, nbytes)) == NULL)
741556Srgrimes		error("Out of space");
751556Srgrimes	return p;
761556Srgrimes}
771556Srgrimes
781556Srgrimes
791556Srgrimes/*
801556Srgrimes * Make a copy of a string in safe storage.
811556Srgrimes */
821556Srgrimes
831556Srgrimeschar *
841556Srgrimessavestr(s)
851556Srgrimes	char *s;
861556Srgrimes	{
871556Srgrimes	register char *p;
881556Srgrimes
891556Srgrimes	p = ckmalloc(strlen(s) + 1);
901556Srgrimes	scopy(s, p);
911556Srgrimes	return p;
921556Srgrimes}
931556Srgrimes
941556Srgrimes
951556Srgrimes/*
961556Srgrimes * Parse trees for commands are allocated in lifo order, so we use a stack
971556Srgrimes * to make this more efficient, and also to avoid all sorts of exception
981556Srgrimes * handling code to handle interrupts in the middle of a parse.
991556Srgrimes *
1001556Srgrimes * The size 504 was chosen because the Ultrix malloc handles that size
1011556Srgrimes * well.
1021556Srgrimes */
1031556Srgrimes
1041556Srgrimes#define MINSIZE 504		/* minimum size of a block */
1051556Srgrimes
1061556Srgrimes
1071556Srgrimesstruct stack_block {
1081556Srgrimes	struct stack_block *prev;
1091556Srgrimes	char space[MINSIZE];
1101556Srgrimes};
1111556Srgrimes
1121556Srgrimesstruct stack_block stackbase;
1131556Srgrimesstruct stack_block *stackp = &stackbase;
1141556Srgrimeschar *stacknxt = stackbase.space;
1151556Srgrimesint stacknleft = MINSIZE;
1161556Srgrimesint sstrnleft;
1171556Srgrimesint herefd = -1;
1181556Srgrimes
1191556Srgrimes
1201556Srgrimes
1211556Srgrimespointer
1221556Srgrimesstalloc(nbytes) {
1231556Srgrimes	register char *p;
1241556Srgrimes
1251556Srgrimes	nbytes = ALIGN(nbytes);
1261556Srgrimes	if (nbytes > stacknleft) {
1271556Srgrimes		int blocksize;
1281556Srgrimes		struct stack_block *sp;
1291556Srgrimes
1301556Srgrimes		blocksize = nbytes;
1311556Srgrimes		if (blocksize < MINSIZE)
1321556Srgrimes			blocksize = MINSIZE;
1331556Srgrimes		INTOFF;
1341556Srgrimes		sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
1351556Srgrimes		sp->prev = stackp;
1361556Srgrimes		stacknxt = sp->space;
1371556Srgrimes		stacknleft = blocksize;
1381556Srgrimes		stackp = sp;
1391556Srgrimes		INTON;
1401556Srgrimes	}
1411556Srgrimes	p = stacknxt;
1421556Srgrimes	stacknxt += nbytes;
1431556Srgrimes	stacknleft -= nbytes;
1441556Srgrimes	return p;
1451556Srgrimes}
1461556Srgrimes
1471556Srgrimes
1481556Srgrimesvoid
1491556Srgrimesstunalloc(p)
1501556Srgrimes	pointer p;
1511556Srgrimes	{
1521556Srgrimes	if (p == NULL) {		/*DEBUG */
1531556Srgrimes		write(2, "stunalloc\n", 10);
1541556Srgrimes		abort();
1551556Srgrimes	}
1561556Srgrimes	stacknleft += stacknxt - (char *)p;
1571556Srgrimes	stacknxt = p;
1581556Srgrimes}
1591556Srgrimes
1601556Srgrimes
1611556Srgrimes
1621556Srgrimesvoid
1631556Srgrimessetstackmark(mark)
1641556Srgrimes	struct stackmark *mark;
1651556Srgrimes	{
1661556Srgrimes	mark->stackp = stackp;
1671556Srgrimes	mark->stacknxt = stacknxt;
1681556Srgrimes	mark->stacknleft = stacknleft;
1691556Srgrimes}
1701556Srgrimes
1711556Srgrimes
1721556Srgrimesvoid
1731556Srgrimespopstackmark(mark)
1741556Srgrimes	struct stackmark *mark;
1751556Srgrimes	{
1761556Srgrimes	struct stack_block *sp;
1771556Srgrimes
1781556Srgrimes	INTOFF;
1791556Srgrimes	while (stackp != mark->stackp) {
1801556Srgrimes		sp = stackp;
1811556Srgrimes		stackp = sp->prev;
1821556Srgrimes		ckfree(sp);
1831556Srgrimes	}
1841556Srgrimes	stacknxt = mark->stacknxt;
1851556Srgrimes	stacknleft = mark->stacknleft;
1861556Srgrimes	INTON;
1871556Srgrimes}
1881556Srgrimes
1891556Srgrimes
1901556Srgrimes/*
1911556Srgrimes * When the parser reads in a string, it wants to stick the string on the
1921556Srgrimes * stack and only adjust the stack pointer when it knows how big the
1931556Srgrimes * string is.  Stackblock (defined in stack.h) returns a pointer to a block
1941556Srgrimes * of space on top of the stack and stackblocklen returns the length of
1951556Srgrimes * this block.  Growstackblock will grow this space by at least one byte,
1961556Srgrimes * possibly moving it (like realloc).  Grabstackblock actually allocates the
1971556Srgrimes * part of the block that has been used.
1981556Srgrimes */
1991556Srgrimes
2001556Srgrimesvoid
2011556Srgrimesgrowstackblock() {
2021556Srgrimes	char *p;
2031556Srgrimes	int newlen = stacknleft * 2 + 100;
2041556Srgrimes	char *oldspace = stacknxt;
2051556Srgrimes	int oldlen = stacknleft;
2061556Srgrimes	struct stack_block *sp;
2071556Srgrimes
2081556Srgrimes	if (stacknxt == stackp->space && stackp != &stackbase) {
2091556Srgrimes		INTOFF;
2101556Srgrimes		sp = stackp;
2111556Srgrimes		stackp = sp->prev;
2121556Srgrimes		sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
2131556Srgrimes		sp->prev = stackp;
2141556Srgrimes		stackp = sp;
2151556Srgrimes		stacknxt = sp->space;
2161556Srgrimes		stacknleft = newlen;
2171556Srgrimes		INTON;
2181556Srgrimes	} else {
2191556Srgrimes		p = stalloc(newlen);
2201556Srgrimes		bcopy(oldspace, p, oldlen);
2211556Srgrimes		stacknxt = p;			/* free the space */
2221556Srgrimes		stacknleft += newlen;		/* we just allocated */
2231556Srgrimes	}
2241556Srgrimes}
2251556Srgrimes
2261556Srgrimes
2271556Srgrimes
2281556Srgrimesvoid
2291556Srgrimesgrabstackblock(len) {
2301556Srgrimes	len = ALIGN(len);
2311556Srgrimes	stacknxt += len;
2321556Srgrimes	stacknleft -= len;
2331556Srgrimes}
2341556Srgrimes
2351556Srgrimes
2361556Srgrimes
2371556Srgrimes/*
2381556Srgrimes * The following routines are somewhat easier to use that the above.
2391556Srgrimes * The user declares a variable of type STACKSTR, which may be declared
2401556Srgrimes * to be a register.  The macro STARTSTACKSTR initializes things.  Then
2411556Srgrimes * the user uses the macro STPUTC to add characters to the string.  In
2421556Srgrimes * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
2431556Srgrimes * grown as necessary.  When the user is done, she can just leave the
2441556Srgrimes * string there and refer to it using stackblock().  Or she can allocate
2451556Srgrimes * the space for it using grabstackstr().  If it is necessary to allow
2461556Srgrimes * someone else to use the stack temporarily and then continue to grow
2471556Srgrimes * the string, the user should use grabstack to allocate the space, and
2481556Srgrimes * then call ungrabstr(p) to return to the previous mode of operation.
2491556Srgrimes *
2501556Srgrimes * USTPUTC is like STPUTC except that it doesn't check for overflow.
2511556Srgrimes * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
2521556Srgrimes * is space for at least one character.
2531556Srgrimes */
2541556Srgrimes
2551556Srgrimes
2561556Srgrimeschar *
2571556Srgrimesgrowstackstr() {
2581556Srgrimes	int len = stackblocksize();
2591556Srgrimes	if (herefd >= 0 && len >= 1024) {
2601556Srgrimes		xwrite(herefd, stackblock(), len);
2611556Srgrimes		sstrnleft = len - 1;
2621556Srgrimes		return stackblock();
2631556Srgrimes	}
2641556Srgrimes	growstackblock();
2651556Srgrimes	sstrnleft = stackblocksize() - len - 1;
2661556Srgrimes	return stackblock() + len;
2671556Srgrimes}
2681556Srgrimes
2691556Srgrimes
2701556Srgrimes/*
2711556Srgrimes * Called from CHECKSTRSPACE.
2721556Srgrimes */
2731556Srgrimes
2741556Srgrimeschar *
2751556Srgrimesmakestrspace() {
2761556Srgrimes	int len = stackblocksize() - sstrnleft;
2771556Srgrimes	growstackblock();
2781556Srgrimes	sstrnleft = stackblocksize() - len;
2791556Srgrimes	return stackblock() + len;
2801556Srgrimes}
2811556Srgrimes
2821556Srgrimes
2831556Srgrimes
2841556Srgrimesvoid
2851556Srgrimesungrabstackstr(s, p)
2861556Srgrimes	char *s;
2871556Srgrimes	char *p;
2881556Srgrimes	{
2891556Srgrimes	stacknleft += stacknxt - s;
2901556Srgrimes	stacknxt = s;
2911556Srgrimes	sstrnleft = stacknleft - (p - s);
2921556Srgrimes}
293