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 #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
29 using 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
44 struct 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 */
uplug_removeEntryAt(void * list,int32_t listSize,int32_t memberSize,int32_t itemToRemove)73 static 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 */
97 struct UPlugLibrary;
98
99 /**
100 * Library management. Internal.
101 * @internal
102 */
103 typedef struct UPlugLibrary {
104 void *lib; /**< library ptr */
105 char name[UPLUG_NAME_MAX]; /**< library name */
106 uint32_t ref; /**< reference count */
107 } UPlugLibrary;
108
109 static UPlugLibrary staticLibraryList[UPLUG_LIBRARY_INITIAL_COUNT];
110 static UPlugLibrary * libraryList = staticLibraryList;
111 static int32_t libraryCount = 0;
112 static 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 */
searchForLibraryName(const char * libName)119 static 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
searchForLibrary(void * lib)130 static 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
141 U_INTERNAL char * U_EXPORT2
uplug_findLibrary(void * lib,UErrorCode * status)142 uplug_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
157 U_INTERNAL void * U_EXPORT2
uplug_openLibrary(const char * libName,UErrorCode * status)158 uplug_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
205 U_INTERNAL void U_EXPORT2
uplug_closeLibrary(void * lib,UErrorCode * status)206 uplug_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
228 static UPlugData pluginList[UPLUG_PLUGIN_INITIAL_COUNT];
229 static int32_t pluginCount = 0;
230
231
232
233
uplug_pluginNumber(UPlugData * d)234 static 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
246 U_CAPI UPlugData * U_EXPORT2
uplug_nextPlug(UPlugData * prior)247 uplug_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 */
uplug_callPlug(UPlugData * plug,UPlugReason reason,UErrorCode * status)267 static 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
uplug_unloadPlug(UPlugData * plug,UErrorCode * status)279 static 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
uplug_queryPlug(UPlugData * plug,UErrorCode * status)290 static 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
uplug_loadPlug(UPlugData * plug,UErrorCode * status)309 static 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
uplug_allocateEmptyPlug(UErrorCode * status)321 static 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
uplug_allocatePlug(UPlugEntrypoint * entrypoint,const char * config,void * lib,const char * symName,UErrorCode * status)353 static 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
uplug_deallocatePlug(UPlugData * plug,UErrorCode * status)381 static 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
uplug_doUnloadPlug(UPlugData * plugToRemove,UErrorCode * status)404 static void uplug_doUnloadPlug(UPlugData *plugToRemove, UErrorCode *status) {
405 if(plugToRemove != NULL) {
406 uplug_unloadPlug(plugToRemove, status);
407 uplug_deallocatePlug(plugToRemove, status);
408 }
409 }
410
411 U_CAPI void U_EXPORT2
uplug_removePlug(UPlugData * plug,UErrorCode * status)412 uplug_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
432 U_CAPI void U_EXPORT2
uplug_setPlugNoUnload(UPlugData * data,UBool dontUnload)433 uplug_setPlugNoUnload(UPlugData *data, UBool dontUnload)
434 {
435 data->dontUnload = dontUnload;
436 }
437
438
439 U_CAPI void U_EXPORT2
uplug_setPlugLevel(UPlugData * data,UPlugLevel level)440 uplug_setPlugLevel(UPlugData *data, UPlugLevel level) {
441 data->level = level;
442 }
443
444
445 U_CAPI UPlugLevel U_EXPORT2
uplug_getPlugLevel(UPlugData * data)446 uplug_getPlugLevel(UPlugData *data) {
447 return data->level;
448 }
449
450
451 U_CAPI void U_EXPORT2
uplug_setPlugName(UPlugData * data,const char * name)452 uplug_setPlugName(UPlugData *data, const char *name) {
453 uprv_strncpy(data->name, name, UPLUG_NAME_MAX);
454 }
455
456
457 U_CAPI const char * U_EXPORT2
uplug_getPlugName(UPlugData * data)458 uplug_getPlugName(UPlugData *data) {
459 return data->name;
460 }
461
462
463 U_CAPI const char * U_EXPORT2
uplug_getSymbolName(UPlugData * data)464 uplug_getSymbolName(UPlugData *data) {
465 return data->sym;
466 }
467
468 U_CAPI const char * U_EXPORT2
uplug_getLibraryName(UPlugData * data,UErrorCode * status)469 uplug_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
481 U_CAPI void * U_EXPORT2
uplug_getLibrary(UPlugData * data)482 uplug_getLibrary(UPlugData *data) {
483 return data->lib;
484 }
485
486 U_CAPI void * U_EXPORT2
uplug_getContext(UPlugData * data)487 uplug_getContext(UPlugData *data) {
488 return data->context;
489 }
490
491
492 U_CAPI void U_EXPORT2
uplug_setContext(UPlugData * data,void * context)493 uplug_setContext(UPlugData *data, void *context) {
494 data->context = context;
495 }
496
497 U_CAPI const char* U_EXPORT2
uplug_getConfiguration(UPlugData * data)498 uplug_getConfiguration(UPlugData *data) {
499 return data->config;
500 }
501
502 U_INTERNAL UPlugData* U_EXPORT2
uplug_getPlugInternal(int32_t n)503 uplug_getPlugInternal(int32_t n) {
504 if(n <0 || n >= pluginCount) {
505 return NULL;
506 } else {
507 return &(pluginList[n]);
508 }
509 }
510
511
512 U_CAPI UErrorCode U_EXPORT2
uplug_getPlugLoadStatus(UPlugData * plug)513 uplug_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 */
uplug_initPlugFromEntrypointAndLibrary(UPlugEntrypoint * entrypoint,const char * config,void * lib,const char * sym,UErrorCode * status)523 static 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
537 U_CAPI UPlugData* U_EXPORT2
uplug_loadPlugFromEntrypoint(UPlugEntrypoint * entrypoint,const char * config,UErrorCode * status)538 uplug_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
546 static UPlugData*
uplug_initErrorPlug(const char * libName,const char * sym,const char * config,const char * nameOrError,UErrorCode loadStatus,UErrorCode * status)547 uplug_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 */
578 static UPlugData*
uplug_initPlugFromLibrary(const char * libName,const char * sym,const char * config,UErrorCode * status)579 uplug_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
609 U_CAPI UPlugData* U_EXPORT2
uplug_loadPlugFromLibrary(const char * libName,const char * sym,const char * config,UErrorCode * status)610 uplug_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
621 static UPlugLevel gCurrentLevel = UPLUG_LEVEL_LOW;
622
uplug_getCurrentLevel()623 U_CAPI UPlugLevel U_EXPORT2 uplug_getCurrentLevel() {
624 return gCurrentLevel;
625 }
626
uplug_cleanup(void)627 static 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? */
640 gCurrentLevel = UPLUG_LEVEL_LOW;
641 return TRUE;
642 }
643
644 #if U_ENABLE_DYLOAD
645
uplug_loadWaitingPlugs(UErrorCode * status)646 static 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 }
676 }
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
698 /* Name of the plugin config file */
699 static char plugin_file[2048] = "";
700 #endif
701
702 U_INTERNAL const char* U_EXPORT2
uplug_getPluginFile()703 uplug_getPluginFile() {
704 #if U_ENABLE_DYLOAD && !UCONFIG_NO_FILE_IO
705 return plugin_file;
706 #else
707 return NULL;
708 #endif
709 }
710
711
712 // uplug_init() is called first thing from u_init().
713
714 U_CAPI void U_EXPORT2
uplug_init(UErrorCode * status)715 uplug_init(UErrorCode *status) {
716 #if !U_ENABLE_DYLOAD
717 (void)status; /* unused */
718 #elif !UCONFIG_NO_FILE_IO
719 CharString plugin_dir;
720 const char *env = getenv("ICU_PLUGINS");
721
722 if(U_FAILURE(*status)) return;
723 if(env != NULL) {
724 plugin_dir.append(env, -1, *status);
725 }
726 if(U_FAILURE(*status)) return;
727
728 #if defined(DEFAULT_ICU_PLUGINS)
729 if(plugin_dir.isEmpty()) {
730 plugin_dir.append(DEFAULT_ICU_PLUGINS, -1, *status);
731 }
732 #endif
733
734 #if UPLUG_TRACE
735 DBG((stderr, "ICU_PLUGINS=%s\n", plugin_dir.data()));
736 #endif
737
738 if(!plugin_dir.isEmpty()) {
739 FILE *f;
740
741 CharString pluginFile;
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
750 pluginFile.append("//DD:ICUPLUG", -1, *status); /* JAM 20 Oct 2011 */
751 #else
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);
757 #endif
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));
778
779 #if UPLUG_TRACE
780 DBG((stderr, "pluginfile= %s len %d/%d\n", plugin_file, (int)strlen(plugin_file), (int)sizeof(plugin_file)));
781 #endif
782
783 #ifdef __MVS__
784 if (iscics()) /* 12 Nov 2011 JAM */
785 {
786 f = NULL;
787 }
788 else
789 #endif
790 {
791 f = fopen(pluginFile.data(), "r");
792 }
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;
807 while(*p&&isspace((int)*p))
808 p++;
809 if(!*p || *p=='#') continue;
810 libName = p;
811 while(*p&&!isspace((int)*p)) {
812 p++;
813 }
814 if(!*p || *p=='#') continue; /* no tab after libname */
815 *p=0; /* end of libname */
816 p++;
817 while(*p&&isspace((int)*p)) {
818 p++;
819 }
820 if(!*p||*p=='#') continue; /* no symname after libname +tab */
821 symName = p;
822 while(*p&&!isspace((int)*p)) {
823 p++;
824 }
825
826 if(*p) { /* has config */
827 *p=0;
828 ++p;
829 while(*p&&isspace((int)*p)) {
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);
840 while(p>config&&isspace((int)*(--p))) {
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 }
861 fclose(f);
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 */
870 gCurrentLevel = UPLUG_LEVEL_HIGH;
871 ucln_registerCleanup(UCLN_UPLUG, uplug_cleanup);
872 }
873