2 ******************************************************************************
4 * Copyright (C) 2009-2012, 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 */
34 #define DBG(x) fprintf(stderr, "%s:%d: ",__FILE__,__LINE__); fprintf x
38 * Internal structure of an ICU plugin.
42 UPlugEntrypoint
*entrypoint
; /**< plugin entrypoint */
43 uint32_t structSize
; /**< initialized to the size of this structure */
44 uint32_t token
; /**< must be U_PLUG_TOKEN */
45 void *lib
; /**< plugin library, or NULL */
46 char libName
[UPLUG_NAME_MAX
]; /**< library name */
47 char sym
[UPLUG_NAME_MAX
]; /**< plugin symbol, or NULL */
48 char config
[UPLUG_NAME_MAX
]; /**< configuration data */
49 void *context
; /**< user context data */
50 char name
[UPLUG_NAME_MAX
]; /**< name of plugin */
51 UPlugLevel level
; /**< level of plugin */
52 UBool awaitingLoad
; /**< TRUE if the plugin is awaiting a load call */
53 UBool dontUnload
; /**< TRUE if plugin must stay resident (leak plugin and lib) */
54 UErrorCode pluginStatus
; /**< status code of plugin */
59 #define UPLUG_LIBRARY_INITIAL_COUNT 8
60 #define UPLUG_PLUGIN_INITIAL_COUNT 12
64 * @param list the full list
65 * @param listSize the number of entries in the list
66 * @param memberSize the size of one member
67 * @param itemToRemove the item number of the member
68 * @return the new listsize
70 static int32_t uplug_removeEntryAt(void *list
, int32_t listSize
, int32_t memberSize
, int32_t itemToRemove
) {
71 uint8_t *bytePtr
= (uint8_t *)list
;
73 /* get rid of some bad cases first */
78 /* is there anything to move? */
79 if(listSize
> itemToRemove
+1) {
80 memmove(bytePtr
+(itemToRemove
*memberSize
), bytePtr
+((itemToRemove
+1)*memberSize
), memberSize
);
91 * Library management. Internal.
97 * Library management. Internal.
100 typedef struct UPlugLibrary
{
101 void *lib
; /**< library ptr */
102 char name
[UPLUG_NAME_MAX
]; /**< library name */
103 uint32_t ref
; /**< reference count */
106 static UPlugLibrary staticLibraryList
[UPLUG_LIBRARY_INITIAL_COUNT
];
107 static UPlugLibrary
* libraryList
= staticLibraryList
;
108 static int32_t libraryCount
= 0;
109 static int32_t libraryMax
= UPLUG_LIBRARY_INITIAL_COUNT
;
112 * Search for a library. Doesn't lock
113 * @param libName libname to search for
114 * @return the library's struct
116 static int32_t searchForLibraryName(const char *libName
) {
119 for(i
=0;i
<libraryCount
;i
++) {
120 if(!uprv_strcmp(libName
, libraryList
[i
].name
)) {
127 static int32_t searchForLibrary(void *lib
) {
130 for(i
=0;i
<libraryCount
;i
++) {
131 if(lib
==libraryList
[i
].lib
) {
138 U_INTERNAL
char * U_EXPORT2
139 uplug_findLibrary(void *lib
, UErrorCode
*status
) {
142 if(U_FAILURE(*status
)) {
145 libEnt
= searchForLibrary(lib
);
147 ret
= libraryList
[libEnt
].name
;
149 *status
= U_MISSING_RESOURCE_ERROR
;
154 U_INTERNAL
void * U_EXPORT2
155 uplug_openLibrary(const char *libName
, UErrorCode
*status
) {
156 int32_t libEntry
= -1;
159 if(U_FAILURE(*status
)) return NULL
;
161 libEntry
= searchForLibraryName(libName
);
163 libEntry
= libraryCount
++;
164 if(libraryCount
>= libraryMax
) {
165 /* Ran out of library slots. Statically allocated because we can't depend on allocating memory.. */
166 *status
= U_MEMORY_ALLOCATION_ERROR
;
168 DBG((stderr
, "uplug_openLibrary() - out of library slots (max %d)\n", libraryMax
));
172 /* Some operating systems don't want
173 DL operations from multiple threads. */
174 libraryList
[libEntry
].lib
= uprv_dl_open(libName
, status
);
176 DBG((stderr
, "uplug_openLibrary(%s,%s) libEntry %d, lib %p\n", libName
, u_errorName(*status
), libEntry
, lib
));
179 if(libraryList
[libEntry
].lib
== NULL
|| U_FAILURE(*status
)) {
181 libraryList
[libEntry
].lib
= NULL
; /* failure with open */
182 libraryList
[libEntry
].name
[0] = 0;
184 DBG((stderr
, "uplug_openLibrary(%s,%s) libEntry %d, lib %p\n", libName
, u_errorName(*status
), libEntry
, lib
));
186 /* no need to free - just won't increase the count. */
188 } else { /* is it still there? */
190 uprv_strncpy(libraryList
[libEntry
].name
,libName
,UPLUG_NAME_MAX
);
191 libraryList
[libEntry
].ref
=1;
192 lib
= libraryList
[libEntry
].lib
;
196 lib
= libraryList
[libEntry
].lib
;
197 libraryList
[libEntry
].ref
++;
202 U_INTERNAL
void U_EXPORT2
203 uplug_closeLibrary(void *lib
, UErrorCode
*status
) {
207 DBG((stderr
, "uplug_closeLibrary(%p,%s) list %p\n", lib
, u_errorName(*status
), (void*)libraryList
));
209 if(U_FAILURE(*status
)) return;
211 for(i
=0;i
<libraryCount
;i
++) {
212 if(lib
==libraryList
[i
].lib
) {
213 if(--(libraryList
[i
].ref
) == 0) {
214 uprv_dl_close(libraryList
[i
].lib
, status
);
215 libraryCount
= uplug_removeEntryAt(libraryList
, libraryCount
, sizeof(*libraryList
), i
);
220 *status
= U_INTERNAL_PROGRAM_ERROR
; /* could not find the entry! */
225 static UPlugData pluginList
[UPLUG_PLUGIN_INITIAL_COUNT
];
226 static int32_t pluginCount
= 0;
231 static int32_t uplug_pluginNumber(UPlugData
* d
) {
232 UPlugData
*pastPlug
= &pluginList
[pluginCount
];
235 } else if(d
>=pastPlug
) {
238 return (d
-pluginList
)/sizeof(pluginList
[0]);
243 U_CAPI UPlugData
* U_EXPORT2
244 uplug_nextPlug(UPlugData
*prior
) {
248 UPlugData
*nextPlug
= &prior
[1];
249 UPlugData
*pastPlug
= &pluginList
[pluginCount
];
251 if(nextPlug
>=pastPlug
) {
262 * Call the plugin with some params
264 static void uplug_callPlug(UPlugData
*plug
, UPlugReason reason
, UErrorCode
*status
) {
265 UPlugTokenReturn token
;
266 if(plug
==NULL
||U_FAILURE(*status
)) {
269 token
= (*(plug
->entrypoint
))(plug
, reason
, status
);
270 if(token
!=UPLUG_TOKEN
) {
271 *status
= U_INTERNAL_PROGRAM_ERROR
;
276 static void uplug_unloadPlug(UPlugData
*plug
, UErrorCode
*status
) {
277 if(plug
->awaitingLoad
) { /* shouldn't happen. Plugin hasn'tbeen loaded yet.*/
278 *status
= U_INTERNAL_PROGRAM_ERROR
;
281 if(U_SUCCESS(plug
->pluginStatus
)) {
282 /* Don't unload a plug which has a failing load status - means it didn't actually load. */
283 uplug_callPlug(plug
, UPLUG_REASON_UNLOAD
, status
);
287 static void uplug_queryPlug(UPlugData
*plug
, UErrorCode
*status
) {
288 if(!plug
->awaitingLoad
|| !(plug
->level
== UPLUG_LEVEL_UNKNOWN
) ) { /* shouldn't happen. Plugin hasn'tbeen loaded yet.*/
289 *status
= U_INTERNAL_PROGRAM_ERROR
;
292 plug
->level
= UPLUG_LEVEL_INVALID
;
293 uplug_callPlug(plug
, UPLUG_REASON_QUERY
, status
);
294 if(U_SUCCESS(*status
)) {
295 if(plug
->level
== UPLUG_LEVEL_INVALID
) {
296 plug
->pluginStatus
= U_PLUGIN_DIDNT_SET_LEVEL
;
297 plug
->awaitingLoad
= FALSE
;
300 plug
->pluginStatus
= U_INTERNAL_PROGRAM_ERROR
;
301 plug
->awaitingLoad
= FALSE
;
306 static void uplug_loadPlug(UPlugData
*plug
, UErrorCode
*status
) {
307 if(!plug
->awaitingLoad
|| (plug
->level
< UPLUG_LEVEL_LOW
) ) { /* shouldn't happen. Plugin hasn'tbeen loaded yet.*/
308 *status
= U_INTERNAL_PROGRAM_ERROR
;
311 uplug_callPlug(plug
, UPLUG_REASON_LOAD
, status
);
312 plug
->awaitingLoad
= FALSE
;
313 if(!U_SUCCESS(*status
)) {
314 plug
->pluginStatus
= U_INTERNAL_PROGRAM_ERROR
;
318 static UPlugData
*uplug_allocateEmptyPlug(UErrorCode
*status
)
320 UPlugData
*plug
= NULL
;
322 if(U_FAILURE(*status
)) {
326 if(pluginCount
== UPLUG_PLUGIN_INITIAL_COUNT
) {
327 *status
= U_MEMORY_ALLOCATION_ERROR
;
331 plug
= &pluginList
[pluginCount
++];
333 plug
->token
= UPLUG_TOKEN
;
334 plug
->structSize
= sizeof(UPlugData
);
336 plug
->level
= UPLUG_LEVEL_UNKNOWN
; /* initialize to null state */
337 plug
->awaitingLoad
= TRUE
;
338 plug
->dontUnload
= FALSE
;
339 plug
->pluginStatus
= U_ZERO_ERROR
;
340 plug
->libName
[0] = 0;
344 plug
->entrypoint
=NULL
;
350 static UPlugData
*uplug_allocatePlug(UPlugEntrypoint
*entrypoint
, const char *config
, void *lib
, const char *symName
,
351 UErrorCode
*status
) {
354 if(U_FAILURE(*status
)) {
358 plug
= uplug_allocateEmptyPlug(status
);
360 uprv_strncpy(plug
->config
, config
, UPLUG_NAME_MAX
);
366 uprv_strncpy(plug
->sym
, symName
, UPLUG_NAME_MAX
);
371 plug
->entrypoint
= entrypoint
;
373 uplug_queryPlug(plug
, status
);
378 static void uplug_deallocatePlug(UPlugData
*plug
, UErrorCode
*status
) {
379 UErrorCode subStatus
= U_ZERO_ERROR
;
380 if(!plug
->dontUnload
) {
382 uplug_closeLibrary(plug
->lib
, &subStatus
);
386 if(U_SUCCESS(*status
) && U_FAILURE(subStatus
)) {
389 /* shift plugins up and decrement count. */
390 if(U_SUCCESS(*status
)) {
391 /* all ok- remove. */
392 pluginCount
= uplug_removeEntryAt(pluginList
, pluginCount
, sizeof(plug
[0]), uplug_pluginNumber(plug
));
394 /* not ok- leave as a message. */
395 plug
->awaitingLoad
=FALSE
;
397 plug
->dontUnload
=TRUE
;
401 static void uplug_doUnloadPlug(UPlugData
*plugToRemove
, UErrorCode
*status
) {
402 if(plugToRemove
!= NULL
) {
403 uplug_unloadPlug(plugToRemove
, status
);
404 uplug_deallocatePlug(plugToRemove
, status
);
408 U_CAPI
void U_EXPORT2
409 uplug_removePlug(UPlugData
*plug
, UErrorCode
*status
) {
410 UPlugData
*cursor
= NULL
;
411 UPlugData
*plugToRemove
= NULL
;
412 if(U_FAILURE(*status
)) return;
414 for(cursor
=pluginList
;cursor
!=NULL
;) {
419 cursor
= uplug_nextPlug(cursor
);
423 uplug_doUnloadPlug(plugToRemove
, status
);
429 U_CAPI
void U_EXPORT2
430 uplug_setPlugNoUnload(UPlugData
*data
, UBool dontUnload
)
432 data
->dontUnload
= dontUnload
;
436 U_CAPI
void U_EXPORT2
437 uplug_setPlugLevel(UPlugData
*data
, UPlugLevel level
) {
442 U_CAPI UPlugLevel U_EXPORT2
443 uplug_getPlugLevel(UPlugData
*data
) {
448 U_CAPI
void U_EXPORT2
449 uplug_setPlugName(UPlugData
*data
, const char *name
) {
450 uprv_strncpy(data
->name
, name
, UPLUG_NAME_MAX
);
454 U_CAPI
const char * U_EXPORT2
455 uplug_getPlugName(UPlugData
*data
) {
460 U_CAPI
const char * U_EXPORT2
461 uplug_getSymbolName(UPlugData
*data
) {
465 U_CAPI
const char * U_EXPORT2
466 uplug_getLibraryName(UPlugData
*data
, UErrorCode
*status
) {
467 if(data
->libName
[0]) {
468 return data
->libName
;
471 return uplug_findLibrary(data
->lib
, status
);
478 U_CAPI
void * U_EXPORT2
479 uplug_getLibrary(UPlugData
*data
) {
483 U_CAPI
void * U_EXPORT2
484 uplug_getContext(UPlugData
*data
) {
485 return data
->context
;
489 U_CAPI
void U_EXPORT2
490 uplug_setContext(UPlugData
*data
, void *context
) {
491 data
->context
= context
;
494 U_CAPI
const char* U_EXPORT2
495 uplug_getConfiguration(UPlugData
*data
) {
499 U_INTERNAL UPlugData
* U_EXPORT2
500 uplug_getPlugInternal(int32_t n
) {
501 if(n
<0 || n
>= pluginCount
) {
504 return &(pluginList
[n
]);
509 U_CAPI UErrorCode U_EXPORT2
510 uplug_getPlugLoadStatus(UPlugData
*plug
) {
511 return plug
->pluginStatus
;
518 * Initialize a plugin fron an entrypoint and library - but don't load it.
520 static UPlugData
* uplug_initPlugFromEntrypointAndLibrary(UPlugEntrypoint
*entrypoint
, const char *config
, void *lib
, const char *sym
,
521 UErrorCode
*status
) {
522 UPlugData
*plug
= NULL
;
524 plug
= uplug_allocatePlug(entrypoint
, config
, lib
, sym
, status
);
526 if(U_SUCCESS(*status
)) {
529 uplug_deallocatePlug(plug
, status
);
534 U_CAPI UPlugData
* U_EXPORT2
535 uplug_loadPlugFromEntrypoint(UPlugEntrypoint
*entrypoint
, const char *config
, UErrorCode
*status
) {
536 UPlugData
* plug
= uplug_initPlugFromEntrypointAndLibrary(entrypoint
, config
, NULL
, NULL
, status
);
537 uplug_loadPlug(plug
, status
);
544 uplug_initErrorPlug(const char *libName
, const char *sym
, const char *config
, const char *nameOrError
, UErrorCode loadStatus
, UErrorCode
*status
)
546 UPlugData
*plug
= uplug_allocateEmptyPlug(status
);
547 if(U_FAILURE(*status
)) return NULL
;
549 plug
->pluginStatus
= loadStatus
;
550 plug
->awaitingLoad
= FALSE
; /* Won't load. */
551 plug
->dontUnload
= TRUE
; /* cannot unload. */
554 uprv_strncpy(plug
->sym
, sym
, UPLUG_NAME_MAX
);
558 uprv_strncpy(plug
->libName
, libName
, UPLUG_NAME_MAX
);
561 if(nameOrError
!=NULL
) {
562 uprv_strncpy(plug
->name
, nameOrError
, UPLUG_NAME_MAX
);
566 uprv_strncpy(plug
->config
, config
, UPLUG_NAME_MAX
);
573 * Fetch a plugin from DLL, and then initialize it from a library- but don't load it.
576 uplug_initPlugFromLibrary(const char *libName
, const char *sym
, const char *config
, UErrorCode
*status
) {
578 UPlugData
*plug
= NULL
;
579 if(U_FAILURE(*status
)) { return NULL
; }
580 lib
= uplug_openLibrary(libName
, status
);
581 if(lib
!=NULL
&& U_SUCCESS(*status
)) {
582 UPlugEntrypoint
*entrypoint
= NULL
;
583 entrypoint
= (UPlugEntrypoint
*)uprv_dlsym_func(lib
, sym
, status
);
585 if(entrypoint
!=NULL
&&U_SUCCESS(*status
)) {
586 plug
= uplug_initPlugFromEntrypointAndLibrary(entrypoint
, config
, lib
, sym
, status
);
587 if(plug
!=NULL
&&U_SUCCESS(*status
)) {
588 plug
->lib
= lib
; /* plug takes ownership of library */
589 lib
= NULL
; /* library is now owned by plugin. */
592 UErrorCode subStatus
= U_ZERO_ERROR
;
593 plug
= uplug_initErrorPlug(libName
,sym
,config
,"ERROR: Could not load entrypoint",(lib
==NULL
)?U_MISSING_RESOURCE_ERROR
:*status
,&subStatus
);
595 if(lib
!=NULL
) { /* still need to close the lib */
596 UErrorCode subStatus
= U_ZERO_ERROR
;
597 uplug_closeLibrary(lib
, &subStatus
); /* don't care here */
600 UErrorCode subStatus
= U_ZERO_ERROR
;
601 plug
= uplug_initErrorPlug(libName
,sym
,config
,"ERROR: could not load library",(lib
==NULL
)?U_MISSING_RESOURCE_ERROR
:*status
,&subStatus
);
606 U_CAPI UPlugData
* U_EXPORT2
607 uplug_loadPlugFromLibrary(const char *libName
, const char *sym
, const char *config
, UErrorCode
*status
) {
608 UPlugData
*plug
= NULL
;
609 if(U_FAILURE(*status
)) { return NULL
; }
610 plug
= uplug_initPlugFromLibrary(libName
, sym
, config
, status
);
611 uplug_loadPlug(plug
, status
);
618 U_CAPI UPlugLevel U_EXPORT2
uplug_getCurrentLevel() {
619 if(cmemory_inUse()) {
620 return UPLUG_LEVEL_HIGH
;
622 return UPLUG_LEVEL_LOW
;
626 static UBool U_CALLCONV
uplug_cleanup(void)
630 UPlugData
*pluginToRemove
;
632 for(i
=0;i
<pluginCount
;i
++) {
633 UErrorCode subStatus
= U_ZERO_ERROR
;
634 pluginToRemove
= &pluginList
[i
];
635 /* unload and deallocate */
636 uplug_doUnloadPlug(pluginToRemove
, &subStatus
);
638 /* close other held libs? */
644 static void uplug_loadWaitingPlugs(UErrorCode
*status
) {
646 UPlugLevel currentLevel
= uplug_getCurrentLevel();
648 if(U_FAILURE(*status
)) {
652 DBG((stderr
, "uplug_loadWaitingPlugs() Level: %d\n", currentLevel
));
654 /* pass #1: low level plugs */
655 for(i
=0;i
<pluginCount
;i
++) {
656 UErrorCode subStatus
= U_ZERO_ERROR
;
657 UPlugData
*pluginToLoad
= &pluginList
[i
];
658 if(pluginToLoad
->awaitingLoad
) {
659 if(pluginToLoad
->level
== UPLUG_LEVEL_LOW
) {
660 if(currentLevel
> UPLUG_LEVEL_LOW
) {
661 pluginToLoad
->pluginStatus
= U_PLUGIN_TOO_HIGH
;
664 uplug_loadPlug(pluginToLoad
, &subStatus
);
665 newLevel
= uplug_getCurrentLevel();
666 if(newLevel
> currentLevel
) {
667 pluginToLoad
->pluginStatus
= U_PLUGIN_CHANGED_LEVEL_WARNING
;
668 currentLevel
= newLevel
;
671 pluginToLoad
->awaitingLoad
= FALSE
;
675 for(i
=0;i
<pluginCount
;i
++) {
676 UErrorCode subStatus
= U_ZERO_ERROR
;
677 UPlugData
*pluginToLoad
= &pluginList
[i
];
679 if(pluginToLoad
->awaitingLoad
) {
680 if(pluginToLoad
->level
== UPLUG_LEVEL_INVALID
) {
681 pluginToLoad
->pluginStatus
= U_PLUGIN_DIDNT_SET_LEVEL
;
682 } else if(pluginToLoad
->level
== UPLUG_LEVEL_UNKNOWN
) {
683 pluginToLoad
->pluginStatus
= U_INTERNAL_PROGRAM_ERROR
;
685 uplug_loadPlug(pluginToLoad
, &subStatus
);
687 pluginToLoad
->awaitingLoad
= FALSE
;
692 DBG((stderr
, " Done Loading Plugs. Level: %d\n", (int32_t)uplug_getCurrentLevel()));
696 /* Name of the plugin config file */
697 static char plugin_file
[2048] = "";
700 U_INTERNAL
const char* U_EXPORT2
701 uplug_getPluginFile() {
710 U_CAPI
void U_EXPORT2
711 uplug_init(UErrorCode
*status
) {
713 (void)status
; /* unused */
715 const char *plugin_dir
;
717 if(U_FAILURE(*status
)) return;
718 plugin_dir
= getenv("ICU_PLUGINS");
720 #if defined(DEFAULT_ICU_PLUGINS)
721 if(plugin_dir
== NULL
|| !*plugin_dir
) {
722 plugin_dir
= DEFAULT_ICU_PLUGINS
;
727 DBG((stderr
, "ICU_PLUGINS=%s\n", plugin_dir
));
730 if(plugin_dir
!= NULL
&& *plugin_dir
) {
735 /* There are potentially a lot of ways to implement a plugin directory on OS390/zOS */
736 /* Keeping in mind that unauthorized file access is logged, monitored, and enforced */
737 /* I've chosen to open a DDNAME if BATCH and leave it alone for (presumably) UNIX */
738 /* System Services. Alternative techniques might be allocating a member in */
739 /* SYS1.PARMLIB or setting an environment variable "ICU_PLUGIN_PATH" (?). The */
740 /* DDNAME can be connected to a file in the HFS if need be. */
742 uprv_strncpy(plugin_file
,"//DD:ICUPLUG", 2047); /* JAM 20 Oct 2011 */
744 uprv_strncpy(plugin_file
, plugin_dir
, 2047);
745 uprv_strncat(plugin_file
, U_FILE_SEP_STRING
,2047);
746 uprv_strncat(plugin_file
, "icuplugins",2047);
747 uprv_strncat(plugin_file
, U_ICU_VERSION_SHORT
,2047);
748 uprv_strncat(plugin_file
, ".txt" ,2047);
752 DBG((stderr
, "pluginfile= %s\n", plugin_file
));
756 if (iscics()) /* 12 Nov 2011 JAM */
763 f
= fopen(plugin_file
, "r");
768 char *p
, *libName
=NULL
, *symName
=NULL
, *config
=NULL
;
772 while(fgets(linebuf
,1023,f
)) {
775 if(!*linebuf
|| *linebuf
=='#') {
779 while(*p
&&isspace((int)*p
))
781 if(!*p
|| *p
=='#') continue;
783 while(*p
&&!isspace((int)*p
)) {
786 if(!*p
|| *p
=='#') continue; /* no tab after libname */
787 *p
=0; /* end of libname */
789 while(*p
&&isspace((int)*p
)) {
792 if(!*p
||*p
=='#') continue; /* no symname after libname +tab */
794 while(*p
&&!isspace((int)*p
)) {
798 if(*p
) { /* has config */
801 while(*p
&&isspace((int)*p
)) {
809 /* chop whitespace at the end of the config */
810 if(config
!=NULL
&&*config
!=0) {
811 p
= config
+strlen(config
);
812 while(p
>config
&&isspace((int)*(--p
))) {
817 /* OK, we're good. */
819 UErrorCode subStatus
= U_ZERO_ERROR
;
820 UPlugData
*plug
= uplug_initPlugFromLibrary(libName
, symName
, config
, &subStatus
);
821 if(U_FAILURE(subStatus
) && U_SUCCESS(*status
)) {
825 DBG((stderr
, "PLUGIN libName=[%s], sym=[%s], config=[%s]\n", libName
, symName
, config
));
826 DBG((stderr
, " -> %p, %s\n", (void*)plug
, u_errorName(subStatus
)));
828 (void)plug
; /* unused */
836 DBG((stderr
, "Can't open plugin file %s\n", plugin_file
));
840 uplug_loadWaitingPlugs(status
);
841 #endif /* U_ENABLE_DYLOAD */
842 ucln_registerCleanup(UCLN_UPLUG
, uplug_cleanup
);