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
33253734Speter#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;
87253734Speter
88251876Speter    qsort(pItems,nItems,sizeof *pItems,crude_order);
89251876Speter    for(n=0 ; n < nItems ; ++n) {
90253734Speter        pData[n].nPredecessors=0;
91253734Speter        pData[n].ppPredecessors=apr_pcalloc(p,nItems*sizeof *pData[n].ppPredecessors);
92253734Speter        pData[n].pNext=NULL;
93253734Speter        pData[n].pData=&pItems[n];
94251876Speter    }
95251876Speter
96251876Speter    for(n=0 ; n < nItems ; ++n) {
97253734Speter        int i,k;
98251876Speter
99253734Speter        for(i=0 ; pItems[n].aszPredecessors && pItems[n].aszPredecessors[i] ; ++i)
100253734Speter            for(k=0 ; k < nItems ; ++k)
101253734Speter                if(!strcmp(pItems[k].szName,pItems[n].aszPredecessors[i])) {
102253734Speter                    int l;
103251876Speter
104253734Speter                    for(l=0 ; l < pData[n].nPredecessors ; ++l)
105253734Speter                        if(pData[n].ppPredecessors[l] == &pData[k])
106253734Speter                            goto got_it;
107253734Speter                    pData[n].ppPredecessors[pData[n].nPredecessors]=&pData[k];
108253734Speter                    ++pData[n].nPredecessors;
109253734Speter                got_it:
110253734Speter                    break;
111253734Speter                }
112253734Speter        for(i=0 ; pItems[n].aszSuccessors && pItems[n].aszSuccessors[i] ; ++i)
113253734Speter            for(k=0 ; k < nItems ; ++k)
114253734Speter                if(!strcmp(pItems[k].szName,pItems[n].aszSuccessors[i])) {
115253734Speter                    int l;
116251876Speter
117253734Speter                    for(l=0 ; l < pData[k].nPredecessors ; ++l)
118253734Speter                        if(pData[k].ppPredecessors[l] == &pData[n])
119253734Speter                            goto got_it2;
120253734Speter                    pData[k].ppPredecessors[pData[k].nPredecessors]=&pData[n];
121253734Speter                    ++pData[k].nPredecessors;
122253734Speter                got_it2:
123253734Speter                    break;
124253734Speter                }
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) {
146253734Speter        int n,i,k;
147251876Speter
148253734Speter        for(n=0 ; ; ++n) {
149253734Speter            if(n == nItems)
150253734Speter                assert(0);      /* we have a loop... */
151253734Speter            if(!pData[n].pNext) {
152253734Speter                if(pData[n].nPredecessors) {
153253734Speter                    for(k=0 ; ; ++k) {
154253734Speter                        assert(k < nItems);
155253734Speter                        if(pData[n].ppPredecessors[k])
156253734Speter                            break;
157253734Speter                    }
158253734Speter                    for(i=0 ; ; ++i) {
159253734Speter                        assert(i < nItems);
160253734Speter                        if(&pData[i] == pData[n].ppPredecessors[k]) {
161253734Speter                            n=i-1;
162253734Speter                            break;
163253734Speter                        }
164253734Speter                    }
165253734Speter                } else
166253734Speter                    break;
167253734Speter            }
168253734Speter        }
169253734Speter        if(pTail)
170253734Speter            pTail->pNext=&pData[n];
171253734Speter        else
172253734Speter            pHead=&pData[n];
173253734Speter        pTail=&pData[n];
174253734Speter        pTail->pNext=pTail;     /* fudge it so it looks linked */
175253734Speter        for(i=0 ; i < nItems ; ++i)
176253734Speter            for(k=0 ; k < nItems ; ++k)
177253734Speter                if(pData[i].ppPredecessors[k] == &pData[n]) {
178253734Speter                    --pData[i].nPredecessors;
179253734Speter                    pData[i].ppPredecessors[k]=NULL;
180253734Speter                    break;
181253734Speter                }
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,
188253734Speter                                     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)
200253734Speter        printf("Sorting %s:",szName);
201251876Speter    for(n=0 ; pSort ; pSort=pSort->pNext,++n) {
202253734Speter        TSortData *pHook;
203253734Speter        assert(n < pHooks->nelts);
204253734Speter        pHook=apr_array_push(pNew);
205253734Speter        memcpy(pHook,pSort->pData,sizeof *pHook);
206253734Speter        if(apr_hook_debug_enabled)
207253734Speter            printf(" %s",pHook->szName);
208251876Speter    }
209251876Speter    if(apr_hook_debug_enabled)
210253734Speter        fputc('\n',stdout);
211253734Speter
212253734Speter    /* destroy the pool - the sorted hooks were already copied */
213253734Speter    apr_pool_destroy(p);
214253734Speter
215251876Speter    return pNew;
216251876Speter}
217251876Speter
218251876Speter#ifndef NETWARE
219251876Speterstatic apr_array_header_t *s_aHooksToSort;
220251876Speter#endif
221251876Speter
222251876Spetertypedef struct
223251876Speter{
224251876Speter    const char *szHookName;
225251876Speter    apr_array_header_t **paHooks;
226251876Speter} HookSortEntry;
227251876Speter
228251876SpeterAPU_DECLARE(void) apr_hook_sort_register(const char *szHookName,
229253734Speter                                        apr_array_header_t **paHooks)
230251876Speter{
231251876Speter#ifdef NETWARE
232251876Speter    get_apd
233251876Speter#endif
234251876Speter    HookSortEntry *pEntry;
235251876Speter
236251876Speter    if(!s_aHooksToSort)
237251876Speter        s_aHooksToSort=apr_array_make(apr_hook_global_pool,1,sizeof(HookSortEntry));
238251876Speter    pEntry=apr_array_push(s_aHooksToSort);
239251876Speter    pEntry->szHookName=szHookName;
240251876Speter    pEntry->paHooks=paHooks;
241251876Speter}
242251876Speter
243251876SpeterAPU_DECLARE(void) apr_hook_sort_all(void)
244251876Speter{
245251876Speter#ifdef NETWARE
246251876Speter    get_apd
247251876Speter#endif
248251876Speter    int n;
249251876Speter
250251876Speter    if (!s_aHooksToSort) {
251251876Speter        s_aHooksToSort = apr_array_make(apr_hook_global_pool, 1, sizeof(HookSortEntry));
252251876Speter    }
253253734Speter
254251876Speter    for(n=0 ; n < s_aHooksToSort->nelts ; ++n) {
255253734Speter        HookSortEntry *pEntry=&((HookSortEntry *)s_aHooksToSort->elts)[n];
256253734Speter        *pEntry->paHooks=sort_hook(*pEntry->paHooks,pEntry->szHookName);
257251876Speter    }
258251876Speter}
259251876Speter
260251876Speter#ifndef NETWARE
261251876Speterstatic apr_hash_t *s_phOptionalHooks;
262251876Speterstatic apr_hash_t *s_phOptionalFunctions;
263251876Speter#endif
264251876Speter
265251876SpeterAPU_DECLARE(void) apr_hook_deregister_all(void)
266251876Speter{
267251876Speter#ifdef NETWARE
268251876Speter    get_apd
269251876Speter#endif
270253734Speter    int n;
271251876Speter
272251876Speter    if (!s_aHooksToSort) {
273251876Speter        return;
274251876Speter    }
275251876Speter
276251876Speter    for(n=0 ; n < s_aHooksToSort->nelts ; ++n) {
277251876Speter        HookSortEntry *pEntry=&((HookSortEntry *)s_aHooksToSort->elts)[n];
278251876Speter        *pEntry->paHooks=NULL;
279251876Speter    }
280251876Speter    s_aHooksToSort=NULL;
281251876Speter    s_phOptionalHooks=NULL;
282251876Speter    s_phOptionalFunctions=NULL;
283251876Speter}
284251876Speter
285251876SpeterAPU_DECLARE(void) apr_hook_debug_show(const char *szName,
286251876Speter                                      const char * const *aszPre,
287253734Speter                                      const char * const *aszSucc)
288251876Speter{
289251876Speter    int nFirst;
290251876Speter
291251876Speter    printf("  Hooked %s",szName);
292251876Speter    if(aszPre) {
293253734Speter        fputs(" pre(",stdout);
294253734Speter        nFirst=1;
295253734Speter        while(*aszPre) {
296253734Speter            if(!nFirst)
297253734Speter                fputc(',',stdout);
298253734Speter            nFirst=0;
299253734Speter            fputs(*aszPre,stdout);
300253734Speter            ++aszPre;
301253734Speter        }
302253734Speter        fputc(')',stdout);
303251876Speter    }
304251876Speter    if(aszSucc) {
305253734Speter        fputs(" succ(",stdout);
306253734Speter        nFirst=1;
307253734Speter        while(*aszSucc) {
308253734Speter            if(!nFirst)
309253734Speter                fputc(',',stdout);
310253734Speter            nFirst=0;
311253734Speter            fputs(*aszSucc,stdout);
312253734Speter            ++aszSucc;
313253734Speter        }
314253734Speter        fputc(')',stdout);
315251876Speter    }
316251876Speter    fputc('\n',stdout);
317251876Speter}
318251876Speter
319251876Speter/* Optional hook support */
320251876Speter
321251876SpeterAPR_DECLARE_EXTERNAL_HOOK(apr,APU,void,_optional,(void))
322251876Speter
323251876SpeterAPU_DECLARE(apr_array_header_t *) apr_optional_hook_get(const char *szName)
324251876Speter{
325251876Speter#ifdef NETWARE
326251876Speter    get_apd
327251876Speter#endif
328251876Speter    apr_array_header_t **ppArray;
329251876Speter
330251876Speter    if(!s_phOptionalHooks)
331253734Speter        return NULL;
332251876Speter    ppArray=apr_hash_get(s_phOptionalHooks,szName,strlen(szName));
333251876Speter    if(!ppArray)
334253734Speter        return NULL;
335251876Speter    return *ppArray;
336251876Speter}
337251876Speter
338251876SpeterAPU_DECLARE(void) apr_optional_hook_add(const char *szName,void (*pfn)(void),
339253734Speter                                        const char * const *aszPre,
340253734Speter                                        const char * const *aszSucc,int nOrder)
341251876Speter{
342251876Speter#ifdef NETWARE
343251876Speter    get_apd
344251876Speter#endif
345251876Speter    apr_array_header_t *pArray=apr_optional_hook_get(szName);
346251876Speter    apr_LINK__optional_t *pHook;
347251876Speter
348251876Speter    if(!pArray) {
349253734Speter        apr_array_header_t **ppArray;
350251876Speter
351253734Speter        pArray=apr_array_make(apr_hook_global_pool,1,
352253734Speter                              sizeof(apr_LINK__optional_t));
353253734Speter        if(!s_phOptionalHooks)
354253734Speter            s_phOptionalHooks=apr_hash_make(apr_hook_global_pool);
355253734Speter        ppArray=apr_palloc(apr_hook_global_pool,sizeof *ppArray);
356253734Speter        *ppArray=pArray;
357253734Speter        apr_hash_set(s_phOptionalHooks,szName,strlen(szName),ppArray);
358253734Speter        apr_hook_sort_register(szName,ppArray);
359251876Speter    }
360251876Speter    pHook=apr_array_push(pArray);
361251876Speter    pHook->pFunc=pfn;
362251876Speter    pHook->aszPredecessors=aszPre;
363251876Speter    pHook->aszSuccessors=aszSucc;
364251876Speter    pHook->nOrder=nOrder;
365251876Speter    pHook->szName=apr_hook_debug_current;
366251876Speter    if(apr_hook_debug_enabled)
367253734Speter        apr_hook_debug_show(szName,aszPre,aszSucc);
368251876Speter}
369251876Speter
370251876Speter/* optional function support */
371251876Speter
372251876SpeterAPU_DECLARE(apr_opt_fn_t *) apr_dynamic_fn_retrieve(const char *szName)
373251876Speter{
374251876Speter#ifdef NETWARE
375251876Speter    get_apd
376251876Speter#endif
377251876Speter    if(!s_phOptionalFunctions)
378253734Speter        return NULL;
379251876Speter    return (void(*)(void))apr_hash_get(s_phOptionalFunctions,szName,strlen(szName));
380251876Speter}
381251876Speter
382251876Speter/* Deprecated */
383251876SpeterAPU_DECLARE_NONSTD(void) apr_dynamic_fn_register(const char *szName,
384251876Speter                                                  apr_opt_fn_t *pfn)
385251876Speter{
386251876Speter#ifdef NETWARE
387251876Speter    get_apd
388251876Speter#endif
389251876Speter    if(!s_phOptionalFunctions)
390253734Speter        s_phOptionalFunctions=apr_hash_make(apr_hook_global_pool);
391251876Speter    apr_hash_set(s_phOptionalFunctions,szName,strlen(szName),(void *)pfn);
392251876Speter}
393251876Speter
394251876Speter#if 0
395251876Spetervoid main()
396251876Speter{
397251876Speter    const char *aszAPre[]={"b","c",NULL};
398251876Speter    const char *aszBPost[]={"a",NULL};
399251876Speter    const char *aszCPost[]={"b",NULL};
400251876Speter    TSortData t1[]=
401251876Speter    {
402253734Speter        { "a",aszAPre,NULL },
403253734Speter        { "b",NULL,aszBPost },
404253734Speter        { "c",NULL,aszCPost }
405251876Speter    };
406251876Speter    TSort *pResult;
407251876Speter
408251876Speter    pResult=prepare(t1,3);
409251876Speter    pResult=tsort(pResult,3);
410251876Speter
411251876Speter    for( ; pResult ; pResult=pResult->pNext)
412253734Speter        printf("%s\n",pResult->pData->szName);
413251876Speter}
414251876Speter#endif
415