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