1 /* 2 ****************************************************************************** 3 * 4 * Copyright (C) 2009-2011, 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 lib) */ 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 memberSize, 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)*memberSize), 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", libraryMax)); 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_errorName(*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(*libraryList), 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 *status) { 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 actually 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) ) { /* shouldn'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 happen. 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 *config, 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 *entrypoint, 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, UErrorCode *status) { 532 UPlugData* plug = uplug_initPlugFromEntrypointAndLibrary(entrypoint, config, NULL, 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, const 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 load it. 569 */ 570 571 #if U_ENABLE_DYLOAD 572 573 static UPlugData* 574 uplug_initPlugFromLibrary(const char *libName, const char *sym, const char *config, 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 entrypoint = (UPlugEntrypoint*)uprv_dlsym_func(lib, sym, status); 582 583 if(entrypoint!=NULL&&U_SUCCESS(*status)) { 584 plug = uplug_initPlugFromEntrypointAndLibrary(entrypoint, config, lib, sym, status); 585 if(plug!=NULL&&U_SUCCESS(*status)) { 586 plug->lib = lib; /* plug takes ownership of library */ 587 lib = NULL; /* library is now owned by plugin. */ 588 } 589 } else { 590 UErrorCode subStatus = U_ZERO_ERROR; 591 plug = uplug_initErrorPlug(libName,sym,config,"ERROR: Could not load entrypoint",(lib==NULL)?U_MISSING_RESOURCE_ERROR:*status,&subStatus); 592 } 593 if(lib!=NULL) { /* still need to close the lib */ 594 UErrorCode subStatus = U_ZERO_ERROR; 595 uplug_closeLibrary(lib, &subStatus); /* don't care here */ 596 } 597 } else { 598 UErrorCode subStatus = U_ZERO_ERROR; 599 plug = uplug_initErrorPlug(libName,sym,config,"ERROR: could not load library",(lib==NULL)?U_MISSING_RESOURCE_ERROR:*status,&subStatus); 600 } 601 return plug; 602 } 603 604 U_CAPI UPlugData* U_EXPORT2 605 uplug_loadPlugFromLibrary(const char *libName, const char *sym, const char *config, UErrorCode *status) { 606 UPlugData *plug = NULL; 607 if(U_FAILURE(*status)) { return NULL; } 608 plug = uplug_initPlugFromLibrary(libName, sym, config, status); 609 uplug_loadPlug(plug, status); 610 611 return plug; 612 } 613 614 #endif 615 616 U_CAPI UPlugLevel U_EXPORT2 uplug_getCurrentLevel() { 617 if(cmemory_inUse()) { 618 return UPLUG_LEVEL_HIGH; 619 } else { 620 return UPLUG_LEVEL_LOW; 621 } 622 } 623 624 static UBool U_CALLCONV uplug_cleanup(void) 625 { 626 int32_t i; 627 628 UPlugData *pluginToRemove; 629 /* cleanup plugs */ 630 for(i=0;i<pluginCount;i++) { 631 UErrorCode subStatus = U_ZERO_ERROR; 632 pluginToRemove = &pluginList[i]; 633 /* unload and deallocate */ 634 uplug_doUnloadPlug(pluginToRemove, &subStatus); 635 } 636 /* close other held libs? */ 637 return TRUE; 638 } 639 640 static void uplug_loadWaitingPlugs(UErrorCode *status) { 641 int32_t i; 642 UPlugLevel currentLevel = uplug_getCurrentLevel(); 643 644 if(U_FAILURE(*status)) { 645 return; 646 } 647 #if UPLUG_TRACE 648 DBG((stderr, "uplug_loadWaitingPlugs() Level: %d\n", currentLevel)); 649 #endif 650 /* pass #1: low level plugs */ 651 for(i=0;i<pluginCount;i++) { 652 UErrorCode subStatus = U_ZERO_ERROR; 653 UPlugData *pluginToLoad = &pluginList[i]; 654 if(pluginToLoad->awaitingLoad) { 655 if(pluginToLoad->level == UPLUG_LEVEL_LOW) { 656 if(currentLevel > UPLUG_LEVEL_LOW) { 657 pluginToLoad->pluginStatus = U_PLUGIN_TOO_HIGH; 658 } else { 659 UPlugLevel newLevel; 660 uplug_loadPlug(pluginToLoad, &subStatus); 661 newLevel = uplug_getCurrentLevel(); 662 if(newLevel > currentLevel) { 663 pluginToLoad->pluginStatus = U_PLUGIN_CHANGED_LEVEL_WARNING; 664 currentLevel = newLevel; 665 } 666 } 667 pluginToLoad->awaitingLoad = FALSE; 668 } 669 } 670 } 671 currentLevel = uplug_getCurrentLevel(); 672 673 for(i=0;i<pluginCount;i++) { 674 UErrorCode subStatus = U_ZERO_ERROR; 675 UPlugData *pluginToLoad = &pluginList[i]; 676 677 if(pluginToLoad->awaitingLoad) { 678 if(pluginToLoad->level == UPLUG_LEVEL_INVALID) { 679 pluginToLoad->pluginStatus = U_PLUGIN_DIDNT_SET_LEVEL; 680 } else if(pluginToLoad->level == UPLUG_LEVEL_UNKNOWN) { 681 pluginToLoad->pluginStatus = U_INTERNAL_PROGRAM_ERROR; 682 } else { 683 uplug_loadPlug(pluginToLoad, &subStatus); 684 } 685 pluginToLoad->awaitingLoad = FALSE; 686 } 687 } 688 689 #if UPLUG_TRACE 690 DBG((stderr, " Done Loading Plugs. Level: %d\n", (int32_t)uplug_getCurrentLevel())); 691 #endif 692 } 693 694 #if U_ENABLE_DYLOAD 695 /* Name of the plugin config file */ 696 static char plugin_file[2048] = ""; 697 #endif 698 699 U_INTERNAL const char* U_EXPORT2 700 uplug_getPluginFile() { 701 #if U_ENABLE_DYLOAD 702 return plugin_file; 703 #else 704 return NULL; 705 #endif 706 } 707 708 709 U_CAPI void U_EXPORT2 710 uplug_init(UErrorCode *status) { 711 #if !U_ENABLE_DYLOAD 712 (void)status; /* unused */ 713 #else 714 const char *plugin_dir; 715 716 if(U_FAILURE(*status)) return; 717 plugin_dir = getenv("ICU_PLUGINS"); 718 719 #if defined(DEFAULT_ICU_PLUGINS) 720 if(plugin_dir == NULL || !*plugin_dir) { 721 plugin_dir = DEFAULT_ICU_PLUGINS; 722 } 723 #endif 724 725 #if UPLUG_TRACE 726 DBG((stderr, "ICU_PLUGINS=%s\n", plugin_dir)); 727 #endif 728 729 if(plugin_dir != NULL && *plugin_dir) { 730 FILE *f; 731 732 733 uprv_strncpy(plugin_file, plugin_dir, 2047); 734 uprv_strncat(plugin_file, U_FILE_SEP_STRING,2047); 735 uprv_strncat(plugin_file, "icuplugins",2047); 736 uprv_strncat(plugin_file, U_ICU_VERSION_SHORT ,2047); 737 uprv_strncat(plugin_file, ".txt" ,2047); 738 739 #if UPLUG_TRACE 740 DBG((stderr, "pluginfile= %s\n", plugin_file)); 741 #endif 742 743 f = fopen(plugin_file, "r"); 744 745 if(f != NULL) { 746 char linebuf[1024]; 747 char *p, *libName=NULL, *symName=NULL, *config=NULL; 748 int32_t line = 0; 749 750 751 while(fgets(linebuf,1023,f)) { 752 line++; 753 754 if(!*linebuf || *linebuf=='#') { 755 continue; 756 } else { 757 p = linebuf; 758 while(*p&&isspace(*p)) 759 p++; 760 if(!*p || *p=='#') continue; 761 libName = p; 762 while(*p&&!isspace(*p)) { 763 p++; 764 } 765 if(!*p || *p=='#') continue; /* no tab after libname */ 766 *p=0; /* end of libname */ 767 p++; 768 while(*p&&isspace(*p)) { 769 p++; 770 } 771 if(!*p||*p=='#') continue; /* no symname after libname +tab */ 772 symName = p; 773 while(*p&&!isspace(*p)) { 774 p++; 775 } 776 777 if(*p) { /* has config */ 778 *p=0; 779 ++p; 780 while(*p&&isspace(*p)) { 781 p++; 782 } 783 if(*p) { 784 config = p; 785 } 786 } 787 788 /* chop whitespace at the end of the config */ 789 if(config!=NULL&&*config!=0) { 790 p = config+strlen(config); 791 while(p>config&&isspace(*(--p))) { 792 *p=0; 793 } 794 } 795 796 /* OK, we're good. */ 797 { 798 UErrorCode subStatus = U_ZERO_ERROR; 799 UPlugData *plug = uplug_initPlugFromLibrary(libName, symName, config, &subStatus); 800 if(U_FAILURE(subStatus) && U_SUCCESS(*status)) { 801 *status = subStatus; 802 } 803 #if UPLUG_TRACE 804 DBG((stderr, "PLUGIN libName=[%s], sym=[%s], config=[%s]\n", libName, symName, config)); 805 DBG((stderr, " -> %p, %s\n", (void*)plug, u_errorName(subStatus))); 806 #else 807 (void)plug; /* unused */ 808 #endif 809 } 810 } 811 } 812 fclose(f); 813 } else { 814 #if UPLUG_TRACE 815 DBG((stderr, "Can't open plugin file %s\n", plugin_file)); 816 #endif 817 } 818 } 819 uplug_loadWaitingPlugs(status); 820 #endif /* U_ENABLE_DYLOAD */ 821 ucln_registerCleanup(UCLN_UPLUG, uplug_cleanup); 822 } 823