VirtualBox

source: kBuild/trunk/src/kash/memalloc.c@ 3456

Last change on this file since 3456 was 3456, checked in by bird, 5 years ago

kash: parser.c,memalloc.c/.h,expand.c: Prepared the parser for using a separate allocator.

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Id
File size: 10.7 KB
Line 
1/* $NetBSD: memalloc.c,v 1.28 2003/08/07 09:05:34 agc 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. 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#if 0
36#ifndef lint
37static char sccsid[] = "@(#)memalloc.c 8.3 (Berkeley) 5/4/95";
38#else
39__RCSID("$NetBSD: memalloc.c,v 1.28 2003/08/07 09:05:34 agc Exp $");
40#endif /* not lint */
41#endif
42
43#include <stdlib.h>
44#include <assert.h>
45
46#include "shell.h"
47#include "output.h"
48#include "memalloc.h"
49#include "error.h"
50#include "machdep.h"
51#include "mystring.h"
52#include "shinstance.h"
53#include "nodes.h"
54
55/*
56 * Like malloc, but returns an error when out of space.
57 */
58
59pointer
60ckmalloc(shinstance *psh, size_t nbytes)
61{
62 pointer p;
63
64 p = sh_malloc(psh, nbytes);
65 if (p == NULL)
66 error(psh, "Out of space");
67 return p;
68}
69
70
71/*
72 * Same for realloc.
73 */
74
75pointer
76ckrealloc(struct shinstance *psh, pointer p, size_t nbytes)
77{
78 p = sh_realloc(psh, p, nbytes);
79 if (p == NULL)
80 error(psh, "Out of space");
81 return p;
82}
83
84
85/*
86 * Make a copy of a string in safe storage.
87 */
88
89char *
90savestr(struct shinstance *psh, const char *s)
91{
92 char *p;
93 size_t len = strlen(s);
94
95 p = ckmalloc(psh, len + 1);
96 memcpy(p, s, len + 1);
97 return p;
98}
99
100
101/*
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.
105 *
106 * The size 504 was chosen because the Ultrix malloc handles that size
107 * well.
108 */
109
110//#define MINSIZE 504 /* minimum size of a block */
111
112//struct stack_block {
113// struct stack_block *prev;
114// char space[MINSIZE];
115//};
116
117//struct stack_block stackbase;
118//struct stack_block *stackp = &stackbase;
119//struct stackmark *markp;
120//char *stacknxt = stackbase.space;
121//int stacknleft = MINSIZE;
122//int sstrnleft;
123//int herefd = -1;
124
125pointer
126stalloc(shinstance *psh, size_t nbytes)
127{
128 char *p;
129
130 nbytes = SHELL_ALIGN(nbytes);
131 if (nbytes > (size_t)psh->stacknleft || psh->stacknleft < 0) {
132 size_t blocksize;
133 struct stack_block *sp;
134
135 blocksize = nbytes;
136 if (blocksize < MINSIZE)
137 blocksize = MINSIZE;
138 INTOFF;
139 sp = ckmalloc(psh, sizeof(struct stack_block) - MINSIZE + blocksize);
140 sp->prev = psh->stackp;
141 psh->stacknxt = sp->space;
142 psh->stacknleft = (int)blocksize;
143 psh->stackp = sp;
144 INTON;
145 }
146 p = psh->stacknxt;
147 psh->stacknxt += nbytes;
148 psh->stacknleft -= (int)nbytes;
149 return p;
150}
151
152
153char *
154stsavestr(struct shinstance *psh, const char *src)
155{
156 if (src) {
157 size_t size = strlen(src) + 1;
158 char *dst = (char *)stalloc(psh, size);
159 return (char *)memcpy(dst, src, size);
160 }
161 return NULL;
162}
163
164
165void
166stunalloc(shinstance *psh, pointer p)
167{
168 if (p == NULL) { /*DEBUG */
169 shfile_write(&psh->fdtab, 2, "stunalloc\n", 10);
170 sh_abort(psh);
171 }
172 psh->stacknleft += (int)(psh->stacknxt - (char *)p);
173 psh->stacknxt = p;
174}
175
176
177
178void
179setstackmark(shinstance *psh, struct stackmark *mark)
180{
181 mark->stackp = psh->stackp;
182 mark->stacknxt = psh->stacknxt;
183 mark->stacknleft = psh->stacknleft;
184 mark->marknext = psh->markp;
185 psh->markp = mark;
186}
187
188
189void
190popstackmark(shinstance *psh, struct stackmark *mark)
191{
192 struct stack_block *sp;
193
194 INTOFF;
195 psh->markp = mark->marknext;
196 while (psh->stackp != mark->stackp) {
197 sp = psh->stackp;
198 psh->stackp = sp->prev;
199 ckfree(psh, sp);
200 }
201 psh->stacknxt = mark->stacknxt;
202 psh->stacknleft = mark->stacknleft;
203 INTON;
204}
205
206
207/*
208 * When the parser reads in a string, it wants to stick the string on the
209 * stack and only adjust the stack pointer when it knows how big the
210 * string is. Stackblock (defined in stack.h) returns a pointer to a block
211 * of space on top of the stack and stackblocklen returns the length of
212 * this block. Growstackblock will grow this space by at least one byte,
213 * possibly moving it (like realloc). Grabstackblock actually allocates the
214 * part of the block that has been used.
215 */
216
217void
218growstackblock(shinstance *psh)
219{
220 int newlen = SHELL_ALIGN(psh->stacknleft * 2 + 100);
221
222 if (psh->stacknxt == psh->stackp->space && psh->stackp != &psh->stackbase) {
223 struct stack_block *oldstackp;
224 struct stackmark *xmark;
225 struct stack_block *sp;
226
227 INTOFF;
228 oldstackp = psh->stackp;
229 sp = psh->stackp;
230 psh->stackp = sp->prev;
231 sp = ckrealloc(psh, (pointer)sp,
232 sizeof(struct stack_block) - MINSIZE + newlen);
233 sp->prev = psh->stackp;
234 psh->stackp = sp;
235 psh->stacknxt = sp->space;
236 psh->stacknleft = newlen;
237
238 /*
239 * Stack marks pointing to the start of the old block
240 * must be relocated to point to the new block
241 */
242 xmark = psh->markp;
243 while (xmark != NULL && xmark->stackp == oldstackp) {
244 xmark->stackp = psh->stackp;
245 xmark->stacknxt = psh->stacknxt;
246 xmark->stacknleft = psh->stacknleft;
247 xmark = xmark->marknext;
248 }
249 INTON;
250 } else {
251 char *oldspace = psh->stacknxt;
252 int oldlen = psh->stacknleft;
253 char *p = stalloc(psh, newlen);
254
255 (void)memcpy(p, oldspace, oldlen);
256 psh->stacknxt = p; /* free the space */
257 psh->stacknleft += newlen; /* we just allocated */
258 }
259}
260
261void
262grabstackblock(shinstance *psh, int len)
263{
264 len = SHELL_ALIGN(len);
265 psh->stacknxt += len;
266 psh->stacknleft -= len;
267}
268
269/*
270 * The following routines are somewhat easier to use than the above.
271 * The user declares a variable of type STACKSTR, which may be declared
272 * to be a register. The macro STARTSTACKSTR initializes things. Then
273 * the user uses the macro STPUTC to add characters to the string. In
274 * effect, STPUTC(psh, c, p) is the same as *p++ = c except that the stack is
275 * grown as necessary. When the user is done, she can just leave the
276 * string there and refer to it using stackblock(psh). Or she can allocate
277 * the space for it using grabstackstr(). If it is necessary to allow
278 * someone else to use the stack temporarily and then continue to grow
279 * the string, the user should use grabstack to allocate the space, and
280 * then call ungrabstr(p) to return to the previous mode of operation.
281 *
282 * USTPUTC is like STPUTC except that it doesn't check for overflow.
283 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
284 * is space for at least one character.
285 */
286
287char *
288growstackstr(shinstance *psh)
289{
290 int len = stackblocksize(psh);
291 if (psh->herefd >= 0 && len >= 1024) {
292 xwrite(psh, psh->herefd, stackblock(psh), len);
293 psh->sstrnleft = len - 1;
294 return stackblock(psh);
295 }
296 growstackblock(psh);
297 psh->sstrnleft = stackblocksize(psh) - len - 1;
298 return stackblock(psh) + len;
299}
300
301/*
302 * Called from CHECKSTRSPACE.
303 */
304
305char *
306makestrspace(shinstance *psh)
307{
308 int len = stackblocksize(psh) - psh->sstrnleft;
309 growstackblock(psh);
310 psh->sstrnleft = stackblocksize(psh) - len;
311 return stackblock(psh) + len;
312}
313
314
315/*
316 * Got better control having a dedicated function for this.
317 *
318 * Was: #define grabstackstr(psh, p) stalloc((psh), stackblocksize(psh) - (psh)->sstrnleft)
319 */
320char *
321grabstackstr(shinstance *psh, char *end)
322{
323 char * const pstart = stackblock(psh);
324 size_t nbytes = (size_t)(end - pstart);
325
326 assert((uintptr_t)end >= (uintptr_t)pstart);
327 /*assert(end[-1] == '\0'); - not if it's followed by ungrabstrackstr(), sigh. */
328 assert(SHELL_ALIGN((uintptr_t)pstart) == (uintptr_t)pstart);
329 assert(stackblocksize(psh) - psh->sstrnleft >= nbytes);
330
331 nbytes = SHELL_ALIGN(nbytes);
332 psh->stacknxt += nbytes;
333 psh->stacknleft -= (int)nbytes;
334 assert(psh->stacknleft >= 0);
335
336 return pstart;
337}
338
339void
340ungrabstackstr(shinstance *psh, char *s, char *p)
341{
342 assert((size_t)(psh->stacknxt - p) <= SHELL_SIZE);
343 assert((uintptr_t)s >= (uintptr_t)&psh->stackp->space[0]);
344 assert((uintptr_t)p >= (uintptr_t)s);
345
346 psh->stacknleft += (int)(psh->stacknxt - s);
347 psh->stacknxt = s;
348 psh->sstrnleft = (int)(psh->stacknleft - (p - s));
349
350}
351
352
353/*
354 * Parser stack allocator.
355 */
356void *pstalloc(struct shinstance *psh, size_t nbytes)
357{
358 return stalloc(psh, nbytes);
359}
360
361union node *pstallocnode(struct shinstance *psh, size_t nbytes)
362{
363 return (union node *)pstalloc(psh, nbytes);
364}
365
366struct nodelist *pstalloclist(struct shinstance *psh)
367{
368 return (struct nodelist *)pstalloc(psh, sizeof(struct nodelist));
369}
370
371char *pstsavestr(struct shinstance *psh, const char *str)
372{
373 if (str) {
374 size_t nbytes = strlen(str) + 1;
375 return (char *)memcpy(pstalloc(psh, nbytes), str, nbytes);
376 }
377 return NULL;
378}
379
380char *pstmakestrspace(struct shinstance *psh, size_t minbytes, char *end)
381{
382 size_t const len = end - stackblock(psh);
383 assert(stackblocksize(psh) - psh->sstrnleft == len);
384TRACE2((psh, "pstmakestrspace: len=%u minbytes=%u (=> %u)\n", len, minbytes, len + minbytes));
385 minbytes += len;
386 while (stackblocksize(psh) < minbytes)
387 growstackblock(psh);
388 psh->sstrnleft = (int)(stackblocksize(psh) - len);
389 return (char *)stackblock(psh) + len;
390}
391
392/* PSTPUTC helper */
393char *pstputcgrow(shinstance *psh, char *end, char c)
394{
395 psh->sstrnleft++; /* PSTPUTC() already incremented it. */
396 end = pstmakestrspace(psh, 1, end);
397 assert(psh->sstrnleft > 0);
398 psh->sstrnleft--;
399 *end++ = c;
400 return end;
401}
402
403
404char *pstgrabstr(struct shinstance *psh, char *end)
405{
406 char * const pstart = stackblock(psh);
407 size_t nbytes = (size_t)(end - pstart);
408
409 assert((uintptr_t)end > (uintptr_t)pstart);
410 assert(end[-1] == '\0');
411 assert(SHELL_ALIGN((uintptr_t)pstart) == (uintptr_t)pstart);
412 assert(stackblocksize(psh) - psh->sstrnleft >= nbytes);
413
414 nbytes = SHELL_ALIGN(nbytes); /** @todo don't align strings, align the other allocations. */
415 psh->stacknxt += nbytes;
416 psh->stacknleft -= (int)nbytes;
417
418 return pstart;
419}
420
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette