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