tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

icuplug.cpp (23455B)


      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 nullptr */
     56  char libName[UPLUG_NAME_MAX];   /**< library name */
     57  char sym[UPLUG_NAME_MAX];        /**< plugin symbol, or nullptr */
     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_CAPI char * U_EXPORT2
    149 uplug_findLibrary(void *lib, UErrorCode *status) {
    150  int32_t libEnt;
    151  char *ret = nullptr;
    152  if(U_FAILURE(*status)) {
    153    return nullptr;
    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_CAPI void * U_EXPORT2
    165 uplug_openLibrary(const char *libName, UErrorCode *status) {
    166  int32_t libEntry = -1;
    167  void *lib = nullptr;
    168    
    169  if(U_FAILURE(*status)) return nullptr;
    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 nullptr;
    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 == nullptr || U_FAILURE(*status)) {
    190      /* cleanup. */
    191      libraryList[libEntry].lib = nullptr; /* 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_CAPI 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==nullptr) {
    256    return pluginList;
    257  } else {
    258    UPlugData *nextPlug = &prior[1];
    259    UPlugData *pastPlug = &pluginList[pluginCount];
    260    
    261    if(nextPlug>=pastPlug) {
    262      return nullptr;
    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==nullptr||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't been 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't been 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't been 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 = nullptr;
    334 
    335  if(U_FAILURE(*status)) {
    336    return nullptr;
    337  }
    338 
    339  if(pluginCount == UPLUG_PLUGIN_INITIAL_COUNT) {
    340    *status = U_MEMORY_ALLOCATION_ERROR;
    341    return nullptr;
    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=nullptr;
    357  plug->entrypoint=nullptr;
    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 nullptr;
    368  }
    369 
    370  if(config!=nullptr) {
    371    uprv_strncpy(plug->config, config, UPLUG_NAME_MAX);
    372  } else {
    373    plug->config[0] = 0;
    374  }
    375    
    376  if(symName!=nullptr) {
    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 = nullptr;
    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 != nullptr) {
    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 = nullptr;
    422  UPlugData *plugToRemove = nullptr;
    423  if(U_FAILURE(*status)) return;
    424    
    425  for(cursor=pluginList;cursor!=nullptr;) {
    426    if(cursor==plug) {
    427      plugToRemove = plug;
    428      cursor=nullptr;
    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 nullptr;
    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_CAPI UPlugData* U_EXPORT2
    511 uplug_getPlugInternal(int32_t n) { 
    512  if(n <0 || n >= pluginCount) {
    513    return nullptr;
    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 from 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 = nullptr;
    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 nullptr;
    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, nullptr, nullptr, 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 nullptr;
    559 
    560  plug->pluginStatus = loadStatus;
    561  plug->awaitingLoad = false; /* Won't load. */
    562  plug->dontUnload = true; /* cannot unload. */
    563 
    564  if(sym!=nullptr) {
    565    uprv_strncpy(plug->sym, sym, UPLUG_NAME_MAX);
    566  }
    567 
    568  if(libName!=nullptr) {
    569    uprv_strncpy(plug->libName, libName, UPLUG_NAME_MAX);
    570  }
    571 
    572  if(nameOrError!=nullptr) {
    573    uprv_strncpy(plug->name, nameOrError, UPLUG_NAME_MAX);
    574  }
    575 
    576  if(config!=nullptr) {
    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 = nullptr;
    589  UPlugData *plug = nullptr;
    590  if(U_FAILURE(*status)) { return nullptr; }
    591  lib = uplug_openLibrary(libName, status);
    592  if(lib!=nullptr && U_SUCCESS(*status)) {
    593    UPlugEntrypoint *entrypoint = nullptr;
    594    entrypoint = (UPlugEntrypoint*)uprv_dlsym_func(lib, sym, status);
    595 
    596    if(entrypoint!=nullptr&&U_SUCCESS(*status)) {
    597      plug = uplug_initPlugFromEntrypointAndLibrary(entrypoint, config, lib, sym, status);
    598      if(plug!=nullptr&&U_SUCCESS(*status)) {
    599        plug->lib = lib; /* plug takes ownership of library */
    600        lib = nullptr; /* 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==nullptr)?U_MISSING_RESOURCE_ERROR:*status,&subStatus);
    605    }
    606    if(lib!=nullptr) { /* 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==nullptr)?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 = nullptr;
    620  if(U_FAILURE(*status)) { return nullptr; }
    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()
    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_CAPI const char* U_EXPORT2
    711 uplug_getPluginFile() {
    712 #if U_ENABLE_DYLOAD && !UCONFIG_NO_FILE_IO
    713  return plugin_file;
    714 #else
    715  return nullptr;
    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 != nullptr) {
    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 ICU_PLUGINS_DD
    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    pluginFile.extract(plugin_file, sizeof(plugin_file), *status);
    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 = nullptr;
    795    }
    796    else
    797 #endif
    798    {
    799        f = fopen(pluginFile.data(), "r");
    800    }
    801 
    802    if(f != nullptr) {
    803      char linebuf[1024];
    804      char *p, *libName=nullptr, *symName=nullptr, *config=nullptr;
    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!=nullptr&&*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