Home | History | Annotate | Download | only in common
      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