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