OLD | NEW |
| (Empty) |
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 li
b) */ | |
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 memberS
ize, 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)*memberS
ize), 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", libr
aryMax)); | |
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_er
rorName(*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(*li
braryList), 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 *stat
us) { | |
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 act
ually 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) ) { /* should
n'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 ha
ppen. 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 *co
nfig, 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 *entryp
oint, 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, UE
rrorCode *status) { | |
536 UPlugData* plug = uplug_initPlugFromEntrypointAndLibrary(entrypoint, config, N
ULL, 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, co
nst 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 loa
d it. | |
574 */ | |
575 static UPlugData* | |
576 uplug_initPlugFromLibrary(const char *libName, const char *sym, const char *conf
ig, 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 entry
point",(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 *conf
ig, 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_getCurrentLev
el())); | |
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 enfor
ced */ | |
737 /* I've chosen to open a DDNAME if BATCH and leave it alone for (presumably) UNI
X */ | |
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 } | |
OLD | NEW |