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