source: trunk/src/kash/memalloc.c@ 3461

Last change on this file since 3461 was 3461, checked in by bird, 5 years ago

kash: Cache one pstack_block since parsecmd seems to be called for each statement line in a script. Also, mark pstack blocks as 'done' before returning from parsecmd and prevent them from becoming current (curpstack) again upon popping.

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Id
File size: 18.9 KB
Line 
1/* $NetBSD: memalloc.c,v 1.28 2003/08/07 09:05:34 agc Exp $ */
2
3/*-
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Kenneth Almquist.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#if 0
36#ifndef lint
37static char sccsid[] = "@(#)memalloc.c 8.3 (Berkeley) 5/4/95";
38#else
39__RCSID("$NetBSD: memalloc.c,v 1.28 2003/08/07 09:05:34 agc Exp $");
40#endif /* not lint */
41#endif
42
43#include <stdlib.h>
44#include <stddef.h>
45#include <assert.h>
46
47#include "shell.h"
48#include "output.h"
49#include "memalloc.h"
50#include "error.h"
51#include "machdep.h"
52#include "mystring.h"
53#include "shinstance.h"
54#include "nodes.h"
55
56/*
57 * Like malloc, but returns an error when out of space.
58 */
59
60pointer
61ckmalloc(shinstance *psh, size_t nbytes)
62{
63 pointer p;
64
65 p = sh_malloc(psh, nbytes);
66 if (p == NULL)
67 error(psh, "Out of space");
68 return p;
69}
70
71
72/*
73 * Same for realloc.
74 */
75
76pointer
77ckrealloc(struct shinstance *psh, pointer p, size_t nbytes)
78{
79 p = sh_realloc(psh, p, nbytes);
80 if (p == NULL)
81 error(psh, "Out of space");
82 return p;
83}
84
85
86/*
87 * Make a copy of a string in safe storage.
88 */
89
90char *
91savestr(struct shinstance *psh, const char *s)
92{
93 char *p;
94 size_t len = strlen(s);
95
96 p = ckmalloc(psh, len + 1);
97 memcpy(p, s, len + 1);
98 return p;
99}
100
101
102/*
103 * Parse trees for commands are allocated in lifo order, so we use a stack
104 * to make this more efficient, and also to avoid all sorts of exception
105 * handling code to handle interrupts in the middle of a parse.
106 *
107 * The size 504 was chosen because the Ultrix malloc handles that size
108 * well.
109 */
110
111//#define MINSIZE 504 /* minimum size of a block */
112
113//struct stack_block {
114// struct stack_block *prev;
115// char space[MINSIZE];
116//};
117
118//struct stack_block stackbase;
119//struct stack_block *stackp = &stackbase;
120//struct stackmark *markp;
121//char *stacknxt = stackbase.space;
122//int stacknleft = MINSIZE;
123//int sstrnleft;
124//int herefd = -1;
125
126pointer
127stalloc(shinstance *psh, size_t nbytes)
128{
129 char *p;
130
131 nbytes = SHELL_ALIGN(nbytes);
132 if (nbytes > (size_t)psh->stacknleft || psh->stacknleft < 0) {
133 size_t blocksize;
134 struct stack_block *sp;
135
136 blocksize = nbytes;
137 if (blocksize < MINSIZE)
138 blocksize = MINSIZE;
139 INTOFF;
140 sp = ckmalloc(psh, sizeof(struct stack_block) - MINSIZE + blocksize);
141 sp->prev = psh->stackp;
142 psh->stacknxt = sp->space;
143 psh->stacknleft = (int)blocksize;
144 psh->stackp = sp;
145 INTON;
146 }
147 p = psh->stacknxt;
148 psh->stacknxt += nbytes;
149 psh->stacknleft -= (int)nbytes;
150 return p;
151}
152
153
154char *
155stsavestr(struct shinstance *psh, const char *src)
156{
157 if (src) {
158 size_t size = strlen(src) + 1;
159 char *dst = (char *)stalloc(psh, size);
160 return (char *)memcpy(dst, src, size);
161 }
162 return NULL;
163}
164
165
166void
167stunalloc(shinstance *psh, pointer p)
168{
169 if (p == NULL) { /*DEBUG */
170 shfile_write(&psh->fdtab, 2, "stunalloc\n", 10);
171 sh_abort(psh);
172 }
173 psh->stacknleft += (int)(psh->stacknxt - (char *)p);
174 psh->stacknxt = p;
175}
176
177
178
179void
180setstackmark(shinstance *psh, struct stackmark *mark)
181{
182 mark->stackp = psh->stackp;
183 mark->stacknxt = psh->stacknxt;
184 mark->stacknleft = psh->stacknleft;
185 mark->marknext = psh->markp;
186#ifdef KASH_SEPARATE_PARSER_ALLOCATOR
187 mark->pstacksize = psh->pstacksize;
188#endif
189 psh->markp = mark;
190}
191
192
193void
194popstackmark(shinstance *psh, struct stackmark *mark)
195{
196 struct stack_block *sp;
197
198 INTOFF;
199 psh->markp = mark->marknext;
200 while (psh->stackp != mark->stackp) {
201 sp = psh->stackp;
202 psh->stackp = sp->prev;
203 ckfree(psh, sp);
204 }
205 psh->stacknxt = mark->stacknxt;
206 psh->stacknleft = mark->stacknleft;
207
208#ifdef KASH_SEPARATE_PARSER_ALLOCATOR
209 pstackpop(psh, mark->pstacksize);
210#endif
211 INTON;
212}
213
214
215/*
216 * When the parser reads in a string, it wants to stick the string on the
217 * stack and only adjust the stack pointer when it knows how big the
218 * string is. Stackblock (defined in stack.h) returns a pointer to a block
219 * of space on top of the stack and stackblocklen returns the length of
220 * this block. Growstackblock will grow this space by at least one byte,
221 * possibly moving it (like realloc). Grabstackblock actually allocates the
222 * part of the block that has been used.
223 */
224
225void
226growstackblock(shinstance *psh)
227{
228 int newlen = SHELL_ALIGN(psh->stacknleft * 2 + 100);
229
230 if (psh->stacknxt == psh->stackp->space && psh->stackp != &psh->stackbase) {
231 struct stack_block *oldstackp;
232 struct stackmark *xmark;
233 struct stack_block *sp;
234
235 INTOFF;
236 oldstackp = psh->stackp;
237 sp = psh->stackp;
238 psh->stackp = sp->prev;
239 sp = ckrealloc(psh, (pointer)sp,
240 sizeof(struct stack_block) - MINSIZE + newlen);
241 sp->prev = psh->stackp;
242 psh->stackp = sp;
243 psh->stacknxt = sp->space;
244 psh->stacknleft = newlen;
245
246 /*
247 * Stack marks pointing to the start of the old block
248 * must be relocated to point to the new block
249 */
250 xmark = psh->markp;
251 while (xmark != NULL && xmark->stackp == oldstackp) {
252 xmark->stackp = psh->stackp;
253 xmark->stacknxt = psh->stacknxt;
254 xmark->stacknleft = psh->stacknleft;
255 xmark = xmark->marknext;
256 }
257 INTON;
258 } else {
259 char *oldspace = psh->stacknxt;
260 int oldlen = psh->stacknleft;
261 char *p = stalloc(psh, newlen);
262
263 (void)memcpy(p, oldspace, oldlen);
264 psh->stacknxt = p; /* free the space */
265 psh->stacknleft += newlen; /* we just allocated */
266 }
267}
268
269void
270grabstackblock(shinstance *psh, int len)
271{
272 len = SHELL_ALIGN(len);
273 psh->stacknxt += len;
274 psh->stacknleft -= len;
275}
276
277/*
278 * The following routines are somewhat easier to use than the above.
279 * The user declares a variable of type STACKSTR, which may be declared
280 * to be a register. The macro STARTSTACKSTR initializes things. Then
281 * the user uses the macro STPUTC to add characters to the string. In
282 * effect, STPUTC(psh, c, p) is the same as *p++ = c except that the stack is
283 * grown as necessary. When the user is done, she can just leave the
284 * string there and refer to it using stackblock(psh). Or she can allocate
285 * the space for it using grabstackstr(). If it is necessary to allow
286 * someone else to use the stack temporarily and then continue to grow
287 * the string, the user should use grabstack to allocate the space, and
288 * then call ungrabstr(p) to return to the previous mode of operation.
289 *
290 * USTPUTC is like STPUTC except that it doesn't check for overflow.
291 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
292 * is space for at least one character.
293 */
294
295char *
296growstackstr(shinstance *psh)
297{
298 int len = stackblocksize(psh);
299 if (psh->herefd >= 0 && len >= 1024) {
300 xwrite(psh, psh->herefd, stackblock(psh), len);
301 psh->sstrnleft = len - 1;
302 return stackblock(psh);
303 }
304 growstackblock(psh);
305 psh->sstrnleft = stackblocksize(psh) - len - 1;
306 return stackblock(psh) + len;
307}
308
309/*
310 * Called from CHECKSTRSPACE.
311 */
312
313char *
314makestrspace(shinstance *psh)
315{
316 int len = stackblocksize(psh) - psh->sstrnleft;
317 growstackblock(psh);
318 psh->sstrnleft = stackblocksize(psh) - len;
319 return stackblock(psh) + len;
320}
321
322
323/*
324 * Got better control having a dedicated function for this.
325 *
326 * Was: #define grabstackstr(psh, p) stalloc((psh), stackblocksize(psh) - (psh)->sstrnleft)
327 */
328char *
329grabstackstr(shinstance *psh, char *end)
330{
331 char * const pstart = stackblock(psh);
332 size_t nbytes = (size_t)(end - pstart);
333
334 assert((uintptr_t)end >= (uintptr_t)pstart);
335 /*assert(end[-1] == '\0'); - not if it's followed by ungrabstrackstr(), sigh. */
336 assert(SHELL_ALIGN((uintptr_t)pstart) == (uintptr_t)pstart);
337 assert(stackblocksize(psh) - psh->sstrnleft >= nbytes);
338
339 nbytes = SHELL_ALIGN(nbytes);
340 psh->stacknxt += nbytes;
341 psh->stacknleft -= (int)nbytes;
342 assert(psh->stacknleft >= 0);
343
344 return pstart;
345}
346
347void
348ungrabstackstr(shinstance *psh, char *s, char *p)
349{
350 assert((size_t)(psh->stacknxt - p) <= SHELL_SIZE);
351 assert((uintptr_t)s >= (uintptr_t)&psh->stackp->space[0]);
352 assert((uintptr_t)p >= (uintptr_t)s);
353
354 psh->stacknleft += (int)(psh->stacknxt - s);
355 psh->stacknxt = s;
356 psh->sstrnleft = (int)(psh->stacknleft - (p - s));
357
358}
359
360
361/*
362 * Parser stack allocator.
363 */
364#ifdef KASH_SEPARATE_PARSER_ALLOCATOR
365
366unsigned pstackrelease(shinstance *psh, pstack_block *pst, const char *caller)
367{
368 unsigned refs;
369 if (pst) {
370 refs = sh_atomic_dec(&pst->refs);
371 TRACE2((NULL, "pstackrelease: %p - %u refs (%s)\n", pst, refs, caller)); K_NOREF(caller);
372 if (refs == 0) {
373 struct stack_block *top;
374 while ((top = pst->top) != &pst->first)
375 {
376 pst->top = top->prev;
377 assert(pst->top);
378 top->prev = NULL;
379 sh_free(psh, top);
380 }
381 pst->nextbyte = NULL;
382 pst->top = NULL;
383
384 if (!psh->freepstack)
385 psh->freepstack = pst;
386 else
387 sh_free(psh, pst);
388 }
389 } else
390 refs = 0;
391 return refs;
392}
393
394void pstackpop(shinstance *psh, unsigned target)
395{
396 assert(target <= psh->pstacksize);
397 while (target < psh->pstacksize) {
398 unsigned idx = --psh->pstacksize;
399 pstack_block *pst = psh->pstack[idx];
400 psh->pstack[idx] = NULL;
401 if (psh->curpstack == pst) {
402 pstack_block *pstnext;
403 if (idx <= 0 || (pstnext = psh->pstack[idx - 1])->done)
404 psh->curpstack = NULL;
405 else
406 psh->curpstack = pstnext;
407 }
408 pstackrelease(psh, pst, "popstackmark");
409 }
410
411# ifndef NDEBUG
412 if (psh->curpstack) {
413 unsigned i;
414 for (i = 0; i < psh->pstacksize; i++)
415 if (psh->curpstack == psh->pstack[i])
416 break;
417 assert(i < psh->pstacksize);
418 }
419# endif
420}
421
422
423unsigned pstackretain(pstack_block *pst)
424{
425 unsigned refs = sh_atomic_inc(&pst->refs);
426 assert(refs > 1);
427 assert(refs < 256 /* bogus, but useful */);
428 return refs;
429}
430
431K_INLINE void pstackpush(shinstance *psh, pstack_block *pst)
432{
433 unsigned i = psh->pstacksize;
434 if (i + 1 < psh->pstackalloced) {
435 /* likely, except for the first time */
436 } else {
437 psh->pstack = (pstack_block **)ckrealloc(psh, psh->pstack, sizeof(psh->pstack[0]) * (i + 32));
438 memset(&psh->pstack[i], 0, sizeof(psh->pstack[0]) * 32);
439 }
440 psh->pstack[i] = pst;
441 psh->pstacksize = i + 1;
442}
443
444/* Does not make it current! */
445unsigned pstackretainpush(shinstance *psh, pstack_block *pst)
446{
447 unsigned refs = pstackretain(pst);
448 pstackpush(psh, pst);
449 TRACE2((psh, "pstackretainpush: %p - entry %u - %u refs\n", pst, psh->pstacksize - 1, refs));
450 return refs;
451}
452
453pstack_block *pstackallocpush(shinstance *psh)
454{
455 size_t const blocksize = offsetof(pstack_block, first.space) + MINSIZE;
456 pstack_block *pst;
457
458 INTOFF;
459
460 /*
461 * Allocate and initialize it.
462 */
463 pst = psh->freepstack;
464 if (pst)
465 psh->freepstack = NULL;
466 else
467 pst = (pstack_block *)ckmalloc(psh, blocksize);
468 pst->nextbyte = &pst->first.space[0];
469 pst->avail = blocksize - offsetof(pstack_block, first.space);
470 pst->topsize = blocksize - offsetof(pstack_block, first.space);
471 pst->top = &pst->first;
472 pst->strleft = 0;
473 pst->allocations = 0;
474 pst->bytesalloced = 0;
475 pst->nodesalloced = 0;
476 pst->entriesalloced = 0;
477 pst->strbytesalloced = 0;
478 pst->blocks = 0;
479 pst->fragmentation = 0;
480 pst->refs = 1;
481 pst->done = K_FALSE;
482 pst->first.prev = NULL;
483
484 /*
485 * Push it onto the stack and make it current.
486 */
487 pstackpush(psh, pst);
488 psh->curpstack = pst;
489
490 INTON;
491 TRACE2((psh, "pstackallocpush: %p - entry %u\n", pst, psh->pstacksize - 1));
492 return pst;
493}
494
495/**
496 * Marks the block as done, preventing it from being marked current again.
497 */
498void pstackmarkdone(pstack_block *pst)
499{
500 pst->done = K_TRUE;
501}
502
503/**
504 * Allocates and pushes a new block onto the stack, min payload size @a nbytes.
505 */
506static void pstallocnewblock(shinstance *psh, pstack_block *pst, size_t nbytes)
507{
508 /* Allocate a new stack node. */
509 struct stack_block *sp;
510 size_t const blocksize = nbytes <= MINSIZE
511 ? offsetof(struct stack_block, space) + MINSIZE
512 : K_ALIGN_Z(nbytes + offsetof(struct stack_block, space), 1024);
513
514 INTOFF;
515 sp = ckmalloc(psh, blocksize);
516 sp->prev = pst->top;
517 pst->fragmentation += pst->avail;
518 pst->topsize = blocksize - offsetof(struct stack_block, space);
519 pst->avail = blocksize - offsetof(struct stack_block, space);
520 pst->nextbyte = sp->space;
521 pst->top = sp;
522 pst->blocks += 1;
523 INTON;
524}
525
526/**
527 * Tries to grow the current stack block to hold a minimum of @a nbytes,
528 * will allocate a new block and copy over pending string bytes if that's not
529 * possible.
530 */
531static void pstgrowblock(shinstance *psh, pstack_block *pst, size_t nbytes, size_t tocopy)
532{
533 struct stack_block *top = pst->top;
534 size_t blocksize;
535
536 assert(pst->avail < nbytes); /* only called when we need more space */
537 assert(tocopy <= pst->avail);
538
539 /* Double the size used thus far and add some fudge and alignment. Make
540 sure to at least allocate MINSIZE. */
541 blocksize = K_MAX(K_ALIGN_Z(pst->avail * 2 + 100 + offsetof(struct stack_block, space), 64), MINSIZE);
542
543 /* If that isn't sufficient, do request size w/ some fudge and alignment. */
544 if (blocksize < nbytes + offsetof(struct stack_block, space))
545 blocksize = K_ALIGN_Z(nbytes + offsetof(struct stack_block, space) + 100, 1024);
546
547 /*
548 * Reallocate the current stack node if we can.
549 */
550 if ( pst->nextbyte == &top->space[0] /* can't have anything else in the block */
551 && top->prev != NULL /* first block is embedded in pst and cannot be reallocated */ ) {
552 top = (struct stack_block *)ckrealloc(psh, top, blocksize);
553 pst->top = top;
554 pst->topsize = blocksize - offsetof(struct stack_block, space);
555 pst->avail = blocksize - offsetof(struct stack_block, space);
556 pst->nextbyte = top->space;
557 }
558 /*
559 * Otherwise allocate a new node and copy over the avail bytes
560 * from the old one.
561 */
562 else {
563 char const * const copysrc = pst->nextbyte;
564 pstallocnewblock(psh, pst, nbytes);
565 assert(pst->avail >= nbytes);
566 assert(pst->avail >= tocopy);
567 memcpy(pst->nextbyte, copysrc, tocopy);
568 }
569}
570
571K_INLINE void *pstallocint(shinstance *psh, pstack_block *pst, size_t nbytes)
572{
573 void *ret;
574
575 /*
576 * Align the size and make sure we've got sufficient bytes available:
577 */
578 nbytes = SHELL_ALIGN(nbytes);
579 if (pst->avail >= nbytes && (ssize_t)pst->avail >= 0) { /* likely*/ }
580 else pstallocnewblock(psh, pst, nbytes);
581
582 /*
583 * Carve out the return block.
584 */
585 ret = pst->nextbyte;
586 pst->nextbyte += nbytes;
587 pst->avail -= nbytes;
588 pst->bytesalloced += nbytes;
589 pst->allocations += 1;
590 return ret;
591}
592
593#endif KASH_SEPARATE_PARSER_ALLOCATOR
594
595
596void *pstalloc(struct shinstance *psh, size_t nbytes)
597{
598#ifdef KASH_SEPARATE_PARSER_ALLOCATOR
599 return pstallocint(psh, psh->curpstack, nbytes);
600#else
601 return stalloc(psh, nbytes);
602#endif
603}
604
605union node *pstallocnode(struct shinstance *psh, size_t nbytes)
606{
607#ifdef KASH_SEPARATE_PARSER_ALLOCATOR
608 pstack_block * const pst = psh->curpstack;
609 union node * const ret = (union node *)pstallocint(psh, pst, nbytes);
610 pst->nodesalloced++;
611 ret->pblock = pst;
612 return ret;
613#else
614 return (union node *)pstalloc(psh, nbytes);
615#endif
616}
617
618struct nodelist *pstalloclist(struct shinstance *psh)
619{
620#ifdef KASH_SEPARATE_PARSER_ALLOCATOR
621 pstack_block *pst = psh->curpstack;
622 pst->entriesalloced++;
623 return (struct nodelist *)pstallocint(psh, pst, sizeof(struct nodelist));
624#endif
625 return (struct nodelist *)pstalloc(psh, sizeof(struct nodelist));
626}
627
628char *pstsavestr(struct shinstance *psh, const char *str)
629{
630 if (str) {
631 size_t const nbytes = strlen(str) + 1;
632#ifdef KASH_SEPARATE_PARSER_ALLOCATOR
633 pstack_block *pst = psh->curpstack;
634 pst->strbytesalloced += SHELL_ALIGN(nbytes);
635 return (char *)memcpy(pstallocint(psh, pst, nbytes), str, nbytes);
636#else
637 return (char *)memcpy(pstalloc(psh, nbytes), str, nbytes);
638#endif
639 }
640 return NULL;
641}
642
643char *pstmakestrspace(struct shinstance *psh, size_t minbytes, char *end)
644{
645#ifdef KASH_SEPARATE_PARSER_ALLOCATOR
646 pstack_block *pst = psh->curpstack;
647 size_t const len = end - pst->nextbyte;
648
649 assert(pst->avail - pst->strleft == len);
650 TRACE2((psh, "pstmakestrspace: len=%u minbytes=%u (=> %u)\n", len, minbytes, len + minbytes));
651
652 pstgrowblock(psh, pst, minbytes + len, len);
653
654 pst->strleft = pst->avail - len;
655 return pst->nextbyte + len;
656
657#else
658 size_t const len = end - stackblock(psh);
659
660 assert(stackblocksize(psh) - psh->sstrnleft == len);
661 TRACE2((psh, "pstmakestrspace: len=%u minbytes=%u (=> %u)\n", len, minbytes, len + minbytes));
662
663 minbytes += len;
664 while (stackblocksize(psh) < minbytes)
665 growstackblock(psh);
666
667 psh->sstrnleft = (int)(stackblocksize(psh) - len);
668 return (char *)stackblock(psh) + len;
669#endif
670}
671
672/* PSTPUTC helper */
673char *pstputcgrow(shinstance *psh, char *end, char c)
674{
675#ifdef KASH_SEPARATE_PARSER_ALLOCATOR
676 pstack_block *pst = psh->curpstack;
677 pst->strleft++; /* PSTPUTC() already incremented it. */
678 end = pstmakestrspace(psh, 1, end);
679 assert(pst->strleft > 0);
680 pst->strleft--;
681#else
682 psh->sstrnleft++; /* PSTPUTC() already incremented it. */
683 end = pstmakestrspace(psh, 1, end);
684 assert(psh->sstrnleft > 0);
685 psh->sstrnleft--;
686#endif
687 *end++ = c;
688 return end;
689}
690
691
692char *pstgrabstr(struct shinstance *psh, char *end)
693{
694#ifdef KASH_SEPARATE_PARSER_ALLOCATOR
695 pstack_block *pst = psh->curpstack;
696 char * const pstart = pst->nextbyte;
697 size_t nbytes = (size_t)(end - pstart);
698
699 assert((uintptr_t)end > (uintptr_t)pstart);
700 assert(end[-1] == '\0');
701 assert(SHELL_ALIGN((uintptr_t)pstart) == (uintptr_t)pstart);
702 assert(pst->avail - pst->strleft >= nbytes);
703
704 nbytes = SHELL_ALIGN(nbytes); /** @todo don't align strings, align the other allocations. */
705 pst->nextbyte += nbytes;
706 pst->avail -= nbytes;
707 pst->strbytesalloced += nbytes;
708
709 return pstart;
710
711#else
712 char * const pstart = stackblock(psh);
713 size_t nbytes = (size_t)(end - pstart);
714
715 assert((uintptr_t)end > (uintptr_t)pstart);
716 assert(end[-1] == '\0');
717 assert(SHELL_ALIGN((uintptr_t)pstart) == (uintptr_t)pstart);
718 assert(stackblocksize(psh) - psh->sstrnleft >= nbytes);
719
720 nbytes = SHELL_ALIGN(nbytes); /** @todo don't align strings, align the other allocations. */
721 psh->stacknxt += nbytes;
722 psh->stacknleft -= (int)nbytes;
723
724 return pstart;
725#endif
726}
727
Note: See TracBrowser for help on using the repository browser.