|
1 /* |
|
2 ****************************************************************************** |
|
3 * |
|
4 * Copyright (C) 2009-2012, 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 |
|
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 |
|
541 #if U_ENABLE_DYLOAD |
|
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 */ |
|
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; |
|
583 entrypoint = (UPlugEntrypoint*)uprv_dlsym_func(lib, sym, status); |
|
584 |
|
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 |
|
642 #if U_ENABLE_DYLOAD |
|
643 |
|
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 } |
|
674 } |
|
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 |
|
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 |
|
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 |
|
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); |
|
749 #endif |
|
750 |
|
751 #if UPLUG_TRACE |
|
752 DBG((stderr, "pluginfile= %s\n", plugin_file)); |
|
753 #endif |
|
754 |
|
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 } |
|
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; |
|
779 while(*p&&isspace((int)*p)) |
|
780 p++; |
|
781 if(!*p || *p=='#') continue; |
|
782 libName = p; |
|
783 while(*p&&!isspace((int)*p)) { |
|
784 p++; |
|
785 } |
|
786 if(!*p || *p=='#') continue; /* no tab after libname */ |
|
787 *p=0; /* end of libname */ |
|
788 p++; |
|
789 while(*p&&isspace((int)*p)) { |
|
790 p++; |
|
791 } |
|
792 if(!*p||*p=='#') continue; /* no symname after libname +tab */ |
|
793 symName = p; |
|
794 while(*p&&!isspace((int)*p)) { |
|
795 p++; |
|
796 } |
|
797 |
|
798 if(*p) { /* has config */ |
|
799 *p=0; |
|
800 ++p; |
|
801 while(*p&&isspace((int)*p)) { |
|
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); |
|
812 while(p>config&&isspace((int)*(--p))) { |
|
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 } |
|
833 fclose(f); |
|
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 } |