1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-11-04 08:17:17 -05:00
elinks/src/util/memlist.c
2007-04-26 15:02:04 +02:00

180 lines
3.6 KiB
C

/* These routines represent handling of struct memory_list. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdarg.h>
#include <stdlib.h>
#include "elinks.h"
#include "util/error.h"
#include "util/memlist.h"
#include "util/memory.h"
/*
* memory_list is used to track information about all allocated memory
* belonging to something. Then we can free it when we won't need it
* anymore, but the one who allocated it won't be able to get control
* back in order to free it himself.
*/
#define ML_SIZE(n) (sizeof(struct memory_list) + (n) * sizeof(void *))
/* Create a memory list. If p is NULL or allocation fails, it will
* returns NULL.
* It always stops at first NULL element. */
#if defined(DEBUG_MEMLIST) && defined(HAVE_VARIADIC_MACROS)
struct memory_list *
debug_getml(unsigned char *file, int line, void *p, ...)
#else
struct memory_list *
getml(void *p, ...)
#endif
{
struct memory_list *ml;
va_list ap;
void *q;
int n = 1;
/* If first element is NULL, there's no need to allocate memory, so
* just return. */
if (!p) return NULL;
/* How many elements ? */
va_start(ap, p);
while ((q = va_arg(ap, void *))) n++;
va_end(ap);
/* Allocate space for memory list. */
ml = mem_alloc(ML_SIZE(n));
if (!ml) return NULL;
/* First element. */
ml->n = 1;
ml->p[0] = p;
/* Next ones. */
va_start(ap, p);
while ((q = va_arg(ap, void *))) ml->p[ml->n++] = q;
va_end(ap);
/* The end. */
return ml;
}
/* Add elements to a memory list.
* If memory list exists, it enlarges it, else it creates it.
* if there's no elements or first element is NULL, it does nothing.
* It always stops at first NULL element. */
#if defined(DEBUG_MEMLIST) && defined(HAVE_VARIADIC_MACROS)
void
debug_add_to_ml(unsigned char *file, int line, struct memory_list **ml, ...)
#else
void
add_to_ml(struct memory_list **ml, ...)
#endif
{
va_list ap;
void *q;
int n = 0;
/* How many new elements ? */
va_start(ap, ml);
while ((q = va_arg(ap, void *))) n++;
va_end(ap);
/* None, so just return. */
if (!n) {
#ifdef DEBUG_MEMLIST
#ifdef HAVE_VARIADIC_MACROS
errline = line, errfile = file;
#else
errline = 0, errfile = "?";
#endif
elinks_error("add_to_ml(%p, NULL, ...)", ml);
#endif
return;
}
if (!*ml) {
/* If getml() wasn't called before or returned NULL,
* then we create it. */
*ml = mem_alloc(ML_SIZE(n));
if (!*ml) return;
(*ml)->n = 0;
} else {
/* Enlarge existing ml. */
struct memory_list *nml;
nml = mem_realloc(*ml, ML_SIZE(n + (*ml)->n));
if (!nml) return;
*ml = nml;
}
/* Set ml with new elements and update count. */
va_start(ap, ml);
while ((q = va_arg(ap, void *))) (*ml)->p[(*ml)->n++] = q;
va_end(ap);
}
#ifdef DEBUG_MEMLIST
void
debug_add_one_to_ml(unsigned char *file, int line, struct memory_list **ml, void *p)
#else
void
add_one_to_ml(struct memory_list **ml, void *p)
#endif
{
/* None, so just return. */
if (!p) {
#ifdef DEBUG_MEMLIST
errline = line, errfile = file;
elinks_error("add_one_to_ml(%p, NULL)", ml);
#endif
return;
}
if (!*ml) {
/* If getml() wasn't called before or returned NULL,
* then we create it. */
*ml = mem_alloc(ML_SIZE(1));
if (!*ml) return;
(*ml)->n = 0;
} else {
/* Enlarge existing ml. */
struct memory_list *nml;
nml = mem_realloc(*ml, ML_SIZE(1 + (*ml)->n));
if (!nml) return;
*ml = nml;
}
/* Set ml with new element and update count. */
(*ml)->p[(*ml)->n++] = p;
}
/* Free elements and memory list.
* It returns safely if passed a NULL pointer. */
void
freeml(struct memory_list *ml)
{
int i;
if (!ml) return;
for (i = 0; i < ml->n; i++)
mem_free(ml->p[i]);
mem_free(ml);
}
#undef ML_SIZE