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