1 /*-
2  * Copyright (c) 2001 Lev Walkin <vlm@lionet.info>.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $Id: memmem.c,v 1.3 2005/03/03 20:35:26 vlm Exp $
27  */
28 
29 #include "intern.h"
30 #include "libmimedir.h"
31 
32 struct mdir_memchunk {
33 	void *p;
34 	struct mdir_memchunk *next;
35 };
36 
37 
38 int
_mdir_mem_replacechunk(struct mdir_memchunk * mdm,void * op,void * p)39 _mdir_mem_replacechunk(struct mdir_memchunk *mdm, void *op, void *p) {
40 	if(!mdm)
41 		return -1;
42 
43 	if(mdm->p == op) {
44 		mdm->p = p;
45 		return 0;
46 	}
47 
48 	return _mdir_mem_replacechunk(mdm->next, op, p);
49 }
50 
51 void *
_mdir_mem_realloc(void ** arg,void * op,size_t size)52 _mdir_mem_realloc(void **arg, void *op, size_t size) {
53 	void *p;
54 
55 	p = realloc(op, size);
56 
57 	if(op != p)
58 		_mdir_mem_replacechunk((struct mdir_memchunk *)*arg, op, p);
59 
60 	return p;
61 }
62 
63 int
_mdir_mem_forgetchunk2(struct mdir_memchunk * mdm,void * p)64 _mdir_mem_forgetchunk2(struct mdir_memchunk *mdm, void *p) {
65 	if(!mdm)
66 		return -1;
67 
68 	if(mdm->p == p) {
69 		mdm->p = NULL;
70 		return 0;
71 	}
72 
73 	return _mdir_mem_forgetchunk2(mdm->next, p);
74 }
75 
76 void
_mdir_mem_forgetchunk(void ** arg,void * p)77 _mdir_mem_forgetchunk(void **arg, void *p) {
78 	if(_mdir_mem_forgetchunk2((struct mdir_memchunk *)*arg, p)) {
79 		fprintf(stderr, "forgetchunk() on not allocated data: %p\n", p);
80 		abort();
81 	}
82 }
83 
84 void
_mdir_mem_free(void ** arg,void * p)85 _mdir_mem_free(void **arg, void *p) {
86 	if(_mdir_mem_forgetchunk2((struct mdir_memchunk *)*arg, p)) {
87 		fprintf(stderr, "free() on not allocated data: %p\n", p);
88 		abort();
89 	} else {
90 		free(p);
91 	}
92 }
93 
94 
95 int
_mdir_mem_addchunk(void ** arg,void * p)96 _mdir_mem_addchunk(void **arg, void *p) {
97 	struct mdir_memchunk *mch;
98 
99 	mch = (struct mdir_memchunk *)malloc(sizeof(struct mdir_memchunk));
100 	if(!mch)
101 		return -1;
102 
103 	/* Add to the head */
104 	mch->next = *arg;
105 	mch->p = p;
106 	*arg = mch;
107 
108 	return 0;
109 };
110 
111 void
_mdir_mem_forget2(struct mdir_memchunk * mdm,int freeit)112 _mdir_mem_forget2(struct mdir_memchunk *mdm, int freeit) {
113 	if(!mdm)
114 		return;
115 
116 	if(freeit && mdm->p) {
117 		free(mdm->p);
118 	}
119 
120 	/* One test or every chunk test? To be, or not to be? */
121 	_mdir_mem_forget2(mdm->next, freeit);
122 
123 	free(mdm);
124 };
125 
126 void
_mdir_mem_forget(void ** arg,int freeit)127 _mdir_mem_forget(void **arg, int freeit) {
128 	_mdir_mem_forget2((struct mdir_memchunk *)*arg, freeit);
129 	*(void **)arg = NULL;
130 };
131 
132 void *
_mdir_mem_malloc(void ** arg,size_t size)133 _mdir_mem_malloc(void **arg, size_t size) {
134 	void *p;
135 
136 	p = malloc(size);
137 	if(!p)
138 		return NULL;
139 
140 	if(_mdir_mem_addchunk(arg, p)) {
141 		free(p);
142 		return NULL;
143 	};
144 
145 	return p;
146 };
147 
148 char *
_mdir_mem_strdup(void ** arg,char * str)149 _mdir_mem_strdup(void **arg, char *str) {
150 	char *p;
151 
152 	p = strdup(str);
153 	if(!p) return NULL;
154 
155 	if(_mdir_mem_addchunk(arg, p)) {
156 		free(p);
157 		return NULL;
158 	};
159 
160 	return p;
161 };
162 
163 char *
_mdir_mem_stradd(void ** arg,char * src,char * str)164 _mdir_mem_stradd(void **arg, char *src, char *str) {
165 	size_t len;
166 	char *p;
167 
168 	len = strlen(src);
169 
170 	p = (char *)_mdir_mem_realloc(arg, src, len + strlen(str) + 1);
171 	if(!p) {
172 		_mdir_mem_free(arg, src);
173 		return NULL;
174 	}
175 
176 	strcpy(p + len, str);
177 
178 	return p;
179 }
180 
181 size_t
_mdir_count_values(char ** list)182 _mdir_count_values(char **list) {
183 	size_t z;
184 
185 	if(!list)
186 		return 0;
187 
188 	for(z = 0; *list; list++, z++);
189 
190 	return z;
191 }
192 
193 char **
_mdir_mem_list_extend(void ** arg,char *** list)194 _mdir_mem_list_extend(void **arg, char ***list) {
195 	char **p;
196 	size_t cv;
197 
198 	if(!list) {
199 		p = (char **)_mdir_mem_malloc(arg, sizeof(char *) << 1);
200 		p[0] = NULL;
201 		p[1] = NULL;
202 		return p;
203 	}
204 
205 	cv = _mdir_count_values(*list);
206 	p = (char **)_mdir_mem_realloc(arg, *list, (cv + 2) * sizeof(char *));
207 	if(!p)
208 		return NULL;
209 
210 	p[cv + 1] = NULL;
211 	*list = p;
212 
213 	return p + cv;
214 }
215 
216 void
_mdir_list_free(char ** list)217 _mdir_list_free(char **list) {
218 	char **vp;
219 	for(vp = list; *vp; vp++)
220 		free(*vp);
221 	free(list);
222 }
223 
224 
225