Magellan Linux

Annotation of /trunk/mkinitrd-magellan/klibc/usr/dash/memalloc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1122 - (hide annotations) (download)
Wed Aug 18 21:11:40 2010 UTC (13 years, 8 months ago) by niro
File MIME type: text/plain
File size: 7406 byte(s)
-updated to klibc-1.5.19
1 niro 532 /*-
2     * Copyright (c) 1991, 1993
3     * The Regents of the University of California. All rights reserved.
4     * Copyright (c) 1997-2005
5     * Herbert Xu <herbert@gondor.apana.org.au>. 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. 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.
21     *
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
32     * SUCH DAMAGE.
33     */
34    
35     #include <stdlib.h>
36     #include <unistd.h>
37    
38     #include "shell.h"
39     #include "output.h"
40     #include "memalloc.h"
41     #include "error.h"
42     #include "machdep.h"
43     #include "mystring.h"
44     #include "system.h"
45    
46     /*
47     * Like malloc, but returns an error when out of space.
48     */
49    
50     pointer
51     ckmalloc(size_t nbytes)
52     {
53     pointer p;
54    
55     p = malloc(nbytes);
56     if (p == NULL)
57     sh_error("Out of space");
58     return p;
59     }
60    
61    
62     /*
63     * Same for realloc.
64     */
65    
66     pointer
67     ckrealloc(pointer p, size_t nbytes)
68     {
69     p = realloc(p, nbytes);
70     if (p == NULL)
71     sh_error("Out of space");
72     return p;
73     }
74    
75    
76     /*
77     * Make a copy of a string in safe storage.
78     */
79    
80     char *
81     savestr(const char *s)
82     {
83     char *p = strdup(s);
84     if (!p)
85     sh_error("Out of space");
86     return p;
87     }
88    
89    
90     /*
91     * Parse trees for commands are allocated in lifo order, so we use a stack
92     * to make this more efficient, and also to avoid all sorts of exception
93     * handling code to handle interrupts in the middle of a parse.
94     *
95     * The size 504 was chosen because the Ultrix malloc handles that size
96     * well.
97     */
98    
99     /* minimum size of a block */
100     #define MINSIZE SHELL_ALIGN(504)
101    
102     struct stack_block {
103     struct stack_block *prev;
104     char space[MINSIZE];
105     };
106    
107     struct stack_block stackbase;
108     struct stack_block *stackp = &stackbase;
109     char *stacknxt = stackbase.space;
110     size_t stacknleft = MINSIZE;
111     char *sstrend = stackbase.space + MINSIZE;
112    
113     pointer
114     stalloc(size_t nbytes)
115     {
116     char *p;
117     size_t aligned;
118    
119     aligned = SHELL_ALIGN(nbytes);
120     if (aligned > stacknleft) {
121     size_t len;
122     size_t blocksize;
123     struct stack_block *sp;
124    
125     blocksize = aligned;
126     if (blocksize < MINSIZE)
127     blocksize = MINSIZE;
128     len = sizeof(struct stack_block) - MINSIZE + blocksize;
129     if (len < blocksize)
130     sh_error("Out of space");
131     INTOFF;
132     sp = ckmalloc(len);
133     sp->prev = stackp;
134     stacknxt = sp->space;
135     stacknleft = blocksize;
136     sstrend = stacknxt + blocksize;
137     stackp = sp;
138     INTON;
139     }
140     p = stacknxt;
141     stacknxt += aligned;
142     stacknleft -= aligned;
143     return p;
144     }
145    
146    
147     void
148     stunalloc(pointer p)
149     {
150     #ifdef DEBUG
151     if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
152     write(2, "stunalloc\n", 10);
153     abort();
154     }
155     #endif
156     stacknleft += stacknxt - (char *)p;
157     stacknxt = p;
158     }
159    
160    
161    
162 niro 1122 void pushstackmark(struct stackmark *mark, size_t len)
163 niro 532 {
164     mark->stackp = stackp;
165     mark->stacknxt = stacknxt;
166     mark->stacknleft = stacknleft;
167 niro 1122 grabstackblock(len);
168 niro 532 }
169    
170 niro 1122 void setstackmark(struct stackmark *mark)
171     {
172     pushstackmark(mark, stacknxt == stackp->space && stackp != &stackbase);
173     }
174 niro 532
175 niro 1122
176 niro 532 void
177     popstackmark(struct stackmark *mark)
178     {
179     struct stack_block *sp;
180    
181     INTOFF;
182     while (stackp != mark->stackp) {
183     sp = stackp;
184     stackp = sp->prev;
185     ckfree(sp);
186     }
187     stacknxt = mark->stacknxt;
188     stacknleft = mark->stacknleft;
189     sstrend = mark->stacknxt + mark->stacknleft;
190     INTON;
191     }
192    
193    
194     /*
195     * When the parser reads in a string, it wants to stick the string on the
196     * stack and only adjust the stack pointer when it knows how big the
197     * string is. Stackblock (defined in stack.h) returns a pointer to a block
198     * of space on top of the stack and stackblocklen returns the length of
199     * this block. Growstackblock will grow this space by at least one byte,
200     * possibly moving it (like realloc). Grabstackblock actually allocates the
201     * part of the block that has been used.
202     */
203    
204     void
205     growstackblock(void)
206     {
207     size_t newlen;
208    
209     newlen = stacknleft * 2;
210     if (newlen < stacknleft)
211     sh_error("Out of space");
212     if (newlen < 128)
213     newlen += 128;
214    
215     if (stacknxt == stackp->space && stackp != &stackbase) {
216     struct stack_block *oldstackp;
217     struct stack_block *sp;
218     struct stack_block *prevstackp;
219     size_t grosslen;
220    
221     INTOFF;
222     oldstackp = stackp;
223     sp = stackp;
224     prevstackp = sp->prev;
225     grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
226     sp = ckrealloc((pointer)sp, grosslen);
227     sp->prev = prevstackp;
228     stackp = sp;
229     stacknxt = sp->space;
230     stacknleft = newlen;
231     sstrend = sp->space + newlen;
232     INTON;
233     } else {
234     char *oldspace = stacknxt;
235     int oldlen = stacknleft;
236     char *p = stalloc(newlen);
237    
238     /* free the space we just allocated */
239     stacknxt = memcpy(p, oldspace, oldlen);
240     stacknleft += newlen;
241     }
242     }
243    
244     /*
245     * The following routines are somewhat easier to use than the above.
246     * The user declares a variable of type STACKSTR, which may be declared
247     * to be a register. The macro STARTSTACKSTR initializes things. Then
248     * the user uses the macro STPUTC to add characters to the string. In
249     * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
250     * grown as necessary. When the user is done, she can just leave the
251     * string there and refer to it using stackblock(). Or she can allocate
252     * the space for it using grabstackstr(). If it is necessary to allow
253     * someone else to use the stack temporarily and then continue to grow
254     * the string, the user should use grabstack to allocate the space, and
255     * then call ungrabstr(p) to return to the previous mode of operation.
256     *
257     * USTPUTC is like STPUTC except that it doesn't check for overflow.
258     * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
259     * is space for at least one character.
260     */
261    
262     void *
263     growstackstr(void)
264     {
265     size_t len = stackblocksize();
266     growstackblock();
267     return stackblock() + len;
268     }
269    
270     /*
271     * Called from CHECKSTRSPACE.
272     */
273    
274     char *
275     makestrspace(size_t newlen, char *p)
276     {
277     size_t len = p - stacknxt;
278     size_t size = stackblocksize();
279    
280     for (;;) {
281     size_t nleft;
282    
283     size = stackblocksize();
284     nleft = size - len;
285     if (nleft >= newlen)
286     break;
287     growstackblock();
288     }
289     return stackblock() + len;
290     }
291    
292     char *
293     stnputs(const char *s, size_t n, char *p)
294     {
295     p = makestrspace(n, p);
296     p = mempcpy(p, s, n);
297     return p;
298     }
299    
300     char *
301     stputs(const char *s, char *p)
302     {
303     return stnputs(s, strlen(s), p);
304     }