]> git.saurik.com Git - apple/icu.git/blame - icuSources/common/icuplug.cpp
ICU-551.30.tar.gz
[apple/icu.git] / icuSources / common / icuplug.cpp
CommitLineData
729e4ab9
A
1/*
2******************************************************************************
3*
b331163b 4* Copyright (C) 2009-2015, International Business Machines
729e4ab9
A
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>
4388f060
A
23#ifdef __MVS__ /* defined by z/OS compiler */
24#define _POSIX_SOURCE
25#include <cics.h> /* 12 Nov 2011 JAM iscics() function */
26#endif
b331163b
A
27#include "charstr.h"
28
29using namespace icu;
729e4ab9
A
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
51004dcb 544#if U_ENABLE_DYLOAD
729e4ab9
A
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 */
729e4ab9
A
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;
4388f060
A
586 entrypoint = (UPlugEntrypoint*)uprv_dlsym_func(lib, sym, status);
587
729e4ab9
A
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
b331163b
A
621static UPlugLevel gCurrentLevel = UPLUG_LEVEL_LOW;
622
729e4ab9 623U_CAPI UPlugLevel U_EXPORT2 uplug_getCurrentLevel() {
b331163b 624 return gCurrentLevel;
729e4ab9
A
625}
626
627static UBool U_CALLCONV uplug_cleanup(void)
628{
629 int32_t i;
630
631 UPlugData *pluginToRemove;
632 /* cleanup plugs */
633 for(i=0;i<pluginCount;i++) {
634 UErrorCode subStatus = U_ZERO_ERROR;
635 pluginToRemove = &pluginList[i];
636 /* unload and deallocate */
637 uplug_doUnloadPlug(pluginToRemove, &subStatus);
638 }
639 /* close other held libs? */
b331163b 640 gCurrentLevel = UPLUG_LEVEL_LOW;
729e4ab9
A
641 return TRUE;
642}
643
51004dcb
A
644#if U_ENABLE_DYLOAD
645
729e4ab9
A
646static void uplug_loadWaitingPlugs(UErrorCode *status) {
647 int32_t i;
648 UPlugLevel currentLevel = uplug_getCurrentLevel();
649
650 if(U_FAILURE(*status)) {
651 return;
652 }
653#if UPLUG_TRACE
654 DBG((stderr, "uplug_loadWaitingPlugs() Level: %d\n", currentLevel));
655#endif
656 /* pass #1: low level plugs */
657 for(i=0;i<pluginCount;i++) {
658 UErrorCode subStatus = U_ZERO_ERROR;
659 UPlugData *pluginToLoad = &pluginList[i];
660 if(pluginToLoad->awaitingLoad) {
661 if(pluginToLoad->level == UPLUG_LEVEL_LOW) {
662 if(currentLevel > UPLUG_LEVEL_LOW) {
663 pluginToLoad->pluginStatus = U_PLUGIN_TOO_HIGH;
664 } else {
665 UPlugLevel newLevel;
666 uplug_loadPlug(pluginToLoad, &subStatus);
667 newLevel = uplug_getCurrentLevel();
668 if(newLevel > currentLevel) {
669 pluginToLoad->pluginStatus = U_PLUGIN_CHANGED_LEVEL_WARNING;
670 currentLevel = newLevel;
671 }
672 }
673 pluginToLoad->awaitingLoad = FALSE;
674 }
675 }
4388f060 676 }
729e4ab9
A
677 for(i=0;i<pluginCount;i++) {
678 UErrorCode subStatus = U_ZERO_ERROR;
679 UPlugData *pluginToLoad = &pluginList[i];
680
681 if(pluginToLoad->awaitingLoad) {
682 if(pluginToLoad->level == UPLUG_LEVEL_INVALID) {
683 pluginToLoad->pluginStatus = U_PLUGIN_DIDNT_SET_LEVEL;
684 } else if(pluginToLoad->level == UPLUG_LEVEL_UNKNOWN) {
685 pluginToLoad->pluginStatus = U_INTERNAL_PROGRAM_ERROR;
686 } else {
687 uplug_loadPlug(pluginToLoad, &subStatus);
688 }
689 pluginToLoad->awaitingLoad = FALSE;
690 }
691 }
692
693#if UPLUG_TRACE
694 DBG((stderr, " Done Loading Plugs. Level: %d\n", (int32_t)uplug_getCurrentLevel()));
695#endif
696}
697
729e4ab9
A
698/* Name of the plugin config file */
699static char plugin_file[2048] = "";
700#endif
701
702U_INTERNAL const char* U_EXPORT2
703uplug_getPluginFile() {
b331163b 704#if U_ENABLE_DYLOAD && !UCONFIG_NO_FILE_IO
729e4ab9
A
705 return plugin_file;
706#else
707 return NULL;
708#endif
709}
710
711
b331163b
A
712// uplug_init() is called first thing from u_init().
713
729e4ab9
A
714U_CAPI void U_EXPORT2
715uplug_init(UErrorCode *status) {
716#if !U_ENABLE_DYLOAD
717 (void)status; /* unused */
b331163b
A
718#elif !UCONFIG_NO_FILE_IO
719 CharString plugin_dir;
720 const char *env = getenv("ICU_PLUGINS");
729e4ab9
A
721
722 if(U_FAILURE(*status)) return;
b331163b
A
723 if(env != NULL) {
724 plugin_dir.append(env, -1, *status);
725 }
726 if(U_FAILURE(*status)) return;
729e4ab9
A
727
728#if defined(DEFAULT_ICU_PLUGINS)
b331163b
A
729 if(plugin_dir.isEmpty()) {
730 plugin_dir.append(DEFAULT_ICU_PLUGINS, -1, *status);
729e4ab9
A
731 }
732#endif
733
734#if UPLUG_TRACE
b331163b 735 DBG((stderr, "ICU_PLUGINS=%s\n", plugin_dir.data()));
729e4ab9
A
736#endif
737
b331163b 738 if(!plugin_dir.isEmpty()) {
729e4ab9
A
739 FILE *f;
740
b331163b 741 CharString pluginFile;
4388f060
A
742#ifdef OS390BATCH
743/* There are potentially a lot of ways to implement a plugin directory on OS390/zOS */
744/* Keeping in mind that unauthorized file access is logged, monitored, and enforced */
745/* I've chosen to open a DDNAME if BATCH and leave it alone for (presumably) UNIX */
746/* System Services. Alternative techniques might be allocating a member in */
747/* SYS1.PARMLIB or setting an environment variable "ICU_PLUGIN_PATH" (?). The */
748/* DDNAME can be connected to a file in the HFS if need be. */
749
b331163b 750 pluginFile.append("//DD:ICUPLUG", -1, *status); /* JAM 20 Oct 2011 */
4388f060 751#else
b331163b
A
752 pluginFile.append(plugin_dir, *status);
753 pluginFile.append(U_FILE_SEP_STRING, -1, *status);
754 pluginFile.append("icuplugins", -1, *status);
755 pluginFile.append(U_ICU_VERSION_SHORT, -1, *status);
756 pluginFile.append(".txt", -1, *status);
4388f060 757#endif
b331163b
A
758
759#if UPLUG_TRACE
760 DBG((stderr, "status=%s\n", u_errorName(*status)));
761#endif
762
763 if(U_FAILURE(*status)) {
764 return;
765 }
766 if((size_t)pluginFile.length() > (sizeof(plugin_file)-1)) {
767 *status = U_BUFFER_OVERFLOW_ERROR;
768#if UPLUG_TRACE
769 DBG((stderr, "status=%s\n", u_errorName(*status)));
770#endif
771 return;
772 }
773
774 /* plugin_file is not used for processing - it is only used
775 so that uplug_getPluginFile() works (i.e. icuinfo)
776 */
777 uprv_strncpy(plugin_file, pluginFile.data(), sizeof(plugin_file));
729e4ab9
A
778
779#if UPLUG_TRACE
b331163b 780 DBG((stderr, "pluginfile= %s len %d/%d\n", plugin_file, (int)strlen(plugin_file), (int)sizeof(plugin_file)));
729e4ab9
A
781#endif
782
4388f060
A
783#ifdef __MVS__
784 if (iscics()) /* 12 Nov 2011 JAM */
785 {
786 f = NULL;
787 }
788 else
789#endif
790 {
b331163b 791 f = fopen(pluginFile.data(), "r");
4388f060 792 }
729e4ab9
A
793
794 if(f != NULL) {
795 char linebuf[1024];
796 char *p, *libName=NULL, *symName=NULL, *config=NULL;
797 int32_t line = 0;
798
799
800 while(fgets(linebuf,1023,f)) {
801 line++;
802
803 if(!*linebuf || *linebuf=='#') {
804 continue;
805 } else {
806 p = linebuf;
4388f060 807 while(*p&&isspace((int)*p))
729e4ab9
A
808 p++;
809 if(!*p || *p=='#') continue;
810 libName = p;
4388f060 811 while(*p&&!isspace((int)*p)) {
729e4ab9
A
812 p++;
813 }
814 if(!*p || *p=='#') continue; /* no tab after libname */
815 *p=0; /* end of libname */
816 p++;
4388f060 817 while(*p&&isspace((int)*p)) {
729e4ab9
A
818 p++;
819 }
820 if(!*p||*p=='#') continue; /* no symname after libname +tab */
821 symName = p;
4388f060 822 while(*p&&!isspace((int)*p)) {
729e4ab9
A
823 p++;
824 }
825
826 if(*p) { /* has config */
827 *p=0;
828 ++p;
4388f060 829 while(*p&&isspace((int)*p)) {
729e4ab9
A
830 p++;
831 }
832 if(*p) {
833 config = p;
834 }
835 }
836
837 /* chop whitespace at the end of the config */
838 if(config!=NULL&&*config!=0) {
839 p = config+strlen(config);
4388f060 840 while(p>config&&isspace((int)*(--p))) {
729e4ab9
A
841 *p=0;
842 }
843 }
844
845 /* OK, we're good. */
846 {
847 UErrorCode subStatus = U_ZERO_ERROR;
848 UPlugData *plug = uplug_initPlugFromLibrary(libName, symName, config, &subStatus);
849 if(U_FAILURE(subStatus) && U_SUCCESS(*status)) {
850 *status = subStatus;
851 }
852#if UPLUG_TRACE
853 DBG((stderr, "PLUGIN libName=[%s], sym=[%s], config=[%s]\n", libName, symName, config));
854 DBG((stderr, " -> %p, %s\n", (void*)plug, u_errorName(subStatus)));
855#else
856 (void)plug; /* unused */
857#endif
858 }
859 }
860 }
4388f060 861 fclose(f);
729e4ab9
A
862 } else {
863#if UPLUG_TRACE
864 DBG((stderr, "Can't open plugin file %s\n", plugin_file));
865#endif
866 }
867 }
868 uplug_loadWaitingPlugs(status);
869#endif /* U_ENABLE_DYLOAD */
b331163b 870 gCurrentLevel = UPLUG_LEVEL_HIGH;
729e4ab9
A
871 ucln_registerCleanup(UCLN_UPLUG, uplug_cleanup);
872}