Fix memory leak when maintaining resources. When extra resources are
[apr-util.git] / hooks / apr_hooks.c
blobc9d5f4b036eb79158facac8774dfebd3f7491bcc
1 /* Copyright 2000-2004 The Apache Software Foundation
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 #include <assert.h>
17 #include <stdio.h>
18 #include <stdlib.h>
20 #include "apr_pools.h"
21 #include "apr_tables.h"
22 #include "apr.h"
23 #include "apr_hooks.h"
24 #include "apr_hash.h"
25 #include "apr_optional_hooks.h"
26 #include "apr_optional.h"
27 #define APR_WANT_MEMFUNC
28 #define APR_WANT_STRFUNC
29 #include "apr_want.h"
31 #if 0
32 #define apr_palloc(pool,size) malloc(size)
33 #endif
35 APU_DECLARE_DATA apr_pool_t *apr_hook_global_pool = NULL;
36 APU_DECLARE_DATA int apr_hook_debug_enabled = 0;
37 APU_DECLARE_DATA const char *apr_hook_debug_current = NULL;
39 /** @deprecated @see apr_hook_global_pool */
40 APU_DECLARE_DATA apr_pool_t *apr_global_hook_pool = NULL;
42 /** @deprecated @see apr_hook_debug_enabled */
43 APU_DECLARE_DATA int apr_debug_module_hooks = 0;
45 /** @deprecated @see apr_hook_debug_current */
46 APU_DECLARE_DATA const char *apr_current_hooking_module = NULL;
48 /* NB: This must echo the LINK_##name structure */
49 typedef struct
51 void (*dummy)(void *);
52 const char *szName;
53 const char * const *aszPredecessors;
54 const char * const *aszSuccessors;
55 int nOrder;
56 } TSortData;
58 typedef struct tsort_
60 void *pData;
61 int nPredecessors;
62 struct tsort_ **ppPredecessors;
63 struct tsort_ *pNext;
64 } TSort;
66 #ifdef NETWARE
67 #include "apr_private.h"
68 #define get_apd APP_DATA* apd = (APP_DATA*)get_app_data(gLibId);
69 #define s_aHooksToSort ((apr_array_header_t *)(apd->gs_aHooksToSort))
70 #define s_phOptionalHooks ((apr_hash_t *)(apd->gs_phOptionalHooks))
71 #define s_phOptionalFunctions ((apr_hash_t *)(apd->gs_phOptionalFunctions))
72 #endif
74 static int crude_order(const void *a_,const void *b_)
76 const TSortData *a=a_;
77 const TSortData *b=b_;
79 return a->nOrder-b->nOrder;
82 static TSort *prepare(apr_pool_t *p,TSortData *pItems,int nItems)
84 TSort *pData=apr_palloc(p,nItems*sizeof *pData);
85 int n;
87 qsort(pItems,nItems,sizeof *pItems,crude_order);
88 for(n=0 ; n < nItems ; ++n) {
89 pData[n].nPredecessors=0;
90 pData[n].ppPredecessors=apr_pcalloc(p,nItems*sizeof *pData[n].ppPredecessors);
91 pData[n].pNext=NULL;
92 pData[n].pData=&pItems[n];
95 for(n=0 ; n < nItems ; ++n) {
96 int i,k;
98 for(i=0 ; pItems[n].aszPredecessors && pItems[n].aszPredecessors[i] ; ++i)
99 for(k=0 ; k < nItems ; ++k)
100 if(!strcmp(pItems[k].szName,pItems[n].aszPredecessors[i])) {
101 int l;
103 for(l=0 ; l < pData[n].nPredecessors ; ++l)
104 if(pData[n].ppPredecessors[l] == &pData[k])
105 goto got_it;
106 pData[n].ppPredecessors[pData[n].nPredecessors]=&pData[k];
107 ++pData[n].nPredecessors;
108 got_it:
109 break;
111 for(i=0 ; pItems[n].aszSuccessors && pItems[n].aszSuccessors[i] ; ++i)
112 for(k=0 ; k < nItems ; ++k)
113 if(!strcmp(pItems[k].szName,pItems[n].aszSuccessors[i])) {
114 int l;
116 for(l=0 ; l < pData[k].nPredecessors ; ++l)
117 if(pData[k].ppPredecessors[l] == &pData[n])
118 goto got_it2;
119 pData[k].ppPredecessors[pData[k].nPredecessors]=&pData[n];
120 ++pData[k].nPredecessors;
121 got_it2:
122 break;
126 return pData;
129 /* Topologically sort, dragging out-of-order items to the front. Note that
130 this tends to preserve things that want to be near the front better, and
131 changing that behaviour might compromise some of Apache's behaviour (in
132 particular, mod_log_forensic might otherwise get pushed to the end, and
133 core.c's log open function used to end up at the end when pushing items
134 to the back was the methedology). Also note that the algorithm could
135 go back to its original simplicity by sorting from the back instead of
136 the front.
138 static TSort *tsort(TSort *pData,int nItems)
140 int nTotal;
141 TSort *pHead=NULL;
142 TSort *pTail=NULL;
144 for(nTotal=0 ; nTotal < nItems ; ++nTotal) {
145 int n,i,k;
147 for(n=0 ; ; ++n) {
148 if(n == nItems)
149 assert(0); /* we have a loop... */
150 if(!pData[n].pNext) {
151 if(pData[n].nPredecessors) {
152 for(k=0 ; ; ++k) {
153 assert(k < nItems);
154 if(pData[n].ppPredecessors[k])
155 break;
157 for(i=0 ; ; ++i) {
158 assert(i < nItems);
159 if(&pData[i] == pData[n].ppPredecessors[k]) {
160 n=i-1;
161 break;
164 } else
165 break;
168 if(pTail)
169 pTail->pNext=&pData[n];
170 else
171 pHead=&pData[n];
172 pTail=&pData[n];
173 pTail->pNext=pTail; /* fudge it so it looks linked */
174 for(i=0 ; i < nItems ; ++i)
175 for(k=0 ; k < nItems ; ++k)
176 if(pData[i].ppPredecessors[k] == &pData[n]) {
177 --pData[i].nPredecessors;
178 pData[i].ppPredecessors[k]=NULL;
179 break;
182 pTail->pNext=NULL; /* unfudge the tail */
183 return pHead;
186 static apr_array_header_t *sort_hook(apr_array_header_t *pHooks,
187 const char *szName)
189 apr_pool_t *p;
190 TSort *pSort;
191 apr_array_header_t *pNew;
192 int n;
194 apr_pool_create(&p, apr_hook_global_pool);
195 pSort=prepare(p,(TSortData *)pHooks->elts,pHooks->nelts);
196 pSort=tsort(pSort,pHooks->nelts);
197 pNew=apr_array_make(apr_hook_global_pool,pHooks->nelts,sizeof(TSortData));
198 if(apr_hook_debug_enabled)
199 printf("Sorting %s:",szName);
200 for(n=0 ; pSort ; pSort=pSort->pNext,++n) {
201 TSortData *pHook;
202 assert(n < pHooks->nelts);
203 pHook=apr_array_push(pNew);
204 memcpy(pHook,pSort->pData,sizeof *pHook);
205 if(apr_hook_debug_enabled)
206 printf(" %s",pHook->szName);
208 if(apr_hook_debug_enabled)
209 fputc('\n',stdout);
210 return pNew;
213 #ifndef NETWARE
214 static apr_array_header_t *s_aHooksToSort;
215 #endif
217 typedef struct
219 const char *szHookName;
220 apr_array_header_t **paHooks;
221 } HookSortEntry;
223 APU_DECLARE(void) apr_hook_sort_register(const char *szHookName,
224 apr_array_header_t **paHooks)
226 #ifdef NETWARE
227 get_apd
228 #endif
229 HookSortEntry *pEntry;
231 if(!s_aHooksToSort)
232 s_aHooksToSort=apr_array_make(apr_hook_global_pool,1,sizeof(HookSortEntry));
233 pEntry=apr_array_push(s_aHooksToSort);
234 pEntry->szHookName=szHookName;
235 pEntry->paHooks=paHooks;
238 APU_DECLARE(void) apr_hook_sort_all(void)
240 #ifdef NETWARE
241 get_apd
242 #endif
243 int n;
245 for(n=0 ; n < s_aHooksToSort->nelts ; ++n) {
246 HookSortEntry *pEntry=&((HookSortEntry *)s_aHooksToSort->elts)[n];
247 *pEntry->paHooks=sort_hook(*pEntry->paHooks,pEntry->szHookName);
251 #ifndef NETWARE
252 static apr_hash_t *s_phOptionalHooks;
253 static apr_hash_t *s_phOptionalFunctions;
254 #endif
256 APU_DECLARE(void) apr_hook_deregister_all(void)
258 #ifdef NETWARE
259 get_apd
260 #endif
261 int n;
263 for(n=0 ; n < s_aHooksToSort->nelts ; ++n) {
264 HookSortEntry *pEntry=&((HookSortEntry *)s_aHooksToSort->elts)[n];
265 *pEntry->paHooks=NULL;
267 s_aHooksToSort=NULL;
268 s_phOptionalHooks=NULL;
269 s_phOptionalFunctions=NULL;
272 APU_DECLARE(void) apr_hook_debug_show(const char *szName,
273 const char * const *aszPre,
274 const char * const *aszSucc)
276 int nFirst;
278 printf(" Hooked %s",szName);
279 if(aszPre) {
280 fputs(" pre(",stdout);
281 nFirst=1;
282 while(*aszPre) {
283 if(!nFirst)
284 fputc(',',stdout);
285 nFirst=0;
286 fputs(*aszPre,stdout);
287 ++aszPre;
289 fputc(')',stdout);
291 if(aszSucc) {
292 fputs(" succ(",stdout);
293 nFirst=1;
294 while(*aszSucc) {
295 if(!nFirst)
296 fputc(',',stdout);
297 nFirst=0;
298 fputs(*aszSucc,stdout);
299 ++aszSucc;
301 fputc(')',stdout);
303 fputc('\n',stdout);
306 /* Optional hook support */
308 APR_DECLARE_EXTERNAL_HOOK(apr,APU,void,_optional,(void))
310 APU_DECLARE(apr_array_header_t *) apr_optional_hook_get(const char *szName)
312 #ifdef NETWARE
313 get_apd
314 #endif
315 apr_array_header_t **ppArray;
317 if(!s_phOptionalHooks)
318 return NULL;
319 ppArray=apr_hash_get(s_phOptionalHooks,szName,strlen(szName));
320 if(!ppArray)
321 return NULL;
322 return *ppArray;
325 APU_DECLARE(void) apr_optional_hook_add(const char *szName,void (*pfn)(void),
326 const char * const *aszPre,
327 const char * const *aszSucc,int nOrder)
329 #ifdef NETWARE
330 get_apd
331 #endif
332 apr_array_header_t *pArray=apr_optional_hook_get(szName);
333 apr_LINK__optional_t *pHook;
335 if(!pArray) {
336 apr_array_header_t **ppArray;
338 pArray=apr_array_make(apr_hook_global_pool,1,
339 sizeof(apr_LINK__optional_t));
340 if(!s_phOptionalHooks)
341 s_phOptionalHooks=apr_hash_make(apr_hook_global_pool);
342 ppArray=apr_palloc(apr_hook_global_pool,sizeof *ppArray);
343 *ppArray=pArray;
344 apr_hash_set(s_phOptionalHooks,szName,strlen(szName),ppArray);
345 apr_hook_sort_register(szName,ppArray);
347 pHook=apr_array_push(pArray);
348 pHook->pFunc=pfn;
349 pHook->aszPredecessors=aszPre;
350 pHook->aszSuccessors=aszSucc;
351 pHook->nOrder=nOrder;
352 pHook->szName=apr_hook_debug_current;
353 if(apr_hook_debug_enabled)
354 apr_hook_debug_show(szName,aszPre,aszSucc);
357 /* optional function support */
359 APU_DECLARE(apr_opt_fn_t *) apr_dynamic_fn_retrieve(const char *szName)
361 #ifdef NETWARE
362 get_apd
363 #endif
364 if(!s_phOptionalFunctions)
365 return NULL;
366 return (void(*)(void))apr_hash_get(s_phOptionalFunctions,szName,strlen(szName));
369 /* Deprecated */
370 APU_DECLARE_NONSTD(void) apr_dynamic_fn_register(const char *szName,
371 apr_opt_fn_t *pfn)
373 #ifdef NETWARE
374 get_apd
375 #endif
376 if(!s_phOptionalFunctions)
377 s_phOptionalFunctions=apr_hash_make(apr_hook_global_pool);
378 apr_hash_set(s_phOptionalFunctions,szName,strlen(szName),(void *)pfn);
381 #if 0
382 void main()
384 const char *aszAPre[]={"b","c",NULL};
385 const char *aszBPost[]={"a",NULL};
386 const char *aszCPost[]={"b",NULL};
387 TSortData t1[]=
389 { "a",aszAPre,NULL },
390 { "b",NULL,aszBPost },
391 { "c",NULL,aszCPost }
393 TSort *pResult;
395 pResult=prepare(t1,3);
396 pResult=tsort(pResult,3);
398 for( ; pResult ; pResult=pResult->pNext)
399 printf("%s\n",pResult->pData->szName);
401 #endif