Subversion Repositories HelenOS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2714 cejka 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
}