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