jpayne@69
|
1 // © 2016 and later: Unicode, Inc. and others.
|
jpayne@69
|
2 // License & terms of use: http://www.unicode.org/copyright.html
|
jpayne@69
|
3 /*
|
jpayne@69
|
4 ******************************************************************************
|
jpayne@69
|
5 *
|
jpayne@69
|
6 * Copyright (C) 2009-2015, International Business Machines
|
jpayne@69
|
7 * Corporation and others. All Rights Reserved.
|
jpayne@69
|
8 *
|
jpayne@69
|
9 ******************************************************************************
|
jpayne@69
|
10 *
|
jpayne@69
|
11 * FILE NAME : icuplug.h
|
jpayne@69
|
12 *
|
jpayne@69
|
13 * Date Name Description
|
jpayne@69
|
14 * 10/29/2009 sl New.
|
jpayne@69
|
15 ******************************************************************************
|
jpayne@69
|
16 */
|
jpayne@69
|
17
|
jpayne@69
|
18 /**
|
jpayne@69
|
19 * \file
|
jpayne@69
|
20 * \brief C API: ICU Plugin API
|
jpayne@69
|
21 *
|
jpayne@69
|
22 * <h2>C API: ICU Plugin API</h2>
|
jpayne@69
|
23 *
|
jpayne@69
|
24 * <p>C API allowing run-time loadable modules that extend or modify ICU functionality.</p>
|
jpayne@69
|
25 *
|
jpayne@69
|
26 * <h3>Loading and Configuration</h3>
|
jpayne@69
|
27 *
|
jpayne@69
|
28 * <p>At ICU startup time, the environment variable "ICU_PLUGINS" will be
|
jpayne@69
|
29 * queried for a directory name. If it is not set, the preprocessor symbol
|
jpayne@69
|
30 * "DEFAULT_ICU_PLUGINS" will be checked for a default value.</p>
|
jpayne@69
|
31 *
|
jpayne@69
|
32 * <p>Within the above-named directory, the file "icuplugins##.txt" will be
|
jpayne@69
|
33 * opened, if present, where ## is the major+minor number of the currently
|
jpayne@69
|
34 * running ICU (such as, 44 for ICU 4.4, thus icuplugins44.txt)</p>
|
jpayne@69
|
35 *
|
jpayne@69
|
36 * <p>The configuration file has this format:</p>
|
jpayne@69
|
37 *
|
jpayne@69
|
38 * <ul>
|
jpayne@69
|
39 * <li>Hash (#) begins a comment line</li>
|
jpayne@69
|
40 *
|
jpayne@69
|
41 * <li>Non-comment lines have two or three components:
|
jpayne@69
|
42 * LIBRARYNAME ENTRYPOINT [ CONFIGURATION .. ]</li>
|
jpayne@69
|
43 *
|
jpayne@69
|
44 * <li>Tabs or spaces separate the three items.</li>
|
jpayne@69
|
45 *
|
jpayne@69
|
46 * <li>LIBRARYNAME is the name of a shared library, either a short name if
|
jpayne@69
|
47 * it is on the loader path, or a full pathname.</li>
|
jpayne@69
|
48 *
|
jpayne@69
|
49 * <li>ENTRYPOINT is the short (undecorated) symbol name of the plugin's
|
jpayne@69
|
50 * entrypoint, as above.</li>
|
jpayne@69
|
51 *
|
jpayne@69
|
52 * <li>CONFIGURATION is the entire rest of the line . It's passed as-is to
|
jpayne@69
|
53 * the plugin.</li>
|
jpayne@69
|
54 * </ul>
|
jpayne@69
|
55 *
|
jpayne@69
|
56 * <p>An example configuration file is, in its entirety:</p>
|
jpayne@69
|
57 *
|
jpayne@69
|
58 * \code
|
jpayne@69
|
59 * # this is icuplugins44.txt
|
jpayne@69
|
60 * testplug.dll myPlugin hello=world
|
jpayne@69
|
61 * \endcode
|
jpayne@69
|
62 * <p>Plugins are categorized as "high" or "low" level. Low level are those
|
jpayne@69
|
63 * which must be run BEFORE high level plugins, and before any operations
|
jpayne@69
|
64 * which cause ICU to be 'initialized'. If a plugin is low level but
|
jpayne@69
|
65 * causes ICU to allocate memory or become initialized, that plugin is said
|
jpayne@69
|
66 * to cause a 'level change'. </p>
|
jpayne@69
|
67 *
|
jpayne@69
|
68 * <p>At load time, ICU first queries all plugins to determine their level,
|
jpayne@69
|
69 * then loads all 'low' plugins first, and then loads all 'high' plugins.
|
jpayne@69
|
70 * Plugins are otherwise loaded in the order listed in the configuration file.</p>
|
jpayne@69
|
71 *
|
jpayne@69
|
72 * <h3>Implementing a Plugin</h3>
|
jpayne@69
|
73 * \code
|
jpayne@69
|
74 * U_CAPI UPlugTokenReturn U_EXPORT2
|
jpayne@69
|
75 * myPlugin (UPlugData *plug, UPlugReason reason, UErrorCode *status) {
|
jpayne@69
|
76 * if(reason==UPLUG_REASON_QUERY) {
|
jpayne@69
|
77 * uplug_setPlugName(plug, "Simple Plugin");
|
jpayne@69
|
78 * uplug_setPlugLevel(plug, UPLUG_LEVEL_HIGH);
|
jpayne@69
|
79 * } else if(reason==UPLUG_REASON_LOAD) {
|
jpayne@69
|
80 * ... Set up some ICU things here....
|
jpayne@69
|
81 * } else if(reason==UPLUG_REASON_UNLOAD) {
|
jpayne@69
|
82 * ... unload, clean up ...
|
jpayne@69
|
83 * }
|
jpayne@69
|
84 * return UPLUG_TOKEN;
|
jpayne@69
|
85 * }
|
jpayne@69
|
86 * \endcode
|
jpayne@69
|
87 *
|
jpayne@69
|
88 * <p>The UPlugData* is an opaque pointer to the plugin-specific data, and is
|
jpayne@69
|
89 * used in all other API calls.</p>
|
jpayne@69
|
90 *
|
jpayne@69
|
91 * <p>The API contract is:</p>
|
jpayne@69
|
92 * <ol><li>The plugin MUST always return UPLUG_TOKEN as a return value- to
|
jpayne@69
|
93 * indicate that it is a valid plugin.</li>
|
jpayne@69
|
94 *
|
jpayne@69
|
95 * <li>When the 'reason' parameter is set to UPLUG_REASON_QUERY, the
|
jpayne@69
|
96 * plugin MUST call uplug_setPlugLevel() to indicate whether it is a high
|
jpayne@69
|
97 * level or low level plugin.</li>
|
jpayne@69
|
98 *
|
jpayne@69
|
99 * <li>When the 'reason' parameter is UPLUG_REASON_QUERY, the plugin
|
jpayne@69
|
100 * SHOULD call uplug_setPlugName to indicate a human readable plugin name.</li></ol>
|
jpayne@69
|
101 *
|
jpayne@69
|
102 *
|
jpayne@69
|
103 * \internal ICU 4.4 Technology Preview
|
jpayne@69
|
104 */
|
jpayne@69
|
105
|
jpayne@69
|
106
|
jpayne@69
|
107 #ifndef ICUPLUG_H
|
jpayne@69
|
108 #define ICUPLUG_H
|
jpayne@69
|
109
|
jpayne@69
|
110 #include "unicode/utypes.h"
|
jpayne@69
|
111
|
jpayne@69
|
112
|
jpayne@69
|
113 #if UCONFIG_ENABLE_PLUGINS || defined(U_IN_DOXYGEN)
|
jpayne@69
|
114
|
jpayne@69
|
115
|
jpayne@69
|
116
|
jpayne@69
|
117 /* === Basic types === */
|
jpayne@69
|
118
|
jpayne@69
|
119 #ifndef U_HIDE_INTERNAL_API
|
jpayne@69
|
120 /**
|
jpayne@69
|
121 * @{
|
jpayne@69
|
122 * Opaque structure passed to/from a plugin.
|
jpayne@69
|
123 * use the APIs to access it.
|
jpayne@69
|
124 * @internal ICU 4.4 Technology Preview
|
jpayne@69
|
125 */
|
jpayne@69
|
126
|
jpayne@69
|
127 struct UPlugData;
|
jpayne@69
|
128 typedef struct UPlugData UPlugData;
|
jpayne@69
|
129
|
jpayne@69
|
130 /** @} */
|
jpayne@69
|
131
|
jpayne@69
|
132 /**
|
jpayne@69
|
133 * Random Token to identify a valid ICU plugin. Plugins must return this
|
jpayne@69
|
134 * from the entrypoint.
|
jpayne@69
|
135 * @internal ICU 4.4 Technology Preview
|
jpayne@69
|
136 */
|
jpayne@69
|
137 #define UPLUG_TOKEN 0x54762486
|
jpayne@69
|
138
|
jpayne@69
|
139 /**
|
jpayne@69
|
140 * Max width of names, symbols, and configuration strings
|
jpayne@69
|
141 * @internal ICU 4.4 Technology Preview
|
jpayne@69
|
142 */
|
jpayne@69
|
143 #define UPLUG_NAME_MAX 100
|
jpayne@69
|
144
|
jpayne@69
|
145
|
jpayne@69
|
146 /**
|
jpayne@69
|
147 * Return value from a plugin entrypoint.
|
jpayne@69
|
148 * Must always be set to UPLUG_TOKEN
|
jpayne@69
|
149 * @see UPLUG_TOKEN
|
jpayne@69
|
150 * @internal ICU 4.4 Technology Preview
|
jpayne@69
|
151 */
|
jpayne@69
|
152 typedef uint32_t UPlugTokenReturn;
|
jpayne@69
|
153
|
jpayne@69
|
154 /**
|
jpayne@69
|
155 * Reason code for the entrypoint's call
|
jpayne@69
|
156 * @internal ICU 4.4 Technology Preview
|
jpayne@69
|
157 */
|
jpayne@69
|
158 typedef enum {
|
jpayne@69
|
159 UPLUG_REASON_QUERY = 0, /**< The plugin is being queried for info. **/
|
jpayne@69
|
160 UPLUG_REASON_LOAD = 1, /**< The plugin is being loaded. **/
|
jpayne@69
|
161 UPLUG_REASON_UNLOAD = 2, /**< The plugin is being unloaded. **/
|
jpayne@69
|
162 /**
|
jpayne@69
|
163 * Number of known reasons.
|
jpayne@69
|
164 * @internal The numeric value may change over time, see ICU ticket #12420.
|
jpayne@69
|
165 */
|
jpayne@69
|
166 UPLUG_REASON_COUNT
|
jpayne@69
|
167 } UPlugReason;
|
jpayne@69
|
168
|
jpayne@69
|
169
|
jpayne@69
|
170 /**
|
jpayne@69
|
171 * Level of plugin loading
|
jpayne@69
|
172 * INITIAL: UNKNOWN
|
jpayne@69
|
173 * QUERY: INVALID -> { LOW | HIGH }
|
jpayne@69
|
174 * ERR -> INVALID
|
jpayne@69
|
175 * @internal ICU 4.4 Technology Preview
|
jpayne@69
|
176 */
|
jpayne@69
|
177 typedef enum {
|
jpayne@69
|
178 UPLUG_LEVEL_INVALID = 0, /**< The plugin is invalid, hasn't called uplug_setLevel, or can't load. **/
|
jpayne@69
|
179 UPLUG_LEVEL_UNKNOWN = 1, /**< The plugin is waiting to be installed. **/
|
jpayne@69
|
180 UPLUG_LEVEL_LOW = 2, /**< The plugin must be called before u_init completes **/
|
jpayne@69
|
181 UPLUG_LEVEL_HIGH = 3, /**< The plugin can run at any time. **/
|
jpayne@69
|
182 /**
|
jpayne@69
|
183 * Number of known levels.
|
jpayne@69
|
184 * @internal The numeric value may change over time, see ICU ticket #12420.
|
jpayne@69
|
185 */
|
jpayne@69
|
186 UPLUG_LEVEL_COUNT
|
jpayne@69
|
187 } UPlugLevel;
|
jpayne@69
|
188
|
jpayne@69
|
189 /**
|
jpayne@69
|
190 * Entrypoint for an ICU plugin.
|
jpayne@69
|
191 * @param plug the UPlugData handle.
|
jpayne@69
|
192 * @param status the plugin's extended status code.
|
jpayne@69
|
193 * @return A valid plugin must return UPLUG_TOKEN
|
jpayne@69
|
194 * @internal ICU 4.4 Technology Preview
|
jpayne@69
|
195 */
|
jpayne@69
|
196 typedef UPlugTokenReturn (U_EXPORT2 UPlugEntrypoint) (
|
jpayne@69
|
197 UPlugData *plug,
|
jpayne@69
|
198 UPlugReason reason,
|
jpayne@69
|
199 UErrorCode *status);
|
jpayne@69
|
200
|
jpayne@69
|
201 /* === Needed for Implementing === */
|
jpayne@69
|
202
|
jpayne@69
|
203 /**
|
jpayne@69
|
204 * Request that this plugin not be unloaded at cleanup time.
|
jpayne@69
|
205 * This is appropriate for plugins which cannot be cleaned up.
|
jpayne@69
|
206 * @see u_cleanup()
|
jpayne@69
|
207 * @param plug plugin
|
jpayne@69
|
208 * @param dontUnload set true if this plugin can't be unloaded
|
jpayne@69
|
209 * @internal ICU 4.4 Technology Preview
|
jpayne@69
|
210 */
|
jpayne@69
|
211 U_INTERNAL void U_EXPORT2
|
jpayne@69
|
212 uplug_setPlugNoUnload(UPlugData *plug, UBool dontUnload);
|
jpayne@69
|
213
|
jpayne@69
|
214 /**
|
jpayne@69
|
215 * Set the level of this plugin.
|
jpayne@69
|
216 * @param plug plugin data handle
|
jpayne@69
|
217 * @param level the level of this plugin
|
jpayne@69
|
218 * @internal ICU 4.4 Technology Preview
|
jpayne@69
|
219 */
|
jpayne@69
|
220 U_INTERNAL void U_EXPORT2
|
jpayne@69
|
221 uplug_setPlugLevel(UPlugData *plug, UPlugLevel level);
|
jpayne@69
|
222
|
jpayne@69
|
223 /**
|
jpayne@69
|
224 * Get the level of this plugin.
|
jpayne@69
|
225 * @param plug plugin data handle
|
jpayne@69
|
226 * @return the level of this plugin
|
jpayne@69
|
227 * @internal ICU 4.4 Technology Preview
|
jpayne@69
|
228 */
|
jpayne@69
|
229 U_INTERNAL UPlugLevel U_EXPORT2
|
jpayne@69
|
230 uplug_getPlugLevel(UPlugData *plug);
|
jpayne@69
|
231
|
jpayne@69
|
232 /**
|
jpayne@69
|
233 * Get the lowest level of plug which can currently load.
|
jpayne@69
|
234 * For example, if UPLUG_LEVEL_LOW is returned, then low level plugins may load
|
jpayne@69
|
235 * if UPLUG_LEVEL_HIGH is returned, then only high level plugins may load.
|
jpayne@69
|
236 * @return the lowest level of plug which can currently load
|
jpayne@69
|
237 * @internal ICU 4.4 Technology Preview
|
jpayne@69
|
238 */
|
jpayne@69
|
239 U_INTERNAL UPlugLevel U_EXPORT2
|
jpayne@69
|
240 uplug_getCurrentLevel(void);
|
jpayne@69
|
241
|
jpayne@69
|
242
|
jpayne@69
|
243 /**
|
jpayne@69
|
244 * Get plug load status
|
jpayne@69
|
245 * @return The error code of this plugin's load attempt.
|
jpayne@69
|
246 * @internal ICU 4.4 Technology Preview
|
jpayne@69
|
247 */
|
jpayne@69
|
248 U_INTERNAL UErrorCode U_EXPORT2
|
jpayne@69
|
249 uplug_getPlugLoadStatus(UPlugData *plug);
|
jpayne@69
|
250
|
jpayne@69
|
251 /**
|
jpayne@69
|
252 * Set the human-readable name of this plugin.
|
jpayne@69
|
253 * @param plug plugin data handle
|
jpayne@69
|
254 * @param name the name of this plugin. The first UPLUG_NAME_MAX characters willi be copied into a new buffer.
|
jpayne@69
|
255 * @internal ICU 4.4 Technology Preview
|
jpayne@69
|
256 */
|
jpayne@69
|
257 U_INTERNAL void U_EXPORT2
|
jpayne@69
|
258 uplug_setPlugName(UPlugData *plug, const char *name);
|
jpayne@69
|
259
|
jpayne@69
|
260 /**
|
jpayne@69
|
261 * Get the human-readable name of this plugin.
|
jpayne@69
|
262 * @param plug plugin data handle
|
jpayne@69
|
263 * @return the name of this plugin
|
jpayne@69
|
264 * @internal ICU 4.4 Technology Preview
|
jpayne@69
|
265 */
|
jpayne@69
|
266 U_INTERNAL const char * U_EXPORT2
|
jpayne@69
|
267 uplug_getPlugName(UPlugData *plug);
|
jpayne@69
|
268
|
jpayne@69
|
269 /**
|
jpayne@69
|
270 * Return the symbol name for this plugin, if known.
|
jpayne@69
|
271 * @param plug plugin data handle
|
jpayne@69
|
272 * @return the symbol name, or NULL
|
jpayne@69
|
273 * @internal ICU 4.4 Technology Preview
|
jpayne@69
|
274 */
|
jpayne@69
|
275 U_INTERNAL const char * U_EXPORT2
|
jpayne@69
|
276 uplug_getSymbolName(UPlugData *plug);
|
jpayne@69
|
277
|
jpayne@69
|
278 /**
|
jpayne@69
|
279 * Return the library name for this plugin, if known.
|
jpayne@69
|
280 * @param plug plugin data handle
|
jpayne@69
|
281 * @param status error code
|
jpayne@69
|
282 * @return the library name, or NULL
|
jpayne@69
|
283 * @internal ICU 4.4 Technology Preview
|
jpayne@69
|
284 */
|
jpayne@69
|
285 U_INTERNAL const char * U_EXPORT2
|
jpayne@69
|
286 uplug_getLibraryName(UPlugData *plug, UErrorCode *status);
|
jpayne@69
|
287
|
jpayne@69
|
288 /**
|
jpayne@69
|
289 * Return the library used for this plugin, if known.
|
jpayne@69
|
290 * Plugins could use this to load data out of their
|
jpayne@69
|
291 * @param plug plugin data handle
|
jpayne@69
|
292 * @return the library, or NULL
|
jpayne@69
|
293 * @internal ICU 4.4 Technology Preview
|
jpayne@69
|
294 */
|
jpayne@69
|
295 U_INTERNAL void * U_EXPORT2
|
jpayne@69
|
296 uplug_getLibrary(UPlugData *plug);
|
jpayne@69
|
297
|
jpayne@69
|
298 /**
|
jpayne@69
|
299 * Return the plugin-specific context data.
|
jpayne@69
|
300 * @param plug plugin data handle
|
jpayne@69
|
301 * @return the context, or NULL if not set
|
jpayne@69
|
302 * @internal ICU 4.4 Technology Preview
|
jpayne@69
|
303 */
|
jpayne@69
|
304 U_INTERNAL void * U_EXPORT2
|
jpayne@69
|
305 uplug_getContext(UPlugData *plug);
|
jpayne@69
|
306
|
jpayne@69
|
307 /**
|
jpayne@69
|
308 * Set the plugin-specific context data.
|
jpayne@69
|
309 * @param plug plugin data handle
|
jpayne@69
|
310 * @param context new context to set
|
jpayne@69
|
311 * @internal ICU 4.4 Technology Preview
|
jpayne@69
|
312 */
|
jpayne@69
|
313 U_INTERNAL void U_EXPORT2
|
jpayne@69
|
314 uplug_setContext(UPlugData *plug, void *context);
|
jpayne@69
|
315
|
jpayne@69
|
316
|
jpayne@69
|
317 /**
|
jpayne@69
|
318 * Get the configuration string, if available.
|
jpayne@69
|
319 * The string is in the platform default codepage.
|
jpayne@69
|
320 * @param plug plugin data handle
|
jpayne@69
|
321 * @return configuration string, or else null.
|
jpayne@69
|
322 * @internal ICU 4.4 Technology Preview
|
jpayne@69
|
323 */
|
jpayne@69
|
324 U_INTERNAL const char * U_EXPORT2
|
jpayne@69
|
325 uplug_getConfiguration(UPlugData *plug);
|
jpayne@69
|
326
|
jpayne@69
|
327 /**
|
jpayne@69
|
328 * Return all currently installed plugins, from newest to oldest
|
jpayne@69
|
329 * Usage Example:
|
jpayne@69
|
330 * \code
|
jpayne@69
|
331 * UPlugData *plug = NULL;
|
jpayne@69
|
332 * while(plug=uplug_nextPlug(plug)) {
|
jpayne@69
|
333 * ... do something with 'plug' ...
|
jpayne@69
|
334 * }
|
jpayne@69
|
335 * \endcode
|
jpayne@69
|
336 * Not thread safe- do not call while plugs are added or removed.
|
jpayne@69
|
337 * @param prior pass in 'NULL' to get the first (most recent) plug,
|
jpayne@69
|
338 * otherwise pass the value returned on a prior call to uplug_nextPlug
|
jpayne@69
|
339 * @return the next oldest plugin, or NULL if no more.
|
jpayne@69
|
340 * @internal ICU 4.4 Technology Preview
|
jpayne@69
|
341 */
|
jpayne@69
|
342 U_INTERNAL UPlugData* U_EXPORT2
|
jpayne@69
|
343 uplug_nextPlug(UPlugData *prior);
|
jpayne@69
|
344
|
jpayne@69
|
345 /**
|
jpayne@69
|
346 * Inject a plugin as if it were loaded from a library.
|
jpayne@69
|
347 * This is useful for testing plugins.
|
jpayne@69
|
348 * Note that it will have a 'NULL' library pointer associated
|
jpayne@69
|
349 * with it, and therefore no llibrary will be closed at cleanup time.
|
jpayne@69
|
350 * Low level plugins may not be able to load, as ordering can't be enforced.
|
jpayne@69
|
351 * @param entrypoint entrypoint to install
|
jpayne@69
|
352 * @param config user specified configuration string, if available, or NULL.
|
jpayne@69
|
353 * @param status error result
|
jpayne@69
|
354 * @return the new UPlugData associated with this plugin, or NULL if error.
|
jpayne@69
|
355 * @internal ICU 4.4 Technology Preview
|
jpayne@69
|
356 */
|
jpayne@69
|
357 U_INTERNAL UPlugData* U_EXPORT2
|
jpayne@69
|
358 uplug_loadPlugFromEntrypoint(UPlugEntrypoint *entrypoint, const char *config, UErrorCode *status);
|
jpayne@69
|
359
|
jpayne@69
|
360
|
jpayne@69
|
361 /**
|
jpayne@69
|
362 * Inject a plugin from a library, as if the information came from a config file.
|
jpayne@69
|
363 * Low level plugins may not be able to load, and ordering can't be enforced.
|
jpayne@69
|
364 * @param libName DLL name to load
|
jpayne@69
|
365 * @param sym symbol of plugin (UPlugEntrypoint function)
|
jpayne@69
|
366 * @param config configuration string, or NULL
|
jpayne@69
|
367 * @param status error result
|
jpayne@69
|
368 * @return the new UPlugData associated with this plugin, or NULL if error.
|
jpayne@69
|
369 * @internal ICU 4.4 Technology Preview
|
jpayne@69
|
370 */
|
jpayne@69
|
371 U_INTERNAL UPlugData* U_EXPORT2
|
jpayne@69
|
372 uplug_loadPlugFromLibrary(const char *libName, const char *sym, const char *config, UErrorCode *status);
|
jpayne@69
|
373
|
jpayne@69
|
374 /**
|
jpayne@69
|
375 * Remove a plugin.
|
jpayne@69
|
376 * Will request the plugin to be unloaded, and close the library if needed
|
jpayne@69
|
377 * @param plug plugin handle to close
|
jpayne@69
|
378 * @param status error result
|
jpayne@69
|
379 * @internal ICU 4.4 Technology Preview
|
jpayne@69
|
380 */
|
jpayne@69
|
381 U_INTERNAL void U_EXPORT2
|
jpayne@69
|
382 uplug_removePlug(UPlugData *plug, UErrorCode *status);
|
jpayne@69
|
383 #endif /* U_HIDE_INTERNAL_API */
|
jpayne@69
|
384
|
jpayne@69
|
385 #endif /* UCONFIG_ENABLE_PLUGINS */
|
jpayne@69
|
386
|
jpayne@69
|
387 #endif /* _ICUPLUG */
|
jpayne@69
|
388
|