intl/icu/source/common/icuplug.c

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

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

mercurial