2 ******************************************************************************
4 * Copyright (C) 2009-2015, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 ******************************************************************************
9 * FILE NAME : icuplug.c
11 * Date Name Description
13 ******************************************************************************
16 #include "unicode/icuplug.h"
17 #include "icuplugimp.h"
23 #ifdef __MVS__ /* defined by z/OS compiler */
25 #include <cics.h> /* 12 Nov 2011 JAM iscics() function */
37 #define DBG(x) fprintf(stderr, "%s:%d: ",__FILE__,__LINE__); fprintf x
41 * Internal structure of an ICU plugin.
45 UPlugEntrypoint
*entrypoint
; /**< plugin entrypoint */
46 uint32_t structSize
; /**< initialized to the size of this structure */
47 uint32_t token
; /**< must be U_PLUG_TOKEN */
48 void *lib
; /**< plugin library, or NULL */
49 char libName
[UPLUG_NAME_MAX
]; /**< library name */
50 char sym
[UPLUG_NAME_MAX
]; /**< plugin symbol, or NULL */
51 char config
[UPLUG_NAME_MAX
]; /**< configuration data */
52 void *context
; /**< user context data */
53 char name
[UPLUG_NAME_MAX
]; /**< name of plugin */
54 UPlugLevel level
; /**< level of plugin */
55 UBool awaitingLoad
; /**< TRUE if the plugin is awaiting a load call */
56 UBool dontUnload
; /**< TRUE if plugin must stay resident (leak plugin and lib) */
57 UErrorCode pluginStatus
; /**< status code of plugin */
62 #define UPLUG_LIBRARY_INITIAL_COUNT 8
63 #define UPLUG_PLUGIN_INITIAL_COUNT 12
67 * @param list the full list
68 * @param listSize the number of entries in the list
69 * @param memberSize the size of one member
70 * @param itemToRemove the item number of the member
71 * @return the new listsize
73 static int32_t uplug_removeEntryAt(void *list
, int32_t listSize
, int32_t memberSize
, int32_t itemToRemove
) {
74 uint8_t *bytePtr
= (uint8_t *)list
;
76 /* get rid of some bad cases first */
81 /* is there anything to move? */
82 if(listSize
> itemToRemove
+1) {
83 memmove(bytePtr
+(itemToRemove
*memberSize
), bytePtr
+((itemToRemove
+1)*memberSize
), memberSize
);
94 * Library management. Internal.
100 * Library management. Internal.
103 typedef struct UPlugLibrary
{
104 void *lib
; /**< library ptr */
105 char name
[UPLUG_NAME_MAX
]; /**< library name */
106 uint32_t ref
; /**< reference count */
109 static UPlugLibrary staticLibraryList
[UPLUG_LIBRARY_INITIAL_COUNT
];
110 static UPlugLibrary
* libraryList
= staticLibraryList
;
111 static int32_t libraryCount
= 0;
112 static int32_t libraryMax
= UPLUG_LIBRARY_INITIAL_COUNT
;
115 * Search for a library. Doesn't lock
116 * @param libName libname to search for
117 * @return the library's struct
119 static int32_t searchForLibraryName(const char *libName
) {
122 for(i
=0;i
<libraryCount
;i
++) {
123 if(!uprv_strcmp(libName
, libraryList
[i
].name
)) {
130 static int32_t searchForLibrary(void *lib
) {
133 for(i
=0;i
<libraryCount
;i
++) {
134 if(lib
==libraryList
[i
].lib
) {
141 U_INTERNAL
char * U_EXPORT2
142 uplug_findLibrary(void *lib
, UErrorCode
*status
) {
145 if(U_FAILURE(*status
)) {
148 libEnt
= searchForLibrary(lib
);
150 ret
= libraryList
[libEnt
].name
;
152 *status
= U_MISSING_RESOURCE_ERROR
;
157 U_INTERNAL
void * U_EXPORT2
158 uplug_openLibrary(const char *libName
, UErrorCode
*status
) {
159 int32_t libEntry
= -1;
162 if(U_FAILURE(*status
)) return NULL
;
164 libEntry
= searchForLibraryName(libName
);
166 libEntry
= libraryCount
++;
167 if(libraryCount
>= libraryMax
) {
168 /* Ran out of library slots. Statically allocated because we can't depend on allocating memory.. */
169 *status
= U_MEMORY_ALLOCATION_ERROR
;
171 DBG((stderr
, "uplug_openLibrary() - out of library slots (max %d)\n", libraryMax
));
175 /* Some operating systems don't want
176 DL operations from multiple threads. */
177 libraryList
[libEntry
].lib
= uprv_dl_open(libName
, status
);
179 DBG((stderr
, "uplug_openLibrary(%s,%s) libEntry %d, lib %p\n", libName
, u_errorName(*status
), libEntry
, lib
));
182 if(libraryList
[libEntry
].lib
== NULL
|| U_FAILURE(*status
)) {
184 libraryList
[libEntry
].lib
= NULL
; /* failure with open */
185 libraryList
[libEntry
].name
[0] = 0;
187 DBG((stderr
, "uplug_openLibrary(%s,%s) libEntry %d, lib %p\n", libName
, u_errorName(*status
), libEntry
, lib
));
189 /* no need to free - just won't increase the count. */
191 } else { /* is it still there? */
193 uprv_strncpy(libraryList
[libEntry
].name
,libName
,UPLUG_NAME_MAX
);
194 libraryList
[libEntry
].ref
=1;
195 lib
= libraryList
[libEntry
].lib
;
199 lib
= libraryList
[libEntry
].lib
;
200 libraryList
[libEntry
].ref
++;
205 U_INTERNAL
void U_EXPORT2
206 uplug_closeLibrary(void *lib
, UErrorCode
*status
) {
210 DBG((stderr
, "uplug_closeLibrary(%p,%s) list %p\n", lib
, u_errorName(*status
), (void*)libraryList
));
212 if(U_FAILURE(*status
)) return;
214 for(i
=0;i
<libraryCount
;i
++) {
215 if(lib
==libraryList
[i
].lib
) {
216 if(--(libraryList
[i
].ref
) == 0) {
217 uprv_dl_close(libraryList
[i
].lib
, status
);
218 libraryCount
= uplug_removeEntryAt(libraryList
, libraryCount
, sizeof(*libraryList
), i
);
223 *status
= U_INTERNAL_PROGRAM_ERROR
; /* could not find the entry! */
228 static UPlugData pluginList
[UPLUG_PLUGIN_INITIAL_COUNT
];
229 static int32_t pluginCount
= 0;
234 static int32_t uplug_pluginNumber(UPlugData
* d
) {
235 UPlugData
*pastPlug
= &pluginList
[pluginCount
];
238 } else if(d
>=pastPlug
) {
241 return (d
-pluginList
)/sizeof(pluginList
[0]);
246 U_CAPI UPlugData
* U_EXPORT2
247 uplug_nextPlug(UPlugData
*prior
) {
251 UPlugData
*nextPlug
= &prior
[1];
252 UPlugData
*pastPlug
= &pluginList
[pluginCount
];
254 if(nextPlug
>=pastPlug
) {
265 * Call the plugin with some params
267 static void uplug_callPlug(UPlugData
*plug
, UPlugReason reason
, UErrorCode
*status
) {
268 UPlugTokenReturn token
;
269 if(plug
==NULL
||U_FAILURE(*status
)) {
272 token
= (*(plug
->entrypoint
))(plug
, reason
, status
);
273 if(token
!=UPLUG_TOKEN
) {
274 *status
= U_INTERNAL_PROGRAM_ERROR
;
279 static void uplug_unloadPlug(UPlugData
*plug
, UErrorCode
*status
) {
280 if(plug
->awaitingLoad
) { /* shouldn't happen. Plugin hasn'tbeen loaded yet.*/
281 *status
= U_INTERNAL_PROGRAM_ERROR
;
284 if(U_SUCCESS(plug
->pluginStatus
)) {
285 /* Don't unload a plug which has a failing load status - means it didn't actually load. */
286 uplug_callPlug(plug
, UPLUG_REASON_UNLOAD
, status
);
290 static void uplug_queryPlug(UPlugData
*plug
, UErrorCode
*status
) {
291 if(!plug
->awaitingLoad
|| !(plug
->level
== UPLUG_LEVEL_UNKNOWN
) ) { /* shouldn't happen. Plugin hasn'tbeen loaded yet.*/
292 *status
= U_INTERNAL_PROGRAM_ERROR
;
295 plug
->level
= UPLUG_LEVEL_INVALID
;
296 uplug_callPlug(plug
, UPLUG_REASON_QUERY
, status
);
297 if(U_SUCCESS(*status
)) {
298 if(plug
->level
== UPLUG_LEVEL_INVALID
) {
299 plug
->pluginStatus
= U_PLUGIN_DIDNT_SET_LEVEL
;
300 plug
->awaitingLoad
= FALSE
;
303 plug
->pluginStatus
= U_INTERNAL_PROGRAM_ERROR
;
304 plug
->awaitingLoad
= FALSE
;
309 static void uplug_loadPlug(UPlugData
*plug
, UErrorCode
*status
) {
310 if(!plug
->awaitingLoad
|| (plug
->level
< UPLUG_LEVEL_LOW
) ) { /* shouldn't happen. Plugin hasn'tbeen loaded yet.*/
311 *status
= U_INTERNAL_PROGRAM_ERROR
;
314 uplug_callPlug(plug
, UPLUG_REASON_LOAD
, status
);
315 plug
->awaitingLoad
= FALSE
;
316 if(!U_SUCCESS(*status
)) {
317 plug
->pluginStatus
= U_INTERNAL_PROGRAM_ERROR
;
321 static UPlugData
*uplug_allocateEmptyPlug(UErrorCode
*status
)
323 UPlugData
*plug
= NULL
;
325 if(U_FAILURE(*status
)) {
329 if(pluginCount
== UPLUG_PLUGIN_INITIAL_COUNT
) {
330 *status
= U_MEMORY_ALLOCATION_ERROR
;
334 plug
= &pluginList
[pluginCount
++];
336 plug
->token
= UPLUG_TOKEN
;
337 plug
->structSize
= sizeof(UPlugData
);
339 plug
->level
= UPLUG_LEVEL_UNKNOWN
; /* initialize to null state */
340 plug
->awaitingLoad
= TRUE
;
341 plug
->dontUnload
= FALSE
;
342 plug
->pluginStatus
= U_ZERO_ERROR
;
343 plug
->libName
[0] = 0;
347 plug
->entrypoint
=NULL
;
353 static UPlugData
*uplug_allocatePlug(UPlugEntrypoint
*entrypoint
, const char *config
, void *lib
, const char *symName
,
354 UErrorCode
*status
) {
357 if(U_FAILURE(*status
)) {
361 plug
= uplug_allocateEmptyPlug(status
);
363 uprv_strncpy(plug
->config
, config
, UPLUG_NAME_MAX
);
369 uprv_strncpy(plug
->sym
, symName
, UPLUG_NAME_MAX
);
374 plug
->entrypoint
= entrypoint
;
376 uplug_queryPlug(plug
, status
);
381 static void uplug_deallocatePlug(UPlugData
*plug
, UErrorCode
*status
) {
382 UErrorCode subStatus
= U_ZERO_ERROR
;
383 if(!plug
->dontUnload
) {
385 uplug_closeLibrary(plug
->lib
, &subStatus
);
389 if(U_SUCCESS(*status
) && U_FAILURE(subStatus
)) {
392 /* shift plugins up and decrement count. */
393 if(U_SUCCESS(*status
)) {
394 /* all ok- remove. */
395 pluginCount
= uplug_removeEntryAt(pluginList
, pluginCount
, sizeof(plug
[0]), uplug_pluginNumber(plug
));
397 /* not ok- leave as a message. */
398 plug
->awaitingLoad
=FALSE
;
400 plug
->dontUnload
=TRUE
;
404 static void uplug_doUnloadPlug(UPlugData
*plugToRemove
, UErrorCode
*status
) {
405 if(plugToRemove
!= NULL
) {
406 uplug_unloadPlug(plugToRemove
, status
);
407 uplug_deallocatePlug(plugToRemove
, status
);
411 U_CAPI
void U_EXPORT2
412 uplug_removePlug(UPlugData
*plug
, UErrorCode
*status
) {
413 UPlugData
*cursor
= NULL
;
414 UPlugData
*plugToRemove
= NULL
;
415 if(U_FAILURE(*status
)) return;
417 for(cursor
=pluginList
;cursor
!=NULL
;) {
422 cursor
= uplug_nextPlug(cursor
);
426 uplug_doUnloadPlug(plugToRemove
, status
);
432 U_CAPI
void U_EXPORT2
433 uplug_setPlugNoUnload(UPlugData
*data
, UBool dontUnload
)
435 data
->dontUnload
= dontUnload
;
439 U_CAPI
void U_EXPORT2
440 uplug_setPlugLevel(UPlugData
*data
, UPlugLevel level
) {
445 U_CAPI UPlugLevel U_EXPORT2
446 uplug_getPlugLevel(UPlugData
*data
) {
451 U_CAPI
void U_EXPORT2
452 uplug_setPlugName(UPlugData
*data
, const char *name
) {
453 uprv_strncpy(data
->name
, name
, UPLUG_NAME_MAX
);
457 U_CAPI
const char * U_EXPORT2
458 uplug_getPlugName(UPlugData
*data
) {
463 U_CAPI
const char * U_EXPORT2
464 uplug_getSymbolName(UPlugData
*data
) {
468 U_CAPI
const char * U_EXPORT2
469 uplug_getLibraryName(UPlugData
*data
, UErrorCode
*status
) {
470 if(data
->libName
[0]) {
471 return data
->libName
;
474 return uplug_findLibrary(data
->lib
, status
);
481 U_CAPI
void * U_EXPORT2
482 uplug_getLibrary(UPlugData
*data
) {
486 U_CAPI
void * U_EXPORT2
487 uplug_getContext(UPlugData
*data
) {
488 return data
->context
;
492 U_CAPI
void U_EXPORT2
493 uplug_setContext(UPlugData
*data
, void *context
) {
494 data
->context
= context
;
497 U_CAPI
const char* U_EXPORT2
498 uplug_getConfiguration(UPlugData
*data
) {
502 U_INTERNAL UPlugData
* U_EXPORT2
503 uplug_getPlugInternal(int32_t n
) {
504 if(n
<0 || n
>= pluginCount
) {
507 return &(pluginList
[n
]);
512 U_CAPI UErrorCode U_EXPORT2
513 uplug_getPlugLoadStatus(UPlugData
*plug
) {
514 return plug
->pluginStatus
;
521 * Initialize a plugin fron an entrypoint and library - but don't load it.
523 static UPlugData
* uplug_initPlugFromEntrypointAndLibrary(UPlugEntrypoint
*entrypoint
, const char *config
, void *lib
, const char *sym
,
524 UErrorCode
*status
) {
525 UPlugData
*plug
= NULL
;
527 plug
= uplug_allocatePlug(entrypoint
, config
, lib
, sym
, status
);
529 if(U_SUCCESS(*status
)) {
532 uplug_deallocatePlug(plug
, status
);
537 U_CAPI UPlugData
* U_EXPORT2
538 uplug_loadPlugFromEntrypoint(UPlugEntrypoint
*entrypoint
, const char *config
, UErrorCode
*status
) {
539 UPlugData
* plug
= uplug_initPlugFromEntrypointAndLibrary(entrypoint
, config
, NULL
, NULL
, status
);
540 uplug_loadPlug(plug
, status
);
547 uplug_initErrorPlug(const char *libName
, const char *sym
, const char *config
, const char *nameOrError
, UErrorCode loadStatus
, UErrorCode
*status
)
549 UPlugData
*plug
= uplug_allocateEmptyPlug(status
);
550 if(U_FAILURE(*status
)) return NULL
;
552 plug
->pluginStatus
= loadStatus
;
553 plug
->awaitingLoad
= FALSE
; /* Won't load. */
554 plug
->dontUnload
= TRUE
; /* cannot unload. */
557 uprv_strncpy(plug
->sym
, sym
, UPLUG_NAME_MAX
);
561 uprv_strncpy(plug
->libName
, libName
, UPLUG_NAME_MAX
);
564 if(nameOrError
!=NULL
) {
565 uprv_strncpy(plug
->name
, nameOrError
, UPLUG_NAME_MAX
);
569 uprv_strncpy(plug
->config
, config
, UPLUG_NAME_MAX
);
576 * Fetch a plugin from DLL, and then initialize it from a library- but don't load it.
579 uplug_initPlugFromLibrary(const char *libName
, const char *sym
, const char *config
, UErrorCode
*status
) {
581 UPlugData
*plug
= NULL
;
582 if(U_FAILURE(*status
)) { return NULL
; }
583 lib
= uplug_openLibrary(libName
, status
);
584 if(lib
!=NULL
&& U_SUCCESS(*status
)) {
585 UPlugEntrypoint
*entrypoint
= NULL
;
586 entrypoint
= (UPlugEntrypoint
*)uprv_dlsym_func(lib
, sym
, status
);
588 if(entrypoint
!=NULL
&&U_SUCCESS(*status
)) {
589 plug
= uplug_initPlugFromEntrypointAndLibrary(entrypoint
, config
, lib
, sym
, status
);
590 if(plug
!=NULL
&&U_SUCCESS(*status
)) {
591 plug
->lib
= lib
; /* plug takes ownership of library */
592 lib
= NULL
; /* library is now owned by plugin. */
595 UErrorCode subStatus
= U_ZERO_ERROR
;
596 plug
= uplug_initErrorPlug(libName
,sym
,config
,"ERROR: Could not load entrypoint",(lib
==NULL
)?U_MISSING_RESOURCE_ERROR
:*status
,&subStatus
);
598 if(lib
!=NULL
) { /* still need to close the lib */
599 UErrorCode subStatus
= U_ZERO_ERROR
;
600 uplug_closeLibrary(lib
, &subStatus
); /* don't care here */
603 UErrorCode subStatus
= U_ZERO_ERROR
;
604 plug
= uplug_initErrorPlug(libName
,sym
,config
,"ERROR: could not load library",(lib
==NULL
)?U_MISSING_RESOURCE_ERROR
:*status
,&subStatus
);
609 U_CAPI UPlugData
* U_EXPORT2
610 uplug_loadPlugFromLibrary(const char *libName
, const char *sym
, const char *config
, UErrorCode
*status
) {
611 UPlugData
*plug
= NULL
;
612 if(U_FAILURE(*status
)) { return NULL
; }
613 plug
= uplug_initPlugFromLibrary(libName
, sym
, config
, status
);
614 uplug_loadPlug(plug
, status
);
621 static UPlugLevel gCurrentLevel
= UPLUG_LEVEL_LOW
;
623 U_CAPI UPlugLevel U_EXPORT2
uplug_getCurrentLevel() {
624 return gCurrentLevel
;
627 static UBool U_CALLCONV
uplug_cleanup(void)
631 UPlugData
*pluginToRemove
;
633 for(i
=0;i
<pluginCount
;i
++) {
634 UErrorCode subStatus
= U_ZERO_ERROR
;
635 pluginToRemove
= &pluginList
[i
];
636 /* unload and deallocate */
637 uplug_doUnloadPlug(pluginToRemove
, &subStatus
);
639 /* close other held libs? */
640 gCurrentLevel
= UPLUG_LEVEL_LOW
;
646 static void uplug_loadWaitingPlugs(UErrorCode
*status
) {
648 UPlugLevel currentLevel
= uplug_getCurrentLevel();
650 if(U_FAILURE(*status
)) {
654 DBG((stderr
, "uplug_loadWaitingPlugs() Level: %d\n", currentLevel
));
656 /* pass #1: low level plugs */
657 for(i
=0;i
<pluginCount
;i
++) {
658 UErrorCode subStatus
= U_ZERO_ERROR
;
659 UPlugData
*pluginToLoad
= &pluginList
[i
];
660 if(pluginToLoad
->awaitingLoad
) {
661 if(pluginToLoad
->level
== UPLUG_LEVEL_LOW
) {
662 if(currentLevel
> UPLUG_LEVEL_LOW
) {
663 pluginToLoad
->pluginStatus
= U_PLUGIN_TOO_HIGH
;
666 uplug_loadPlug(pluginToLoad
, &subStatus
);
667 newLevel
= uplug_getCurrentLevel();
668 if(newLevel
> currentLevel
) {
669 pluginToLoad
->pluginStatus
= U_PLUGIN_CHANGED_LEVEL_WARNING
;
670 currentLevel
= newLevel
;
673 pluginToLoad
->awaitingLoad
= FALSE
;
677 for(i
=0;i
<pluginCount
;i
++) {
678 UErrorCode subStatus
= U_ZERO_ERROR
;
679 UPlugData
*pluginToLoad
= &pluginList
[i
];
681 if(pluginToLoad
->awaitingLoad
) {
682 if(pluginToLoad
->level
== UPLUG_LEVEL_INVALID
) {
683 pluginToLoad
->pluginStatus
= U_PLUGIN_DIDNT_SET_LEVEL
;
684 } else if(pluginToLoad
->level
== UPLUG_LEVEL_UNKNOWN
) {
685 pluginToLoad
->pluginStatus
= U_INTERNAL_PROGRAM_ERROR
;
687 uplug_loadPlug(pluginToLoad
, &subStatus
);
689 pluginToLoad
->awaitingLoad
= FALSE
;
694 DBG((stderr
, " Done Loading Plugs. Level: %d\n", (int32_t)uplug_getCurrentLevel()));
698 /* Name of the plugin config file */
699 static char plugin_file
[2048] = "";
702 U_INTERNAL
const char* U_EXPORT2
703 uplug_getPluginFile() {
704 #if U_ENABLE_DYLOAD && !UCONFIG_NO_FILE_IO
712 // uplug_init() is called first thing from u_init().
714 U_CAPI
void U_EXPORT2
715 uplug_init(UErrorCode
*status
) {
717 (void)status
; /* unused */
718 #elif !UCONFIG_NO_FILE_IO
719 CharString plugin_dir
;
720 const char *env
= getenv("ICU_PLUGINS");
722 if(U_FAILURE(*status
)) return;
724 plugin_dir
.append(env
, -1, *status
);
726 if(U_FAILURE(*status
)) return;
728 #if defined(DEFAULT_ICU_PLUGINS)
729 if(plugin_dir
.isEmpty()) {
730 plugin_dir
.append(DEFAULT_ICU_PLUGINS
, -1, *status
);
735 DBG((stderr
, "ICU_PLUGINS=%s\n", plugin_dir
.data()));
738 if(!plugin_dir
.isEmpty()) {
741 CharString pluginFile
;
743 /* There are potentially a lot of ways to implement a plugin directory on OS390/zOS */
744 /* Keeping in mind that unauthorized file access is logged, monitored, and enforced */
745 /* I've chosen to open a DDNAME if BATCH and leave it alone for (presumably) UNIX */
746 /* System Services. Alternative techniques might be allocating a member in */
747 /* SYS1.PARMLIB or setting an environment variable "ICU_PLUGIN_PATH" (?). The */
748 /* DDNAME can be connected to a file in the HFS if need be. */
750 pluginFile
.append("//DD:ICUPLUG", -1, *status
); /* JAM 20 Oct 2011 */
752 pluginFile
.append(plugin_dir
, *status
);
753 pluginFile
.append(U_FILE_SEP_STRING
, -1, *status
);
754 pluginFile
.append("icuplugins", -1, *status
);
755 pluginFile
.append(U_ICU_VERSION_SHORT
, -1, *status
);
756 pluginFile
.append(".txt", -1, *status
);
760 DBG((stderr
, "status=%s\n", u_errorName(*status
)));
763 if(U_FAILURE(*status
)) {
766 if((size_t)pluginFile
.length() > (sizeof(plugin_file
)-1)) {
767 *status
= U_BUFFER_OVERFLOW_ERROR
;
769 DBG((stderr
, "status=%s\n", u_errorName(*status
)));
774 /* plugin_file is not used for processing - it is only used
775 so that uplug_getPluginFile() works (i.e. icuinfo)
777 uprv_strncpy(plugin_file
, pluginFile
.data(), sizeof(plugin_file
));
780 DBG((stderr
, "pluginfile= %s len %d/%d\n", plugin_file
, (int)strlen(plugin_file
), (int)sizeof(plugin_file
)));
784 if (iscics()) /* 12 Nov 2011 JAM */
791 f
= fopen(pluginFile
.data(), "r");
796 char *p
, *libName
=NULL
, *symName
=NULL
, *config
=NULL
;
800 while(fgets(linebuf
,1023,f
)) {
803 if(!*linebuf
|| *linebuf
=='#') {
807 while(*p
&&isspace((int)*p
))
809 if(!*p
|| *p
=='#') continue;
811 while(*p
&&!isspace((int)*p
)) {
814 if(!*p
|| *p
=='#') continue; /* no tab after libname */
815 *p
=0; /* end of libname */
817 while(*p
&&isspace((int)*p
)) {
820 if(!*p
||*p
=='#') continue; /* no symname after libname +tab */
822 while(*p
&&!isspace((int)*p
)) {
826 if(*p
) { /* has config */
829 while(*p
&&isspace((int)*p
)) {
837 /* chop whitespace at the end of the config */
838 if(config
!=NULL
&&*config
!=0) {
839 p
= config
+strlen(config
);
840 while(p
>config
&&isspace((int)*(--p
))) {
845 /* OK, we're good. */
847 UErrorCode subStatus
= U_ZERO_ERROR
;
848 UPlugData
*plug
= uplug_initPlugFromLibrary(libName
, symName
, config
, &subStatus
);
849 if(U_FAILURE(subStatus
) && U_SUCCESS(*status
)) {
853 DBG((stderr
, "PLUGIN libName=[%s], sym=[%s], config=[%s]\n", libName
, symName
, config
));
854 DBG((stderr
, " -> %p, %s\n", (void*)plug
, u_errorName(subStatus
)));
856 (void)plug
; /* unused */
864 DBG((stderr
, "Can't open plugin file %s\n", plugin_file
));
868 uplug_loadWaitingPlugs(status
);
869 #endif /* U_ENABLE_DYLOAD */
870 gCurrentLevel
= UPLUG_LEVEL_HIGH
;
871 ucln_registerCleanup(UCLN_UPLUG
, uplug_cleanup
);