Home | History | Annotate | Download | only in common
      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 
     34 using 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 
     49 struct 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  */
     78 static 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  */
    102 struct UPlugLibrary;
    103 
    104 /**
    105  * Library management. Internal.
    106  * @internal
    107  */
    108 typedef struct UPlugLibrary {
    109   void *lib;                           /**< library ptr */
    110   char name[UPLUG_NAME_MAX]; /**< library name */
    111   uint32_t ref;                        /**< reference count */
    112 } UPlugLibrary;
    113 
    114 static UPlugLibrary   staticLibraryList[UPLUG_LIBRARY_INITIAL_COUNT];
    115 static UPlugLibrary * libraryList = staticLibraryList;
    116 static int32_t libraryCount = 0;
    117 static 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  */
    124 static 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 
    135 static 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 
    146 U_INTERNAL char * U_EXPORT2
    147 uplug_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 
    162 U_INTERNAL void * U_EXPORT2
    163 uplug_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 
    210 U_INTERNAL void U_EXPORT2
    211 uplug_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 
    233 static UPlugData pluginList[UPLUG_PLUGIN_INITIAL_COUNT];
    234 static int32_t pluginCount = 0;
    235 
    236 
    237 
    238 
    239 static 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 
    251 U_CAPI UPlugData * U_EXPORT2
    252 uplug_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  */
    272 static 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 
    284 static 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 
    295 static 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 
    314 static 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 
    329 static 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 
    361 static 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 
    387 static 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 
    410 static void uplug_doUnloadPlug(UPlugData *plugToRemove, UErrorCode *status) {
    411   if(plugToRemove != NULL) {
    412     uplug_unloadPlug(plugToRemove, status);
    413     uplug_deallocatePlug(plugToRemove, status);
    414   }
    415 }
    416 
    417 U_CAPI void U_EXPORT2
    418 uplug_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 
    438 U_CAPI void U_EXPORT2
    439 uplug_setPlugNoUnload(UPlugData *data, UBool dontUnload)
    440 {
    441   data->dontUnload = dontUnload;
    442 }
    443 
    444 
    445 U_CAPI void U_EXPORT2
    446 uplug_setPlugLevel(UPlugData *data, UPlugLevel level) {
    447   data->level = level;
    448 }
    449 
    450 
    451 U_CAPI UPlugLevel U_EXPORT2
    452 uplug_getPlugLevel(UPlugData *data) {
    453   return data->level;
    454 }
    455 
    456 
    457 U_CAPI void U_EXPORT2
    458 uplug_setPlugName(UPlugData *data, const char *name) {
    459   uprv_strncpy(data->name, name, UPLUG_NAME_MAX);
    460 }
    461 
    462 
    463 U_CAPI const char * U_EXPORT2
    464 uplug_getPlugName(UPlugData *data) {
    465   return data->name;
    466 }
    467 
    468 
    469 U_CAPI const char * U_EXPORT2
    470 uplug_getSymbolName(UPlugData *data) {
    471   return data->sym;
    472 }
    473 
    474 U_CAPI const char * U_EXPORT2
    475 uplug_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 
    487 U_CAPI void * U_EXPORT2
    488 uplug_getLibrary(UPlugData *data) {
    489   return data->lib;
    490 }
    491 
    492 U_CAPI void * U_EXPORT2
    493 uplug_getContext(UPlugData *data) {
    494   return data->context;
    495 }
    496 
    497 
    498 U_CAPI void U_EXPORT2
    499 uplug_setContext(UPlugData *data, void *context) {
    500   data->context = context;
    501 }
    502 
    503 U_CAPI const char* U_EXPORT2
    504 uplug_getConfiguration(UPlugData *data) {
    505   return data->config;
    506 }
    507 
    508 U_INTERNAL UPlugData* U_EXPORT2
    509 uplug_getPlugInternal(int32_t n) {
    510   if(n <0 || n >= pluginCount) {
    511     return NULL;
    512   } else {
    513     return &(pluginList[n]);
    514   }
    515 }
    516 
    517 
    518 U_CAPI UErrorCode U_EXPORT2
    519 uplug_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  */
    529 static 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 
    543 U_CAPI UPlugData* U_EXPORT2
    544 uplug_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 
    552 static UPlugData*
    553 uplug_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  */
    584 static UPlugData*
    585 uplug_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 
    615 U_CAPI UPlugData* U_EXPORT2
    616 uplug_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 
    627 static UPlugLevel gCurrentLevel = UPLUG_LEVEL_LOW;
    628 
    629 U_CAPI UPlugLevel U_EXPORT2 uplug_getCurrentLevel() {
    630   return gCurrentLevel;
    631 }
    632 
    633 static 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 
    652 static 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 */
    705 static char plugin_file[2048] = "";
    706 #endif
    707 
    708 U_INTERNAL const char* U_EXPORT2
    709 uplug_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 
    720 U_CAPI void U_EXPORT2
    721 uplug_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