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