OLD | NEW |
(Empty) | |
| 1 /* |
| 2 ****************************************************************************** |
| 3 * |
| 4 * Copyright (C) 2009-2010, International Business Machines |
| 5 * Corporation and others. All Rights Reserved. |
| 6 * |
| 7 ****************************************************************************** |
| 8 * |
| 9 * FILE NAME : icuplug.c |
| 10 * |
| 11 * Date Name Description |
| 12 * 10/29/2009 sl New. |
| 13 ****************************************************************************** |
| 14 */ |
| 15 |
| 16 #include "unicode/icuplug.h" |
| 17 #include "icuplugimp.h" |
| 18 #include "cstring.h" |
| 19 #include "cmemory.h" |
| 20 #include "putilimp.h" |
| 21 #include "ucln.h" |
| 22 #include <stdio.h> |
| 23 |
| 24 #ifndef UPLUG_TRACE |
| 25 #define UPLUG_TRACE 0 |
| 26 #endif |
| 27 |
| 28 #if UPLUG_TRACE |
| 29 #include <stdio.h> |
| 30 #define DBG(x) fprintf(stderr, "%s:%d: ",__FILE__,__LINE__); fprintf x |
| 31 #endif |
| 32 |
| 33 /** |
| 34 * Internal structure of an ICU plugin. |
| 35 */ |
| 36 |
| 37 struct UPlugData { |
| 38 UPlugEntrypoint *entrypoint; /**< plugin entrypoint */ |
| 39 uint32_t structSize; /**< initialized to the size of this structure */ |
| 40 uint32_t token; /**< must be U_PLUG_TOKEN */ |
| 41 void *lib; /**< plugin library, or NULL */ |
| 42 char libName[UPLUG_NAME_MAX]; /**< library name */ |
| 43 char sym[UPLUG_NAME_MAX]; /**< plugin symbol, or NULL */ |
| 44 char config[UPLUG_NAME_MAX]; /**< configuration data */ |
| 45 void *context; /**< user context data */ |
| 46 char name[UPLUG_NAME_MAX]; /**< name of plugin */ |
| 47 UPlugLevel level; /**< level of plugin */ |
| 48 UBool awaitingLoad; /**< TRUE if the plugin is awaiting a load call */ |
| 49 UBool dontUnload; /**< TRUE if plugin must stay resident (leak plugin and li
b) */ |
| 50 UErrorCode pluginStatus; /**< status code of plugin */ |
| 51 }; |
| 52 |
| 53 |
| 54 |
| 55 #define UPLUG_LIBRARY_INITIAL_COUNT 8 |
| 56 #define UPLUG_PLUGIN_INITIAL_COUNT 12 |
| 57 |
| 58 /** |
| 59 * Remove an item |
| 60 * @param list the full list |
| 61 * @param listSize the number of entries in the list |
| 62 * @param memberSize the size of one member |
| 63 * @param itemToRemove the item number of the member |
| 64 * @return the new listsize |
| 65 */ |
| 66 static int32_t uplug_removeEntryAt(void *list, int32_t listSize, int32_t memberS
ize, int32_t itemToRemove) { |
| 67 uint8_t *bytePtr = (uint8_t *)list; |
| 68 |
| 69 /* get rid of some bad cases first */ |
| 70 if(listSize<1) { |
| 71 return listSize; |
| 72 } |
| 73 |
| 74 /* is there anything to move? */ |
| 75 if(listSize > itemToRemove+1) { |
| 76 memmove(bytePtr+(itemToRemove*memberSize), bytePtr+((itemToRemove+1)*memberS
ize), memberSize); |
| 77 } |
| 78 |
| 79 return listSize-1; |
| 80 } |
| 81 |
| 82 |
| 83 |
| 84 |
| 85 #if U_ENABLE_DYLOAD |
| 86 /** |
| 87 * Library management. Internal. |
| 88 * @internal |
| 89 */ |
| 90 struct UPlugLibrary; |
| 91 |
| 92 /** |
| 93 * Library management. Internal. |
| 94 * @internal |
| 95 */ |
| 96 typedef struct UPlugLibrary { |
| 97 void *lib; /**< library ptr */ |
| 98 char name[UPLUG_NAME_MAX]; /**< library name */ |
| 99 uint32_t ref; /**< reference count */ |
| 100 } UPlugLibrary; |
| 101 |
| 102 static UPlugLibrary staticLibraryList[UPLUG_LIBRARY_INITIAL_COUNT]; |
| 103 static UPlugLibrary * libraryList = staticLibraryList; |
| 104 static int32_t libraryCount = 0; |
| 105 static int32_t libraryMax = UPLUG_LIBRARY_INITIAL_COUNT; |
| 106 |
| 107 /** |
| 108 * Search for a library. Doesn't lock |
| 109 * @param libName libname to search for |
| 110 * @return the library's struct |
| 111 */ |
| 112 static int32_t searchForLibraryName(const char *libName) { |
| 113 int32_t i; |
| 114 |
| 115 for(i=0;i<libraryCount;i++) { |
| 116 if(!uprv_strcmp(libName, libraryList[i].name)) { |
| 117 return i; |
| 118 } |
| 119 } |
| 120 return -1; |
| 121 } |
| 122 |
| 123 static int32_t searchForLibrary(void *lib) { |
| 124 int32_t i; |
| 125 |
| 126 for(i=0;i<libraryCount;i++) { |
| 127 if(lib==libraryList[i].lib) { |
| 128 return i; |
| 129 } |
| 130 } |
| 131 return -1; |
| 132 } |
| 133 |
| 134 U_INTERNAL char * U_EXPORT2 |
| 135 uplug_findLibrary(void *lib, UErrorCode *status) { |
| 136 int32_t libEnt; |
| 137 char *ret = NULL; |
| 138 if(U_FAILURE(*status)) { |
| 139 return NULL; |
| 140 } |
| 141 libEnt = searchForLibrary(lib); |
| 142 if(libEnt!=-1) { |
| 143 ret = libraryList[libEnt].name; |
| 144 } else { |
| 145 *status = U_MISSING_RESOURCE_ERROR; |
| 146 } |
| 147 return ret; |
| 148 } |
| 149 |
| 150 U_INTERNAL void * U_EXPORT2 |
| 151 uplug_openLibrary(const char *libName, UErrorCode *status) { |
| 152 int32_t libEntry = -1; |
| 153 void *lib = NULL; |
| 154 |
| 155 if(U_FAILURE(*status)) return NULL; |
| 156 |
| 157 libEntry = searchForLibraryName(libName); |
| 158 if(libEntry == -1) { |
| 159 libEntry = libraryCount++; |
| 160 if(libraryCount >= libraryMax) { |
| 161 /* Ran out of library slots. Statically allocated because we can't depend
on allocating memory.. */ |
| 162 *status = U_MEMORY_ALLOCATION_ERROR; |
| 163 #if UPLUG_TRACE |
| 164 DBG((stderr, "uplug_openLibrary() - out of library slots (max %d)\n", libr
aryMax)); |
| 165 #endif |
| 166 return NULL; |
| 167 } |
| 168 /* Some operating systems don't want |
| 169 DL operations from multiple threads. */ |
| 170 libraryList[libEntry].lib = uprv_dl_open(libName, status); |
| 171 #if UPLUG_TRACE |
| 172 DBG((stderr, "uplug_openLibrary(%s,%s) libEntry %d, lib %p\n", libName, u_er
rorName(*status), libEntry, lib)); |
| 173 #endif |
| 174 |
| 175 if(libraryList[libEntry].lib == NULL || U_FAILURE(*status)) { |
| 176 /* cleanup. */ |
| 177 libraryList[libEntry].lib = NULL; /* failure with open */ |
| 178 libraryList[libEntry].name[0] = 0; |
| 179 #if UPLUG_TRACE |
| 180 DBG((stderr, "uplug_openLibrary(%s,%s) libEntry %d, lib %p\n", libName, u_
errorName(*status), libEntry, lib)); |
| 181 #endif |
| 182 /* no need to free - just won't increase the count. */ |
| 183 libraryCount--; |
| 184 } else { /* is it still there? */ |
| 185 /* link it in */ |
| 186 uprv_strncpy(libraryList[libEntry].name,libName,UPLUG_NAME_MAX); |
| 187 libraryList[libEntry].ref=1; |
| 188 lib = libraryList[libEntry].lib; |
| 189 } |
| 190 |
| 191 } else { |
| 192 lib = libraryList[libEntry].lib; |
| 193 libraryList[libEntry].ref++; |
| 194 } |
| 195 return lib; |
| 196 } |
| 197 |
| 198 U_INTERNAL void U_EXPORT2 |
| 199 uplug_closeLibrary(void *lib, UErrorCode *status) { |
| 200 int32_t i; |
| 201 |
| 202 #if UPLUG_TRACE |
| 203 DBG((stderr, "uplug_closeLibrary(%p,%s) list %p\n", lib, u_errorName(*status),
(void*)libraryList)); |
| 204 #endif |
| 205 if(U_FAILURE(*status)) return; |
| 206 |
| 207 for(i=0;i<libraryCount;i++) { |
| 208 if(lib==libraryList[i].lib) { |
| 209 if(--(libraryList[i].ref) == 0) { |
| 210 uprv_dl_close(libraryList[i].lib, status); |
| 211 libraryCount = uplug_removeEntryAt(libraryList, libraryCount, sizeof(*li
braryList), i); |
| 212 } |
| 213 return; |
| 214 } |
| 215 } |
| 216 *status = U_INTERNAL_PROGRAM_ERROR; /* could not find the entry! */ |
| 217 } |
| 218 |
| 219 #endif |
| 220 |
| 221 static UPlugData pluginList[UPLUG_PLUGIN_INITIAL_COUNT]; |
| 222 static int32_t pluginCount = 0; |
| 223 |
| 224 |
| 225 |
| 226 |
| 227 static int32_t uplug_pluginNumber(UPlugData* d) { |
| 228 UPlugData *pastPlug = &pluginList[pluginCount]; |
| 229 if(d<=pluginList) { |
| 230 return 0; |
| 231 } else if(d>=pastPlug) { |
| 232 return pluginCount; |
| 233 } else { |
| 234 return (d-pluginList)/sizeof(pluginList[0]); |
| 235 } |
| 236 } |
| 237 |
| 238 |
| 239 U_CAPI UPlugData * U_EXPORT2 |
| 240 uplug_nextPlug(UPlugData *prior) { |
| 241 if(prior==NULL) { |
| 242 return pluginList; |
| 243 } else { |
| 244 UPlugData *nextPlug = &prior[1]; |
| 245 UPlugData *pastPlug = &pluginList[pluginCount]; |
| 246 |
| 247 if(nextPlug>=pastPlug) { |
| 248 return NULL; |
| 249 } else { |
| 250 return nextPlug; |
| 251 } |
| 252 } |
| 253 } |
| 254 |
| 255 |
| 256 |
| 257 /** |
| 258 * Call the plugin with some params |
| 259 */ |
| 260 static void uplug_callPlug(UPlugData *plug, UPlugReason reason, UErrorCode *stat
us) { |
| 261 UPlugTokenReturn token; |
| 262 if(plug==NULL||U_FAILURE(*status)) { |
| 263 return; |
| 264 } |
| 265 token = (*(plug->entrypoint))(plug, reason, status); |
| 266 if(token!=UPLUG_TOKEN) { |
| 267 *status = U_INTERNAL_PROGRAM_ERROR; |
| 268 } |
| 269 } |
| 270 |
| 271 |
| 272 static void uplug_unloadPlug(UPlugData *plug, UErrorCode *status) { |
| 273 if(plug->awaitingLoad) { /* shouldn't happen. Plugin hasn'tbeen loaded yet.*/ |
| 274 *status = U_INTERNAL_PROGRAM_ERROR; |
| 275 return; |
| 276 } |
| 277 if(U_SUCCESS(plug->pluginStatus)) { |
| 278 /* Don't unload a plug which has a failing load status - means it didn't act
ually load. */ |
| 279 uplug_callPlug(plug, UPLUG_REASON_UNLOAD, status); |
| 280 } |
| 281 } |
| 282 |
| 283 static void uplug_queryPlug(UPlugData *plug, UErrorCode *status) { |
| 284 if(!plug->awaitingLoad || !(plug->level == UPLUG_LEVEL_UNKNOWN) ) { /* should
n't happen. Plugin hasn'tbeen loaded yet.*/ |
| 285 *status = U_INTERNAL_PROGRAM_ERROR; |
| 286 return; |
| 287 } |
| 288 plug->level = UPLUG_LEVEL_INVALID; |
| 289 uplug_callPlug(plug, UPLUG_REASON_QUERY, status); |
| 290 if(U_SUCCESS(*status)) { |
| 291 if(plug->level == UPLUG_LEVEL_INVALID) { |
| 292 plug->pluginStatus = U_PLUGIN_DIDNT_SET_LEVEL; |
| 293 plug->awaitingLoad = FALSE; |
| 294 } |
| 295 } else { |
| 296 plug->pluginStatus = U_INTERNAL_PROGRAM_ERROR; |
| 297 plug->awaitingLoad = FALSE; |
| 298 } |
| 299 } |
| 300 |
| 301 |
| 302 static void uplug_loadPlug(UPlugData *plug, UErrorCode *status) { |
| 303 if(!plug->awaitingLoad || (plug->level < UPLUG_LEVEL_LOW) ) { /* shouldn't ha
ppen. Plugin hasn'tbeen loaded yet.*/ |
| 304 *status = U_INTERNAL_PROGRAM_ERROR; |
| 305 return; |
| 306 } |
| 307 uplug_callPlug(plug, UPLUG_REASON_LOAD, status); |
| 308 plug->awaitingLoad = FALSE; |
| 309 if(!U_SUCCESS(*status)) { |
| 310 plug->pluginStatus = U_INTERNAL_PROGRAM_ERROR; |
| 311 } |
| 312 } |
| 313 |
| 314 static UPlugData *uplug_allocateEmptyPlug(UErrorCode *status) |
| 315 { |
| 316 UPlugData *plug = NULL; |
| 317 |
| 318 if(U_FAILURE(*status)) { |
| 319 return NULL; |
| 320 } |
| 321 |
| 322 if(pluginCount == UPLUG_PLUGIN_INITIAL_COUNT) { |
| 323 *status = U_MEMORY_ALLOCATION_ERROR; |
| 324 return NULL; |
| 325 } |
| 326 |
| 327 plug = &pluginList[pluginCount++]; |
| 328 |
| 329 plug->token = UPLUG_TOKEN; |
| 330 plug->structSize = sizeof(UPlugData); |
| 331 plug->name[0]=0; |
| 332 plug->level = UPLUG_LEVEL_UNKNOWN; /* initialize to null state */ |
| 333 plug->awaitingLoad = TRUE; |
| 334 plug->dontUnload = FALSE; |
| 335 plug->pluginStatus = U_ZERO_ERROR; |
| 336 plug->libName[0] = 0; |
| 337 plug->config[0]=0; |
| 338 plug->sym[0]=0; |
| 339 plug->lib=NULL; |
| 340 plug->entrypoint=NULL; |
| 341 |
| 342 |
| 343 return plug; |
| 344 } |
| 345 |
| 346 static UPlugData *uplug_allocatePlug(UPlugEntrypoint *entrypoint, const char *co
nfig, void *lib, const char *symName, |
| 347 UErrorCode *status) { |
| 348 UPlugData *plug; |
| 349 |
| 350 if(U_FAILURE(*status)) { |
| 351 return NULL; |
| 352 } |
| 353 |
| 354 plug = uplug_allocateEmptyPlug(status); |
| 355 if(config!=NULL) { |
| 356 uprv_strncpy(plug->config, config, UPLUG_NAME_MAX); |
| 357 } else { |
| 358 plug->config[0] = 0; |
| 359 } |
| 360 |
| 361 if(symName!=NULL) { |
| 362 uprv_strncpy(plug->sym, symName, UPLUG_NAME_MAX); |
| 363 } else { |
| 364 plug->sym[0] = 0; |
| 365 } |
| 366 |
| 367 plug->entrypoint = entrypoint; |
| 368 plug->lib = lib; |
| 369 uplug_queryPlug(plug, status); |
| 370 |
| 371 return plug; |
| 372 } |
| 373 |
| 374 static void uplug_deallocatePlug(UPlugData *plug, UErrorCode *status) { |
| 375 UErrorCode subStatus = U_ZERO_ERROR; |
| 376 if(!plug->dontUnload) { |
| 377 #if U_ENABLE_DYLOAD |
| 378 uplug_closeLibrary(plug->lib, &subStatus); |
| 379 #endif |
| 380 } |
| 381 plug->lib = NULL; |
| 382 if(U_SUCCESS(*status) && U_FAILURE(subStatus)) { |
| 383 *status = subStatus; |
| 384 } |
| 385 /* shift plugins up and decrement count. */ |
| 386 if(U_SUCCESS(*status)) { |
| 387 /* all ok- remove. */ |
| 388 pluginCount = uplug_removeEntryAt(pluginList, pluginCount, sizeof(plug[0]),
uplug_pluginNumber(plug)); |
| 389 } else { |
| 390 /* not ok- leave as a message. */ |
| 391 plug->awaitingLoad=FALSE; |
| 392 plug->entrypoint=0; |
| 393 plug->dontUnload=TRUE; |
| 394 } |
| 395 } |
| 396 |
| 397 static void uplug_doUnloadPlug(UPlugData *plugToRemove, UErrorCode *status) { |
| 398 if(plugToRemove != NULL) { |
| 399 uplug_unloadPlug(plugToRemove, status); |
| 400 uplug_deallocatePlug(plugToRemove, status); |
| 401 } |
| 402 } |
| 403 |
| 404 U_CAPI void U_EXPORT2 |
| 405 uplug_removePlug(UPlugData *plug, UErrorCode *status) { |
| 406 UPlugData *cursor = NULL; |
| 407 UPlugData *plugToRemove = NULL; |
| 408 if(U_FAILURE(*status)) return; |
| 409 |
| 410 for(cursor=pluginList;cursor!=NULL;) { |
| 411 if(cursor==plug) { |
| 412 plugToRemove = plug; |
| 413 cursor=NULL; |
| 414 } else { |
| 415 cursor = uplug_nextPlug(cursor); |
| 416 } |
| 417 } |
| 418 |
| 419 uplug_doUnloadPlug(plugToRemove, status); |
| 420 } |
| 421 |
| 422 |
| 423 |
| 424 |
| 425 U_CAPI void U_EXPORT2 |
| 426 uplug_setPlugNoUnload(UPlugData *data, UBool dontUnload) |
| 427 { |
| 428 data->dontUnload = dontUnload; |
| 429 } |
| 430 |
| 431 |
| 432 U_CAPI void U_EXPORT2 |
| 433 uplug_setPlugLevel(UPlugData *data, UPlugLevel level) { |
| 434 data->level = level; |
| 435 } |
| 436 |
| 437 |
| 438 U_CAPI UPlugLevel U_EXPORT2 |
| 439 uplug_getPlugLevel(UPlugData *data) { |
| 440 return data->level; |
| 441 } |
| 442 |
| 443 |
| 444 U_CAPI void U_EXPORT2 |
| 445 uplug_setPlugName(UPlugData *data, const char *name) { |
| 446 uprv_strncpy(data->name, name, UPLUG_NAME_MAX); |
| 447 } |
| 448 |
| 449 |
| 450 U_CAPI const char * U_EXPORT2 |
| 451 uplug_getPlugName(UPlugData *data) { |
| 452 return data->name; |
| 453 } |
| 454 |
| 455 |
| 456 U_CAPI const char * U_EXPORT2 |
| 457 uplug_getSymbolName(UPlugData *data) { |
| 458 return data->sym; |
| 459 } |
| 460 |
| 461 U_CAPI const char * U_EXPORT2 |
| 462 uplug_getLibraryName(UPlugData *data, UErrorCode *status) { |
| 463 if(data->libName[0]) { |
| 464 return data->libName; |
| 465 } else { |
| 466 #if U_ENABLE_DYLOAD |
| 467 return uplug_findLibrary(data->lib, status); |
| 468 #else |
| 469 return NULL; |
| 470 #endif |
| 471 } |
| 472 } |
| 473 |
| 474 U_CAPI void * U_EXPORT2 |
| 475 uplug_getLibrary(UPlugData *data) { |
| 476 return data->lib; |
| 477 } |
| 478 |
| 479 U_CAPI void * U_EXPORT2 |
| 480 uplug_getContext(UPlugData *data) { |
| 481 return data->context; |
| 482 } |
| 483 |
| 484 |
| 485 U_CAPI void U_EXPORT2 |
| 486 uplug_setContext(UPlugData *data, void *context) { |
| 487 data->context = context; |
| 488 } |
| 489 |
| 490 U_CAPI const char* U_EXPORT2 |
| 491 uplug_getConfiguration(UPlugData *data) { |
| 492 return data->config; |
| 493 } |
| 494 |
| 495 U_INTERNAL UPlugData* U_EXPORT2 |
| 496 uplug_getPlugInternal(int32_t n) { |
| 497 if(n <0 || n >= pluginCount) { |
| 498 return NULL; |
| 499 } else { |
| 500 return &(pluginList[n]); |
| 501 } |
| 502 } |
| 503 |
| 504 |
| 505 U_CAPI UErrorCode U_EXPORT2 |
| 506 uplug_getPlugLoadStatus(UPlugData *plug) { |
| 507 return plug->pluginStatus; |
| 508 } |
| 509 |
| 510 |
| 511 |
| 512 |
| 513 /** |
| 514 * Initialize a plugin fron an entrypoint and library - but don't load it. |
| 515 */ |
| 516 static UPlugData* uplug_initPlugFromEntrypointAndLibrary(UPlugEntrypoint *entryp
oint, const char *config, void *lib, const char *sym, |
| 517 UErrorCode *status) { |
| 518 UPlugData *plug = NULL; |
| 519 |
| 520 plug = uplug_allocatePlug(entrypoint, config, lib, sym, status); |
| 521 |
| 522 if(U_SUCCESS(*status)) { |
| 523 return plug; |
| 524 } else { |
| 525 uplug_deallocatePlug(plug, status); |
| 526 return NULL; |
| 527 } |
| 528 } |
| 529 |
| 530 U_CAPI UPlugData* U_EXPORT2 |
| 531 uplug_loadPlugFromEntrypoint(UPlugEntrypoint *entrypoint, const char *config, UE
rrorCode *status) { |
| 532 UPlugData* plug = uplug_initPlugFromEntrypointAndLibrary(entrypoint, config, N
ULL, NULL, status); |
| 533 uplug_loadPlug(plug, status); |
| 534 return plug; |
| 535 } |
| 536 |
| 537 |
| 538 static UPlugData* |
| 539 uplug_initErrorPlug(const char *libName, const char *sym, const char *config, co
nst char *nameOrError, UErrorCode loadStatus, UErrorCode *status) |
| 540 { |
| 541 UPlugData *plug = uplug_allocateEmptyPlug(status); |
| 542 if(U_FAILURE(*status)) return NULL; |
| 543 |
| 544 plug->pluginStatus = loadStatus; |
| 545 plug->awaitingLoad = FALSE; /* Won't load. */ |
| 546 plug->dontUnload = TRUE; /* cannot unload. */ |
| 547 |
| 548 if(sym!=NULL) { |
| 549 uprv_strncpy(plug->sym, sym, UPLUG_NAME_MAX); |
| 550 } |
| 551 |
| 552 if(libName!=NULL) { |
| 553 uprv_strncpy(plug->libName, libName, UPLUG_NAME_MAX); |
| 554 } |
| 555 |
| 556 if(nameOrError!=NULL) { |
| 557 uprv_strncpy(plug->name, nameOrError, UPLUG_NAME_MAX); |
| 558 } |
| 559 |
| 560 if(config!=NULL) { |
| 561 uprv_strncpy(plug->config, config, UPLUG_NAME_MAX); |
| 562 } |
| 563 |
| 564 return plug; |
| 565 } |
| 566 |
| 567 /** |
| 568 * Fetch a plugin from DLL, and then initialize it from a library- but don't loa
d it. |
| 569 */ |
| 570 |
| 571 #if U_ENABLE_DYLOAD |
| 572 |
| 573 static UPlugData* |
| 574 uplug_initPlugFromLibrary(const char *libName, const char *sym, const char *conf
ig, UErrorCode *status) { |
| 575 void *lib = NULL; |
| 576 UPlugData *plug = NULL; |
| 577 if(U_FAILURE(*status)) { return NULL; } |
| 578 lib = uplug_openLibrary(libName, status); |
| 579 if(lib!=NULL && U_SUCCESS(*status)) { |
| 580 UPlugEntrypoint *entrypoint = NULL; |
| 581 /* |
| 582 * ISO forbids the following cast. |
| 583 * See: http://www.trilithium.com/johan/2004/12/problem-with-dlsym/ |
| 584 */ |
| 585 entrypoint = (UPlugEntrypoint*)uprv_dl_sym(lib, sym, status); |
| 586 |
| 587 if(entrypoint!=NULL&&U_SUCCESS(*status)) { |
| 588 plug = uplug_initPlugFromEntrypointAndLibrary(entrypoint, config, lib, sym
, status); |
| 589 if(plug!=NULL&&U_SUCCESS(*status)) { |
| 590 plug->lib = lib; /* plug takes ownership of library */ |
| 591 lib = NULL; /* library is now owned by plugin. */ |
| 592 } |
| 593 } else { |
| 594 UErrorCode subStatus = U_ZERO_ERROR; |
| 595 plug = uplug_initErrorPlug(libName,sym,config,"ERROR: Could not load entry
point",(lib==NULL)?U_MISSING_RESOURCE_ERROR:*status,&subStatus); |
| 596 } |
| 597 if(lib!=NULL) { /* still need to close the lib */ |
| 598 UErrorCode subStatus = U_ZERO_ERROR; |
| 599 uplug_closeLibrary(lib, &subStatus); /* don't care here */ |
| 600 } |
| 601 } else { |
| 602 UErrorCode subStatus = U_ZERO_ERROR; |
| 603 plug = uplug_initErrorPlug(libName,sym,config,"ERROR: could not load library
",(lib==NULL)?U_MISSING_RESOURCE_ERROR:*status,&subStatus); |
| 604 } |
| 605 return plug; |
| 606 } |
| 607 |
| 608 U_CAPI UPlugData* U_EXPORT2 |
| 609 uplug_loadPlugFromLibrary(const char *libName, const char *sym, const char *conf
ig, UErrorCode *status) { |
| 610 UPlugData *plug = NULL; |
| 611 if(U_FAILURE(*status)) { return NULL; } |
| 612 plug = uplug_initPlugFromLibrary(libName, sym, config, status); |
| 613 uplug_loadPlug(plug, status); |
| 614 |
| 615 return plug; |
| 616 } |
| 617 |
| 618 #endif |
| 619 |
| 620 U_CAPI UPlugLevel U_EXPORT2 uplug_getCurrentLevel() { |
| 621 if(cmemory_inUse()) { |
| 622 return UPLUG_LEVEL_HIGH; |
| 623 } else { |
| 624 return UPLUG_LEVEL_LOW; |
| 625 } |
| 626 } |
| 627 |
| 628 static UBool U_CALLCONV uplug_cleanup(void) |
| 629 { |
| 630 int32_t i; |
| 631 |
| 632 UPlugData *pluginToRemove; |
| 633 /* cleanup plugs */ |
| 634 for(i=0;i<pluginCount;i++) { |
| 635 UErrorCode subStatus = U_ZERO_ERROR; |
| 636 pluginToRemove = &pluginList[i]; |
| 637 /* unload and deallocate */ |
| 638 uplug_doUnloadPlug(pluginToRemove, &subStatus); |
| 639 } |
| 640 /* close other held libs? */ |
| 641 return TRUE; |
| 642 } |
| 643 |
| 644 static void uplug_loadWaitingPlugs(UErrorCode *status) { |
| 645 int32_t i; |
| 646 UPlugLevel currentLevel = uplug_getCurrentLevel(); |
| 647 |
| 648 if(U_FAILURE(*status)) { |
| 649 return; |
| 650 } |
| 651 #if UPLUG_TRACE |
| 652 DBG((stderr, "uplug_loadWaitingPlugs() Level: %d\n", currentLevel)); |
| 653 #endif |
| 654 /* pass #1: low level plugs */ |
| 655 for(i=0;i<pluginCount;i++) { |
| 656 UErrorCode subStatus = U_ZERO_ERROR; |
| 657 UPlugData *pluginToLoad = &pluginList[i]; |
| 658 if(pluginToLoad->awaitingLoad) { |
| 659 if(pluginToLoad->level == UPLUG_LEVEL_LOW) { |
| 660 if(currentLevel > UPLUG_LEVEL_LOW) { |
| 661 pluginToLoad->pluginStatus = U_PLUGIN_TOO_HIGH; |
| 662 } else { |
| 663 UPlugLevel newLevel; |
| 664 uplug_loadPlug(pluginToLoad, &subStatus); |
| 665 newLevel = uplug_getCurrentLevel(); |
| 666 if(newLevel > currentLevel) { |
| 667 pluginToLoad->pluginStatus = U_PLUGIN_CHANGED_LEVEL_WARNING; |
| 668 currentLevel = newLevel; |
| 669 } |
| 670 } |
| 671 pluginToLoad->awaitingLoad = FALSE; |
| 672 } |
| 673 } |
| 674 } |
| 675 currentLevel = uplug_getCurrentLevel(); |
| 676 |
| 677 for(i=0;i<pluginCount;i++) { |
| 678 UErrorCode subStatus = U_ZERO_ERROR; |
| 679 UPlugData *pluginToLoad = &pluginList[i]; |
| 680 |
| 681 if(pluginToLoad->awaitingLoad) { |
| 682 if(pluginToLoad->level == UPLUG_LEVEL_INVALID) { |
| 683 pluginToLoad->pluginStatus = U_PLUGIN_DIDNT_SET_LEVEL; |
| 684 } else if(pluginToLoad->level == UPLUG_LEVEL_UNKNOWN) { |
| 685 pluginToLoad->pluginStatus = U_INTERNAL_PROGRAM_ERROR; |
| 686 } else { |
| 687 uplug_loadPlug(pluginToLoad, &subStatus); |
| 688 } |
| 689 pluginToLoad->awaitingLoad = FALSE; |
| 690 } |
| 691 } |
| 692 |
| 693 #if UPLUG_TRACE |
| 694 DBG((stderr, " Done Loading Plugs. Level: %d\n", (int32_t)uplug_getCurrentLev
el())); |
| 695 #endif |
| 696 } |
| 697 |
| 698 #if U_ENABLE_DYLOAD |
| 699 /* Name of the plugin config file */ |
| 700 static char plugin_file[2048] = ""; |
| 701 #endif |
| 702 |
| 703 U_INTERNAL const char* U_EXPORT2 |
| 704 uplug_getPluginFile() { |
| 705 #if U_ENABLE_DYLOAD |
| 706 return plugin_file; |
| 707 #else |
| 708 return NULL; |
| 709 #endif |
| 710 } |
| 711 |
| 712 |
| 713 U_CAPI void U_EXPORT2 |
| 714 uplug_init(UErrorCode *status) { |
| 715 #if !U_ENABLE_DYLOAD |
| 716 (void)status; /* unused */ |
| 717 #else |
| 718 const char *plugin_dir; |
| 719 |
| 720 if(U_FAILURE(*status)) return; |
| 721 plugin_dir = getenv("ICU_PLUGINS"); |
| 722 |
| 723 #if defined(DEFAULT_ICU_PLUGINS) |
| 724 if(plugin_dir == NULL || !*plugin_dir) { |
| 725 plugin_dir = DEFAULT_ICU_PLUGINS; |
| 726 } |
| 727 #endif |
| 728 |
| 729 #if UPLUG_TRACE |
| 730 DBG((stderr, "ICU_PLUGINS=%s\n", plugin_dir)); |
| 731 #endif |
| 732 |
| 733 if(plugin_dir != NULL && *plugin_dir) { |
| 734 FILE *f; |
| 735 |
| 736 |
| 737 uprv_strncpy(plugin_file, plugin_dir, 2047); |
| 738 uprv_strncat(plugin_file, U_FILE_SEP_STRING,2047); |
| 739 uprv_strncat(plugin_file, "icuplugins",2047); |
| 740 uprv_strncat(plugin_file, U_ICU_VERSION_SHORT ,2047); |
| 741 uprv_strncat(plugin_file, ".txt" ,2047); |
| 742 |
| 743 #if UPLUG_TRACE |
| 744 DBG((stderr, "pluginfile= %s\n", plugin_file)); |
| 745 #endif |
| 746 |
| 747 f = fopen(plugin_file, "r"); |
| 748 |
| 749 if(f != NULL) { |
| 750 char linebuf[1024]; |
| 751 char *p, *libName=NULL, *symName=NULL, *config=NULL; |
| 752 int32_t line = 0; |
| 753 |
| 754 |
| 755 while(fgets(linebuf,1023,f)) { |
| 756 line++; |
| 757 |
| 758 if(!*linebuf || *linebuf=='#') { |
| 759 continue; |
| 760 } else { |
| 761 p = linebuf; |
| 762 while(*p&&isspace(*p)) |
| 763 p++; |
| 764 if(!*p || *p=='#') continue; |
| 765 libName = p; |
| 766 while(*p&&!isspace(*p)) { |
| 767 p++; |
| 768 } |
| 769 if(!*p || *p=='#') continue; /* no tab after libname */ |
| 770 *p=0; /* end of libname */ |
| 771 p++; |
| 772 while(*p&&isspace(*p)) { |
| 773 p++; |
| 774 } |
| 775 if(!*p||*p=='#') continue; /* no symname after libname +tab */ |
| 776 symName = p; |
| 777 while(*p&&!isspace(*p)) { |
| 778 p++; |
| 779 } |
| 780 |
| 781 if(*p) { /* has config */ |
| 782 *p=0; |
| 783 ++p; |
| 784 while(*p&&isspace(*p)) { |
| 785 p++; |
| 786 } |
| 787 if(*p) { |
| 788 config = p; |
| 789 } |
| 790 } |
| 791 |
| 792 /* chop whitespace at the end of the config */ |
| 793 if(config!=NULL&&*config!=0) { |
| 794 p = config+strlen(config); |
| 795 while(p>config&&isspace(*(--p))) { |
| 796 *p=0; |
| 797 } |
| 798 } |
| 799 |
| 800 /* OK, we're good. */ |
| 801 { |
| 802 UErrorCode subStatus = U_ZERO_ERROR; |
| 803 UPlugData *plug = uplug_initPlugFromLibrary(libName, symName, config
, &subStatus); |
| 804 if(U_FAILURE(subStatus) && U_SUCCESS(*status)) { |
| 805 *status = subStatus; |
| 806 } |
| 807 #if UPLUG_TRACE |
| 808 DBG((stderr, "PLUGIN libName=[%s], sym=[%s], config=[%s]\n", libName
, symName, config)); |
| 809 DBG((stderr, " -> %p, %s\n", (void*)plug, u_errorName(subStatus))); |
| 810 #else |
| 811 (void)plug; /* unused */ |
| 812 #endif |
| 813 } |
| 814 } |
| 815 } |
| 816 } else { |
| 817 #if UPLUG_TRACE |
| 818 DBG((stderr, "Can't open plugin file %s\n", plugin_file)); |
| 819 #endif |
| 820 } |
| 821 } |
| 822 uplug_loadWaitingPlugs(status); |
| 823 #endif /* U_ENABLE_DYLOAD */ |
| 824 ucln_registerCleanup(UCLN_UPLUG, uplug_cleanup); |
| 825 } |
OLD | NEW |