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 37struct 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 */ 66static 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 */ 90struct UPlugLibrary; 91 92/** 93 * Library management. Internal. 94 * @internal 95 */ 96typedef struct UPlugLibrary { 97 void *lib; /**< library ptr */ 98 char name[UPLUG_NAME_MAX]; /**< library name */ 99 uint32_t ref; /**< reference count */ 100} UPlugLibrary; 101 102static UPlugLibrary staticLibraryList[UPLUG_LIBRARY_INITIAL_COUNT]; 103static UPlugLibrary * libraryList = staticLibraryList; 104static int32_t libraryCount = 0; 105static 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 */ 112static 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 123static 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 134U_INTERNAL char * U_EXPORT2 135uplug_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 150U_INTERNAL void * U_EXPORT2 151uplug_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 198U_INTERNAL void U_EXPORT2 199uplug_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 221static UPlugData pluginList[UPLUG_PLUGIN_INITIAL_COUNT]; 222static int32_t pluginCount = 0; 223 224 225 226 227static 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 239U_CAPI UPlugData * U_EXPORT2 240uplug_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 */ 260static 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 272static 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 283static 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 302static 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 314static 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 346static 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 374static 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 397static void uplug_doUnloadPlug(UPlugData *plugToRemove, UErrorCode *status) { 398 if(plugToRemove != NULL) { 399 uplug_unloadPlug(plugToRemove, status); 400 uplug_deallocatePlug(plugToRemove, status); 401 } 402} 403 404U_CAPI void U_EXPORT2 405uplug_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 425U_CAPI void U_EXPORT2 426uplug_setPlugNoUnload(UPlugData *data, UBool dontUnload) 427{ 428 data->dontUnload = dontUnload; 429} 430 431 432U_CAPI void U_EXPORT2 433uplug_setPlugLevel(UPlugData *data, UPlugLevel level) { 434 data->level = level; 435} 436 437 438U_CAPI UPlugLevel U_EXPORT2 439uplug_getPlugLevel(UPlugData *data) { 440 return data->level; 441} 442 443 444U_CAPI void U_EXPORT2 445uplug_setPlugName(UPlugData *data, const char *name) { 446 uprv_strncpy(data->name, name, UPLUG_NAME_MAX); 447} 448 449 450U_CAPI const char * U_EXPORT2 451uplug_getPlugName(UPlugData *data) { 452 return data->name; 453} 454 455 456U_CAPI const char * U_EXPORT2 457uplug_getSymbolName(UPlugData *data) { 458 return data->sym; 459} 460 461U_CAPI const char * U_EXPORT2 462uplug_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 474U_CAPI void * U_EXPORT2 475uplug_getLibrary(UPlugData *data) { 476 return data->lib; 477} 478 479U_CAPI void * U_EXPORT2 480uplug_getContext(UPlugData *data) { 481 return data->context; 482} 483 484 485U_CAPI void U_EXPORT2 486uplug_setContext(UPlugData *data, void *context) { 487 data->context = context; 488} 489 490U_CAPI const char* U_EXPORT2 491uplug_getConfiguration(UPlugData *data) { 492 return data->config; 493} 494 495U_INTERNAL UPlugData* U_EXPORT2 496uplug_getPlugInternal(int32_t n) { 497 if(n <0 || n >= pluginCount) { 498 return NULL; 499 } else { 500 return &(pluginList[n]); 501 } 502} 503 504 505U_CAPI UErrorCode U_EXPORT2 506uplug_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 */ 516static 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 530U_CAPI UPlugData* U_EXPORT2 531uplug_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 538static UPlugData* 539uplug_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 573static UPlugData* 574uplug_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 /* 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 entrypoint",(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 608U_CAPI UPlugData* U_EXPORT2 609uplug_loadPlugFromLibrary(const char *libName, const char *sym, const char *config, 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 620U_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 628static 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 644static 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_getCurrentLevel())); 695#endif 696} 697 698#if U_ENABLE_DYLOAD 699/* Name of the plugin config file */ 700static char plugin_file[2048] = ""; 701#endif 702 703U_INTERNAL const char* U_EXPORT2 704uplug_getPluginFile() { 705#if U_ENABLE_DYLOAD 706 return plugin_file; 707#else 708 return NULL; 709#endif 710} 711 712 713U_CAPI void U_EXPORT2 714uplug_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} 826