1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 ******************************************************************************
6 * Copyright (C) 2009-2015, International Business Machines
7 * Corporation and others. All Rights Reserved.
9 ******************************************************************************
11 * FILE NAME : icuplug.c
13 * Date Name Description
15 ******************************************************************************
18 #include "unicode/icuplug.h"
21 #if UCONFIG_ENABLE_PLUGINS
24 #include "icuplugimp.h"
30 #ifdef __MVS__ /* defined by z/OS compiler */
32 #include <cics.h> /* 12 Nov 2011 JAM iscics() function */
44 #define DBG(x) fprintf(stderr, "%s:%d: ",__FILE__,__LINE__); fprintf x
48 * Internal structure of an ICU plugin.
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 */
69 #define UPLUG_LIBRARY_INITIAL_COUNT 8
70 #define UPLUG_PLUGIN_INITIAL_COUNT 12
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
80 static int32_t uplug_removeEntryAt(void *list
, int32_t listSize
, int32_t memberSize
, int32_t itemToRemove
) {
81 uint8_t *bytePtr
= (uint8_t *)list
;
83 /* get rid of some bad cases first */
88 /* is there anything to move? */
89 if(listSize
> itemToRemove
+1) {
90 memmove(bytePtr
+(itemToRemove
*memberSize
), bytePtr
+((itemToRemove
+1)*memberSize
), memberSize
);
101 * Library management. Internal.
107 * Library management. Internal.
110 typedef struct UPlugLibrary
{
111 void *lib
; /**< library ptr */
112 char name
[UPLUG_NAME_MAX
]; /**< library name */
113 uint32_t ref
; /**< reference count */
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
;
122 * Search for a library. Doesn't lock
123 * @param libName libname to search for
124 * @return the library's struct
126 static int32_t searchForLibraryName(const char *libName
) {
129 for(i
=0;i
<libraryCount
;i
++) {
130 if(!uprv_strcmp(libName
, libraryList
[i
].name
)) {
137 static int32_t searchForLibrary(void *lib
) {
140 for(i
=0;i
<libraryCount
;i
++) {
141 if(lib
==libraryList
[i
].lib
) {
148 U_INTERNAL
char * U_EXPORT2
149 uplug_findLibrary(void *lib
, UErrorCode
*status
) {
152 if(U_FAILURE(*status
)) {
155 libEnt
= searchForLibrary(lib
);
157 ret
= libraryList
[libEnt
].name
;
159 *status
= U_MISSING_RESOURCE_ERROR
;
164 U_INTERNAL
void * U_EXPORT2
165 uplug_openLibrary(const char *libName
, UErrorCode
*status
) {
166 int32_t libEntry
= -1;
169 if(U_FAILURE(*status
)) return NULL
;
171 libEntry
= searchForLibraryName(libName
);
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
;
178 DBG((stderr
, "uplug_openLibrary() - out of library slots (max %d)\n", libraryMax
));
182 /* Some operating systems don't want
183 DL operations from multiple threads. */
184 libraryList
[libEntry
].lib
= uprv_dl_open(libName
, status
);
186 DBG((stderr
, "uplug_openLibrary(%s,%s) libEntry %d, lib %p\n", libName
, u_errorName(*status
), libEntry
, lib
));
189 if(libraryList
[libEntry
].lib
== NULL
|| U_FAILURE(*status
)) {
191 libraryList
[libEntry
].lib
= NULL
; /* failure with open */
192 libraryList
[libEntry
].name
[0] = 0;
194 DBG((stderr
, "uplug_openLibrary(%s,%s) libEntry %d, lib %p\n", libName
, u_errorName(*status
), libEntry
, lib
));
196 /* no need to free - just won't increase the count. */
198 } else { /* is it still there? */
200 uprv_strncpy(libraryList
[libEntry
].name
,libName
,UPLUG_NAME_MAX
);
201 libraryList
[libEntry
].ref
=1;
202 lib
= libraryList
[libEntry
].lib
;
206 lib
= libraryList
[libEntry
].lib
;
207 libraryList
[libEntry
].ref
++;
212 U_INTERNAL
void U_EXPORT2
213 uplug_closeLibrary(void *lib
, UErrorCode
*status
) {
217 DBG((stderr
, "uplug_closeLibrary(%p,%s) list %p\n", lib
, u_errorName(*status
), (void*)libraryList
));
219 if(U_FAILURE(*status
)) return;
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
);
230 *status
= U_INTERNAL_PROGRAM_ERROR
; /* could not find the entry! */
235 static UPlugData pluginList
[UPLUG_PLUGIN_INITIAL_COUNT
];
236 static int32_t pluginCount
= 0;
241 static int32_t uplug_pluginNumber(UPlugData
* d
) {
242 UPlugData
*pastPlug
= &pluginList
[pluginCount
];
245 } else if(d
>=pastPlug
) {
248 return (d
-pluginList
)/sizeof(pluginList
[0]);
253 U_CAPI UPlugData
* U_EXPORT2
254 uplug_nextPlug(UPlugData
*prior
) {
258 UPlugData
*nextPlug
= &prior
[1];
259 UPlugData
*pastPlug
= &pluginList
[pluginCount
];
261 if(nextPlug
>=pastPlug
) {
272 * Call the plugin with some params
274 static void uplug_callPlug(UPlugData
*plug
, UPlugReason reason
, UErrorCode
*status
) {
275 UPlugTokenReturn token
;
276 if(plug
==NULL
||U_FAILURE(*status
)) {
279 token
= (*(plug
->entrypoint
))(plug
, reason
, status
);
280 if(token
!=UPLUG_TOKEN
) {
281 *status
= U_INTERNAL_PROGRAM_ERROR
;
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
;
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
);
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
;
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
;
310 plug
->pluginStatus
= U_INTERNAL_PROGRAM_ERROR
;
311 plug
->awaitingLoad
= FALSE
;
316 static void uplug_loadPlug(UPlugData
*plug
, UErrorCode
*status
) {
317 if(U_FAILURE(*status
)) {
320 if(!plug
->awaitingLoad
|| (plug
->level
< UPLUG_LEVEL_LOW
) ) { /* shouldn't happen. Plugin hasn'tbeen loaded yet.*/
321 *status
= U_INTERNAL_PROGRAM_ERROR
;
324 uplug_callPlug(plug
, UPLUG_REASON_LOAD
, status
);
325 plug
->awaitingLoad
= FALSE
;
326 if(!U_SUCCESS(*status
)) {
327 plug
->pluginStatus
= U_INTERNAL_PROGRAM_ERROR
;
331 static UPlugData
*uplug_allocateEmptyPlug(UErrorCode
*status
)
333 UPlugData
*plug
= NULL
;
335 if(U_FAILURE(*status
)) {
339 if(pluginCount
== UPLUG_PLUGIN_INITIAL_COUNT
) {
340 *status
= U_MEMORY_ALLOCATION_ERROR
;
344 plug
= &pluginList
[pluginCount
++];
346 plug
->token
= UPLUG_TOKEN
;
347 plug
->structSize
= sizeof(UPlugData
);
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;
357 plug
->entrypoint
=NULL
;
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
)) {
371 uprv_strncpy(plug
->config
, config
, UPLUG_NAME_MAX
);
377 uprv_strncpy(plug
->sym
, symName
, UPLUG_NAME_MAX
);
382 plug
->entrypoint
= entrypoint
;
384 uplug_queryPlug(plug
, status
);
389 static void uplug_deallocatePlug(UPlugData
*plug
, UErrorCode
*status
) {
390 UErrorCode subStatus
= U_ZERO_ERROR
;
391 if(!plug
->dontUnload
) {
393 uplug_closeLibrary(plug
->lib
, &subStatus
);
397 if(U_SUCCESS(*status
) && U_FAILURE(subStatus
)) {
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
));
405 /* not ok- leave as a message. */
406 plug
->awaitingLoad
=FALSE
;
408 plug
->dontUnload
=TRUE
;
412 static void uplug_doUnloadPlug(UPlugData
*plugToRemove
, UErrorCode
*status
) {
413 if(plugToRemove
!= NULL
) {
414 uplug_unloadPlug(plugToRemove
, status
);
415 uplug_deallocatePlug(plugToRemove
, status
);
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;
425 for(cursor
=pluginList
;cursor
!=NULL
;) {
430 cursor
= uplug_nextPlug(cursor
);
434 uplug_doUnloadPlug(plugToRemove
, status
);
440 U_CAPI
void U_EXPORT2
441 uplug_setPlugNoUnload(UPlugData
*data
, UBool dontUnload
)
443 data
->dontUnload
= dontUnload
;
447 U_CAPI
void U_EXPORT2
448 uplug_setPlugLevel(UPlugData
*data
, UPlugLevel level
) {
453 U_CAPI UPlugLevel U_EXPORT2
454 uplug_getPlugLevel(UPlugData
*data
) {
459 U_CAPI
void U_EXPORT2
460 uplug_setPlugName(UPlugData
*data
, const char *name
) {
461 uprv_strncpy(data
->name
, name
, UPLUG_NAME_MAX
);
465 U_CAPI
const char * U_EXPORT2
466 uplug_getPlugName(UPlugData
*data
) {
471 U_CAPI
const char * U_EXPORT2
472 uplug_getSymbolName(UPlugData
*data
) {
476 U_CAPI
const char * U_EXPORT2
477 uplug_getLibraryName(UPlugData
*data
, UErrorCode
*status
) {
478 if(data
->libName
[0]) {
479 return data
->libName
;
482 return uplug_findLibrary(data
->lib
, status
);
489 U_CAPI
void * U_EXPORT2
490 uplug_getLibrary(UPlugData
*data
) {
494 U_CAPI
void * U_EXPORT2
495 uplug_getContext(UPlugData
*data
) {
496 return data
->context
;
500 U_CAPI
void U_EXPORT2
501 uplug_setContext(UPlugData
*data
, void *context
) {
502 data
->context
= context
;
505 U_CAPI
const char* U_EXPORT2
506 uplug_getConfiguration(UPlugData
*data
) {
510 U_INTERNAL UPlugData
* U_EXPORT2
511 uplug_getPlugInternal(int32_t n
) {
512 if(n
<0 || n
>= pluginCount
) {
515 return &(pluginList
[n
]);
520 U_CAPI UErrorCode U_EXPORT2
521 uplug_getPlugLoadStatus(UPlugData
*plug
) {
522 return plug
->pluginStatus
;
529 * Initialize a plugin fron an entrypoint and library - but don't load it.
531 static UPlugData
* uplug_initPlugFromEntrypointAndLibrary(UPlugEntrypoint
*entrypoint
, const char *config
, void *lib
, const char *sym
,
532 UErrorCode
*status
) {
533 UPlugData
*plug
= NULL
;
535 plug
= uplug_allocatePlug(entrypoint
, config
, lib
, sym
, status
);
537 if(U_SUCCESS(*status
)) {
540 uplug_deallocatePlug(plug
, status
);
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
);
555 uplug_initErrorPlug(const char *libName
, const char *sym
, const char *config
, const char *nameOrError
, UErrorCode loadStatus
, UErrorCode
*status
)
557 UPlugData
*plug
= uplug_allocateEmptyPlug(status
);
558 if(U_FAILURE(*status
)) return NULL
;
560 plug
->pluginStatus
= loadStatus
;
561 plug
->awaitingLoad
= FALSE
; /* Won't load. */
562 plug
->dontUnload
= TRUE
; /* cannot unload. */
565 uprv_strncpy(plug
->sym
, sym
, UPLUG_NAME_MAX
);
569 uprv_strncpy(plug
->libName
, libName
, UPLUG_NAME_MAX
);
572 if(nameOrError
!=NULL
) {
573 uprv_strncpy(plug
->name
, nameOrError
, UPLUG_NAME_MAX
);
577 uprv_strncpy(plug
->config
, config
, UPLUG_NAME_MAX
);
584 * Fetch a plugin from DLL, and then initialize it from a library- but don't load it.
587 uplug_initPlugFromLibrary(const char *libName
, const char *sym
, const char *config
, UErrorCode
*status
) {
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
);
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. */
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
);
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 */
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
);
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
);
629 static UPlugLevel gCurrentLevel
= UPLUG_LEVEL_LOW
;
631 U_CAPI UPlugLevel U_EXPORT2
uplug_getCurrentLevel() {
632 return gCurrentLevel
;
635 static UBool U_CALLCONV
uplug_cleanup(void)
639 UPlugData
*pluginToRemove
;
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
);
647 /* close other held libs? */
648 gCurrentLevel
= UPLUG_LEVEL_LOW
;
654 static void uplug_loadWaitingPlugs(UErrorCode
*status
) {
656 UPlugLevel currentLevel
= uplug_getCurrentLevel();
658 if(U_FAILURE(*status
)) {
662 DBG((stderr
, "uplug_loadWaitingPlugs() Level: %d\n", currentLevel
));
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
;
674 uplug_loadPlug(pluginToLoad
, &subStatus
);
675 newLevel
= uplug_getCurrentLevel();
676 if(newLevel
> currentLevel
) {
677 pluginToLoad
->pluginStatus
= U_PLUGIN_CHANGED_LEVEL_WARNING
;
678 currentLevel
= newLevel
;
681 pluginToLoad
->awaitingLoad
= FALSE
;
685 for(i
=0;i
<pluginCount
;i
++) {
686 UErrorCode subStatus
= U_ZERO_ERROR
;
687 UPlugData
*pluginToLoad
= &pluginList
[i
];
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
;
695 uplug_loadPlug(pluginToLoad
, &subStatus
);
697 pluginToLoad
->awaitingLoad
= FALSE
;
702 DBG((stderr
, " Done Loading Plugs. Level: %d\n", (int32_t)uplug_getCurrentLevel()));
706 /* Name of the plugin config file */
707 static char plugin_file
[2048] = "";
710 U_INTERNAL
const char* U_EXPORT2
711 uplug_getPluginFile() {
712 #if U_ENABLE_DYLOAD && !UCONFIG_NO_FILE_IO
720 // uplug_init() is called first thing from u_init().
722 U_CAPI
void U_EXPORT2
723 uplug_init(UErrorCode
*status
) {
725 (void)status
; /* unused */
726 #elif !UCONFIG_NO_FILE_IO
727 CharString plugin_dir
;
728 const char *env
= getenv("ICU_PLUGINS");
730 if(U_FAILURE(*status
)) return;
732 plugin_dir
.append(env
, -1, *status
);
734 if(U_FAILURE(*status
)) return;
736 #if defined(DEFAULT_ICU_PLUGINS)
737 if(plugin_dir
.isEmpty()) {
738 plugin_dir
.append(DEFAULT_ICU_PLUGINS
, -1, *status
);
743 DBG((stderr
, "ICU_PLUGINS=%s\n", plugin_dir
.data()));
746 if(!plugin_dir
.isEmpty()) {
749 CharString pluginFile
;
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. */
758 pluginFile
.append("//DD:ICUPLUG", -1, *status
); /* JAM 20 Oct 2011 */
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
);
768 DBG((stderr
, "status=%s\n", u_errorName(*status
)));
771 if(U_FAILURE(*status
)) {
774 if((size_t)pluginFile
.length() > (sizeof(plugin_file
)-1)) {
775 *status
= U_BUFFER_OVERFLOW_ERROR
;
777 DBG((stderr
, "status=%s\n", u_errorName(*status
)));
782 /* plugin_file is not used for processing - it is only used
783 so that uplug_getPluginFile() works (i.e. icuinfo)
785 uprv_strncpy(plugin_file
, pluginFile
.data(), sizeof(plugin_file
));
788 DBG((stderr
, "pluginfile= %s len %d/%d\n", plugin_file
, (int)strlen(plugin_file
), (int)sizeof(plugin_file
)));
792 if (iscics()) /* 12 Nov 2011 JAM */
799 f
= fopen(pluginFile
.data(), "r");
804 char *p
, *libName
=NULL
, *symName
=NULL
, *config
=NULL
;
808 while(fgets(linebuf
,1023,f
)) {
811 if(!*linebuf
|| *linebuf
=='#') {
815 while(*p
&&isspace((int)*p
))
817 if(!*p
|| *p
=='#') continue;
819 while(*p
&&!isspace((int)*p
)) {
822 if(!*p
|| *p
=='#') continue; /* no tab after libname */
823 *p
=0; /* end of libname */
825 while(*p
&&isspace((int)*p
)) {
828 if(!*p
||*p
=='#') continue; /* no symname after libname +tab */
830 while(*p
&&!isspace((int)*p
)) {
834 if(*p
) { /* has config */
837 while(*p
&&isspace((int)*p
)) {
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
))) {
853 /* OK, we're good. */
855 UErrorCode subStatus
= U_ZERO_ERROR
;
856 UPlugData
*plug
= uplug_initPlugFromLibrary(libName
, symName
, config
, &subStatus
);
857 if(U_FAILURE(subStatus
) && U_SUCCESS(*status
)) {
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
)));
864 (void)plug
; /* unused */
872 DBG((stderr
, "Can't open plugin file %s\n", plugin_file
));
876 uplug_loadWaitingPlugs(status
);
877 #endif /* U_ENABLE_DYLOAD */
878 gCurrentLevel
= UPLUG_LEVEL_HIGH
;
879 ucln_registerCleanup(UCLN_UPLUG
, uplug_cleanup
);