mirror of
https://github.com/rkd77/elinks.git
synced 2024-11-04 08:17:17 -05:00
180 lines
3.6 KiB
C
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
|