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 #ifdef HAVE_SYS_CDEFS_H
36 #include <sys/cdefs.h>
40 static char sccsid
[] = "@(#)memalloc.c 8.3 (Berkeley) 5/4/95";
42 __RCSID("$NetBSD: memalloc.c,v 1.28 2003/08/07 09:05:34 agc Exp $");
57 * Like malloc, but returns an error when out of space.
67 error("Out of space");
77 ckrealloc(pointer p
, int nbytes
)
79 p
= realloc(p
, nbytes
);
81 error("Out of space");
87 * Make a copy of a string in safe storage.
91 savestr(const char *s
)
95 p
= ckmalloc(strlen(s
) + 1);
102 * Parse trees for commands are allocated in lifo order, so we use a stack
103 * to make this more efficient, and also to avoid all sorts of exception
104 * handling code to handle interrupts in the middle of a parse.
106 * The size 504 was chosen because the Ultrix malloc handles that size
110 #define MINSIZE 504 /* minimum size of a block */
113 struct stack_block
*prev
;
117 struct stack_block stackbase
;
118 struct stack_block
*stackp
= &stackbase
;
119 struct stackmark
*markp
;
120 char *stacknxt
= stackbase
.space
;
121 int stacknleft
= MINSIZE
;
130 nbytes
= SHELL_ALIGN(nbytes
);
131 if (nbytes
> stacknleft
) {
133 struct stack_block
*sp
;
136 if (blocksize
< MINSIZE
)
139 sp
= ckmalloc(sizeof(struct stack_block
) - MINSIZE
+ blocksize
);
141 stacknxt
= sp
->space
;
142 stacknleft
= blocksize
;
148 stacknleft
-= nbytes
;
156 if (p
== NULL
) { /*DEBUG */
157 write(2, "stunalloc\n", 10);
160 stacknleft
+= stacknxt
- (char *)p
;
167 setstackmark(struct stackmark
*mark
)
169 mark
->stackp
= stackp
;
170 mark
->stacknxt
= stacknxt
;
171 mark
->stacknleft
= stacknleft
;
172 mark
->marknext
= markp
;
178 popstackmark(struct stackmark
*mark
)
180 struct stack_block
*sp
;
183 markp
= mark
->marknext
;
184 while (stackp
!= mark
->stackp
) {
189 stacknxt
= mark
->stacknxt
;
190 stacknleft
= mark
->stacknleft
;
196 * When the parser reads in a string, it wants to stick the string on the
197 * stack and only adjust the stack pointer when it knows how big the
198 * string is. Stackblock (defined in stack.h) returns a pointer to a block
199 * of space on top of the stack and stackblocklen returns the length of
200 * this block. Growstackblock will grow this space by at least one byte,
201 * possibly moving it (like realloc). Grabstackblock actually allocates the
202 * part of the block that has been used.
208 int newlen
= SHELL_ALIGN(stacknleft
* 2 + 100);
210 if (stacknxt
== stackp
->space
&& stackp
!= &stackbase
) {
211 struct stack_block
*oldstackp
;
212 struct stackmark
*xmark
;
213 struct stack_block
*sp
;
219 sp
= ckrealloc((pointer
)sp
,
220 sizeof(struct stack_block
) - MINSIZE
+ newlen
);
223 stacknxt
= sp
->space
;
227 * Stack marks pointing to the start of the old block
228 * must be relocated to point to the new block
231 while (xmark
!= NULL
&& xmark
->stackp
== oldstackp
) {
232 xmark
->stackp
= stackp
;
233 xmark
->stacknxt
= stacknxt
;
234 xmark
->stacknleft
= stacknleft
;
235 xmark
= xmark
->marknext
;
239 char *oldspace
= stacknxt
;
240 int oldlen
= stacknleft
;
241 char *p
= stalloc(newlen
);
243 (void)memcpy(p
, oldspace
, oldlen
);
244 stacknxt
= p
; /* free the space */
245 stacknleft
+= newlen
; /* we just allocated */
250 grabstackblock(int len
)
252 len
= SHELL_ALIGN(len
);
258 * The following routines are somewhat easier to use than the above.
259 * The user declares a variable of type STACKSTR, which may be declared
260 * to be a register. The macro STARTSTACKSTR initializes things. Then
261 * the user uses the macro STPUTC to add characters to the string. In
262 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
263 * grown as necessary. When the user is done, she can just leave the
264 * string there and refer to it using stackblock(). Or she can allocate
265 * the space for it using grabstackstr(). If it is necessary to allow
266 * someone else to use the stack temporarily and then continue to grow
267 * the string, the user should use grabstack to allocate the space, and
268 * then call ungrabstr(p) to return to the previous mode of operation.
270 * USTPUTC is like STPUTC except that it doesn't check for overflow.
271 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
272 * is space for at least one character.
278 int len
= stackblocksize();
279 if (herefd
>= 0 && len
>= 1024) {
280 xwrite(herefd
, stackblock(), len
);
285 sstrnleft
= stackblocksize() - len
- 1;
286 return stackblock() + len
;
290 * Called from CHECKSTRSPACE.
296 int len
= stackblocksize() - sstrnleft
;
298 sstrnleft
= stackblocksize() - len
;
299 return stackblock() + len
;
303 ungrabstackstr(char *s
, char *p
)
305 stacknleft
+= stacknxt
- s
;
307 sstrnleft
= stacknleft
- (p
- s
);