]>
Commit | Line | Data |
---|---|---|
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 | ||
29 | using 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 | ||
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 | */ | |
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 | */ | |
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 | ||
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 | |
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 | |
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 | |
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 | ||
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 | |
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 | */ | |
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | |
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 | |
433 | uplug_setPlugNoUnload(UPlugData *data, UBool dontUnload) | |
434 | { | |
435 | data->dontUnload = dontUnload; | |
436 | } | |
437 | ||
438 | ||
439 | U_CAPI void U_EXPORT2 | |
440 | uplug_setPlugLevel(UPlugData *data, UPlugLevel level) { | |
441 | data->level = level; | |
442 | } | |
443 | ||
444 | ||
445 | U_CAPI UPlugLevel U_EXPORT2 | |
446 | uplug_getPlugLevel(UPlugData *data) { | |
447 | return data->level; | |
448 | } | |
449 | ||
450 | ||
451 | U_CAPI void U_EXPORT2 | |
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 | |
458 | uplug_getPlugName(UPlugData *data) { | |
459 | return data->name; | |
460 | } | |
461 | ||
462 | ||
463 | U_CAPI const char * U_EXPORT2 | |
464 | uplug_getSymbolName(UPlugData *data) { | |
465 | return data->sym; | |
466 | } | |
467 | ||
468 | U_CAPI const char * U_EXPORT2 | |
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 | |
482 | uplug_getLibrary(UPlugData *data) { | |
483 | return data->lib; | |
484 | } | |
485 | ||
486 | U_CAPI void * U_EXPORT2 | |
487 | uplug_getContext(UPlugData *data) { | |
488 | return data->context; | |
489 | } | |
490 | ||
491 | ||
492 | U_CAPI void U_EXPORT2 | |
493 | uplug_setContext(UPlugData *data, void *context) { | |
494 | data->context = context; | |
495 | } | |
496 | ||
497 | U_CAPI const char* U_EXPORT2 | |
498 | uplug_getConfiguration(UPlugData *data) { | |
499 | return data->config; | |
500 | } | |
501 | ||
502 | U_INTERNAL UPlugData* U_EXPORT2 | |
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 | |
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 | */ | |
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 | |
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 | ||
51004dcb | 544 | #if U_ENABLE_DYLOAD |
729e4ab9 A |
545 | |
546 | static UPlugData* | |
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 | */ | |
729e4ab9 A |
578 | static UPlugData* |
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; | |
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 | ||
609 | U_CAPI UPlugData* U_EXPORT2 | |
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 | ||
b331163b A |
621 | static UPlugLevel gCurrentLevel = UPLUG_LEVEL_LOW; |
622 | ||
729e4ab9 | 623 | U_CAPI UPlugLevel U_EXPORT2 uplug_getCurrentLevel() { |
b331163b | 624 | return gCurrentLevel; |
729e4ab9 A |
625 | } |
626 | ||
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? */ | |
b331163b | 640 | gCurrentLevel = UPLUG_LEVEL_LOW; |
729e4ab9 A |
641 | return TRUE; |
642 | } | |
643 | ||
51004dcb A |
644 | #if U_ENABLE_DYLOAD |
645 | ||
729e4ab9 A |
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 | } | |
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 */ |
699 | static char plugin_file[2048] = ""; | |
700 | #endif | |
701 | ||
702 | U_INTERNAL const char* U_EXPORT2 | |
703 | uplug_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 |
714 | U_CAPI void U_EXPORT2 |
715 | uplug_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 | } |