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