date and time created 91/03/07 20:27:58 by bostic
[unix-history] / usr / src / bin / sh / memalloc.c
CommitLineData
a7251d1d
KB
1/*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
7 *
8 * %sccs.include.redist.c%
9 */
10
11#ifndef lint
12static char sccsid[] = "@(#)memalloc.c 5.1 (Berkeley) %G%";
13#endif /* not lint */
14
15#include "shell.h"
16#include "output.h"
17#include "memalloc.h"
18#include "error.h"
19#include "machdep.h"
20#include "mystring.h"
21
22/*
23 * Like malloc, but returns an error when out of space.
24 */
25
26pointer
27ckmalloc(nbytes) {
28 register pointer p;
29 pointer malloc();
30
31 if ((p = malloc(nbytes)) == NULL)
32 error("Out of space");
33 return p;
34}
35
36
37/*
38 * Same for realloc.
39 */
40
41pointer
42ckrealloc(p, nbytes)
43 register pointer p;
44 {
45 pointer realloc();
46
47 if ((p = realloc(p, nbytes)) == NULL)
48 error("Out of space");
49 return p;
50}
51
52
53/*
54 * Make a copy of a string in safe storage.
55 */
56
57char *
58savestr(s)
59 char *s;
60 {
61 register char *p;
62
63 p = ckmalloc(strlen(s) + 1);
64 scopy(s, p);
65 return p;
66}
67
68
69/*
70 * Parse trees for commands are allocated in lifo order, so we use a stack
71 * to make this more efficient, and also to avoid all sorts of exception
72 * handling code to handle interrupts in the middle of a parse.
73 *
74 * The size 504 was chosen because the Ultrix malloc handles that size
75 * well.
76 */
77
78#define MINSIZE 504 /* minimum size of a block */
79
80
81struct stack_block {
82 struct stack_block *prev;
83 char space[MINSIZE];
84};
85
86struct stack_block stackbase;
87struct stack_block *stackp = &stackbase;
88char *stacknxt = stackbase.space;
89int stacknleft = MINSIZE;
90int sstrnleft;
91int herefd = -1;
92
93
94
95pointer
96stalloc(nbytes) {
97 register char *p;
98
99 nbytes = ALIGN(nbytes);
100 if (nbytes > stacknleft) {
101 int blocksize;
102 struct stack_block *sp;
103
104 blocksize = nbytes;
105 if (blocksize < MINSIZE)
106 blocksize = MINSIZE;
107 INTOFF;
108 sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
109 sp->prev = stackp;
110 stacknxt = sp->space;
111 stacknleft = blocksize;
112 stackp = sp;
113 INTON;
114 }
115 p = stacknxt;
116 stacknxt += nbytes;
117 stacknleft -= nbytes;
118 return p;
119}
120
121
122void
123stunalloc(p)
124 pointer p;
125 {
126 if (p == NULL) { /*DEBUG */
127 write(2, "stunalloc\n", 10);
128 abort();
129 }
130 stacknleft += stacknxt - (char *)p;
131 stacknxt = p;
132}
133
134
135
136void
137setstackmark(mark)
138 struct stackmark *mark;
139 {
140 mark->stackp = stackp;
141 mark->stacknxt = stacknxt;
142 mark->stacknleft = stacknleft;
143}
144
145
146void
147popstackmark(mark)
148 struct stackmark *mark;
149 {
150 struct stack_block *sp;
151
152 INTOFF;
153 while (stackp != mark->stackp) {
154 sp = stackp;
155 stackp = sp->prev;
156 ckfree(sp);
157 }
158 stacknxt = mark->stacknxt;
159 stacknleft = mark->stacknleft;
160 INTON;
161}
162
163
164/*
165 * When the parser reads in a string, it wants to stick the string on the
166 * stack and only adjust the stack pointer when it knows how big the
167 * string is. Stackblock (defined in stack.h) returns a pointer to a block
168 * of space on top of the stack and stackblocklen returns the length of
169 * this block. Growstackblock will grow this space by at least one byte,
170 * possibly moving it (like realloc). Grabstackblock actually allocates the
171 * part of the block that has been used.
172 */
173
174void
175growstackblock() {
176 char *p;
177 int newlen = stacknleft * 2 + 100;
178 char *oldspace = stacknxt;
179 int oldlen = stacknleft;
180 struct stack_block *sp;
181
182 if (stacknxt == stackp->space) {
183 INTOFF;
184 sp = stackp;
185 stackp = sp->prev;
186 sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
187 sp->prev = stackp;
188 stackp = sp;
189 stacknxt = sp->space;
190 stacknleft = newlen;
191 INTON;
192 } else {
193 p = stalloc(newlen);
194 bcopy(oldspace, p, oldlen);
195 stacknxt = p; /* free the space */
196 stacknleft += newlen; /* we just allocated */
197 }
198}
199
200
201
202void
203grabstackblock(len) {
204 len = ALIGN(len);
205 stacknxt += len;
206 stacknleft -= len;
207}
208
209
210
211/*
212 * The following routines are somewhat easier to use that the above.
213 * The user declares a variable of type STACKSTR, which may be declared
214 * to be a register. The macro STARTSTACKSTR initializes things. Then
215 * the user uses the macro STPUTC to add characters to the string. In
216 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
217 * grown as necessary. When the user is done, she can just leave the
218 * string there and refer to it using stackblock(). Or she can allocate
219 * the space for it using grabstackstr(). If it is necessary to allow
220 * someone else to use the stack temporarily and then continue to grow
221 * the string, the user should use grabstack to allocate the space, and
222 * then call ungrabstr(p) to return to the previous mode of operation.
223 *
224 * USTPUTC is like STPUTC except that it doesn't check for overflow.
225 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
226 * is space for at least one character.
227 */
228
229
230char *
231growstackstr() {
232 int len = stackblocksize();
233 if (herefd && len >= 1024) {
234 xwrite(herefd, stackblock(), len);
235 sstrnleft = len - 1;
236 return stackblock();
237 }
238 growstackblock();
239 sstrnleft = stackblocksize() - len - 1;
240 return stackblock() + len;
241}
242
243
244/*
245 * Called from CHECKSTRSPACE.
246 */
247
248char *
249makestrspace() {
250 int len = stackblocksize() - sstrnleft;
251 growstackblock();
252 sstrnleft = stackblocksize() - len;
253 return stackblock() + len;
254}
255
256
257
258void
259ungrabstackstr(s, p)
260 char *s;
261 char *p;
262 {
263 stacknleft += stacknxt - s;
264 stacknxt = s;
265 sstrnleft = stacknleft - (p - s);
266}