1 /* $NetBSD: memalloc.c,v 1.28 2003/08/07 09:05:34 agc Exp $ */
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #include <sys/cdefs.h>
38 static char sccsid
[] = "@(#)memalloc.c 8.3 (Berkeley) 5/4/95";
40 __RCSID("$NetBSD: memalloc.c,v 1.28 2003/08/07 09:05:34 agc Exp $");
55 * Like malloc, but returns an error when out of space.
59 ckmalloc(size_t nbytes
)
65 error("Out of space");
75 ckrealloc(pointer p
, int nbytes
)
77 p
= realloc(p
, nbytes
);
79 error("Out of space");
85 * Make a copy of a string in safe storage.
89 savestr(const char *s
)
93 p
= ckmalloc(strlen(s
) + 1);
100 * Parse trees for commands are allocated in lifo order, so we use a stack
101 * to make this more efficient, and also to avoid all sorts of exception
102 * handling code to handle interrupts in the middle of a parse.
104 * The size 504 was chosen because the Ultrix malloc handles that size
108 #define MINSIZE 504 /* minimum size of a block */
111 struct stack_block
*prev
;
115 struct stack_block stackbase
;
116 struct stack_block
*stackp
= &stackbase
;
117 struct stackmark
*markp
;
118 char *stacknxt
= stackbase
.space
;
119 int stacknleft
= MINSIZE
;
128 nbytes
= SHELL_ALIGN(nbytes
);
129 if (nbytes
> stacknleft
) {
131 struct stack_block
*sp
;
134 if (blocksize
< MINSIZE
)
137 sp
= ckmalloc(sizeof(struct stack_block
) - MINSIZE
+ blocksize
);
139 stacknxt
= sp
->space
;
140 stacknleft
= blocksize
;
146 stacknleft
-= nbytes
;
154 if (p
== NULL
) { /*DEBUG */
155 write(2, "stunalloc\n", 10);
158 stacknleft
+= stacknxt
- (char *)p
;
165 setstackmark(struct stackmark
*mark
)
167 mark
->stackp
= stackp
;
168 mark
->stacknxt
= stacknxt
;
169 mark
->stacknleft
= stacknleft
;
170 mark
->marknext
= markp
;
176 popstackmark(struct stackmark
*mark
)
178 struct stack_block
*sp
;
181 markp
= mark
->marknext
;
182 while (stackp
!= mark
->stackp
) {
187 stacknxt
= mark
->stacknxt
;
188 stacknleft
= mark
->stacknleft
;
194 * When the parser reads in a string, it wants to stick the string on the
195 * stack and only adjust the stack pointer when it knows how big the
196 * string is. Stackblock (defined in stack.h) returns a pointer to a block
197 * of space on top of the stack and stackblocklen returns the length of
198 * this block. Growstackblock will grow this space by at least one byte,
199 * possibly moving it (like realloc). Grabstackblock actually allocates the
200 * part of the block that has been used.
206 int newlen
= SHELL_ALIGN(stacknleft
* 2 + 100);
208 if (stacknxt
== stackp
->space
&& stackp
!= &stackbase
) {
209 struct stack_block
*oldstackp
;
210 struct stackmark
*xmark
;
211 struct stack_block
*sp
;
217 sp
= ckrealloc((pointer
)sp
,
218 sizeof(struct stack_block
) - MINSIZE
+ newlen
);
221 stacknxt
= sp
->space
;
225 * Stack marks pointing to the start of the old block
226 * must be relocated to point to the new block
229 while (xmark
!= NULL
&& xmark
->stackp
== oldstackp
) {
230 xmark
->stackp
= stackp
;
231 xmark
->stacknxt
= stacknxt
;
232 xmark
->stacknleft
= stacknleft
;
233 xmark
= xmark
->marknext
;
237 char *oldspace
= stacknxt
;
238 int oldlen
= stacknleft
;
239 char *p
= stalloc(newlen
);
241 (void)memcpy(p
, oldspace
, oldlen
);
242 stacknxt
= p
; /* free the space */
243 stacknleft
+= newlen
; /* we just allocated */
248 grabstackblock(int len
)
250 len
= SHELL_ALIGN(len
);
256 * The following routines are somewhat easier to use than the above.
257 * The user declares a variable of type STACKSTR, which may be declared
258 * to be a register. The macro STARTSTACKSTR initializes things. Then
259 * the user uses the macro STPUTC to add characters to the string. In
260 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
261 * grown as necessary. When the user is done, she can just leave the
262 * string there and refer to it using stackblock(). Or she can allocate
263 * the space for it using grabstackstr(). If it is necessary to allow
264 * someone else to use the stack temporarily and then continue to grow
265 * the string, the user should use grabstack to allocate the space, and
266 * then call ungrabstr(p) to return to the previous mode of operation.
268 * USTPUTC is like STPUTC except that it doesn't check for overflow.
269 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
270 * is space for at least one character.
276 int len
= stackblocksize();
277 if (herefd
>= 0 && len
>= 1024) {
278 xwrite(herefd
, stackblock(), len
);
283 sstrnleft
= stackblocksize() - len
- 1;
284 return stackblock() + len
;
288 * Called from CHECKSTRSPACE.
294 int len
= stackblocksize() - sstrnleft
;
296 sstrnleft
= stackblocksize() - len
;
297 return stackblock() + len
;
301 ungrabstackstr(char *s
, char *p
)
303 stacknleft
+= stacknxt
- s
;
305 sstrnleft
= stacknleft
- (p
- s
);