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