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