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