Path: blob/master/thirdparty/icu4c/common/icuplug.cpp
9902 views
// © 2016 and later: Unicode, Inc. and others.1// License & terms of use: http://www.unicode.org/copyright.html2/*3******************************************************************************4*5* Copyright (C) 2009-2015, International Business Machines6* Corporation and others. All Rights Reserved.7*8******************************************************************************9*10* FILE NAME : icuplug.c11*12* Date Name Description13* 10/29/2009 sl New.14******************************************************************************15*/1617#include "unicode/icuplug.h"181920#if UCONFIG_ENABLE_PLUGINS212223#include "icuplugimp.h"24#include "cstring.h"25#include "cmemory.h"26#include "putilimp.h"27#include "ucln.h"28#include <stdio.h>29#ifdef __MVS__ /* defined by z/OS compiler */30#define _POSIX_SOURCE31#include <cics.h> /* 12 Nov 2011 JAM iscics() function */32#endif33#include "charstr.h"3435using namespace icu;3637#ifndef UPLUG_TRACE38#define UPLUG_TRACE 039#endif4041#if UPLUG_TRACE42#include <stdio.h>43#define DBG(x) fprintf(stderr, "%s:%d: ",__FILE__,__LINE__); fprintf x44#endif4546/**47* Internal structure of an ICU plugin.48*/4950struct UPlugData {51UPlugEntrypoint *entrypoint; /**< plugin entrypoint */52uint32_t structSize; /**< initialized to the size of this structure */53uint32_t token; /**< must be U_PLUG_TOKEN */54void *lib; /**< plugin library, or nullptr */55char libName[UPLUG_NAME_MAX]; /**< library name */56char sym[UPLUG_NAME_MAX]; /**< plugin symbol, or nullptr */57char config[UPLUG_NAME_MAX]; /**< configuration data */58void *context; /**< user context data */59char name[UPLUG_NAME_MAX]; /**< name of plugin */60UPlugLevel level; /**< level of plugin */61UBool awaitingLoad; /**< true if the plugin is awaiting a load call */62UBool dontUnload; /**< true if plugin must stay resident (leak plugin and lib) */63UErrorCode pluginStatus; /**< status code of plugin */64};65666768#define UPLUG_LIBRARY_INITIAL_COUNT 869#define UPLUG_PLUGIN_INITIAL_COUNT 127071/**72* Remove an item73* @param list the full list74* @param listSize the number of entries in the list75* @param memberSize the size of one member76* @param itemToRemove the item number of the member77* @return the new listsize78*/79static int32_t uplug_removeEntryAt(void *list, int32_t listSize, int32_t memberSize, int32_t itemToRemove) {80uint8_t *bytePtr = (uint8_t *)list;8182/* get rid of some bad cases first */83if(listSize<1) {84return listSize;85}8687/* is there anything to move? */88if(listSize > itemToRemove+1) {89memmove(bytePtr+(itemToRemove*memberSize), bytePtr+((itemToRemove+1)*memberSize), memberSize);90}9192return listSize-1;93}9495969798#if U_ENABLE_DYLOAD99/**100* Library management. Internal.101* @internal102*/103struct UPlugLibrary;104105/**106* Library management. Internal.107* @internal108*/109typedef struct UPlugLibrary {110void *lib; /**< library ptr */111char name[UPLUG_NAME_MAX]; /**< library name */112uint32_t ref; /**< reference count */113} UPlugLibrary;114115static UPlugLibrary staticLibraryList[UPLUG_LIBRARY_INITIAL_COUNT];116static UPlugLibrary * libraryList = staticLibraryList;117static int32_t libraryCount = 0;118static int32_t libraryMax = UPLUG_LIBRARY_INITIAL_COUNT;119120/**121* Search for a library. Doesn't lock122* @param libName libname to search for123* @return the library's struct124*/125static int32_t searchForLibraryName(const char *libName) {126int32_t i;127128for(i=0;i<libraryCount;i++) {129if(!uprv_strcmp(libName, libraryList[i].name)) {130return i;131}132}133return -1;134}135136static int32_t searchForLibrary(void *lib) {137int32_t i;138139for(i=0;i<libraryCount;i++) {140if(lib==libraryList[i].lib) {141return i;142}143}144return -1;145}146147U_CAPI char * U_EXPORT2148uplug_findLibrary(void *lib, UErrorCode *status) {149int32_t libEnt;150char *ret = nullptr;151if(U_FAILURE(*status)) {152return nullptr;153}154libEnt = searchForLibrary(lib);155if(libEnt!=-1) {156ret = libraryList[libEnt].name;157} else {158*status = U_MISSING_RESOURCE_ERROR;159}160return ret;161}162163U_CAPI void * U_EXPORT2164uplug_openLibrary(const char *libName, UErrorCode *status) {165int32_t libEntry = -1;166void *lib = nullptr;167168if(U_FAILURE(*status)) return nullptr;169170libEntry = searchForLibraryName(libName);171if(libEntry == -1) {172libEntry = libraryCount++;173if(libraryCount >= libraryMax) {174/* Ran out of library slots. Statically allocated because we can't depend on allocating memory.. */175*status = U_MEMORY_ALLOCATION_ERROR;176#if UPLUG_TRACE177DBG((stderr, "uplug_openLibrary() - out of library slots (max %d)\n", libraryMax));178#endif179return nullptr;180}181/* Some operating systems don't want182DL operations from multiple threads. */183libraryList[libEntry].lib = uprv_dl_open(libName, status);184#if UPLUG_TRACE185DBG((stderr, "uplug_openLibrary(%s,%s) libEntry %d, lib %p\n", libName, u_errorName(*status), libEntry, lib));186#endif187188if(libraryList[libEntry].lib == nullptr || U_FAILURE(*status)) {189/* cleanup. */190libraryList[libEntry].lib = nullptr; /* failure with open */191libraryList[libEntry].name[0] = 0;192#if UPLUG_TRACE193DBG((stderr, "uplug_openLibrary(%s,%s) libEntry %d, lib %p\n", libName, u_errorName(*status), libEntry, lib));194#endif195/* no need to free - just won't increase the count. */196libraryCount--;197} else { /* is it still there? */198/* link it in */199uprv_strncpy(libraryList[libEntry].name,libName,UPLUG_NAME_MAX);200libraryList[libEntry].ref=1;201lib = libraryList[libEntry].lib;202}203204} else {205lib = libraryList[libEntry].lib;206libraryList[libEntry].ref++;207}208return lib;209}210211U_CAPI void U_EXPORT2212uplug_closeLibrary(void *lib, UErrorCode *status) {213int32_t i;214215#if UPLUG_TRACE216DBG((stderr, "uplug_closeLibrary(%p,%s) list %p\n", lib, u_errorName(*status), (void*)libraryList));217#endif218if(U_FAILURE(*status)) return;219220for(i=0;i<libraryCount;i++) {221if(lib==libraryList[i].lib) {222if(--(libraryList[i].ref) == 0) {223uprv_dl_close(libraryList[i].lib, status);224libraryCount = uplug_removeEntryAt(libraryList, libraryCount, sizeof(*libraryList), i);225}226return;227}228}229*status = U_INTERNAL_PROGRAM_ERROR; /* could not find the entry! */230}231232#endif233234static UPlugData pluginList[UPLUG_PLUGIN_INITIAL_COUNT];235static int32_t pluginCount = 0;236237238239240static int32_t uplug_pluginNumber(UPlugData* d) {241UPlugData *pastPlug = &pluginList[pluginCount];242if(d<=pluginList) {243return 0;244} else if(d>=pastPlug) {245return pluginCount;246} else {247return (d-pluginList)/sizeof(pluginList[0]);248}249}250251252U_CAPI UPlugData * U_EXPORT2253uplug_nextPlug(UPlugData *prior) {254if(prior==nullptr) {255return pluginList;256} else {257UPlugData *nextPlug = &prior[1];258UPlugData *pastPlug = &pluginList[pluginCount];259260if(nextPlug>=pastPlug) {261return nullptr;262} else {263return nextPlug;264}265}266}267268269270/**271* Call the plugin with some params272*/273static void uplug_callPlug(UPlugData *plug, UPlugReason reason, UErrorCode *status) {274UPlugTokenReturn token;275if(plug==nullptr||U_FAILURE(*status)) {276return;277}278token = (*(plug->entrypoint))(plug, reason, status);279if(token!=UPLUG_TOKEN) {280*status = U_INTERNAL_PROGRAM_ERROR;281}282}283284285static void uplug_unloadPlug(UPlugData *plug, UErrorCode *status) {286if(plug->awaitingLoad) { /* shouldn't happen. Plugin hasn't been loaded yet.*/287*status = U_INTERNAL_PROGRAM_ERROR;288return;289}290if(U_SUCCESS(plug->pluginStatus)) {291/* Don't unload a plug which has a failing load status - means it didn't actually load. */292uplug_callPlug(plug, UPLUG_REASON_UNLOAD, status);293}294}295296static void uplug_queryPlug(UPlugData *plug, UErrorCode *status) {297if(!plug->awaitingLoad || !(plug->level == UPLUG_LEVEL_UNKNOWN) ) { /* shouldn't happen. Plugin hasn't been loaded yet.*/298*status = U_INTERNAL_PROGRAM_ERROR;299return;300}301plug->level = UPLUG_LEVEL_INVALID;302uplug_callPlug(plug, UPLUG_REASON_QUERY, status);303if(U_SUCCESS(*status)) {304if(plug->level == UPLUG_LEVEL_INVALID) {305plug->pluginStatus = U_PLUGIN_DIDNT_SET_LEVEL;306plug->awaitingLoad = false;307}308} else {309plug->pluginStatus = U_INTERNAL_PROGRAM_ERROR;310plug->awaitingLoad = false;311}312}313314315static void uplug_loadPlug(UPlugData *plug, UErrorCode *status) {316if(U_FAILURE(*status)) {317return;318}319if(!plug->awaitingLoad || (plug->level < UPLUG_LEVEL_LOW) ) { /* shouldn't happen. Plugin hasn't been loaded yet.*/320*status = U_INTERNAL_PROGRAM_ERROR;321return;322}323uplug_callPlug(plug, UPLUG_REASON_LOAD, status);324plug->awaitingLoad = false;325if(!U_SUCCESS(*status)) {326plug->pluginStatus = U_INTERNAL_PROGRAM_ERROR;327}328}329330static UPlugData *uplug_allocateEmptyPlug(UErrorCode *status)331{332UPlugData *plug = nullptr;333334if(U_FAILURE(*status)) {335return nullptr;336}337338if(pluginCount == UPLUG_PLUGIN_INITIAL_COUNT) {339*status = U_MEMORY_ALLOCATION_ERROR;340return nullptr;341}342343plug = &pluginList[pluginCount++];344345plug->token = UPLUG_TOKEN;346plug->structSize = sizeof(UPlugData);347plug->name[0]=0;348plug->level = UPLUG_LEVEL_UNKNOWN; /* initialize to null state */349plug->awaitingLoad = true;350plug->dontUnload = false;351plug->pluginStatus = U_ZERO_ERROR;352plug->libName[0] = 0;353plug->config[0]=0;354plug->sym[0]=0;355plug->lib=nullptr;356plug->entrypoint=nullptr;357358359return plug;360}361362static UPlugData *uplug_allocatePlug(UPlugEntrypoint *entrypoint, const char *config, void *lib, const char *symName,363UErrorCode *status) {364UPlugData *plug = uplug_allocateEmptyPlug(status);365if(U_FAILURE(*status)) {366return nullptr;367}368369if(config!=nullptr) {370uprv_strncpy(plug->config, config, UPLUG_NAME_MAX);371} else {372plug->config[0] = 0;373}374375if(symName!=nullptr) {376uprv_strncpy(plug->sym, symName, UPLUG_NAME_MAX);377} else {378plug->sym[0] = 0;379}380381plug->entrypoint = entrypoint;382plug->lib = lib;383uplug_queryPlug(plug, status);384385return plug;386}387388static void uplug_deallocatePlug(UPlugData *plug, UErrorCode *status) {389UErrorCode subStatus = U_ZERO_ERROR;390if(!plug->dontUnload) {391#if U_ENABLE_DYLOAD392uplug_closeLibrary(plug->lib, &subStatus);393#endif394}395plug->lib = nullptr;396if(U_SUCCESS(*status) && U_FAILURE(subStatus)) {397*status = subStatus;398}399/* shift plugins up and decrement count. */400if(U_SUCCESS(*status)) {401/* all ok- remove. */402pluginCount = uplug_removeEntryAt(pluginList, pluginCount, sizeof(plug[0]), uplug_pluginNumber(plug));403} else {404/* not ok- leave as a message. */405plug->awaitingLoad=false;406plug->entrypoint=0;407plug->dontUnload=true;408}409}410411static void uplug_doUnloadPlug(UPlugData *plugToRemove, UErrorCode *status) {412if(plugToRemove != nullptr) {413uplug_unloadPlug(plugToRemove, status);414uplug_deallocatePlug(plugToRemove, status);415}416}417418U_CAPI void U_EXPORT2419uplug_removePlug(UPlugData *plug, UErrorCode *status) {420UPlugData *cursor = nullptr;421UPlugData *plugToRemove = nullptr;422if(U_FAILURE(*status)) return;423424for(cursor=pluginList;cursor!=nullptr;) {425if(cursor==plug) {426plugToRemove = plug;427cursor=nullptr;428} else {429cursor = uplug_nextPlug(cursor);430}431}432433uplug_doUnloadPlug(plugToRemove, status);434}435436437438439U_CAPI void U_EXPORT2440uplug_setPlugNoUnload(UPlugData *data, UBool dontUnload)441{442data->dontUnload = dontUnload;443}444445446U_CAPI void U_EXPORT2447uplug_setPlugLevel(UPlugData *data, UPlugLevel level) {448data->level = level;449}450451452U_CAPI UPlugLevel U_EXPORT2453uplug_getPlugLevel(UPlugData *data) {454return data->level;455}456457458U_CAPI void U_EXPORT2459uplug_setPlugName(UPlugData *data, const char *name) {460uprv_strncpy(data->name, name, UPLUG_NAME_MAX);461}462463464U_CAPI const char * U_EXPORT2465uplug_getPlugName(UPlugData *data) {466return data->name;467}468469470U_CAPI const char * U_EXPORT2471uplug_getSymbolName(UPlugData *data) {472return data->sym;473}474475U_CAPI const char * U_EXPORT2476uplug_getLibraryName(UPlugData *data, UErrorCode *status) {477if(data->libName[0]) {478return data->libName;479} else {480#if U_ENABLE_DYLOAD481return uplug_findLibrary(data->lib, status);482#else483return nullptr;484#endif485}486}487488U_CAPI void * U_EXPORT2489uplug_getLibrary(UPlugData *data) {490return data->lib;491}492493U_CAPI void * U_EXPORT2494uplug_getContext(UPlugData *data) {495return data->context;496}497498499U_CAPI void U_EXPORT2500uplug_setContext(UPlugData *data, void *context) {501data->context = context;502}503504U_CAPI const char* U_EXPORT2505uplug_getConfiguration(UPlugData *data) {506return data->config;507}508509U_CAPI UPlugData* U_EXPORT2510uplug_getPlugInternal(int32_t n) {511if(n <0 || n >= pluginCount) {512return nullptr;513} else {514return &(pluginList[n]);515}516}517518519U_CAPI UErrorCode U_EXPORT2520uplug_getPlugLoadStatus(UPlugData *plug) {521return plug->pluginStatus;522}523524525526527/**528* Initialize a plugin from an entrypoint and library - but don't load it.529*/530static UPlugData* uplug_initPlugFromEntrypointAndLibrary(UPlugEntrypoint *entrypoint, const char *config, void *lib, const char *sym,531UErrorCode *status) {532UPlugData *plug = nullptr;533534plug = uplug_allocatePlug(entrypoint, config, lib, sym, status);535536if(U_SUCCESS(*status)) {537return plug;538} else {539uplug_deallocatePlug(plug, status);540return nullptr;541}542}543544U_CAPI UPlugData* U_EXPORT2545uplug_loadPlugFromEntrypoint(UPlugEntrypoint *entrypoint, const char *config, UErrorCode *status) {546UPlugData* plug = uplug_initPlugFromEntrypointAndLibrary(entrypoint, config, nullptr, nullptr, status);547uplug_loadPlug(plug, status);548return plug;549}550551#if U_ENABLE_DYLOAD552553static UPlugData*554uplug_initErrorPlug(const char *libName, const char *sym, const char *config, const char *nameOrError, UErrorCode loadStatus, UErrorCode *status)555{556UPlugData *plug = uplug_allocateEmptyPlug(status);557if(U_FAILURE(*status)) return nullptr;558559plug->pluginStatus = loadStatus;560plug->awaitingLoad = false; /* Won't load. */561plug->dontUnload = true; /* cannot unload. */562563if(sym!=nullptr) {564uprv_strncpy(plug->sym, sym, UPLUG_NAME_MAX);565}566567if(libName!=nullptr) {568uprv_strncpy(plug->libName, libName, UPLUG_NAME_MAX);569}570571if(nameOrError!=nullptr) {572uprv_strncpy(plug->name, nameOrError, UPLUG_NAME_MAX);573}574575if(config!=nullptr) {576uprv_strncpy(plug->config, config, UPLUG_NAME_MAX);577}578579return plug;580}581582/**583* Fetch a plugin from DLL, and then initialize it from a library- but don't load it.584*/585static UPlugData*586uplug_initPlugFromLibrary(const char *libName, const char *sym, const char *config, UErrorCode *status) {587void *lib = nullptr;588UPlugData *plug = nullptr;589if(U_FAILURE(*status)) { return nullptr; }590lib = uplug_openLibrary(libName, status);591if(lib!=nullptr && U_SUCCESS(*status)) {592UPlugEntrypoint *entrypoint = nullptr;593entrypoint = (UPlugEntrypoint*)uprv_dlsym_func(lib, sym, status);594595if(entrypoint!=nullptr&&U_SUCCESS(*status)) {596plug = uplug_initPlugFromEntrypointAndLibrary(entrypoint, config, lib, sym, status);597if(plug!=nullptr&&U_SUCCESS(*status)) {598plug->lib = lib; /* plug takes ownership of library */599lib = nullptr; /* library is now owned by plugin. */600}601} else {602UErrorCode subStatus = U_ZERO_ERROR;603plug = uplug_initErrorPlug(libName,sym,config,"ERROR: Could not load entrypoint",(lib==nullptr)?U_MISSING_RESOURCE_ERROR:*status,&subStatus);604}605if(lib!=nullptr) { /* still need to close the lib */606UErrorCode subStatus = U_ZERO_ERROR;607uplug_closeLibrary(lib, &subStatus); /* don't care here */608}609} else {610UErrorCode subStatus = U_ZERO_ERROR;611plug = uplug_initErrorPlug(libName,sym,config,"ERROR: could not load library",(lib==nullptr)?U_MISSING_RESOURCE_ERROR:*status,&subStatus);612}613return plug;614}615616U_CAPI UPlugData* U_EXPORT2617uplug_loadPlugFromLibrary(const char *libName, const char *sym, const char *config, UErrorCode *status) {618UPlugData *plug = nullptr;619if(U_FAILURE(*status)) { return nullptr; }620plug = uplug_initPlugFromLibrary(libName, sym, config, status);621uplug_loadPlug(plug, status);622623return plug;624}625626#endif627628static UPlugLevel gCurrentLevel = UPLUG_LEVEL_LOW;629630U_CAPI UPlugLevel U_EXPORT2 uplug_getCurrentLevel() {631return gCurrentLevel;632}633634static UBool U_CALLCONV uplug_cleanup()635{636int32_t i;637638UPlugData *pluginToRemove;639/* cleanup plugs */640for(i=0;i<pluginCount;i++) {641UErrorCode subStatus = U_ZERO_ERROR;642pluginToRemove = &pluginList[i];643/* unload and deallocate */644uplug_doUnloadPlug(pluginToRemove, &subStatus);645}646/* close other held libs? */647gCurrentLevel = UPLUG_LEVEL_LOW;648return true;649}650651#if U_ENABLE_DYLOAD652653static void uplug_loadWaitingPlugs(UErrorCode *status) {654int32_t i;655UPlugLevel currentLevel = uplug_getCurrentLevel();656657if(U_FAILURE(*status)) {658return;659}660#if UPLUG_TRACE661DBG((stderr, "uplug_loadWaitingPlugs() Level: %d\n", currentLevel));662#endif663/* pass #1: low level plugs */664for(i=0;i<pluginCount;i++) {665UErrorCode subStatus = U_ZERO_ERROR;666UPlugData *pluginToLoad = &pluginList[i];667if(pluginToLoad->awaitingLoad) {668if(pluginToLoad->level == UPLUG_LEVEL_LOW) {669if(currentLevel > UPLUG_LEVEL_LOW) {670pluginToLoad->pluginStatus = U_PLUGIN_TOO_HIGH;671} else {672UPlugLevel newLevel;673uplug_loadPlug(pluginToLoad, &subStatus);674newLevel = uplug_getCurrentLevel();675if(newLevel > currentLevel) {676pluginToLoad->pluginStatus = U_PLUGIN_CHANGED_LEVEL_WARNING;677currentLevel = newLevel;678}679}680pluginToLoad->awaitingLoad = false;681}682}683}684for(i=0;i<pluginCount;i++) {685UErrorCode subStatus = U_ZERO_ERROR;686UPlugData *pluginToLoad = &pluginList[i];687688if(pluginToLoad->awaitingLoad) {689if(pluginToLoad->level == UPLUG_LEVEL_INVALID) {690pluginToLoad->pluginStatus = U_PLUGIN_DIDNT_SET_LEVEL;691} else if(pluginToLoad->level == UPLUG_LEVEL_UNKNOWN) {692pluginToLoad->pluginStatus = U_INTERNAL_PROGRAM_ERROR;693} else {694uplug_loadPlug(pluginToLoad, &subStatus);695}696pluginToLoad->awaitingLoad = false;697}698}699700#if UPLUG_TRACE701DBG((stderr, " Done Loading Plugs. Level: %d\n", (int32_t)uplug_getCurrentLevel()));702#endif703}704705/* Name of the plugin config file */706static char plugin_file[2048] = "";707#endif708709U_CAPI const char* U_EXPORT2710uplug_getPluginFile() {711#if U_ENABLE_DYLOAD && !UCONFIG_NO_FILE_IO712return plugin_file;713#else714return nullptr;715#endif716}717718719// uplug_init() is called first thing from u_init().720721U_CAPI void U_EXPORT2722uplug_init(UErrorCode *status) {723#if !U_ENABLE_DYLOAD724(void)status; /* unused */725#elif !UCONFIG_NO_FILE_IO726CharString plugin_dir;727const char *env = getenv("ICU_PLUGINS");728729if(U_FAILURE(*status)) return;730if(env != nullptr) {731plugin_dir.append(env, -1, *status);732}733if(U_FAILURE(*status)) return;734735#if defined(DEFAULT_ICU_PLUGINS)736if(plugin_dir.isEmpty()) {737plugin_dir.append(DEFAULT_ICU_PLUGINS, -1, *status);738}739#endif740741#if UPLUG_TRACE742DBG((stderr, "ICU_PLUGINS=%s\n", plugin_dir.data()));743#endif744745if(!plugin_dir.isEmpty()) {746FILE *f;747748CharString pluginFile;749#ifdef ICU_PLUGINS_DD750/* There are potentially a lot of ways to implement a plugin directory on OS390/zOS */751/* Keeping in mind that unauthorized file access is logged, monitored, and enforced */752/* I've chosen to open a DDNAME if BATCH and leave it alone for (presumably) UNIX */753/* System Services. Alternative techniques might be allocating a member in */754/* SYS1.PARMLIB or setting an environment variable "ICU_PLUGIN_PATH" (?). The */755/* DDNAME can be connected to a file in the HFS if need be. */756757pluginFile.append("//DD:ICUPLUG", -1, *status); /* JAM 20 Oct 2011 */758#else759pluginFile.append(plugin_dir, *status);760pluginFile.append(U_FILE_SEP_STRING, -1, *status);761pluginFile.append("icuplugins", -1, *status);762pluginFile.append(U_ICU_VERSION_SHORT, -1, *status);763pluginFile.append(".txt", -1, *status);764#endif765766#if UPLUG_TRACE767DBG((stderr, "status=%s\n", u_errorName(*status)));768#endif769770if(U_FAILURE(*status)) {771return;772}773if((size_t)pluginFile.length() > (sizeof(plugin_file)-1)) {774*status = U_BUFFER_OVERFLOW_ERROR;775#if UPLUG_TRACE776DBG((stderr, "status=%s\n", u_errorName(*status)));777#endif778return;779}780781/* plugin_file is not used for processing - it is only used782so that uplug_getPluginFile() works (i.e. icuinfo)783*/784pluginFile.extract(plugin_file, sizeof(plugin_file), *status);785786#if UPLUG_TRACE787DBG((stderr, "pluginfile= %s len %d/%d\n", plugin_file, (int)strlen(plugin_file), (int)sizeof(plugin_file)));788#endif789790#ifdef __MVS__791if (iscics()) /* 12 Nov 2011 JAM */792{793f = nullptr;794}795else796#endif797{798f = fopen(pluginFile.data(), "r");799}800801if(f != nullptr) {802char linebuf[1024];803char *p, *libName=nullptr, *symName=nullptr, *config=nullptr;804int32_t line = 0;805806807while(fgets(linebuf,1023,f)) {808line++;809810if(!*linebuf || *linebuf=='#') {811continue;812} else {813p = linebuf;814while(*p&&isspace((int)*p))815p++;816if(!*p || *p=='#') continue;817libName = p;818while(*p&&!isspace((int)*p)) {819p++;820}821if(!*p || *p=='#') continue; /* no tab after libname */822*p=0; /* end of libname */823p++;824while(*p&&isspace((int)*p)) {825p++;826}827if(!*p||*p=='#') continue; /* no symname after libname +tab */828symName = p;829while(*p&&!isspace((int)*p)) {830p++;831}832833if(*p) { /* has config */834*p=0;835++p;836while(*p&&isspace((int)*p)) {837p++;838}839if(*p) {840config = p;841}842}843844/* chop whitespace at the end of the config */845if(config!=nullptr&&*config!=0) {846p = config+strlen(config);847while(p>config&&isspace((int)*(--p))) {848*p=0;849}850}851852/* OK, we're good. */853{854UErrorCode subStatus = U_ZERO_ERROR;855UPlugData *plug = uplug_initPlugFromLibrary(libName, symName, config, &subStatus);856if(U_FAILURE(subStatus) && U_SUCCESS(*status)) {857*status = subStatus;858}859#if UPLUG_TRACE860DBG((stderr, "PLUGIN libName=[%s], sym=[%s], config=[%s]\n", libName, symName, config));861DBG((stderr, " -> %p, %s\n", (void*)plug, u_errorName(subStatus)));862#else863(void)plug; /* unused */864#endif865}866}867}868fclose(f);869} else {870#if UPLUG_TRACE871DBG((stderr, "Can't open plugin file %s\n", plugin_file));872#endif873}874}875uplug_loadWaitingPlugs(status);876#endif /* U_ENABLE_DYLOAD */877gCurrentLevel = UPLUG_LEVEL_HIGH;878ucln_registerCleanup(UCLN_UPLUG, uplug_cleanup);879}880881#endif882883884885886