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