• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 ******************************************************************************
3 *
4 *   Copyright (C) 2009-2011, 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 
24 #ifndef UPLUG_TRACE
25 #define UPLUG_TRACE 0
26 #endif
27 
28 #if UPLUG_TRACE
29 #include <stdio.h>
30 #define DBG(x) fprintf(stderr, "%s:%d: ",__FILE__,__LINE__); fprintf x
31 #endif
32 
33 /**
34  * Internal structure of an ICU plugin.
35  */
36 
37 struct UPlugData {
38   UPlugEntrypoint  *entrypoint; /**< plugin entrypoint */
39   uint32_t structSize;    /**< initialized to the size of this structure */
40   uint32_t token;         /**< must be U_PLUG_TOKEN */
41   void *lib;              /**< plugin library, or NULL */
42   char libName[UPLUG_NAME_MAX];   /**< library name */
43   char sym[UPLUG_NAME_MAX];        /**< plugin symbol, or NULL */
44   char config[UPLUG_NAME_MAX];     /**< configuration data */
45   void *context;          /**< user context data */
46   char name[UPLUG_NAME_MAX];   /**< name of plugin */
47   UPlugLevel  level; /**< level of plugin */
48   UBool   awaitingLoad; /**< TRUE if the plugin is awaiting a load call */
49   UBool   dontUnload; /**< TRUE if plugin must stay resident (leak plugin and lib) */
50   UErrorCode pluginStatus; /**< status code of plugin */
51 };
52 
53 
54 
55 #define UPLUG_LIBRARY_INITIAL_COUNT 8
56 #define UPLUG_PLUGIN_INITIAL_COUNT 12
57 
58 /**
59  * Remove an item
60  * @param list the full list
61  * @param listSize the number of entries in the list
62  * @param memberSize the size of one member
63  * @param itemToRemove the item number of the member
64  * @return the new listsize
65  */
uplug_removeEntryAt(void * list,int32_t listSize,int32_t memberSize,int32_t itemToRemove)66 static int32_t uplug_removeEntryAt(void *list, int32_t listSize, int32_t memberSize, int32_t itemToRemove) {
67   uint8_t *bytePtr = (uint8_t *)list;
68 
69   /* get rid of some bad cases first */
70   if(listSize<1) {
71     return listSize;
72   }
73 
74   /* is there anything to move? */
75   if(listSize > itemToRemove+1) {
76     memmove(bytePtr+(itemToRemove*memberSize), bytePtr+((itemToRemove+1)*memberSize), memberSize);
77   }
78 
79   return listSize-1;
80 }
81 
82 
83 
84 
85 #if U_ENABLE_DYLOAD
86 /**
87  * Library management. Internal.
88  * @internal
89  */
90 struct UPlugLibrary;
91 
92 /**
93  * Library management. Internal.
94  * @internal
95  */
96 typedef struct UPlugLibrary {
97   void *lib;                           /**< library ptr */
98   char name[UPLUG_NAME_MAX]; /**< library name */
99   uint32_t ref;                        /**< reference count */
100 } UPlugLibrary;
101 
102 static UPlugLibrary   staticLibraryList[UPLUG_LIBRARY_INITIAL_COUNT];
103 static UPlugLibrary * libraryList = staticLibraryList;
104 static int32_t libraryCount = 0;
105 static int32_t libraryMax = UPLUG_LIBRARY_INITIAL_COUNT;
106 
107 /**
108  * Search for a library. Doesn't lock
109  * @param libName libname to search for
110  * @return the library's struct
111  */
searchForLibraryName(const char * libName)112 static int32_t searchForLibraryName(const char *libName) {
113   int32_t i;
114 
115   for(i=0;i<libraryCount;i++) {
116     if(!uprv_strcmp(libName, libraryList[i].name)) {
117       return i;
118     }
119   }
120   return -1;
121 }
122 
searchForLibrary(void * lib)123 static int32_t searchForLibrary(void *lib) {
124   int32_t i;
125 
126   for(i=0;i<libraryCount;i++) {
127     if(lib==libraryList[i].lib) {
128       return i;
129     }
130   }
131   return -1;
132 }
133 
134 U_INTERNAL char * U_EXPORT2
uplug_findLibrary(void * lib,UErrorCode * status)135 uplug_findLibrary(void *lib, UErrorCode *status) {
136   int32_t libEnt;
137   char *ret = NULL;
138   if(U_FAILURE(*status)) {
139     return NULL;
140   }
141   libEnt = searchForLibrary(lib);
142   if(libEnt!=-1) {
143     ret = libraryList[libEnt].name;
144   } else {
145     *status = U_MISSING_RESOURCE_ERROR;
146   }
147   return ret;
148 }
149 
150 U_INTERNAL void * U_EXPORT2
uplug_openLibrary(const char * libName,UErrorCode * status)151 uplug_openLibrary(const char *libName, UErrorCode *status) {
152   int32_t libEntry = -1;
153   void *lib = NULL;
154 
155   if(U_FAILURE(*status)) return NULL;
156 
157   libEntry = searchForLibraryName(libName);
158   if(libEntry == -1) {
159     libEntry = libraryCount++;
160     if(libraryCount >= libraryMax) {
161       /* Ran out of library slots. Statically allocated because we can't depend on allocating memory.. */
162       *status = U_MEMORY_ALLOCATION_ERROR;
163 #if UPLUG_TRACE
164       DBG((stderr, "uplug_openLibrary() - out of library slots (max %d)\n", libraryMax));
165 #endif
166       return NULL;
167     }
168     /* Some operating systems don't want
169        DL operations from multiple threads. */
170     libraryList[libEntry].lib = uprv_dl_open(libName, status);
171 #if UPLUG_TRACE
172     DBG((stderr, "uplug_openLibrary(%s,%s) libEntry %d, lib %p\n", libName, u_errorName(*status), libEntry, lib));
173 #endif
174 
175     if(libraryList[libEntry].lib == NULL || U_FAILURE(*status)) {
176       /* cleanup. */
177       libraryList[libEntry].lib = NULL; /* failure with open */
178       libraryList[libEntry].name[0] = 0;
179 #if UPLUG_TRACE
180       DBG((stderr, "uplug_openLibrary(%s,%s) libEntry %d, lib %p\n", libName, u_errorName(*status), libEntry, lib));
181 #endif
182       /* no need to free - just won't increase the count. */
183       libraryCount--;
184     } else { /* is it still there? */
185       /* link it in */
186       uprv_strncpy(libraryList[libEntry].name,libName,UPLUG_NAME_MAX);
187       libraryList[libEntry].ref=1;
188       lib = libraryList[libEntry].lib;
189     }
190 
191   } else {
192     lib = libraryList[libEntry].lib;
193     libraryList[libEntry].ref++;
194   }
195   return lib;
196 }
197 
198 U_INTERNAL void U_EXPORT2
uplug_closeLibrary(void * lib,UErrorCode * status)199 uplug_closeLibrary(void *lib, UErrorCode *status) {
200   int32_t i;
201 
202 #if UPLUG_TRACE
203   DBG((stderr, "uplug_closeLibrary(%p,%s) list %p\n", lib, u_errorName(*status), (void*)libraryList));
204 #endif
205   if(U_FAILURE(*status)) return;
206 
207   for(i=0;i<libraryCount;i++) {
208     if(lib==libraryList[i].lib) {
209       if(--(libraryList[i].ref) == 0) {
210         uprv_dl_close(libraryList[i].lib, status);
211         libraryCount = uplug_removeEntryAt(libraryList, libraryCount, sizeof(*libraryList), i);
212       }
213       return;
214     }
215   }
216   *status = U_INTERNAL_PROGRAM_ERROR; /* could not find the entry! */
217 }
218 
219 #endif
220 
221 static UPlugData pluginList[UPLUG_PLUGIN_INITIAL_COUNT];
222 static int32_t pluginCount = 0;
223 
224 
225 
226 
uplug_pluginNumber(UPlugData * d)227 static int32_t uplug_pluginNumber(UPlugData* d) {
228   UPlugData *pastPlug = &pluginList[pluginCount];
229   if(d<=pluginList) {
230     return 0;
231   } else if(d>=pastPlug) {
232     return pluginCount;
233   } else {
234     return (d-pluginList)/sizeof(pluginList[0]);
235   }
236 }
237 
238 
239 U_CAPI UPlugData * U_EXPORT2
uplug_nextPlug(UPlugData * prior)240 uplug_nextPlug(UPlugData *prior) {
241   if(prior==NULL) {
242     return pluginList;
243   } else {
244     UPlugData *nextPlug = &prior[1];
245     UPlugData *pastPlug = &pluginList[pluginCount];
246 
247     if(nextPlug>=pastPlug) {
248       return NULL;
249     } else {
250       return nextPlug;
251     }
252   }
253 }
254 
255 
256 
257 /**
258  * Call the plugin with some params
259  */
uplug_callPlug(UPlugData * plug,UPlugReason reason,UErrorCode * status)260 static void uplug_callPlug(UPlugData *plug, UPlugReason reason, UErrorCode *status) {
261   UPlugTokenReturn token;
262   if(plug==NULL||U_FAILURE(*status)) {
263     return;
264   }
265   token = (*(plug->entrypoint))(plug, reason, status);
266   if(token!=UPLUG_TOKEN) {
267     *status = U_INTERNAL_PROGRAM_ERROR;
268   }
269 }
270 
271 
uplug_unloadPlug(UPlugData * plug,UErrorCode * status)272 static void uplug_unloadPlug(UPlugData *plug, UErrorCode *status) {
273   if(plug->awaitingLoad) {  /* shouldn't happen. Plugin hasn'tbeen loaded yet.*/
274     *status = U_INTERNAL_PROGRAM_ERROR;
275     return;
276   }
277   if(U_SUCCESS(plug->pluginStatus)) {
278     /* Don't unload a plug which has a failing load status - means it didn't actually load. */
279     uplug_callPlug(plug, UPLUG_REASON_UNLOAD, status);
280   }
281 }
282 
uplug_queryPlug(UPlugData * plug,UErrorCode * status)283 static void uplug_queryPlug(UPlugData *plug, UErrorCode *status) {
284   if(!plug->awaitingLoad || !(plug->level == UPLUG_LEVEL_UNKNOWN) ) {  /* shouldn't happen. Plugin hasn'tbeen loaded yet.*/
285     *status = U_INTERNAL_PROGRAM_ERROR;
286     return;
287   }
288   plug->level = UPLUG_LEVEL_INVALID;
289   uplug_callPlug(plug, UPLUG_REASON_QUERY, status);
290   if(U_SUCCESS(*status)) {
291     if(plug->level == UPLUG_LEVEL_INVALID) {
292       plug->pluginStatus = U_PLUGIN_DIDNT_SET_LEVEL;
293       plug->awaitingLoad = FALSE;
294     }
295   } else {
296     plug->pluginStatus = U_INTERNAL_PROGRAM_ERROR;
297     plug->awaitingLoad = FALSE;
298   }
299 }
300 
301 
uplug_loadPlug(UPlugData * plug,UErrorCode * status)302 static void uplug_loadPlug(UPlugData *plug, UErrorCode *status) {
303   if(!plug->awaitingLoad || (plug->level < UPLUG_LEVEL_LOW) ) {  /* shouldn't happen. Plugin hasn'tbeen loaded yet.*/
304     *status = U_INTERNAL_PROGRAM_ERROR;
305     return;
306   }
307   uplug_callPlug(plug, UPLUG_REASON_LOAD, status);
308   plug->awaitingLoad = FALSE;
309   if(!U_SUCCESS(*status)) {
310     plug->pluginStatus = U_INTERNAL_PROGRAM_ERROR;
311   }
312 }
313 
uplug_allocateEmptyPlug(UErrorCode * status)314 static UPlugData *uplug_allocateEmptyPlug(UErrorCode *status)
315 {
316   UPlugData *plug = NULL;
317 
318   if(U_FAILURE(*status)) {
319     return NULL;
320   }
321 
322   if(pluginCount == UPLUG_PLUGIN_INITIAL_COUNT) {
323     *status = U_MEMORY_ALLOCATION_ERROR;
324     return NULL;
325   }
326 
327   plug = &pluginList[pluginCount++];
328 
329   plug->token = UPLUG_TOKEN;
330   plug->structSize = sizeof(UPlugData);
331   plug->name[0]=0;
332   plug->level = UPLUG_LEVEL_UNKNOWN; /* initialize to null state */
333   plug->awaitingLoad = TRUE;
334   plug->dontUnload = FALSE;
335   plug->pluginStatus = U_ZERO_ERROR;
336   plug->libName[0] = 0;
337   plug->config[0]=0;
338   plug->sym[0]=0;
339   plug->lib=NULL;
340   plug->entrypoint=NULL;
341 
342 
343   return plug;
344 }
345 
uplug_allocatePlug(UPlugEntrypoint * entrypoint,const char * config,void * lib,const char * symName,UErrorCode * status)346 static UPlugData *uplug_allocatePlug(UPlugEntrypoint *entrypoint, const char *config, void *lib, const char *symName,
347                                      UErrorCode *status) {
348   UPlugData *plug;
349 
350   if(U_FAILURE(*status)) {
351     return NULL;
352   }
353 
354   plug = uplug_allocateEmptyPlug(status);
355   if(config!=NULL) {
356     uprv_strncpy(plug->config, config, UPLUG_NAME_MAX);
357   } else {
358     plug->config[0] = 0;
359   }
360 
361   if(symName!=NULL) {
362     uprv_strncpy(plug->sym, symName, UPLUG_NAME_MAX);
363   } else {
364     plug->sym[0] = 0;
365   }
366 
367   plug->entrypoint = entrypoint;
368   plug->lib = lib;
369   uplug_queryPlug(plug, status);
370 
371   return plug;
372 }
373 
uplug_deallocatePlug(UPlugData * plug,UErrorCode * status)374 static void uplug_deallocatePlug(UPlugData *plug, UErrorCode *status) {
375   UErrorCode subStatus = U_ZERO_ERROR;
376   if(!plug->dontUnload) {
377 #if U_ENABLE_DYLOAD
378     uplug_closeLibrary(plug->lib, &subStatus);
379 #endif
380   }
381   plug->lib = NULL;
382   if(U_SUCCESS(*status) && U_FAILURE(subStatus)) {
383     *status = subStatus;
384   }
385   /* shift plugins up and decrement count. */
386   if(U_SUCCESS(*status)) {
387     /* all ok- remove. */
388     pluginCount = uplug_removeEntryAt(pluginList, pluginCount, sizeof(plug[0]), uplug_pluginNumber(plug));
389   } else {
390     /* not ok- leave as a message. */
391     plug->awaitingLoad=FALSE;
392     plug->entrypoint=0;
393     plug->dontUnload=TRUE;
394   }
395 }
396 
uplug_doUnloadPlug(UPlugData * plugToRemove,UErrorCode * status)397 static void uplug_doUnloadPlug(UPlugData *plugToRemove, UErrorCode *status) {
398   if(plugToRemove != NULL) {
399     uplug_unloadPlug(plugToRemove, status);
400     uplug_deallocatePlug(plugToRemove, status);
401   }
402 }
403 
404 U_CAPI void U_EXPORT2
uplug_removePlug(UPlugData * plug,UErrorCode * status)405 uplug_removePlug(UPlugData *plug, UErrorCode *status)  {
406   UPlugData *cursor = NULL;
407   UPlugData *plugToRemove = NULL;
408   if(U_FAILURE(*status)) return;
409 
410   for(cursor=pluginList;cursor!=NULL;) {
411     if(cursor==plug) {
412       plugToRemove = plug;
413       cursor=NULL;
414     } else {
415       cursor = uplug_nextPlug(cursor);
416     }
417   }
418 
419   uplug_doUnloadPlug(plugToRemove, status);
420 }
421 
422 
423 
424 
425 U_CAPI void U_EXPORT2
uplug_setPlugNoUnload(UPlugData * data,UBool dontUnload)426 uplug_setPlugNoUnload(UPlugData *data, UBool dontUnload)
427 {
428   data->dontUnload = dontUnload;
429 }
430 
431 
432 U_CAPI void U_EXPORT2
uplug_setPlugLevel(UPlugData * data,UPlugLevel level)433 uplug_setPlugLevel(UPlugData *data, UPlugLevel level) {
434   data->level = level;
435 }
436 
437 
438 U_CAPI UPlugLevel U_EXPORT2
uplug_getPlugLevel(UPlugData * data)439 uplug_getPlugLevel(UPlugData *data) {
440   return data->level;
441 }
442 
443 
444 U_CAPI void U_EXPORT2
uplug_setPlugName(UPlugData * data,const char * name)445 uplug_setPlugName(UPlugData *data, const char *name) {
446   uprv_strncpy(data->name, name, UPLUG_NAME_MAX);
447 }
448 
449 
450 U_CAPI const char * U_EXPORT2
uplug_getPlugName(UPlugData * data)451 uplug_getPlugName(UPlugData *data) {
452   return data->name;
453 }
454 
455 
456 U_CAPI const char * U_EXPORT2
uplug_getSymbolName(UPlugData * data)457 uplug_getSymbolName(UPlugData *data) {
458   return data->sym;
459 }
460 
461 U_CAPI const char * U_EXPORT2
uplug_getLibraryName(UPlugData * data,UErrorCode * status)462 uplug_getLibraryName(UPlugData *data, UErrorCode *status) {
463   if(data->libName[0]) {
464     return data->libName;
465   } else {
466 #if U_ENABLE_DYLOAD
467     return uplug_findLibrary(data->lib, status);
468 #else
469     return NULL;
470 #endif
471   }
472 }
473 
474 U_CAPI void * U_EXPORT2
uplug_getLibrary(UPlugData * data)475 uplug_getLibrary(UPlugData *data) {
476   return data->lib;
477 }
478 
479 U_CAPI void * U_EXPORT2
uplug_getContext(UPlugData * data)480 uplug_getContext(UPlugData *data) {
481   return data->context;
482 }
483 
484 
485 U_CAPI void U_EXPORT2
uplug_setContext(UPlugData * data,void * context)486 uplug_setContext(UPlugData *data, void *context) {
487   data->context = context;
488 }
489 
490 U_CAPI const char* U_EXPORT2
uplug_getConfiguration(UPlugData * data)491 uplug_getConfiguration(UPlugData *data) {
492   return data->config;
493 }
494 
495 U_INTERNAL UPlugData* U_EXPORT2
uplug_getPlugInternal(int32_t n)496 uplug_getPlugInternal(int32_t n) {
497   if(n <0 || n >= pluginCount) {
498     return NULL;
499   } else {
500     return &(pluginList[n]);
501   }
502 }
503 
504 
505 U_CAPI UErrorCode U_EXPORT2
uplug_getPlugLoadStatus(UPlugData * plug)506 uplug_getPlugLoadStatus(UPlugData *plug) {
507   return plug->pluginStatus;
508 }
509 
510 
511 
512 
513 /**
514  * Initialize a plugin fron an entrypoint and library - but don't load it.
515  */
uplug_initPlugFromEntrypointAndLibrary(UPlugEntrypoint * entrypoint,const char * config,void * lib,const char * sym,UErrorCode * status)516 static UPlugData* uplug_initPlugFromEntrypointAndLibrary(UPlugEntrypoint *entrypoint, const char *config, void *lib, const char *sym,
517                                                          UErrorCode *status) {
518   UPlugData *plug = NULL;
519 
520   plug = uplug_allocatePlug(entrypoint, config, lib, sym, status);
521 
522   if(U_SUCCESS(*status)) {
523     return plug;
524   } else {
525     uplug_deallocatePlug(plug, status);
526     return NULL;
527   }
528 }
529 
530 U_CAPI UPlugData* U_EXPORT2
uplug_loadPlugFromEntrypoint(UPlugEntrypoint * entrypoint,const char * config,UErrorCode * status)531 uplug_loadPlugFromEntrypoint(UPlugEntrypoint *entrypoint, const char *config, UErrorCode *status) {
532   UPlugData* plug = uplug_initPlugFromEntrypointAndLibrary(entrypoint, config, NULL, NULL, status);
533   uplug_loadPlug(plug, status);
534   return plug;
535 }
536 
537 
538 static UPlugData*
uplug_initErrorPlug(const char * libName,const char * sym,const char * config,const char * nameOrError,UErrorCode loadStatus,UErrorCode * status)539 uplug_initErrorPlug(const char *libName, const char *sym, const char *config, const char *nameOrError, UErrorCode loadStatus, UErrorCode *status)
540 {
541   UPlugData *plug = uplug_allocateEmptyPlug(status);
542   if(U_FAILURE(*status)) return NULL;
543 
544   plug->pluginStatus = loadStatus;
545   plug->awaitingLoad = FALSE; /* Won't load. */
546   plug->dontUnload = TRUE; /* cannot unload. */
547 
548   if(sym!=NULL) {
549     uprv_strncpy(plug->sym, sym, UPLUG_NAME_MAX);
550   }
551 
552   if(libName!=NULL) {
553     uprv_strncpy(plug->libName, libName, UPLUG_NAME_MAX);
554   }
555 
556   if(nameOrError!=NULL) {
557     uprv_strncpy(plug->name, nameOrError, UPLUG_NAME_MAX);
558   }
559 
560   if(config!=NULL) {
561     uprv_strncpy(plug->config, config, UPLUG_NAME_MAX);
562   }
563 
564   return plug;
565 }
566 
567 /**
568  * Fetch a plugin from DLL, and then initialize it from a library- but don't load it.
569  */
570 
571 #if U_ENABLE_DYLOAD
572 
573 static UPlugData*
uplug_initPlugFromLibrary(const char * libName,const char * sym,const char * config,UErrorCode * status)574 uplug_initPlugFromLibrary(const char *libName, const char *sym, const char *config, UErrorCode *status) {
575   void *lib = NULL;
576   UPlugData *plug = NULL;
577   if(U_FAILURE(*status)) { return NULL; }
578   lib = uplug_openLibrary(libName, status);
579   if(lib!=NULL && U_SUCCESS(*status)) {
580     UPlugEntrypoint *entrypoint = NULL;
581     entrypoint = (UPlugEntrypoint*)uprv_dlsym_func(lib, sym, status);
582 
583     if(entrypoint!=NULL&&U_SUCCESS(*status)) {
584       plug = uplug_initPlugFromEntrypointAndLibrary(entrypoint, config, lib, sym, status);
585       if(plug!=NULL&&U_SUCCESS(*status)) {
586         plug->lib = lib; /* plug takes ownership of library */
587         lib = NULL; /* library is now owned by plugin. */
588       }
589     } else {
590       UErrorCode subStatus = U_ZERO_ERROR;
591       plug = uplug_initErrorPlug(libName,sym,config,"ERROR: Could not load entrypoint",(lib==NULL)?U_MISSING_RESOURCE_ERROR:*status,&subStatus);
592     }
593     if(lib!=NULL) { /* still need to close the lib */
594       UErrorCode subStatus = U_ZERO_ERROR;
595       uplug_closeLibrary(lib, &subStatus); /* don't care here */
596     }
597   } else {
598     UErrorCode subStatus = U_ZERO_ERROR;
599     plug = uplug_initErrorPlug(libName,sym,config,"ERROR: could not load library",(lib==NULL)?U_MISSING_RESOURCE_ERROR:*status,&subStatus);
600   }
601   return plug;
602 }
603 
604 U_CAPI UPlugData* U_EXPORT2
uplug_loadPlugFromLibrary(const char * libName,const char * sym,const char * config,UErrorCode * status)605 uplug_loadPlugFromLibrary(const char *libName, const char *sym, const char *config, UErrorCode *status) {
606   UPlugData *plug = NULL;
607   if(U_FAILURE(*status)) { return NULL; }
608   plug = uplug_initPlugFromLibrary(libName, sym, config, status);
609   uplug_loadPlug(plug, status);
610 
611   return plug;
612 }
613 
614 #endif
615 
uplug_getCurrentLevel()616 U_CAPI UPlugLevel U_EXPORT2 uplug_getCurrentLevel() {
617   if(cmemory_inUse()) {
618     return UPLUG_LEVEL_HIGH;
619   } else {
620     return UPLUG_LEVEL_LOW;
621   }
622 }
623 
uplug_cleanup(void)624 static UBool U_CALLCONV uplug_cleanup(void)
625 {
626   int32_t i;
627 
628   UPlugData *pluginToRemove;
629   /* cleanup plugs */
630   for(i=0;i<pluginCount;i++) {
631     UErrorCode subStatus = U_ZERO_ERROR;
632     pluginToRemove = &pluginList[i];
633     /* unload and deallocate */
634     uplug_doUnloadPlug(pluginToRemove, &subStatus);
635   }
636   /* close other held libs? */
637   return TRUE;
638 }
639 
uplug_loadWaitingPlugs(UErrorCode * status)640 static void uplug_loadWaitingPlugs(UErrorCode *status) {
641   int32_t i;
642   UPlugLevel currentLevel = uplug_getCurrentLevel();
643 
644   if(U_FAILURE(*status)) {
645     return;
646   }
647 #if UPLUG_TRACE
648   DBG((stderr,  "uplug_loadWaitingPlugs() Level: %d\n", currentLevel));
649 #endif
650   /* pass #1: low level plugs */
651   for(i=0;i<pluginCount;i++) {
652     UErrorCode subStatus = U_ZERO_ERROR;
653     UPlugData *pluginToLoad = &pluginList[i];
654     if(pluginToLoad->awaitingLoad) {
655       if(pluginToLoad->level == UPLUG_LEVEL_LOW) {
656         if(currentLevel > UPLUG_LEVEL_LOW) {
657           pluginToLoad->pluginStatus = U_PLUGIN_TOO_HIGH;
658         } else {
659           UPlugLevel newLevel;
660           uplug_loadPlug(pluginToLoad, &subStatus);
661           newLevel = uplug_getCurrentLevel();
662           if(newLevel > currentLevel) {
663             pluginToLoad->pluginStatus = U_PLUGIN_CHANGED_LEVEL_WARNING;
664             currentLevel = newLevel;
665           }
666         }
667         pluginToLoad->awaitingLoad = FALSE;
668       }
669     }
670   }
671   currentLevel = uplug_getCurrentLevel();
672 
673   for(i=0;i<pluginCount;i++) {
674     UErrorCode subStatus = U_ZERO_ERROR;
675     UPlugData *pluginToLoad = &pluginList[i];
676 
677     if(pluginToLoad->awaitingLoad) {
678       if(pluginToLoad->level == UPLUG_LEVEL_INVALID) {
679         pluginToLoad->pluginStatus = U_PLUGIN_DIDNT_SET_LEVEL;
680       } else if(pluginToLoad->level == UPLUG_LEVEL_UNKNOWN) {
681         pluginToLoad->pluginStatus = U_INTERNAL_PROGRAM_ERROR;
682       } else {
683         uplug_loadPlug(pluginToLoad, &subStatus);
684       }
685       pluginToLoad->awaitingLoad = FALSE;
686     }
687   }
688 
689 #if UPLUG_TRACE
690   DBG((stderr,  " Done Loading Plugs. Level: %d\n", (int32_t)uplug_getCurrentLevel()));
691 #endif
692 }
693 
694 #if U_ENABLE_DYLOAD
695 /* Name of the plugin config file */
696 static char plugin_file[2048] = "";
697 #endif
698 
699 U_INTERNAL const char* U_EXPORT2
uplug_getPluginFile()700 uplug_getPluginFile() {
701 #if U_ENABLE_DYLOAD
702   return plugin_file;
703 #else
704   return NULL;
705 #endif
706 }
707 
708 
709 U_CAPI void U_EXPORT2
uplug_init(UErrorCode * status)710 uplug_init(UErrorCode *status) {
711 #if !U_ENABLE_DYLOAD
712   (void)status; /* unused */
713 #else
714   const char *plugin_dir;
715 
716   if(U_FAILURE(*status)) return;
717   plugin_dir = getenv("ICU_PLUGINS");
718 
719 #if defined(DEFAULT_ICU_PLUGINS)
720   if(plugin_dir == NULL || !*plugin_dir) {
721     plugin_dir = DEFAULT_ICU_PLUGINS;
722   }
723 #endif
724 
725 #if UPLUG_TRACE
726   DBG((stderr, "ICU_PLUGINS=%s\n", plugin_dir));
727 #endif
728 
729   if(plugin_dir != NULL && *plugin_dir) {
730     FILE *f;
731 
732 
733     uprv_strncpy(plugin_file, plugin_dir, 2047);
734     uprv_strncat(plugin_file, U_FILE_SEP_STRING,2047);
735     uprv_strncat(plugin_file, "icuplugins",2047);
736     uprv_strncat(plugin_file, U_ICU_VERSION_SHORT ,2047);
737     uprv_strncat(plugin_file, ".txt" ,2047);
738 
739 #if UPLUG_TRACE
740     DBG((stderr, "pluginfile= %s\n", plugin_file));
741 #endif
742 
743     f = fopen(plugin_file, "r");
744 
745     if(f != NULL) {
746       char linebuf[1024];
747       char *p, *libName=NULL, *symName=NULL, *config=NULL;
748       int32_t line = 0;
749 
750 
751       while(fgets(linebuf,1023,f)) {
752         line++;
753 
754         if(!*linebuf || *linebuf=='#') {
755           continue;
756         } else {
757           p = linebuf;
758           while(*p&&isspace(*p))
759             p++;
760           if(!*p || *p=='#') continue;
761           libName = p;
762           while(*p&&!isspace(*p)) {
763             p++;
764           }
765           if(!*p || *p=='#') continue; /* no tab after libname */
766           *p=0; /* end of libname */
767           p++;
768           while(*p&&isspace(*p)) {
769             p++;
770           }
771           if(!*p||*p=='#') continue; /* no symname after libname +tab */
772           symName = p;
773           while(*p&&!isspace(*p)) {
774             p++;
775           }
776 
777           if(*p) { /* has config */
778             *p=0;
779             ++p;
780             while(*p&&isspace(*p)) {
781               p++;
782             }
783             if(*p) {
784               config = p;
785             }
786           }
787 
788           /* chop whitespace at the end of the config */
789           if(config!=NULL&&*config!=0) {
790             p = config+strlen(config);
791             while(p>config&&isspace(*(--p))) {
792               *p=0;
793             }
794           }
795 
796           /* OK, we're good. */
797           {
798             UErrorCode subStatus = U_ZERO_ERROR;
799             UPlugData *plug = uplug_initPlugFromLibrary(libName, symName, config, &subStatus);
800             if(U_FAILURE(subStatus) && U_SUCCESS(*status)) {
801               *status = subStatus;
802             }
803 #if UPLUG_TRACE
804             DBG((stderr, "PLUGIN libName=[%s], sym=[%s], config=[%s]\n", libName, symName, config));
805             DBG((stderr, " -> %p, %s\n", (void*)plug, u_errorName(subStatus)));
806 #else
807             (void)plug; /* unused */
808 #endif
809           }
810         }
811       }
812       fclose(f);
813     } else {
814 #if UPLUG_TRACE
815       DBG((stderr, "Can't open plugin file %s\n", plugin_file));
816 #endif
817     }
818   }
819   uplug_loadWaitingPlugs(status);
820 #endif /* U_ENABLE_DYLOAD */
821   ucln_registerCleanup(UCLN_UPLUG, uplug_cleanup);
822 }
823