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