icuplug.cpp 23 KB

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