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