• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 ******************************************************************************
3 *
4 *   Copyright (C) 2009-2012, International Business Machines
5 *   Corporation and others.  All Rights Reserved.
6 *
7 ******************************************************************************
8 *
9 *  FILE NAME : icuplug.c
10 *
11 *   Date         Name        Description
12 *   10/29/2009   sl          New.
13 ******************************************************************************
14 */
15 
16 #include "unicode/icuplug.h"
17 #include "icuplugimp.h"
18 #include "cstring.h"
19 #include "cmemory.h"
20 #include "putilimp.h"
21 #include "ucln.h"
22 #include <stdio.h>
23 #ifdef __MVS__  /* defined by z/OS compiler */
24 #define _POSIX_SOURCE
25 #include <cics.h> /* 12 Nov 2011 JAM iscics() function */
26 #endif
27 
28 #ifndef UPLUG_TRACE
29 #define UPLUG_TRACE 0
30 #endif
31 
32 #if UPLUG_TRACE
33 #include <stdio.h>
34 #define DBG(x) fprintf(stderr, "%s:%d: ",__FILE__,__LINE__); fprintf x
35 #endif
36 
37 /**
38  * Internal structure of an ICU plugin.
39  */
40 
41 struct UPlugData {
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 */
55 };
56 
57 
58 
59 #define UPLUG_LIBRARY_INITIAL_COUNT 8
60 #define UPLUG_PLUGIN_INITIAL_COUNT 12
61 
62 /**
63  * Remove an item
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
69  */
uplug_removeEntryAt(void * list,int32_t listSize,int32_t memberSize,int32_t itemToRemove)70 static int32_t uplug_removeEntryAt(void *list, int32_t listSize, int32_t memberSize, int32_t itemToRemove) {
71   uint8_t *bytePtr = (uint8_t *)list;
72 
73   /* get rid of some bad cases first */
74   if(listSize<1) {
75     return listSize;
76   }
77 
78   /* is there anything to move? */
79   if(listSize > itemToRemove+1) {
80     memmove(bytePtr+(itemToRemove*memberSize), bytePtr+((itemToRemove+1)*memberSize), memberSize);
81   }
82 
83   return listSize-1;
84 }
85 
86 
87 
88 
89 #if U_ENABLE_DYLOAD
90 /**
91  * Library management. Internal.
92  * @internal
93  */
94 struct UPlugLibrary;
95 
96 /**
97  * Library management. Internal.
98  * @internal
99  */
100 typedef struct UPlugLibrary {
101   void *lib;                           /**< library ptr */
102   char name[UPLUG_NAME_MAX]; /**< library name */
103   uint32_t ref;                        /**< reference count */
104 } UPlugLibrary;
105 
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;
110 
111 /**
112  * Search for a library. Doesn't lock
113  * @param libName libname to search for
114  * @return the library's struct
115  */
searchForLibraryName(const char * libName)116 static int32_t searchForLibraryName(const char *libName) {
117   int32_t i;
118 
119   for(i=0;i<libraryCount;i++) {
120     if(!uprv_strcmp(libName, libraryList[i].name)) {
121       return i;
122     }
123   }
124   return -1;
125 }
126 
searchForLibrary(void * lib)127 static int32_t searchForLibrary(void *lib) {
128   int32_t i;
129 
130   for(i=0;i<libraryCount;i++) {
131     if(lib==libraryList[i].lib) {
132       return i;
133     }
134   }
135   return -1;
136 }
137 
138 U_INTERNAL char * U_EXPORT2
uplug_findLibrary(void * lib,UErrorCode * status)139 uplug_findLibrary(void *lib, UErrorCode *status) {
140   int32_t libEnt;
141   char *ret = NULL;
142   if(U_FAILURE(*status)) {
143     return NULL;
144   }
145   libEnt = searchForLibrary(lib);
146   if(libEnt!=-1) {
147     ret = libraryList[libEnt].name;
148   } else {
149     *status = U_MISSING_RESOURCE_ERROR;
150   }
151   return ret;
152 }
153 
154 U_INTERNAL void * U_EXPORT2
uplug_openLibrary(const char * libName,UErrorCode * status)155 uplug_openLibrary(const char *libName, UErrorCode *status) {
156   int32_t libEntry = -1;
157   void *lib = NULL;
158 
159   if(U_FAILURE(*status)) return NULL;
160 
161   libEntry = searchForLibraryName(libName);
162   if(libEntry == -1) {
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;
167 #if UPLUG_TRACE
168       DBG((stderr, "uplug_openLibrary() - out of library slots (max %d)\n", libraryMax));
169 #endif
170       return NULL;
171     }
172     /* Some operating systems don't want
173        DL operations from multiple threads. */
174     libraryList[libEntry].lib = uprv_dl_open(libName, status);
175 #if UPLUG_TRACE
176     DBG((stderr, "uplug_openLibrary(%s,%s) libEntry %d, lib %p\n", libName, u_errorName(*status), libEntry, lib));
177 #endif
178 
179     if(libraryList[libEntry].lib == NULL || U_FAILURE(*status)) {
180       /* cleanup. */
181       libraryList[libEntry].lib = NULL; /* failure with open */
182       libraryList[libEntry].name[0] = 0;
183 #if UPLUG_TRACE
184       DBG((stderr, "uplug_openLibrary(%s,%s) libEntry %d, lib %p\n", libName, u_errorName(*status), libEntry, lib));
185 #endif
186       /* no need to free - just won't increase the count. */
187       libraryCount--;
188     } else { /* is it still there? */
189       /* link it in */
190       uprv_strncpy(libraryList[libEntry].name,libName,UPLUG_NAME_MAX);
191       libraryList[libEntry].ref=1;
192       lib = libraryList[libEntry].lib;
193     }
194 
195   } else {
196     lib = libraryList[libEntry].lib;
197     libraryList[libEntry].ref++;
198   }
199   return lib;
200 }
201 
202 U_INTERNAL void U_EXPORT2
uplug_closeLibrary(void * lib,UErrorCode * status)203 uplug_closeLibrary(void *lib, UErrorCode *status) {
204   int32_t i;
205 
206 #if UPLUG_TRACE
207   DBG((stderr, "uplug_closeLibrary(%p,%s) list %p\n", lib, u_errorName(*status), (void*)libraryList));
208 #endif
209   if(U_FAILURE(*status)) return;
210 
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);
216       }
217       return;
218     }
219   }
220   *status = U_INTERNAL_PROGRAM_ERROR; /* could not find the entry! */
221 }
222 
223 #endif
224 
225 static UPlugData pluginList[UPLUG_PLUGIN_INITIAL_COUNT];
226 static int32_t pluginCount = 0;
227 
228 
229 
230 
uplug_pluginNumber(UPlugData * d)231 static int32_t uplug_pluginNumber(UPlugData* d) {
232   UPlugData *pastPlug = &pluginList[pluginCount];
233   if(d<=pluginList) {
234     return 0;
235   } else if(d>=pastPlug) {
236     return pluginCount;
237   } else {
238     return (d-pluginList)/sizeof(pluginList[0]);
239   }
240 }
241 
242 
243 U_CAPI UPlugData * U_EXPORT2
uplug_nextPlug(UPlugData * prior)244 uplug_nextPlug(UPlugData *prior) {
245   if(prior==NULL) {
246     return pluginList;
247   } else {
248     UPlugData *nextPlug = &prior[1];
249     UPlugData *pastPlug = &pluginList[pluginCount];
250 
251     if(nextPlug>=pastPlug) {
252       return NULL;
253     } else {
254       return nextPlug;
255     }
256   }
257 }
258 
259 
260 
261 /**
262  * Call the plugin with some params
263  */
uplug_callPlug(UPlugData * plug,UPlugReason reason,UErrorCode * status)264 static void uplug_callPlug(UPlugData *plug, UPlugReason reason, UErrorCode *status) {
265   UPlugTokenReturn token;
266   if(plug==NULL||U_FAILURE(*status)) {
267     return;
268   }
269   token = (*(plug->entrypoint))(plug, reason, status);
270   if(token!=UPLUG_TOKEN) {
271     *status = U_INTERNAL_PROGRAM_ERROR;
272   }
273 }
274 
275 
uplug_unloadPlug(UPlugData * plug,UErrorCode * status)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;
279     return;
280   }
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);
284   }
285 }
286 
uplug_queryPlug(UPlugData * plug,UErrorCode * 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;
290     return;
291   }
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;
298     }
299   } else {
300     plug->pluginStatus = U_INTERNAL_PROGRAM_ERROR;
301     plug->awaitingLoad = FALSE;
302   }
303 }
304 
305 
uplug_loadPlug(UPlugData * plug,UErrorCode * status)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;
309     return;
310   }
311   uplug_callPlug(plug, UPLUG_REASON_LOAD, status);
312   plug->awaitingLoad = FALSE;
313   if(!U_SUCCESS(*status)) {
314     plug->pluginStatus = U_INTERNAL_PROGRAM_ERROR;
315   }
316 }
317 
uplug_allocateEmptyPlug(UErrorCode * status)318 static UPlugData *uplug_allocateEmptyPlug(UErrorCode *status)
319 {
320   UPlugData *plug = NULL;
321 
322   if(U_FAILURE(*status)) {
323     return NULL;
324   }
325 
326   if(pluginCount == UPLUG_PLUGIN_INITIAL_COUNT) {
327     *status = U_MEMORY_ALLOCATION_ERROR;
328     return NULL;
329   }
330 
331   plug = &pluginList[pluginCount++];
332 
333   plug->token = UPLUG_TOKEN;
334   plug->structSize = sizeof(UPlugData);
335   plug->name[0]=0;
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;
341   plug->config[0]=0;
342   plug->sym[0]=0;
343   plug->lib=NULL;
344   plug->entrypoint=NULL;
345 
346 
347   return plug;
348 }
349 
uplug_allocatePlug(UPlugEntrypoint * entrypoint,const char * config,void * lib,const char * symName,UErrorCode * status)350 static UPlugData *uplug_allocatePlug(UPlugEntrypoint *entrypoint, const char *config, void *lib, const char *symName,
351                                      UErrorCode *status) {
352   UPlugData *plug;
353 
354   if(U_FAILURE(*status)) {
355     return NULL;
356   }
357 
358   plug = uplug_allocateEmptyPlug(status);
359   if(config!=NULL) {
360     uprv_strncpy(plug->config, config, UPLUG_NAME_MAX);
361   } else {
362     plug->config[0] = 0;
363   }
364 
365   if(symName!=NULL) {
366     uprv_strncpy(plug->sym, symName, UPLUG_NAME_MAX);
367   } else {
368     plug->sym[0] = 0;
369   }
370 
371   plug->entrypoint = entrypoint;
372   plug->lib = lib;
373   uplug_queryPlug(plug, status);
374 
375   return plug;
376 }
377 
uplug_deallocatePlug(UPlugData * plug,UErrorCode * status)378 static void uplug_deallocatePlug(UPlugData *plug, UErrorCode *status) {
379   UErrorCode subStatus = U_ZERO_ERROR;
380   if(!plug->dontUnload) {
381 #if U_ENABLE_DYLOAD
382     uplug_closeLibrary(plug->lib, &subStatus);
383 #endif
384   }
385   plug->lib = NULL;
386   if(U_SUCCESS(*status) && U_FAILURE(subStatus)) {
387     *status = subStatus;
388   }
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));
393   } else {
394     /* not ok- leave as a message. */
395     plug->awaitingLoad=FALSE;
396     plug->entrypoint=0;
397     plug->dontUnload=TRUE;
398   }
399 }
400 
uplug_doUnloadPlug(UPlugData * plugToRemove,UErrorCode * status)401 static void uplug_doUnloadPlug(UPlugData *plugToRemove, UErrorCode *status) {
402   if(plugToRemove != NULL) {
403     uplug_unloadPlug(plugToRemove, status);
404     uplug_deallocatePlug(plugToRemove, status);
405   }
406 }
407 
408 U_CAPI void U_EXPORT2
uplug_removePlug(UPlugData * plug,UErrorCode * status)409 uplug_removePlug(UPlugData *plug, UErrorCode *status)  {
410   UPlugData *cursor = NULL;
411   UPlugData *plugToRemove = NULL;
412   if(U_FAILURE(*status)) return;
413 
414   for(cursor=pluginList;cursor!=NULL;) {
415     if(cursor==plug) {
416       plugToRemove = plug;
417       cursor=NULL;
418     } else {
419       cursor = uplug_nextPlug(cursor);
420     }
421   }
422 
423   uplug_doUnloadPlug(plugToRemove, status);
424 }
425 
426 
427 
428 
429 U_CAPI void U_EXPORT2
uplug_setPlugNoUnload(UPlugData * data,UBool dontUnload)430 uplug_setPlugNoUnload(UPlugData *data, UBool dontUnload)
431 {
432   data->dontUnload = dontUnload;
433 }
434 
435 
436 U_CAPI void U_EXPORT2
uplug_setPlugLevel(UPlugData * data,UPlugLevel level)437 uplug_setPlugLevel(UPlugData *data, UPlugLevel level) {
438   data->level = level;
439 }
440 
441 
442 U_CAPI UPlugLevel U_EXPORT2
uplug_getPlugLevel(UPlugData * data)443 uplug_getPlugLevel(UPlugData *data) {
444   return data->level;
445 }
446 
447 
448 U_CAPI void U_EXPORT2
uplug_setPlugName(UPlugData * data,const char * name)449 uplug_setPlugName(UPlugData *data, const char *name) {
450   uprv_strncpy(data->name, name, UPLUG_NAME_MAX);
451 }
452 
453 
454 U_CAPI const char * U_EXPORT2
uplug_getPlugName(UPlugData * data)455 uplug_getPlugName(UPlugData *data) {
456   return data->name;
457 }
458 
459 
460 U_CAPI const char * U_EXPORT2
uplug_getSymbolName(UPlugData * data)461 uplug_getSymbolName(UPlugData *data) {
462   return data->sym;
463 }
464 
465 U_CAPI const char * U_EXPORT2
uplug_getLibraryName(UPlugData * data,UErrorCode * status)466 uplug_getLibraryName(UPlugData *data, UErrorCode *status) {
467   if(data->libName[0]) {
468     return data->libName;
469   } else {
470 #if U_ENABLE_DYLOAD
471     return uplug_findLibrary(data->lib, status);
472 #else
473     return NULL;
474 #endif
475   }
476 }
477 
478 U_CAPI void * U_EXPORT2
uplug_getLibrary(UPlugData * data)479 uplug_getLibrary(UPlugData *data) {
480   return data->lib;
481 }
482 
483 U_CAPI void * U_EXPORT2
uplug_getContext(UPlugData * data)484 uplug_getContext(UPlugData *data) {
485   return data->context;
486 }
487 
488 
489 U_CAPI void U_EXPORT2
uplug_setContext(UPlugData * data,void * context)490 uplug_setContext(UPlugData *data, void *context) {
491   data->context = context;
492 }
493 
494 U_CAPI const char* U_EXPORT2
uplug_getConfiguration(UPlugData * data)495 uplug_getConfiguration(UPlugData *data) {
496   return data->config;
497 }
498 
499 U_INTERNAL UPlugData* U_EXPORT2
uplug_getPlugInternal(int32_t n)500 uplug_getPlugInternal(int32_t n) {
501   if(n <0 || n >= pluginCount) {
502     return NULL;
503   } else {
504     return &(pluginList[n]);
505   }
506 }
507 
508 
509 U_CAPI UErrorCode U_EXPORT2
uplug_getPlugLoadStatus(UPlugData * plug)510 uplug_getPlugLoadStatus(UPlugData *plug) {
511   return plug->pluginStatus;
512 }
513 
514 
515 
516 
517 /**
518  * Initialize a plugin fron an entrypoint and library - but don't load it.
519  */
uplug_initPlugFromEntrypointAndLibrary(UPlugEntrypoint * entrypoint,const char * config,void * lib,const char * sym,UErrorCode * status)520 static UPlugData* uplug_initPlugFromEntrypointAndLibrary(UPlugEntrypoint *entrypoint, const char *config, void *lib, const char *sym,
521                                                          UErrorCode *status) {
522   UPlugData *plug = NULL;
523 
524   plug = uplug_allocatePlug(entrypoint, config, lib, sym, status);
525 
526   if(U_SUCCESS(*status)) {
527     return plug;
528   } else {
529     uplug_deallocatePlug(plug, status);
530     return NULL;
531   }
532 }
533 
534 U_CAPI UPlugData* U_EXPORT2
uplug_loadPlugFromEntrypoint(UPlugEntrypoint * entrypoint,const char * config,UErrorCode * status)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);
538   return plug;
539 }
540 
541 #if U_ENABLE_DYLOAD
542 
543 static UPlugData*
uplug_initErrorPlug(const char * libName,const char * sym,const char * config,const char * nameOrError,UErrorCode loadStatus,UErrorCode * status)544 uplug_initErrorPlug(const char *libName, const char *sym, const char *config, const char *nameOrError, UErrorCode loadStatus, UErrorCode *status)
545 {
546   UPlugData *plug = uplug_allocateEmptyPlug(status);
547   if(U_FAILURE(*status)) return NULL;
548 
549   plug->pluginStatus = loadStatus;
550   plug->awaitingLoad = FALSE; /* Won't load. */
551   plug->dontUnload = TRUE; /* cannot unload. */
552 
553   if(sym!=NULL) {
554     uprv_strncpy(plug->sym, sym, UPLUG_NAME_MAX);
555   }
556 
557   if(libName!=NULL) {
558     uprv_strncpy(plug->libName, libName, UPLUG_NAME_MAX);
559   }
560 
561   if(nameOrError!=NULL) {
562     uprv_strncpy(plug->name, nameOrError, UPLUG_NAME_MAX);
563   }
564 
565   if(config!=NULL) {
566     uprv_strncpy(plug->config, config, UPLUG_NAME_MAX);
567   }
568 
569   return plug;
570 }
571 
572 /**
573  * Fetch a plugin from DLL, and then initialize it from a library- but don't load it.
574  */
575 static UPlugData*
uplug_initPlugFromLibrary(const char * libName,const char * sym,const char * config,UErrorCode * status)576 uplug_initPlugFromLibrary(const char *libName, const char *sym, const char *config, UErrorCode *status) {
577   void *lib = NULL;
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);
584 
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. */
590       }
591     } else {
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);
594     }
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 */
598     }
599   } else {
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);
602   }
603   return plug;
604 }
605 
606 U_CAPI UPlugData* U_EXPORT2
uplug_loadPlugFromLibrary(const char * libName,const char * sym,const char * config,UErrorCode * status)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);
612 
613   return plug;
614 }
615 
616 #endif
617 
uplug_getCurrentLevel()618 U_CAPI UPlugLevel U_EXPORT2 uplug_getCurrentLevel() {
619   if(cmemory_inUse()) {
620     return UPLUG_LEVEL_HIGH;
621   } else {
622     return UPLUG_LEVEL_LOW;
623   }
624 }
625 
uplug_cleanup(void)626 static UBool U_CALLCONV uplug_cleanup(void)
627 {
628   int32_t i;
629 
630   UPlugData *pluginToRemove;
631   /* cleanup plugs */
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);
637   }
638   /* close other held libs? */
639   return TRUE;
640 }
641 
642 #if U_ENABLE_DYLOAD
643 
uplug_loadWaitingPlugs(UErrorCode * status)644 static void uplug_loadWaitingPlugs(UErrorCode *status) {
645   int32_t i;
646   UPlugLevel currentLevel = uplug_getCurrentLevel();
647 
648   if(U_FAILURE(*status)) {
649     return;
650   }
651 #if UPLUG_TRACE
652   DBG((stderr,  "uplug_loadWaitingPlugs() Level: %d\n", currentLevel));
653 #endif
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;
662         } else {
663           UPlugLevel newLevel;
664           uplug_loadPlug(pluginToLoad, &subStatus);
665           newLevel = uplug_getCurrentLevel();
666           if(newLevel > currentLevel) {
667             pluginToLoad->pluginStatus = U_PLUGIN_CHANGED_LEVEL_WARNING;
668             currentLevel = newLevel;
669           }
670         }
671         pluginToLoad->awaitingLoad = FALSE;
672       }
673     }
674   }
675   for(i=0;i<pluginCount;i++) {
676     UErrorCode subStatus = U_ZERO_ERROR;
677     UPlugData *pluginToLoad = &pluginList[i];
678 
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;
684       } else {
685         uplug_loadPlug(pluginToLoad, &subStatus);
686       }
687       pluginToLoad->awaitingLoad = FALSE;
688     }
689   }
690 
691 #if UPLUG_TRACE
692   DBG((stderr,  " Done Loading Plugs. Level: %d\n", (int32_t)uplug_getCurrentLevel()));
693 #endif
694 }
695 
696 /* Name of the plugin config file */
697 static char plugin_file[2048] = "";
698 #endif
699 
700 U_INTERNAL const char* U_EXPORT2
uplug_getPluginFile()701 uplug_getPluginFile() {
702 #if U_ENABLE_DYLOAD
703   return plugin_file;
704 #else
705   return NULL;
706 #endif
707 }
708 
709 
710 U_CAPI void U_EXPORT2
uplug_init(UErrorCode * status)711 uplug_init(UErrorCode *status) {
712 #if !U_ENABLE_DYLOAD
713   (void)status; /* unused */
714 #else
715   const char *plugin_dir;
716 
717   if(U_FAILURE(*status)) return;
718   plugin_dir = getenv("ICU_PLUGINS");
719 
720 #if defined(DEFAULT_ICU_PLUGINS)
721   if(plugin_dir == NULL || !*plugin_dir) {
722     plugin_dir = DEFAULT_ICU_PLUGINS;
723   }
724 #endif
725 
726 #if UPLUG_TRACE
727   DBG((stderr, "ICU_PLUGINS=%s\n", plugin_dir));
728 #endif
729 
730   if(plugin_dir != NULL && *plugin_dir) {
731     FILE *f;
732 
733 
734 #ifdef OS390BATCH
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.                          */
741 
742     uprv_strncpy(plugin_file,"//DD:ICUPLUG", 2047);        /* JAM 20 Oct 2011 */
743 #else
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);
749 #endif
750 
751 #if UPLUG_TRACE
752     DBG((stderr, "pluginfile= %s\n", plugin_file));
753 #endif
754 
755 #ifdef __MVS__
756     if (iscics()) /* 12 Nov 2011 JAM */
757     {
758         f = NULL;
759     }
760     else
761 #endif
762     {
763          f = fopen(plugin_file, "r");
764     }
765 
766     if(f != NULL) {
767       char linebuf[1024];
768       char *p, *libName=NULL, *symName=NULL, *config=NULL;
769       int32_t line = 0;
770 
771 
772       while(fgets(linebuf,1023,f)) {
773         line++;
774 
775         if(!*linebuf || *linebuf=='#') {
776           continue;
777         } else {
778           p = linebuf;
779           while(*p&&isspace((int)*p))
780             p++;
781           if(!*p || *p=='#') continue;
782           libName = p;
783           while(*p&&!isspace((int)*p)) {
784             p++;
785           }
786           if(!*p || *p=='#') continue; /* no tab after libname */
787           *p=0; /* end of libname */
788           p++;
789           while(*p&&isspace((int)*p)) {
790             p++;
791           }
792           if(!*p||*p=='#') continue; /* no symname after libname +tab */
793           symName = p;
794           while(*p&&!isspace((int)*p)) {
795             p++;
796           }
797 
798           if(*p) { /* has config */
799             *p=0;
800             ++p;
801             while(*p&&isspace((int)*p)) {
802               p++;
803             }
804             if(*p) {
805               config = p;
806             }
807           }
808 
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))) {
813               *p=0;
814             }
815           }
816 
817           /* OK, we're good. */
818           {
819             UErrorCode subStatus = U_ZERO_ERROR;
820             UPlugData *plug = uplug_initPlugFromLibrary(libName, symName, config, &subStatus);
821             if(U_FAILURE(subStatus) && U_SUCCESS(*status)) {
822               *status = subStatus;
823             }
824 #if UPLUG_TRACE
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)));
827 #else
828             (void)plug; /* unused */
829 #endif
830           }
831         }
832       }
833       fclose(f);
834     } else {
835 #if UPLUG_TRACE
836       DBG((stderr, "Can't open plugin file %s\n", plugin_file));
837 #endif
838     }
839   }
840   uplug_loadWaitingPlugs(status);
841 #endif /* U_ENABLE_DYLOAD */
842   ucln_registerCleanup(UCLN_UPLUG, uplug_cleanup);
843 }
844