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