Bug 880: Prevent SIGSEGV in init_python when -no-home is used.
[elinks.git] / src / util / memlist.c
blobed24ccd778b5e6f842a5e8b1bb478053c0645a06
1 /* These routines represent handling of struct memory_list. */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include <stdarg.h>
8 #include <stdlib.h>
10 #include "elinks.h"
12 #include "util/error.h"
13 #include "util/memlist.h"
14 #include "util/memory.h"
18 * memory_list is used to track information about all allocated memory
19 * belonging to something. Then we can free it when we won't need it
20 * anymore, but the one who allocated it won't be able to get control
21 * back in order to free it himself.
24 #define ML_SIZE(n) (sizeof(struct memory_list) + (n) * sizeof(void *))
26 /* Create a memory list. If p is NULL or allocation fails, it will
27 * returns NULL.
28 * It always stops at first NULL element. */
29 #ifdef DEBUG_MEMLIST
30 struct memory_list *
31 debug_getml(unsigned char *file, int line, void *p, ...)
32 #else
33 struct memory_list *
34 getml(void *p, ...)
35 #endif
37 struct memory_list *ml;
38 va_list ap;
39 void *q;
40 int n = 1;
42 /* If first element is NULL, there's no need to allocate memory, so
43 * just return. */
44 if (!p) return NULL;
46 /* How many elements ? */
47 va_start(ap, p);
48 while ((q = va_arg(ap, void *))) n++;
49 va_end(ap);
51 /* Allocate space for memory list. */
52 ml = mem_alloc(ML_SIZE(n));
53 if (!ml) return NULL;
55 /* First element. */
56 ml->n = 1;
57 ml->p[0] = p;
59 /* Next ones. */
60 va_start(ap, p);
61 while ((q = va_arg(ap, void *))) ml->p[ml->n++] = q;
62 va_end(ap);
64 /* The end. */
65 return ml;
68 /* Add elements to a memory list.
69 * If memory list exists, it enlarges it, else it creates it.
70 * if there's no elements or first element is NULL, it does nothing.
71 * It always stops at first NULL element. */
72 #ifdef DEBUG_MEMLIST
73 void
74 debug_add_to_ml(unsigned char *file, int line, struct memory_list **ml, ...)
75 #else
76 void
77 add_to_ml(struct memory_list **ml, ...)
78 #endif
80 va_list ap;
81 void *q;
82 int n = 0;
84 /* How many new elements ? */
85 va_start(ap, ml);
86 while ((q = va_arg(ap, void *))) n++;
87 va_end(ap);
89 /* None, so just return. */
90 if (!n) {
91 #ifdef DEBUG_MEMLIST
92 errline = line, errfile = file;
93 elinks_error("add_to_ml(%p, NULL, ...)", ml);
94 #endif
95 return;
98 if (!*ml) {
99 /* If getml() wasn't called before or returned NULL,
100 * then we create it. */
101 *ml = mem_alloc(ML_SIZE(n));
102 if (!*ml) return;
104 (*ml)->n = 0;
105 } else {
106 /* Enlarge existing ml. */
107 struct memory_list *nml;
109 nml = mem_realloc(*ml, ML_SIZE(n + (*ml)->n));
110 if (!nml) return;
112 *ml = nml;
115 /* Set ml with new elements and update count. */
116 va_start(ap, ml);
117 while ((q = va_arg(ap, void *))) (*ml)->p[(*ml)->n++] = q;
118 va_end(ap);
121 #ifdef DEBUG_MEMLIST
122 void
123 debug_add_one_to_ml(unsigned char *file, int line, struct memory_list **ml, void *p)
124 #else
125 void
126 add_one_to_ml(struct memory_list **ml, void *p)
127 #endif
129 /* None, so just return. */
130 if (!p) {
131 #ifdef DEBUG_MEMLIST
132 errline = line, errfile = file;
133 elinks_error("add_one_to_ml(%p, NULL)", ml);
134 #endif
135 return;
138 if (!*ml) {
139 /* If getml() wasn't called before or returned NULL,
140 * then we create it. */
141 *ml = mem_alloc(ML_SIZE(1));
142 if (!*ml) return;
144 (*ml)->n = 0;
145 } else {
146 /* Enlarge existing ml. */
147 struct memory_list *nml;
149 nml = mem_realloc(*ml, ML_SIZE(1 + (*ml)->n));
150 if (!nml) return;
152 *ml = nml;
155 /* Set ml with new element and update count. */
156 (*ml)->p[(*ml)->n++] = p;
160 /* Free elements and memory list.
161 * It returns safely if passed a NULL pointer. */
162 void
163 freeml(struct memory_list *ml)
165 int i;
167 if (!ml) return;
169 for (i = 0; i < ml->n; i++)
170 mem_free(ml->p[i]);
172 mem_free(ml);
175 #undef ML_SIZE