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"
19 #if UCONFIG_ENABLE_PLUGINS
22 #include "icuplugimp.h"
28 #ifdef __MVS__ /* defined by z/OS compiler */
30 #include <cics.h> /* 12 Nov 2011 JAM iscics() function */
42 #define DBG(x) fprintf(stderr, "%s:%d: ",__FILE__,__LINE__); fprintf x
46 * Internal structure of an ICU plugin.
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 */
67 #define UPLUG_LIBRARY_INITIAL_COUNT 8
68 #define UPLUG_PLUGIN_INITIAL_COUNT 12
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
78 static int32_t uplug_removeEntryAt(void *list
, int32_t listSize
, int32_t memberSize
, int32_t itemToRemove
) {
79 uint8_t *bytePtr
= (uint8_t *)list
;
81 /* get rid of some bad cases first */
86 /* is there anything to move? */
87 if(listSize
> itemToRemove
+1) {
88 memmove(bytePtr
+(itemToRemove
*memberSize
), bytePtr
+((itemToRemove
+1)*memberSize
), memberSize
);
99 * Library management. Internal.
105 * Library management. Internal.
108 typedef struct UPlugLibrary
{
109 void *lib
; /**< library ptr */
110 char name
[UPLUG_NAME_MAX
]; /**< library name */
111 uint32_t ref
; /**< reference count */
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
;
120 * Search for a library. Doesn't lock
121 * @param libName libname to search for
122 * @return the library's struct
124 static int32_t searchForLibraryName(const char *libName
) {
127 for(i
=0;i
<libraryCount
;i
++) {
128 if(!uprv_strcmp(libName
, libraryList
[i
].name
)) {
135 static int32_t searchForLibrary(void *lib
) {
138 for(i
=0;i
<libraryCount
;i
++) {
139 if(lib
==libraryList
[i
].lib
) {
146 U_INTERNAL
char * U_EXPORT2
147 uplug_findLibrary(void *lib
, UErrorCode
*status
) {
150 if(U_FAILURE(*status
)) {
153 libEnt
= searchForLibrary(lib
);
155 ret
= libraryList
[libEnt
].name
;
157 *status
= U_MISSING_RESOURCE_ERROR
;
162 U_INTERNAL
void * U_EXPORT2
163 uplug_openLibrary(const char *libName
, UErrorCode
*status
) {
164 int32_t libEntry
= -1;
167 if(U_FAILURE(*status
)) return NULL
;
169 libEntry
= searchForLibraryName(libName
);
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
;
176 DBG((stderr
, "uplug_openLibrary() - out of library slots (max %d)\n", libraryMax
));
180 /* Some operating systems don't want
181 DL operations from multiple threads. */
182 libraryList
[libEntry
].lib
= uprv_dl_open(libName
, status
);
184 DBG((stderr
, "uplug_openLibrary(%s,%s) libEntry %d, lib %p\n", libName
, u_errorName(*status
), libEntry
, lib
));
187 if(libraryList
[libEntry
].lib
== NULL
|| U_FAILURE(*status
)) {
189 libraryList
[libEntry
].lib
= NULL
; /* failure with open */
190 libraryList
[libEntry
].name
[0] = 0;
192 DBG((stderr
, "uplug_openLibrary(%s,%s) libEntry %d, lib %p\n", libName
, u_errorName(*status
), libEntry
, lib
));
194 /* no need to free - just won't increase the count. */
196 } else { /* is it still there? */
198 uprv_strncpy(libraryList
[libEntry
].name
,libName
,UPLUG_NAME_MAX
);
199 libraryList
[libEntry
].ref
=1;
200 lib
= libraryList
[libEntry
].lib
;
204 lib
= libraryList
[libEntry
].lib
;
205 libraryList
[libEntry
].ref
++;
210 U_INTERNAL
void U_EXPORT2
211 uplug_closeLibrary(void *lib
, UErrorCode
*status
) {
215 DBG((stderr
, "uplug_closeLibrary(%p,%s) list %p\n", lib
, u_errorName(*status
), (void*)libraryList
));
217 if(U_FAILURE(*status
)) return;
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
);
228 *status
= U_INTERNAL_PROGRAM_ERROR
; /* could not find the entry! */
233 static UPlugData pluginList
[UPLUG_PLUGIN_INITIAL_COUNT
];
234 static int32_t pluginCount
= 0;
239 static int32_t uplug_pluginNumber(UPlugData
* d
) {
240 UPlugData
*pastPlug
= &pluginList
[pluginCount
];
243 } else if(d
>=pastPlug
) {
246 return (d
-pluginList
)/sizeof(pluginList
[0]);
251 U_CAPI UPlugData
* U_EXPORT2
252 uplug_nextPlug(UPlugData
*prior
) {
256 UPlugData
*nextPlug
= &prior
[1];
257 UPlugData
*pastPlug
= &pluginList
[pluginCount
];
259 if(nextPlug
>=pastPlug
) {
270 * Call the plugin with some params
272 static void uplug_callPlug(UPlugData
*plug
, UPlugReason reason
, UErrorCode
*status
) {
273 UPlugTokenReturn token
;
274 if(plug
==NULL
||U_FAILURE(*status
)) {
277 token
= (*(plug
->entrypoint
))(plug
, reason
, status
);
278 if(token
!=UPLUG_TOKEN
) {
279 *status
= U_INTERNAL_PROGRAM_ERROR
;
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
;
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
);
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
;
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
;
308 plug
->pluginStatus
= U_INTERNAL_PROGRAM_ERROR
;
309 plug
->awaitingLoad
= FALSE
;
314 static void uplug_loadPlug(UPlugData
*plug
, UErrorCode
*status
) {
315 if(U_FAILURE(*status
)) {
318 if(!plug
->awaitingLoad
|| (plug
->level
< UPLUG_LEVEL_LOW
) ) { /* shouldn't happen. Plugin hasn'tbeen loaded yet.*/
319 *status
= U_INTERNAL_PROGRAM_ERROR
;
322 uplug_callPlug(plug
, UPLUG_REASON_LOAD
, status
);
323 plug
->awaitingLoad
= FALSE
;
324 if(!U_SUCCESS(*status
)) {
325 plug
->pluginStatus
= U_INTERNAL_PROGRAM_ERROR
;
329 static UPlugData
*uplug_allocateEmptyPlug(UErrorCode
*status
)
331 UPlugData
*plug
= NULL
;
333 if(U_FAILURE(*status
)) {
337 if(pluginCount
== UPLUG_PLUGIN_INITIAL_COUNT
) {
338 *status
= U_MEMORY_ALLOCATION_ERROR
;
342 plug
= &pluginList
[pluginCount
++];
344 plug
->token
= UPLUG_TOKEN
;
345 plug
->structSize
= sizeof(UPlugData
);
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;
355 plug
->entrypoint
=NULL
;
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
)) {
369 uprv_strncpy(plug
->config
, config
, UPLUG_NAME_MAX
);
375 uprv_strncpy(plug
->sym
, symName
, UPLUG_NAME_MAX
);
380 plug
->entrypoint
= entrypoint
;
382 uplug_queryPlug(plug
, status
);
387 static void uplug_deallocatePlug(UPlugData
*plug
, UErrorCode
*status
) {
388 UErrorCode subStatus
= U_ZERO_ERROR
;
389 if(!plug
->dontUnload
) {
391 uplug_closeLibrary(plug
->lib
, &subStatus
);
395 if(U_SUCCESS(*status
) && U_FAILURE(subStatus
)) {
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
));
403 /* not ok- leave as a message. */
404 plug
->awaitingLoad
=FALSE
;
406 plug
->dontUnload
=TRUE
;
410 static void uplug_doUnloadPlug(UPlugData
*plugToRemove
, UErrorCode
*status
) {
411 if(plugToRemove
!= NULL
) {
412 uplug_unloadPlug(plugToRemove
, status
);
413 uplug_deallocatePlug(plugToRemove
, status
);
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;
423 for(cursor
=pluginList
;cursor
!=NULL
;) {
428 cursor
= uplug_nextPlug(cursor
);
432 uplug_doUnloadPlug(plugToRemove
, status
);
438 U_CAPI
void U_EXPORT2
439 uplug_setPlugNoUnload(UPlugData
*data
, UBool dontUnload
)
441 data
->dontUnload
= dontUnload
;
445 U_CAPI
void U_EXPORT2
446 uplug_setPlugLevel(UPlugData
*data
, UPlugLevel level
) {
451 U_CAPI UPlugLevel U_EXPORT2
452 uplug_getPlugLevel(UPlugData
*data
) {
457 U_CAPI
void U_EXPORT2
458 uplug_setPlugName(UPlugData
*data
, const char *name
) {
459 uprv_strncpy(data
->name
, name
, UPLUG_NAME_MAX
);
463 U_CAPI
const char * U_EXPORT2
464 uplug_getPlugName(UPlugData
*data
) {
469 U_CAPI
const char * U_EXPORT2
470 uplug_getSymbolName(UPlugData
*data
) {
474 U_CAPI
const char * U_EXPORT2
475 uplug_getLibraryName(UPlugData
*data
, UErrorCode
*status
) {
476 if(data
->libName
[0]) {
477 return data
->libName
;
480 return uplug_findLibrary(data
->lib
, status
);
487 U_CAPI
void * U_EXPORT2
488 uplug_getLibrary(UPlugData
*data
) {
492 U_CAPI
void * U_EXPORT2
493 uplug_getContext(UPlugData
*data
) {
494 return data
->context
;
498 U_CAPI
void U_EXPORT2
499 uplug_setContext(UPlugData
*data
, void *context
) {
500 data
->context
= context
;
503 U_CAPI
const char* U_EXPORT2
504 uplug_getConfiguration(UPlugData
*data
) {
508 U_INTERNAL UPlugData
* U_EXPORT2
509 uplug_getPlugInternal(int32_t n
) {
510 if(n
<0 || n
>= pluginCount
) {
513 return &(pluginList
[n
]);
518 U_CAPI UErrorCode U_EXPORT2
519 uplug_getPlugLoadStatus(UPlugData
*plug
) {
520 return plug
->pluginStatus
;
527 * Initialize a plugin fron an entrypoint and library - but don't load it.
529 static UPlugData
* uplug_initPlugFromEntrypointAndLibrary(UPlugEntrypoint
*entrypoint
, const char *config
, void *lib
, const char *sym
,
530 UErrorCode
*status
) {
531 UPlugData
*plug
= NULL
;
533 plug
= uplug_allocatePlug(entrypoint
, config
, lib
, sym
, status
);
535 if(U_SUCCESS(*status
)) {
538 uplug_deallocatePlug(plug
, status
);
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
);
553 uplug_initErrorPlug(const char *libName
, const char *sym
, const char *config
, const char *nameOrError
, UErrorCode loadStatus
, UErrorCode
*status
)
555 UPlugData
*plug
= uplug_allocateEmptyPlug(status
);
556 if(U_FAILURE(*status
)) return NULL
;
558 plug
->pluginStatus
= loadStatus
;
559 plug
->awaitingLoad
= FALSE
; /* Won't load. */
560 plug
->dontUnload
= TRUE
; /* cannot unload. */
563 uprv_strncpy(plug
->sym
, sym
, UPLUG_NAME_MAX
);
567 uprv_strncpy(plug
->libName
, libName
, UPLUG_NAME_MAX
);
570 if(nameOrError
!=NULL
) {
571 uprv_strncpy(plug
->name
, nameOrError
, UPLUG_NAME_MAX
);
575 uprv_strncpy(plug
->config
, config
, UPLUG_NAME_MAX
);
582 * Fetch a plugin from DLL, and then initialize it from a library- but don't load it.
585 uplug_initPlugFromLibrary(const char *libName
, const char *sym
, const char *config
, UErrorCode
*status
) {
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
);
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. */
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
);
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 */
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
);
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
);
627 static UPlugLevel gCurrentLevel
= UPLUG_LEVEL_LOW
;
629 U_CAPI UPlugLevel U_EXPORT2
uplug_getCurrentLevel() {
630 return gCurrentLevel
;
633 static UBool U_CALLCONV
uplug_cleanup(void)
637 UPlugData
*pluginToRemove
;
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
);
645 /* close other held libs? */
646 gCurrentLevel
= UPLUG_LEVEL_LOW
;
652 static void uplug_loadWaitingPlugs(UErrorCode
*status
) {
654 UPlugLevel currentLevel
= uplug_getCurrentLevel();
656 if(U_FAILURE(*status
)) {
660 DBG((stderr
, "uplug_loadWaitingPlugs() Level: %d\n", currentLevel
));
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
;
672 uplug_loadPlug(pluginToLoad
, &subStatus
);
673 newLevel
= uplug_getCurrentLevel();
674 if(newLevel
> currentLevel
) {
675 pluginToLoad
->pluginStatus
= U_PLUGIN_CHANGED_LEVEL_WARNING
;
676 currentLevel
= newLevel
;
679 pluginToLoad
->awaitingLoad
= FALSE
;
683 for(i
=0;i
<pluginCount
;i
++) {
684 UErrorCode subStatus
= U_ZERO_ERROR
;
685 UPlugData
*pluginToLoad
= &pluginList
[i
];
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
;
693 uplug_loadPlug(pluginToLoad
, &subStatus
);
695 pluginToLoad
->awaitingLoad
= FALSE
;
700 DBG((stderr
, " Done Loading Plugs. Level: %d\n", (int32_t)uplug_getCurrentLevel()));
704 /* Name of the plugin config file */
705 static char plugin_file
[2048] = "";
708 U_INTERNAL
const char* U_EXPORT2
709 uplug_getPluginFile() {
710 #if U_ENABLE_DYLOAD && !UCONFIG_NO_FILE_IO
718 // uplug_init() is called first thing from u_init().
720 U_CAPI
void U_EXPORT2
721 uplug_init(UErrorCode
*status
) {
723 (void)status
; /* unused */
724 #elif !UCONFIG_NO_FILE_IO
725 CharString plugin_dir
;
726 const char *env
= getenv("ICU_PLUGINS");
728 if(U_FAILURE(*status
)) return;
730 plugin_dir
.append(env
, -1, *status
);
732 if(U_FAILURE(*status
)) return;
734 #if defined(DEFAULT_ICU_PLUGINS)
735 if(plugin_dir
.isEmpty()) {
736 plugin_dir
.append(DEFAULT_ICU_PLUGINS
, -1, *status
);
741 DBG((stderr
, "ICU_PLUGINS=%s\n", plugin_dir
.data()));
744 if(!plugin_dir
.isEmpty()) {
747 CharString pluginFile
;
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. */
756 pluginFile
.append("//DD:ICUPLUG", -1, *status
); /* JAM 20 Oct 2011 */
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
);
766 DBG((stderr
, "status=%s\n", u_errorName(*status
)));
769 if(U_FAILURE(*status
)) {
772 if((size_t)pluginFile
.length() > (sizeof(plugin_file
)-1)) {
773 *status
= U_BUFFER_OVERFLOW_ERROR
;
775 DBG((stderr
, "status=%s\n", u_errorName(*status
)));
780 /* plugin_file is not used for processing - it is only used
781 so that uplug_getPluginFile() works (i.e. icuinfo)
783 uprv_strncpy(plugin_file
, pluginFile
.data(), sizeof(plugin_file
));
786 DBG((stderr
, "pluginfile= %s len %d/%d\n", plugin_file
, (int)strlen(plugin_file
), (int)sizeof(plugin_file
)));
790 if (iscics()) /* 12 Nov 2011 JAM */
797 f
= fopen(pluginFile
.data(), "r");
802 char *p
, *libName
=NULL
, *symName
=NULL
, *config
=NULL
;
806 while(fgets(linebuf
,1023,f
)) {
809 if(!*linebuf
|| *linebuf
=='#') {
813 while(*p
&&isspace((int)*p
))
815 if(!*p
|| *p
=='#') continue;
817 while(*p
&&!isspace((int)*p
)) {
820 if(!*p
|| *p
=='#') continue; /* no tab after libname */
821 *p
=0; /* end of libname */
823 while(*p
&&isspace((int)*p
)) {
826 if(!*p
||*p
=='#') continue; /* no symname after libname +tab */
828 while(*p
&&!isspace((int)*p
)) {
832 if(*p
) { /* has config */
835 while(*p
&&isspace((int)*p
)) {
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
))) {
851 /* OK, we're good. */
853 UErrorCode subStatus
= U_ZERO_ERROR
;
854 UPlugData
*plug
= uplug_initPlugFromLibrary(libName
, symName
, config
, &subStatus
);
855 if(U_FAILURE(subStatus
) && U_SUCCESS(*status
)) {
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
)));
862 (void)plug
; /* unused */
870 DBG((stderr
, "Can't open plugin file %s\n", plugin_file
));
874 uplug_loadWaitingPlugs(status
);
875 #endif /* U_ENABLE_DYLOAD */
876 gCurrentLevel
= UPLUG_LEVEL_HIGH
;
877 ucln_registerCleanup(UCLN_UPLUG
, uplug_cleanup
);