Goto sanos source index
//
// stmalloc.c
//
// Stacked memory allocation
//
// Copyright (C) 2011 Michael Ringgaard. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. Neither the name of the project nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
#include "sh.h"
void pushstkmark(struct stkmark *oldmark, struct stkmark *newmark) {
if (oldmark) {
newmark->blk = oldmark->blk;
newmark->ptr = oldmark->ptr;
newmark->txt = oldmark->txt;
newmark->end = oldmark->end;
} else {
newmark->blk = NULL;
newmark->ptr = NULL;
newmark->txt = NULL;
newmark->end = NULL;
}
newmark->prev = oldmark;
}
void popstkmark(struct stkmark *mark) {
struct stkblk *blk = mark->blk;
struct stkblk *prev_mark_blk = mark->prev ? mark->prev->blk : NULL;
while (blk && blk != prev_mark_blk) {
struct stkblk *prev = blk->prev;
free(blk);
blk = prev;
}
}
void *stalloc(struct stkmark *mark, int size) {
char *ptr;
if (mark->txt) printf("=== alloc with active string\n");
if (size > mark->end - mark->ptr) {
int blksize;
struct stkblk *blk;
blksize = size;
if (blksize < STKBLKMIN) blksize = STKBLKMIN;
//printf("==== malloc new block (%d bytes)\n", size);
blk = (struct stkblk *) malloc(sizeof(struct stkblk) - STKBLKMIN + blksize);
if (!blk) return NULL;
blk->prev = mark->blk;
mark->blk = blk;
mark->ptr = blk->space;
mark->end = mark->ptr + blksize;
}
ptr = mark->ptr;
memset(ptr, 0, size);
mark->ptr += size;
return ptr;
}
static int streserve(struct stkmark *mark, int size) {
int txtlen;
if (!mark->txt) mark->txt = mark->ptr;
if (mark->txt + size <= mark->end) return 0;
txtlen = mark->txt - mark->ptr;
if (mark->blk && mark->ptr == mark->blk->space && (!mark->prev || mark->blk != mark->prev->blk)) {
int blksize = mark->end - mark->ptr;
int minsize = txtlen + size;
while (blksize < minsize) blksize *= 2;
//printf("==== realloc string block (%d bytes)\n", blksize);
mark->blk = (struct stkblk *) realloc(mark->blk, blksize);
if (!mark->blk) return -1;
mark->ptr = mark->blk->space;
mark->end = mark->ptr + blksize;
mark->txt = mark->ptr + txtlen;
} else {
struct stkblk *blk;
int blksize = txtlen + size;
if (blksize < STKBLKMIN) blksize = STKBLKMIN;
//printf("==== malloc new string block %d\n", blksize);
blk = (struct stkblk *) malloc(sizeof(struct stkblk) - STKBLKMIN + blksize);
if (!blk) return -1;
if (mark->txt) {
//printf("==== copying %d string bytes\n", txtlen);
memcpy(blk->space, mark->ptr, txtlen);
mark->txt = blk->space + txtlen;
}
blk->prev = mark->blk;
mark->blk = blk;
mark->ptr = blk->space;
mark->end = mark->ptr + blksize;
}
if (!mark->txt) mark->txt = mark->ptr;
return 0;
}
int stputbuf(struct stkmark *mark, char *data, int len) {
if (streserve(mark, len) < 0) return -1;
memcpy(mark->txt, data, len);
mark->txt += len;
return 0;
}
int stputstr(struct stkmark *mark, char *str) {
return stputbuf(mark, str, strlen(str));
}
int stputc(struct stkmark *mark, int ch) {
if (streserve(mark, 1) < 0) return -1;
*(mark->txt)++ = ch;
return 0;
}
char *ststrdup(struct stkmark *mark, char *str) {
int len;
char *s;
if (!str) return NULL;
len = strlen(str);
s = stalloc(mark, len + 1);
memcpy(s, str, len + 1);
return s;
}
char *ststr(struct stkmark *mark) {
char *str;
if (!mark->txt) return NULL;
if (stputc(mark, 0) < 0) return NULL;
str = mark->ptr;
mark->ptr = mark->txt;
mark->txt = NULL;
return str;
}
int ststrlen(struct stkmark *mark) {
if (!mark->txt) return -1;
return mark->txt - mark->ptr;
}
char *ststrptr(struct stkmark *mark) {
if (!mark->txt) return NULL;
return mark->ptr;
}
int stfreestr(struct stkmark *mark, char *str) {
if (!str) return 0;
if (mark->blk && mark->blk->space <= str && str <= mark->ptr) {
mark->ptr = str;
return 0;
} else {
return -1;
}
}