apr_hooks.c revision 251876
1251876Speter/* Licensed to the Apache Software Foundation (ASF) under one or more
2251876Speter * contributor license agreements.  See the NOTICE file distributed with
3251876Speter * this work for additional information regarding copyright ownership.
4251876Speter * The ASF licenses this file to You under the Apache License, Version 2.0
5251876Speter * (the "License"); you may not use this file except in compliance with
6251876Speter * the License.  You may obtain a copy of the License at
7251876Speter *
8251876Speter *     http://www.apache.org/licenses/LICENSE-2.0
9251876Speter *
10251876Speter * Unless required by applicable law or agreed to in writing, software
11251876Speter * distributed under the License is distributed on an "AS IS" BASIS,
12251876Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13251876Speter * See the License for the specific language governing permissions and
14251876Speter * limitations under the License.
15251876Speter */
16251876Speter
17251876Speter#include <assert.h>
18251876Speter#include <stdio.h>
19251876Speter#include <stdlib.h>
20251876Speter
21251876Speter#include "apr_pools.h"
22251876Speter#include "apr_tables.h"
23251876Speter#include "apr.h"
24251876Speter#include "apr_hooks.h"
25251876Speter#include "apr_hash.h"
26251876Speter#include "apr_optional_hooks.h"
27251876Speter#include "apr_optional.h"
28251876Speter#define APR_WANT_MEMFUNC
29251876Speter#define APR_WANT_STRFUNC
30251876Speter#include "apr_want.h"
31251876Speter
32251876Speter#if 0
33251876Speter#define apr_palloc(pool,size)	malloc(size)
34251876Speter#endif
35251876Speter
36251876SpeterAPU_DECLARE_DATA apr_pool_t *apr_hook_global_pool = NULL;
37251876SpeterAPU_DECLARE_DATA int apr_hook_debug_enabled = 0;
38251876SpeterAPU_DECLARE_DATA const char *apr_hook_debug_current = NULL;
39251876Speter
40251876Speter/** @deprecated @see apr_hook_global_pool */
41251876SpeterAPU_DECLARE_DATA apr_pool_t *apr_global_hook_pool = NULL;
42251876Speter
43251876Speter/** @deprecated @see apr_hook_debug_enabled */
44251876SpeterAPU_DECLARE_DATA int apr_debug_module_hooks = 0;
45251876Speter
46251876Speter/** @deprecated @see apr_hook_debug_current */
47251876SpeterAPU_DECLARE_DATA const char *apr_current_hooking_module = NULL;
48251876Speter
49251876Speter/* NB: This must echo the LINK_##name structure */
50251876Spetertypedef struct
51251876Speter{
52251876Speter    void (*dummy)(void *);
53251876Speter    const char *szName;
54251876Speter    const char * const *aszPredecessors;
55251876Speter    const char * const *aszSuccessors;
56251876Speter    int nOrder;
57251876Speter} TSortData;
58251876Speter
59251876Spetertypedef struct tsort_
60251876Speter{
61251876Speter    void *pData;
62251876Speter    int nPredecessors;
63251876Speter    struct tsort_ **ppPredecessors;
64251876Speter    struct tsort_ *pNext;
65251876Speter} TSort;
66251876Speter
67251876Speter#ifdef NETWARE
68251876Speter#include "apr_private.h"
69251876Speter#define get_apd                 APP_DATA* apd = (APP_DATA*)get_app_data(gLibId);
70251876Speter#define s_aHooksToSort          ((apr_array_header_t *)(apd->gs_aHooksToSort))
71251876Speter#define s_phOptionalHooks       ((apr_hash_t *)(apd->gs_phOptionalHooks))
72251876Speter#define s_phOptionalFunctions   ((apr_hash_t *)(apd->gs_phOptionalFunctions))
73251876Speter#endif
74251876Speter
75251876Speterstatic int crude_order(const void *a_,const void *b_)
76251876Speter{
77251876Speter    const TSortData *a=a_;
78251876Speter    const TSortData *b=b_;
79251876Speter
80251876Speter    return a->nOrder-b->nOrder;
81251876Speter}
82251876Speter
83251876Speterstatic TSort *prepare(apr_pool_t *p,TSortData *pItems,int nItems)
84251876Speter{
85251876Speter    TSort *pData=apr_palloc(p,nItems*sizeof *pData);
86251876Speter    int n;
87251876Speter
88251876Speter    qsort(pItems,nItems,sizeof *pItems,crude_order);
89251876Speter    for(n=0 ; n < nItems ; ++n) {
90251876Speter	pData[n].nPredecessors=0;
91251876Speter	pData[n].ppPredecessors=apr_pcalloc(p,nItems*sizeof *pData[n].ppPredecessors);
92251876Speter	pData[n].pNext=NULL;
93251876Speter	pData[n].pData=&pItems[n];
94251876Speter    }
95251876Speter
96251876Speter    for(n=0 ; n < nItems ; ++n) {
97251876Speter	int i,k;
98251876Speter
99251876Speter	for(i=0 ; pItems[n].aszPredecessors && pItems[n].aszPredecessors[i] ; ++i)
100251876Speter	    for(k=0 ; k < nItems ; ++k)
101251876Speter		if(!strcmp(pItems[k].szName,pItems[n].aszPredecessors[i])) {
102251876Speter		    int l;
103251876Speter
104251876Speter		    for(l=0 ; l < pData[n].nPredecessors ; ++l)
105251876Speter			if(pData[n].ppPredecessors[l] == &pData[k])
106251876Speter			    goto got_it;
107251876Speter		    pData[n].ppPredecessors[pData[n].nPredecessors]=&pData[k];
108251876Speter		    ++pData[n].nPredecessors;
109251876Speter		got_it:
110251876Speter		    break;
111251876Speter		}
112251876Speter	for(i=0 ; pItems[n].aszSuccessors && pItems[n].aszSuccessors[i] ; ++i)
113251876Speter	    for(k=0 ; k < nItems ; ++k)
114251876Speter		if(!strcmp(pItems[k].szName,pItems[n].aszSuccessors[i])) {
115251876Speter		    int l;
116251876Speter
117251876Speter		    for(l=0 ; l < pData[k].nPredecessors ; ++l)
118251876Speter			if(pData[k].ppPredecessors[l] == &pData[n])
119251876Speter			    goto got_it2;
120251876Speter		    pData[k].ppPredecessors[pData[k].nPredecessors]=&pData[n];
121251876Speter		    ++pData[k].nPredecessors;
122251876Speter		got_it2:
123251876Speter		    break;
124251876Speter		}
125251876Speter    }
126251876Speter
127251876Speter    return pData;
128251876Speter}
129251876Speter
130251876Speter/* Topologically sort, dragging out-of-order items to the front. Note that
131251876Speter   this tends to preserve things that want to be near the front better, and
132251876Speter   changing that behaviour might compromise some of Apache's behaviour (in
133251876Speter   particular, mod_log_forensic might otherwise get pushed to the end, and
134251876Speter   core.c's log open function used to end up at the end when pushing items
135251876Speter   to the back was the methedology). Also note that the algorithm could
136251876Speter   go back to its original simplicity by sorting from the back instead of
137251876Speter   the front.
138251876Speter*/
139251876Speterstatic TSort *tsort(TSort *pData,int nItems)
140251876Speter{
141251876Speter    int nTotal;
142251876Speter    TSort *pHead=NULL;
143251876Speter    TSort *pTail=NULL;
144251876Speter
145251876Speter    for(nTotal=0 ; nTotal < nItems ; ++nTotal) {
146251876Speter	int n,i,k;
147251876Speter
148251876Speter	for(n=0 ; ; ++n) {
149251876Speter	    if(n == nItems)
150251876Speter		assert(0);      /* we have a loop... */
151251876Speter	    if(!pData[n].pNext) {
152251876Speter		if(pData[n].nPredecessors) {
153251876Speter		    for(k=0 ; ; ++k) {
154251876Speter			assert(k < nItems);
155251876Speter			if(pData[n].ppPredecessors[k])
156251876Speter			    break;
157251876Speter		    }
158251876Speter		    for(i=0 ; ; ++i) {
159251876Speter			assert(i < nItems);
160251876Speter			if(&pData[i] == pData[n].ppPredecessors[k]) {
161251876Speter			    n=i-1;
162251876Speter			    break;
163251876Speter			}
164251876Speter		    }
165251876Speter		} else
166251876Speter		    break;
167251876Speter	    }
168251876Speter	}
169251876Speter	if(pTail)
170251876Speter	    pTail->pNext=&pData[n];
171251876Speter	else
172251876Speter	    pHead=&pData[n];
173251876Speter	pTail=&pData[n];
174251876Speter	pTail->pNext=pTail;     /* fudge it so it looks linked */
175251876Speter	for(i=0 ; i < nItems ; ++i)
176251876Speter	    for(k=0 ; k < nItems ; ++k)
177251876Speter		if(pData[i].ppPredecessors[k] == &pData[n]) {
178251876Speter		    --pData[i].nPredecessors;
179251876Speter		    pData[i].ppPredecessors[k]=NULL;
180251876Speter		    break;
181251876Speter		}
182251876Speter    }
183251876Speter    pTail->pNext=NULL;  /* unfudge the tail */
184251876Speter    return pHead;
185251876Speter}
186251876Speter
187251876Speterstatic apr_array_header_t *sort_hook(apr_array_header_t *pHooks,
188251876Speter				     const char *szName)
189251876Speter{
190251876Speter    apr_pool_t *p;
191251876Speter    TSort *pSort;
192251876Speter    apr_array_header_t *pNew;
193251876Speter    int n;
194251876Speter
195251876Speter    apr_pool_create(&p, apr_hook_global_pool);
196251876Speter    pSort=prepare(p,(TSortData *)pHooks->elts,pHooks->nelts);
197251876Speter    pSort=tsort(pSort,pHooks->nelts);
198251876Speter    pNew=apr_array_make(apr_hook_global_pool,pHooks->nelts,sizeof(TSortData));
199251876Speter    if(apr_hook_debug_enabled)
200251876Speter	printf("Sorting %s:",szName);
201251876Speter    for(n=0 ; pSort ; pSort=pSort->pNext,++n) {
202251876Speter	TSortData *pHook;
203251876Speter	assert(n < pHooks->nelts);
204251876Speter	pHook=apr_array_push(pNew);
205251876Speter	memcpy(pHook,pSort->pData,sizeof *pHook);
206251876Speter	if(apr_hook_debug_enabled)
207251876Speter	    printf(" %s",pHook->szName);
208251876Speter    }
209251876Speter    if(apr_hook_debug_enabled)
210251876Speter	fputc('\n',stdout);
211251876Speter    return pNew;
212251876Speter}
213251876Speter
214251876Speter#ifndef NETWARE
215251876Speterstatic apr_array_header_t *s_aHooksToSort;
216251876Speter#endif
217251876Speter
218251876Spetertypedef struct
219251876Speter{
220251876Speter    const char *szHookName;
221251876Speter    apr_array_header_t **paHooks;
222251876Speter} HookSortEntry;
223251876Speter
224251876SpeterAPU_DECLARE(void) apr_hook_sort_register(const char *szHookName,
225251876Speter					apr_array_header_t **paHooks)
226251876Speter{
227251876Speter#ifdef NETWARE
228251876Speter    get_apd
229251876Speter#endif
230251876Speter    HookSortEntry *pEntry;
231251876Speter
232251876Speter    if(!s_aHooksToSort)
233251876Speter        s_aHooksToSort=apr_array_make(apr_hook_global_pool,1,sizeof(HookSortEntry));
234251876Speter    pEntry=apr_array_push(s_aHooksToSort);
235251876Speter    pEntry->szHookName=szHookName;
236251876Speter    pEntry->paHooks=paHooks;
237251876Speter}
238251876Speter
239251876SpeterAPU_DECLARE(void) apr_hook_sort_all(void)
240251876Speter{
241251876Speter#ifdef NETWARE
242251876Speter    get_apd
243251876Speter#endif
244251876Speter    int n;
245251876Speter
246251876Speter    if (!s_aHooksToSort) {
247251876Speter        s_aHooksToSort = apr_array_make(apr_hook_global_pool, 1, sizeof(HookSortEntry));
248251876Speter    }
249251876Speter
250251876Speter    for(n=0 ; n < s_aHooksToSort->nelts ; ++n) {
251251876Speter	HookSortEntry *pEntry=&((HookSortEntry *)s_aHooksToSort->elts)[n];
252251876Speter	*pEntry->paHooks=sort_hook(*pEntry->paHooks,pEntry->szHookName);
253251876Speter    }
254251876Speter}
255251876Speter
256251876Speter#ifndef NETWARE
257251876Speterstatic apr_hash_t *s_phOptionalHooks;
258251876Speterstatic apr_hash_t *s_phOptionalFunctions;
259251876Speter#endif
260251876Speter
261251876SpeterAPU_DECLARE(void) apr_hook_deregister_all(void)
262251876Speter{
263251876Speter#ifdef NETWARE
264251876Speter    get_apd
265251876Speter#endif
266251876Speter    int n;
267251876Speter
268251876Speter    if (!s_aHooksToSort) {
269251876Speter        return;
270251876Speter    }
271251876Speter
272251876Speter    for(n=0 ; n < s_aHooksToSort->nelts ; ++n) {
273251876Speter        HookSortEntry *pEntry=&((HookSortEntry *)s_aHooksToSort->elts)[n];
274251876Speter        *pEntry->paHooks=NULL;
275251876Speter    }
276251876Speter    s_aHooksToSort=NULL;
277251876Speter    s_phOptionalHooks=NULL;
278251876Speter    s_phOptionalFunctions=NULL;
279251876Speter}
280251876Speter
281251876SpeterAPU_DECLARE(void) apr_hook_debug_show(const char *szName,
282251876Speter                                      const char * const *aszPre,
283251876Speter			              const char * const *aszSucc)
284251876Speter{
285251876Speter    int nFirst;
286251876Speter
287251876Speter    printf("  Hooked %s",szName);
288251876Speter    if(aszPre) {
289251876Speter	fputs(" pre(",stdout);
290251876Speter	nFirst=1;
291251876Speter	while(*aszPre) {
292251876Speter	    if(!nFirst)
293251876Speter		fputc(',',stdout);
294251876Speter	    nFirst=0;
295251876Speter	    fputs(*aszPre,stdout);
296251876Speter	    ++aszPre;
297251876Speter	}
298251876Speter	fputc(')',stdout);
299251876Speter    }
300251876Speter    if(aszSucc) {
301251876Speter	fputs(" succ(",stdout);
302251876Speter	nFirst=1;
303251876Speter	while(*aszSucc) {
304251876Speter	    if(!nFirst)
305251876Speter		fputc(',',stdout);
306251876Speter	    nFirst=0;
307251876Speter	    fputs(*aszSucc,stdout);
308251876Speter	    ++aszSucc;
309251876Speter	}
310251876Speter	fputc(')',stdout);
311251876Speter    }
312251876Speter    fputc('\n',stdout);
313251876Speter}
314251876Speter
315251876Speter/* Optional hook support */
316251876Speter
317251876SpeterAPR_DECLARE_EXTERNAL_HOOK(apr,APU,void,_optional,(void))
318251876Speter
319251876SpeterAPU_DECLARE(apr_array_header_t *) apr_optional_hook_get(const char *szName)
320251876Speter{
321251876Speter#ifdef NETWARE
322251876Speter    get_apd
323251876Speter#endif
324251876Speter    apr_array_header_t **ppArray;
325251876Speter
326251876Speter    if(!s_phOptionalHooks)
327251876Speter	return NULL;
328251876Speter    ppArray=apr_hash_get(s_phOptionalHooks,szName,strlen(szName));
329251876Speter    if(!ppArray)
330251876Speter	return NULL;
331251876Speter    return *ppArray;
332251876Speter}
333251876Speter
334251876SpeterAPU_DECLARE(void) apr_optional_hook_add(const char *szName,void (*pfn)(void),
335251876Speter					const char * const *aszPre,
336251876Speter					const char * const *aszSucc,int nOrder)
337251876Speter{
338251876Speter#ifdef NETWARE
339251876Speter    get_apd
340251876Speter#endif
341251876Speter    apr_array_header_t *pArray=apr_optional_hook_get(szName);
342251876Speter    apr_LINK__optional_t *pHook;
343251876Speter
344251876Speter    if(!pArray) {
345251876Speter	apr_array_header_t **ppArray;
346251876Speter
347251876Speter	pArray=apr_array_make(apr_hook_global_pool,1,
348251876Speter			      sizeof(apr_LINK__optional_t));
349251876Speter	if(!s_phOptionalHooks)
350251876Speter	    s_phOptionalHooks=apr_hash_make(apr_hook_global_pool);
351251876Speter	ppArray=apr_palloc(apr_hook_global_pool,sizeof *ppArray);
352251876Speter	*ppArray=pArray;
353251876Speter	apr_hash_set(s_phOptionalHooks,szName,strlen(szName),ppArray);
354251876Speter	apr_hook_sort_register(szName,ppArray);
355251876Speter    }
356251876Speter    pHook=apr_array_push(pArray);
357251876Speter    pHook->pFunc=pfn;
358251876Speter    pHook->aszPredecessors=aszPre;
359251876Speter    pHook->aszSuccessors=aszSucc;
360251876Speter    pHook->nOrder=nOrder;
361251876Speter    pHook->szName=apr_hook_debug_current;
362251876Speter    if(apr_hook_debug_enabled)
363251876Speter	apr_hook_debug_show(szName,aszPre,aszSucc);
364251876Speter}
365251876Speter
366251876Speter/* optional function support */
367251876Speter
368251876SpeterAPU_DECLARE(apr_opt_fn_t *) apr_dynamic_fn_retrieve(const char *szName)
369251876Speter{
370251876Speter#ifdef NETWARE
371251876Speter    get_apd
372251876Speter#endif
373251876Speter    if(!s_phOptionalFunctions)
374251876Speter	return NULL;
375251876Speter    return (void(*)(void))apr_hash_get(s_phOptionalFunctions,szName,strlen(szName));
376251876Speter}
377251876Speter
378251876Speter/* Deprecated */
379251876SpeterAPU_DECLARE_NONSTD(void) apr_dynamic_fn_register(const char *szName,
380251876Speter                                                  apr_opt_fn_t *pfn)
381251876Speter{
382251876Speter#ifdef NETWARE
383251876Speter    get_apd
384251876Speter#endif
385251876Speter    if(!s_phOptionalFunctions)
386251876Speter	s_phOptionalFunctions=apr_hash_make(apr_hook_global_pool);
387251876Speter    apr_hash_set(s_phOptionalFunctions,szName,strlen(szName),(void *)pfn);
388251876Speter}
389251876Speter
390251876Speter#if 0
391251876Spetervoid main()
392251876Speter{
393251876Speter    const char *aszAPre[]={"b","c",NULL};
394251876Speter    const char *aszBPost[]={"a",NULL};
395251876Speter    const char *aszCPost[]={"b",NULL};
396251876Speter    TSortData t1[]=
397251876Speter    {
398251876Speter	{ "a",aszAPre,NULL },
399251876Speter	{ "b",NULL,aszBPost },
400251876Speter	{ "c",NULL,aszCPost }
401251876Speter    };
402251876Speter    TSort *pResult;
403251876Speter
404251876Speter    pResult=prepare(t1,3);
405251876Speter    pResult=tsort(pResult,3);
406251876Speter
407251876Speter    for( ; pResult ; pResult=pResult->pNext)
408251876Speter	printf("%s\n",pResult->pData->szName);
409251876Speter}
410251876Speter#endif
411