xref: /original-bsd/bin/sh/memalloc.c (revision 01e8f48f)
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  * %sccs.include.redist.c%
9  */
10 
11 #ifndef lint
12 static char sccsid[] = "@(#)memalloc.c	8.2 (Berkeley) 04/28/95";
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 
26 pointer
27 ckmalloc(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 
41 pointer
42 ckrealloc(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 
57 char *
58 savestr(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 
81 struct stack_block {
82 	struct stack_block *prev;
83 	char space[MINSIZE];
84 };
85 
86 struct stack_block stackbase;
87 struct stack_block *stackp = &stackbase;
88 char *stacknxt = stackbase.space;
89 int stacknleft = MINSIZE;
90 int sstrnleft;
91 int herefd = -1;
92 
93 
94 
95 pointer
96 stalloc(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 
122 void
123 stunalloc(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 
136 void
137 setstackmark(mark)
138 	struct stackmark *mark;
139 	{
140 	mark->stackp = stackp;
141 	mark->stacknxt = stacknxt;
142 	mark->stacknleft = stacknleft;
143 }
144 
145 
146 void
147 popstackmark(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 
174 void
175 growstackblock() {
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 && stackp != &stackbase) {
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 		memmove(p, oldspace, oldlen);
195 		stacknxt = p;			/* free the space */
196 		stacknleft += newlen;		/* we just allocated */
197 	}
198 }
199 
200 
201 
202 void
203 grabstackblock(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 
230 char *
231 growstackstr() {
232 	int len = stackblocksize();
233 	if (herefd >= 0 && 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 
248 char *
249 makestrspace() {
250 	int len = stackblocksize() - sstrnleft;
251 	growstackblock();
252 	sstrnleft = stackblocksize() - len;
253 	return stackblock() + len;
254 }
255 
256 
257 
258 void
259 ungrabstackstr(s, p)
260 	char *s;
261 	char *p;
262 	{
263 	stacknleft += stacknxt - s;
264 	stacknxt = s;
265 	sstrnleft = stacknleft - (p - s);
266 }
267