memalloc.c

Go to the documentation of this file.
00001 /*-
00002  * Copyright (c) 1991 The Regents of the University of California.
00003  * All rights reserved.
00004  *
00005  * This code is derived from software contributed to Berkeley by
00006  * Kenneth Almquist.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions
00010  * are met:
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  * 3. All advertising materials mentioning features or use of this software
00017  *    must display the following acknowledgement:
00018  *      This product includes software developed by the University of
00019  *      California, Berkeley and its contributors.
00020  * 4. Neither the name of the University nor the names of its contributors
00021  *    may be used to endorse or promote products derived from this software
00022  *    without specific prior written permission.
00023  *
00024  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00025  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00027  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00028  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00029  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00030  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00031  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00032  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00033  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00034  * SUCH DAMAGE.
00035  */
00036 
00037 #ifndef lint
00038 static char sccsid[] = "@(#)memalloc.c  5.2 (Berkeley) 3/13/91";
00039 #endif /* not lint */
00040 
00041 #include "shell.h"
00042 #include "output.h"
00043 #include "memalloc.h"
00044 #include "error.h"
00045 #include "machdep.h"
00046 #include "mystring.h"
00047 
00048 /*
00049  * Like malloc, but returns an error when out of space.
00050  */
00051 
00052 pointer
00053 ckmalloc(nbytes) {
00054         register pointer p;
00055         pointer malloc();
00056 
00057         if ((p = malloc(nbytes)) == NULL)
00058                 error("Out of space");
00059         return p;
00060 }
00061 
00062 
00063 /*
00064  * Same for realloc.
00065  */
00066 
00067 pointer
00068 ckrealloc(p, nbytes)
00069         register pointer p;
00070         {
00071         pointer realloc();
00072 
00073         if ((p = realloc(p, nbytes)) == NULL)
00074                 error("Out of space");
00075         return p;
00076 }
00077 
00078 
00079 /*
00080  * Make a copy of a string in safe storage.
00081  */
00082 
00083 char *
00084 savestr(s)
00085         char *s;
00086         {
00087         register char *p;
00088 
00089         p = ckmalloc(strlen(s) + 1);
00090         scopy(s, p);
00091         return p;
00092 }
00093 
00094 
00095 /*
00096  * Parse trees for commands are allocated in lifo order, so we use a stack
00097  * to make this more efficient, and also to avoid all sorts of exception
00098  * handling code to handle interrupts in the middle of a parse.
00099  *
00100  * The size 504 was chosen because the Ultrix malloc handles that size
00101  * well.
00102  */
00103 
00104 #define MINSIZE 504             /* minimum size of a block */
00105 
00106 
00107 struct stack_block {
00108         struct stack_block *prev;
00109         char space[MINSIZE];
00110 };
00111 
00112 struct stack_block stackbase;
00113 struct stack_block *stackp = &stackbase;
00114 char *stacknxt = stackbase.space;
00115 int stacknleft = MINSIZE;
00116 int sstrnleft;
00117 int herefd = -1;
00118 
00119 
00120 
00121 pointer
00122 stalloc(nbytes) {
00123         register char *p;
00124 
00125         nbytes = ALIGN(nbytes);
00126         if (nbytes > stacknleft) {
00127                 int blocksize;
00128                 struct stack_block *sp;
00129 
00130                 blocksize = nbytes;
00131                 if (blocksize < MINSIZE)
00132                         blocksize = MINSIZE;
00133                 INTOFF;
00134                 sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
00135                 sp->prev = stackp;
00136                 stacknxt = sp->space;
00137                 stacknleft = blocksize;
00138                 stackp = sp;
00139                 INTON;
00140         }
00141         p = stacknxt;
00142         stacknxt += nbytes;
00143         stacknleft -= nbytes;
00144         return p;
00145 }
00146 
00147 
00148 void
00149 stunalloc(p)
00150         pointer p;
00151         {
00152         if (p == NULL) {                /*DEBUG */
00153                 write(2, "stunalloc\n", 10);
00154                 abort();
00155         }
00156         stacknleft += stacknxt - (char *)p;
00157         stacknxt = p;
00158 }
00159 
00160 
00161 
00162 void
00163 setstackmark(mark)
00164         struct stackmark *mark;
00165         {
00166         mark->stackp = stackp;
00167         mark->stacknxt = stacknxt;
00168         mark->stacknleft = stacknleft;
00169 }
00170 
00171 
00172 void
00173 popstackmark(mark)
00174         struct stackmark *mark;
00175         {
00176         struct stack_block *sp;
00177 
00178         INTOFF;
00179         while (stackp != mark->stackp) {
00180                 sp = stackp;
00181                 stackp = sp->prev;
00182                 ckfree(sp);
00183         }
00184         stacknxt = mark->stacknxt;
00185         stacknleft = mark->stacknleft;
00186         INTON;
00187 }
00188 
00189 
00190 /*
00191  * When the parser reads in a string, it wants to stick the string on the
00192  * stack and only adjust the stack pointer when it knows how big the
00193  * string is.  Stackblock (defined in stack.h) returns a pointer to a block
00194  * of space on top of the stack and stackblocklen returns the length of
00195  * this block.  Growstackblock will grow this space by at least one byte,
00196  * possibly moving it (like realloc).  Grabstackblock actually allocates the
00197  * part of the block that has been used.
00198  */
00199 
00200 void
00201 growstackblock() {
00202         char *p;
00203         int newlen = stacknleft * 2 + 100;
00204         char *oldspace = stacknxt;
00205         int oldlen = stacknleft;
00206         struct stack_block *sp;
00207 
00208         if (stacknxt == stackp->space && stackp != &stackbase) {
00209                 INTOFF;
00210                 sp = stackp;
00211                 stackp = sp->prev;
00212                 sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
00213                 sp->prev = stackp;
00214                 stackp = sp;
00215                 stacknxt = sp->space;
00216                 stacknleft = newlen;
00217                 INTON;
00218         } else {
00219                 p = stalloc(newlen);
00220                 bcopy(oldspace, p, oldlen);
00221                 stacknxt = p;                   /* free the space */
00222                 stacknleft += newlen;           /* we just allocated */
00223         }
00224 }
00225 
00226 
00227 
00228 void
00229 grabstackblock(len) {
00230         len = ALIGN(len);
00231         stacknxt += len;
00232         stacknleft -= len;
00233 }
00234 
00235 
00236 
00237 /*
00238  * The following routines are somewhat easier to use that the above.
00239  * The user declares a variable of type STACKSTR, which may be declared
00240  * to be a register.  The macro STARTSTACKSTR initializes things.  Then
00241  * the user uses the macro STPUTC to add characters to the string.  In
00242  * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
00243  * grown as necessary.  When the user is done, she can just leave the
00244  * string there and refer to it using stackblock().  Or she can allocate
00245  * the space for it using grabstackstr().  If it is necessary to allow
00246  * someone else to use the stack temporarily and then continue to grow
00247  * the string, the user should use grabstack to allocate the space, and
00248  * then call ungrabstr(p) to return to the previous mode of operation.
00249  *
00250  * USTPUTC is like STPUTC except that it doesn't check for overflow.
00251  * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
00252  * is space for at least one character.
00253  */
00254 
00255 
00256 char *
00257 growstackstr() {
00258         int len = stackblocksize();
00259         if (herefd >= 0 && len >= 1024) {
00260                 xwrite(herefd, stackblock(), len);
00261                 sstrnleft = len - 1;
00262                 return stackblock();
00263         }
00264         growstackblock();
00265         sstrnleft = stackblocksize() - len - 1;
00266         return stackblock() + len;
00267 }
00268 
00269 
00270 /*
00271  * Called from CHECKSTRSPACE.
00272  */
00273 
00274 char *
00275 makestrspace() {
00276         int len = stackblocksize() - sstrnleft;
00277         growstackblock();
00278         sstrnleft = stackblocksize() - len;
00279         return stackblock() + len;
00280 }
00281 
00282 
00283 
00284 void
00285 ungrabstackstr(s, p)
00286         char *s;
00287         char *p;
00288         {
00289         stacknleft += stacknxt - s;
00290         stacknxt = s;
00291         sstrnleft = stacknleft - (p - s);
00292 }

Generated on Fri Apr 14 22:56:41 2006 for minix by  doxygen 1.4.6