/********************************************
memory.c
libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
based on mawk code coming with the below copyright:
copyright 1991, 1992 Michael D. Brennan
This is a source file for mawk, an implementation of
the AWK programming language.
Mawk is distributed without warranty under the terms of
the GNU General Public License, version 2, 1991.
********************************************/
#include "mawk.h"
#include "memory.h"
static mawk_string_t *xnew_STRING(mawk_state_t *, unsigned);
static mawk_string_t *xnew_STRING(mawk_state_t *MAWK, unsigned len)
{
mawk_string_t *sval = (mawk_string_t *) mawk_zmalloc(MAWK, len + STRING_OH);
sval->len = len;
sval->ref_cnt = 1;
return sval;
}
/* allocate space for a mawk_string_t */
mawk_string_t *mawk_new_STRING0(mawk_state_t *MAWK, unsigned len)
{
if (len == 0) {
MAWK->null_str.ref_cnt++;
return &MAWK->null_str;
}
else {
mawk_string_t *sval = xnew_STRING(MAWK, len);
sval->str[len] = 0;
return sval;
}
}
/* convert char* to mawk_string_t* */
mawk_string_t *mawk_new_STRING(mawk_state_t *MAWK, const char *s)
{
if (s[0] == 0) {
MAWK->null_str.ref_cnt++;
return &MAWK->null_str;
}
else {
mawk_string_t *sval = xnew_STRING(MAWK, strlen(s));
strcpy(sval->str, s);
return sval;
}
}
#ifdef DEBUG
void DB_free_STRING(mawk_state_t *MAWK, register mawk_string_t *sval)
{
if (--sval->ref_cnt == 0)
mawk_zfree(MAWK, sval, sval->len + STRING_OH);
}
#endif
/**************************************************************************
large block allocation: collect all allocation in a double linked list in
MAWK so they can be easily free'd without any leak at the end of script
execution. Also do memory accounting and don't allocate over preset limit.
***************************************************************************/
#define OVERHEAD ((char *)&(r->data) - (char *)(r))
static void *mawk_mm_link(mawk_state_t *MAWK, mawk_mm_t *r)
{
r->next = MAWK->mawk_mm_head;
r->prev = NULL;
if (r->next != NULL)
r->next->prev = r;
MAWK->mawk_mm_head = r;
return &r->data;
}
static void mawk_mm_unlink(mawk_state_t *MAWK, mawk_mm_t *r)
{
if (r->prev != NULL)
r->prev->next = r->next;
else
MAWK->mawk_mm_head = r->next;
if (r->next != NULL)
r->next->prev = r->prev;
}
/* store a pointer in the mawk_mm_head list */
void *mawk_malloc(mawk_state_t *MAWK, int size)
{
mawk_mm_t *r;
if ((MAWK->mm_max > 0) && (MAWK->mm_used + size > MAWK->mm_max))
return NULL;
r = malloc(OVERHEAD + size);
r->size = OVERHEAD + size;
MAWK->mm_used += r->size;
return mawk_mm_link(MAWK, r);
}
void *mawk_realloc(mawk_state_t *MAWK, void *ptr, int size)
{
mawk_mm_t *r;
/* emulate mawk_malloc() for simpler implementation of growing buff */
if (ptr == NULL)
return mawk_malloc(MAWK, size);
r = (mawk_mm_t *)((char *)ptr - OVERHEAD);
mawk_mm_unlink(MAWK, r);
if ((MAWK->mm_max > 0) && (MAWK->mm_used - r->size + size > MAWK->mm_max))
return NULL;
MAWK->mm_used -= r->size;
r = realloc(r, OVERHEAD + size);
if (r == NULL)
return NULL;
r->size = OVERHEAD + size;
MAWK->mm_used += r->size;
return mawk_mm_link(MAWK, r);
}
void mawk_free(mawk_state_t *MAWK, void *ptr)
{
mawk_mm_t *r = (mawk_mm_t *)((char *)ptr - OVERHEAD);
mawk_mm_unlink(MAWK, r);
MAWK->mm_used -= r->size;
free(r);
}
void mawk_free_all(mawk_state_t *MAWK)
{
mawk_mm_t *r, *n;
for(r = MAWK->mawk_mm_head; r != NULL; r = n) {
n = r->next;
free(r);
}
MAWK->mawk_mm_head = NULL;
MAWK->mm_used = 0;
}
char *mawk_strdup(mawk_state_t *MAWK, const char *s)
{
int l;
char *r;
if (s == NULL)
return NULL;
l = strlen(s);
r = mawk_malloc(MAWK, l+1);
memcpy(r, s, l+1);
return r;
}
char *mawk_strdup_(const char *s)
{
int l;
char *r;
if (s == NULL)
return NULL;
l = strlen(s);
r = malloc(l+1);
memcpy(r, s, l+1);
return r;
}