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