xref: /minix3/bin/sh/memalloc.c (revision d90bee97498b3043241050f61aed100786c59df4)
1*d90bee97SLionel Sambuc /*	$NetBSD: memalloc.c,v 1.29 2008/02/15 17:26:06 matt Exp $	*/
2*d90bee97SLionel Sambuc 
3*d90bee97SLionel Sambuc /*-
4*d90bee97SLionel Sambuc  * Copyright (c) 1991, 1993
5*d90bee97SLionel Sambuc  *	The Regents of the University of California.  All rights reserved.
6*d90bee97SLionel Sambuc  *
7*d90bee97SLionel Sambuc  * This code is derived from software contributed to Berkeley by
8*d90bee97SLionel Sambuc  * Kenneth Almquist.
9*d90bee97SLionel Sambuc  *
10*d90bee97SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
11*d90bee97SLionel Sambuc  * modification, are permitted provided that the following conditions
12*d90bee97SLionel Sambuc  * are met:
13*d90bee97SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
14*d90bee97SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
15*d90bee97SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
16*d90bee97SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
17*d90bee97SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
18*d90bee97SLionel Sambuc  * 3. Neither the name of the University nor the names of its contributors
19*d90bee97SLionel Sambuc  *    may be used to endorse or promote products derived from this software
20*d90bee97SLionel Sambuc  *    without specific prior written permission.
21*d90bee97SLionel Sambuc  *
22*d90bee97SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23*d90bee97SLionel Sambuc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24*d90bee97SLionel Sambuc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25*d90bee97SLionel Sambuc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26*d90bee97SLionel Sambuc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27*d90bee97SLionel Sambuc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28*d90bee97SLionel Sambuc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29*d90bee97SLionel Sambuc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30*d90bee97SLionel Sambuc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31*d90bee97SLionel Sambuc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32*d90bee97SLionel Sambuc  * SUCH DAMAGE.
33*d90bee97SLionel Sambuc  */
34*d90bee97SLionel Sambuc 
35*d90bee97SLionel Sambuc #include <sys/cdefs.h>
36*d90bee97SLionel Sambuc #ifndef lint
37*d90bee97SLionel Sambuc #if 0
38*d90bee97SLionel Sambuc static char sccsid[] = "@(#)memalloc.c	8.3 (Berkeley) 5/4/95";
39*d90bee97SLionel Sambuc #else
40*d90bee97SLionel Sambuc __RCSID("$NetBSD: memalloc.c,v 1.29 2008/02/15 17:26:06 matt Exp $");
41*d90bee97SLionel Sambuc #endif
42*d90bee97SLionel Sambuc #endif /* not lint */
43*d90bee97SLionel Sambuc 
44*d90bee97SLionel Sambuc #include <stdlib.h>
45*d90bee97SLionel Sambuc #include <unistd.h>
46*d90bee97SLionel Sambuc 
47*d90bee97SLionel Sambuc #include "shell.h"
48*d90bee97SLionel Sambuc #include "output.h"
49*d90bee97SLionel Sambuc #include "memalloc.h"
50*d90bee97SLionel Sambuc #include "error.h"
51*d90bee97SLionel Sambuc #include "machdep.h"
52*d90bee97SLionel Sambuc #include "mystring.h"
53*d90bee97SLionel Sambuc 
54*d90bee97SLionel Sambuc /*
55*d90bee97SLionel Sambuc  * Like malloc, but returns an error when out of space.
56*d90bee97SLionel Sambuc  */
57*d90bee97SLionel Sambuc 
58*d90bee97SLionel Sambuc pointer
ckmalloc(size_t nbytes)59*d90bee97SLionel Sambuc ckmalloc(size_t nbytes)
60*d90bee97SLionel Sambuc {
61*d90bee97SLionel Sambuc 	pointer p;
62*d90bee97SLionel Sambuc 
63*d90bee97SLionel Sambuc 	p = malloc(nbytes);
64*d90bee97SLionel Sambuc 	if (p == NULL)
65*d90bee97SLionel Sambuc 		error("Out of space");
66*d90bee97SLionel Sambuc 	return p;
67*d90bee97SLionel Sambuc }
68*d90bee97SLionel Sambuc 
69*d90bee97SLionel Sambuc 
70*d90bee97SLionel Sambuc /*
71*d90bee97SLionel Sambuc  * Same for realloc.
72*d90bee97SLionel Sambuc  */
73*d90bee97SLionel Sambuc 
74*d90bee97SLionel Sambuc pointer
ckrealloc(pointer p,int nbytes)75*d90bee97SLionel Sambuc ckrealloc(pointer p, int nbytes)
76*d90bee97SLionel Sambuc {
77*d90bee97SLionel Sambuc 	p = realloc(p, nbytes);
78*d90bee97SLionel Sambuc 	if (p == NULL)
79*d90bee97SLionel Sambuc 		error("Out of space");
80*d90bee97SLionel Sambuc 	return p;
81*d90bee97SLionel Sambuc }
82*d90bee97SLionel Sambuc 
83*d90bee97SLionel Sambuc 
84*d90bee97SLionel Sambuc /*
85*d90bee97SLionel Sambuc  * Make a copy of a string in safe storage.
86*d90bee97SLionel Sambuc  */
87*d90bee97SLionel Sambuc 
88*d90bee97SLionel Sambuc char *
savestr(const char * s)89*d90bee97SLionel Sambuc savestr(const char *s)
90*d90bee97SLionel Sambuc {
91*d90bee97SLionel Sambuc 	char *p;
92*d90bee97SLionel Sambuc 
93*d90bee97SLionel Sambuc 	p = ckmalloc(strlen(s) + 1);
94*d90bee97SLionel Sambuc 	scopy(s, p);
95*d90bee97SLionel Sambuc 	return p;
96*d90bee97SLionel Sambuc }
97*d90bee97SLionel Sambuc 
98*d90bee97SLionel Sambuc 
99*d90bee97SLionel Sambuc /*
100*d90bee97SLionel Sambuc  * Parse trees for commands are allocated in lifo order, so we use a stack
101*d90bee97SLionel Sambuc  * to make this more efficient, and also to avoid all sorts of exception
102*d90bee97SLionel Sambuc  * handling code to handle interrupts in the middle of a parse.
103*d90bee97SLionel Sambuc  *
104*d90bee97SLionel Sambuc  * The size 504 was chosen because the Ultrix malloc handles that size
105*d90bee97SLionel Sambuc  * well.
106*d90bee97SLionel Sambuc  */
107*d90bee97SLionel Sambuc 
108*d90bee97SLionel Sambuc #define MINSIZE 504		/* minimum size of a block */
109*d90bee97SLionel Sambuc 
110*d90bee97SLionel Sambuc struct stack_block {
111*d90bee97SLionel Sambuc 	struct stack_block *prev;
112*d90bee97SLionel Sambuc 	char space[MINSIZE];
113*d90bee97SLionel Sambuc };
114*d90bee97SLionel Sambuc 
115*d90bee97SLionel Sambuc struct stack_block stackbase;
116*d90bee97SLionel Sambuc struct stack_block *stackp = &stackbase;
117*d90bee97SLionel Sambuc struct stackmark *markp;
118*d90bee97SLionel Sambuc char *stacknxt = stackbase.space;
119*d90bee97SLionel Sambuc int stacknleft = MINSIZE;
120*d90bee97SLionel Sambuc int sstrnleft;
121*d90bee97SLionel Sambuc int herefd = -1;
122*d90bee97SLionel Sambuc 
123*d90bee97SLionel Sambuc pointer
stalloc(int nbytes)124*d90bee97SLionel Sambuc stalloc(int nbytes)
125*d90bee97SLionel Sambuc {
126*d90bee97SLionel Sambuc 	char *p;
127*d90bee97SLionel Sambuc 
128*d90bee97SLionel Sambuc 	nbytes = SHELL_ALIGN(nbytes);
129*d90bee97SLionel Sambuc 	if (nbytes > stacknleft) {
130*d90bee97SLionel Sambuc 		int blocksize;
131*d90bee97SLionel Sambuc 		struct stack_block *sp;
132*d90bee97SLionel Sambuc 
133*d90bee97SLionel Sambuc 		blocksize = nbytes;
134*d90bee97SLionel Sambuc 		if (blocksize < MINSIZE)
135*d90bee97SLionel Sambuc 			blocksize = MINSIZE;
136*d90bee97SLionel Sambuc 		INTOFF;
137*d90bee97SLionel Sambuc 		sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
138*d90bee97SLionel Sambuc 		sp->prev = stackp;
139*d90bee97SLionel Sambuc 		stacknxt = sp->space;
140*d90bee97SLionel Sambuc 		stacknleft = blocksize;
141*d90bee97SLionel Sambuc 		stackp = sp;
142*d90bee97SLionel Sambuc 		INTON;
143*d90bee97SLionel Sambuc 	}
144*d90bee97SLionel Sambuc 	p = stacknxt;
145*d90bee97SLionel Sambuc 	stacknxt += nbytes;
146*d90bee97SLionel Sambuc 	stacknleft -= nbytes;
147*d90bee97SLionel Sambuc 	return p;
148*d90bee97SLionel Sambuc }
149*d90bee97SLionel Sambuc 
150*d90bee97SLionel Sambuc 
151*d90bee97SLionel Sambuc void
stunalloc(pointer p)152*d90bee97SLionel Sambuc stunalloc(pointer p)
153*d90bee97SLionel Sambuc {
154*d90bee97SLionel Sambuc 	if (p == NULL) {		/*DEBUG */
155*d90bee97SLionel Sambuc 		write(2, "stunalloc\n", 10);
156*d90bee97SLionel Sambuc 		abort();
157*d90bee97SLionel Sambuc 	}
158*d90bee97SLionel Sambuc 	stacknleft += stacknxt - (char *)p;
159*d90bee97SLionel Sambuc 	stacknxt = p;
160*d90bee97SLionel Sambuc }
161*d90bee97SLionel Sambuc 
162*d90bee97SLionel Sambuc 
163*d90bee97SLionel Sambuc 
164*d90bee97SLionel Sambuc void
setstackmark(struct stackmark * mark)165*d90bee97SLionel Sambuc setstackmark(struct stackmark *mark)
166*d90bee97SLionel Sambuc {
167*d90bee97SLionel Sambuc 	mark->stackp = stackp;
168*d90bee97SLionel Sambuc 	mark->stacknxt = stacknxt;
169*d90bee97SLionel Sambuc 	mark->stacknleft = stacknleft;
170*d90bee97SLionel Sambuc 	mark->marknext = markp;
171*d90bee97SLionel Sambuc 	markp = mark;
172*d90bee97SLionel Sambuc }
173*d90bee97SLionel Sambuc 
174*d90bee97SLionel Sambuc 
175*d90bee97SLionel Sambuc void
popstackmark(struct stackmark * mark)176*d90bee97SLionel Sambuc popstackmark(struct stackmark *mark)
177*d90bee97SLionel Sambuc {
178*d90bee97SLionel Sambuc 	struct stack_block *sp;
179*d90bee97SLionel Sambuc 
180*d90bee97SLionel Sambuc 	INTOFF;
181*d90bee97SLionel Sambuc 	markp = mark->marknext;
182*d90bee97SLionel Sambuc 	while (stackp != mark->stackp) {
183*d90bee97SLionel Sambuc 		sp = stackp;
184*d90bee97SLionel Sambuc 		stackp = sp->prev;
185*d90bee97SLionel Sambuc 		ckfree(sp);
186*d90bee97SLionel Sambuc 	}
187*d90bee97SLionel Sambuc 	stacknxt = mark->stacknxt;
188*d90bee97SLionel Sambuc 	stacknleft = mark->stacknleft;
189*d90bee97SLionel Sambuc 	INTON;
190*d90bee97SLionel Sambuc }
191*d90bee97SLionel Sambuc 
192*d90bee97SLionel Sambuc 
193*d90bee97SLionel Sambuc /*
194*d90bee97SLionel Sambuc  * When the parser reads in a string, it wants to stick the string on the
195*d90bee97SLionel Sambuc  * stack and only adjust the stack pointer when it knows how big the
196*d90bee97SLionel Sambuc  * string is.  Stackblock (defined in stack.h) returns a pointer to a block
197*d90bee97SLionel Sambuc  * of space on top of the stack and stackblocklen returns the length of
198*d90bee97SLionel Sambuc  * this block.  Growstackblock will grow this space by at least one byte,
199*d90bee97SLionel Sambuc  * possibly moving it (like realloc).  Grabstackblock actually allocates the
200*d90bee97SLionel Sambuc  * part of the block that has been used.
201*d90bee97SLionel Sambuc  */
202*d90bee97SLionel Sambuc 
203*d90bee97SLionel Sambuc void
growstackblock(void)204*d90bee97SLionel Sambuc growstackblock(void)
205*d90bee97SLionel Sambuc {
206*d90bee97SLionel Sambuc 	int newlen = SHELL_ALIGN(stacknleft * 2 + 100);
207*d90bee97SLionel Sambuc 
208*d90bee97SLionel Sambuc 	if (stacknxt == stackp->space && stackp != &stackbase) {
209*d90bee97SLionel Sambuc 		struct stack_block *oldstackp;
210*d90bee97SLionel Sambuc 		struct stackmark *xmark;
211*d90bee97SLionel Sambuc 		struct stack_block *sp;
212*d90bee97SLionel Sambuc 
213*d90bee97SLionel Sambuc 		INTOFF;
214*d90bee97SLionel Sambuc 		oldstackp = stackp;
215*d90bee97SLionel Sambuc 		sp = stackp;
216*d90bee97SLionel Sambuc 		stackp = sp->prev;
217*d90bee97SLionel Sambuc 		sp = ckrealloc((pointer)sp,
218*d90bee97SLionel Sambuc 		    sizeof(struct stack_block) - MINSIZE + newlen);
219*d90bee97SLionel Sambuc 		sp->prev = stackp;
220*d90bee97SLionel Sambuc 		stackp = sp;
221*d90bee97SLionel Sambuc 		stacknxt = sp->space;
222*d90bee97SLionel Sambuc 		stacknleft = newlen;
223*d90bee97SLionel Sambuc 
224*d90bee97SLionel Sambuc 		/*
225*d90bee97SLionel Sambuc 		 * Stack marks pointing to the start of the old block
226*d90bee97SLionel Sambuc 		 * must be relocated to point to the new block
227*d90bee97SLionel Sambuc 		 */
228*d90bee97SLionel Sambuc 		xmark = markp;
229*d90bee97SLionel Sambuc 		while (xmark != NULL && xmark->stackp == oldstackp) {
230*d90bee97SLionel Sambuc 			xmark->stackp = stackp;
231*d90bee97SLionel Sambuc 			xmark->stacknxt = stacknxt;
232*d90bee97SLionel Sambuc 			xmark->stacknleft = stacknleft;
233*d90bee97SLionel Sambuc 			xmark = xmark->marknext;
234*d90bee97SLionel Sambuc 		}
235*d90bee97SLionel Sambuc 		INTON;
236*d90bee97SLionel Sambuc 	} else {
237*d90bee97SLionel Sambuc 		char *oldspace = stacknxt;
238*d90bee97SLionel Sambuc 		int oldlen = stacknleft;
239*d90bee97SLionel Sambuc 		char *p = stalloc(newlen);
240*d90bee97SLionel Sambuc 
241*d90bee97SLionel Sambuc 		(void)memcpy(p, oldspace, oldlen);
242*d90bee97SLionel Sambuc 		stacknxt = p;			/* free the space */
243*d90bee97SLionel Sambuc 		stacknleft += newlen;		/* we just allocated */
244*d90bee97SLionel Sambuc 	}
245*d90bee97SLionel Sambuc }
246*d90bee97SLionel Sambuc 
247*d90bee97SLionel Sambuc void
grabstackblock(int len)248*d90bee97SLionel Sambuc grabstackblock(int len)
249*d90bee97SLionel Sambuc {
250*d90bee97SLionel Sambuc 	len = SHELL_ALIGN(len);
251*d90bee97SLionel Sambuc 	stacknxt += len;
252*d90bee97SLionel Sambuc 	stacknleft -= len;
253*d90bee97SLionel Sambuc }
254*d90bee97SLionel Sambuc 
255*d90bee97SLionel Sambuc /*
256*d90bee97SLionel Sambuc  * The following routines are somewhat easier to use than the above.
257*d90bee97SLionel Sambuc  * The user declares a variable of type STACKSTR, which may be declared
258*d90bee97SLionel Sambuc  * to be a register.  The macro STARTSTACKSTR initializes things.  Then
259*d90bee97SLionel Sambuc  * the user uses the macro STPUTC to add characters to the string.  In
260*d90bee97SLionel Sambuc  * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
261*d90bee97SLionel Sambuc  * grown as necessary.  When the user is done, she can just leave the
262*d90bee97SLionel Sambuc  * string there and refer to it using stackblock().  Or she can allocate
263*d90bee97SLionel Sambuc  * the space for it using grabstackstr().  If it is necessary to allow
264*d90bee97SLionel Sambuc  * someone else to use the stack temporarily and then continue to grow
265*d90bee97SLionel Sambuc  * the string, the user should use grabstack to allocate the space, and
266*d90bee97SLionel Sambuc  * then call ungrabstr(p) to return to the previous mode of operation.
267*d90bee97SLionel Sambuc  *
268*d90bee97SLionel Sambuc  * USTPUTC is like STPUTC except that it doesn't check for overflow.
269*d90bee97SLionel Sambuc  * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
270*d90bee97SLionel Sambuc  * is space for at least one character.
271*d90bee97SLionel Sambuc  */
272*d90bee97SLionel Sambuc 
273*d90bee97SLionel Sambuc char *
growstackstr(void)274*d90bee97SLionel Sambuc growstackstr(void)
275*d90bee97SLionel Sambuc {
276*d90bee97SLionel Sambuc 	int len = stackblocksize();
277*d90bee97SLionel Sambuc 	if (herefd >= 0 && len >= 1024) {
278*d90bee97SLionel Sambuc 		xwrite(herefd, stackblock(), len);
279*d90bee97SLionel Sambuc 		sstrnleft = len - 1;
280*d90bee97SLionel Sambuc 		return stackblock();
281*d90bee97SLionel Sambuc 	}
282*d90bee97SLionel Sambuc 	growstackblock();
283*d90bee97SLionel Sambuc 	sstrnleft = stackblocksize() - len - 1;
284*d90bee97SLionel Sambuc 	return stackblock() + len;
285*d90bee97SLionel Sambuc }
286*d90bee97SLionel Sambuc 
287*d90bee97SLionel Sambuc /*
288*d90bee97SLionel Sambuc  * Called from CHECKSTRSPACE.
289*d90bee97SLionel Sambuc  */
290*d90bee97SLionel Sambuc 
291*d90bee97SLionel Sambuc char *
makestrspace(void)292*d90bee97SLionel Sambuc makestrspace(void)
293*d90bee97SLionel Sambuc {
294*d90bee97SLionel Sambuc 	int len = stackblocksize() - sstrnleft;
295*d90bee97SLionel Sambuc 	growstackblock();
296*d90bee97SLionel Sambuc 	sstrnleft = stackblocksize() - len;
297*d90bee97SLionel Sambuc 	return stackblock() + len;
298*d90bee97SLionel Sambuc }
299*d90bee97SLionel Sambuc 
300*d90bee97SLionel Sambuc void
ungrabstackstr(char * s,char * p)301*d90bee97SLionel Sambuc ungrabstackstr(char *s, char *p)
302*d90bee97SLionel Sambuc {
303*d90bee97SLionel Sambuc 	stacknleft += stacknxt - s;
304*d90bee97SLionel Sambuc 	stacknxt = s;
305*d90bee97SLionel Sambuc 	sstrnleft = stacknleft - (p - s);
306*d90bee97SLionel Sambuc 
307*d90bee97SLionel Sambuc }
308