Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief Source for internalnotification plugin
5 : *
6 : * @copyright BSD License (see doc/COPYING or http://www.libelektra.org)
7 : *
8 : */
9 :
10 : #include "internalnotification.h"
11 :
12 : #include <kdb.h>
13 : #include <kdbassert.h>
14 : #include <kdbhelper.h>
15 : #include <kdblogger.h>
16 : #include <kdbnotificationinternal.h>
17 :
18 : #include <ctype.h> // isspace()
19 : #include <errno.h> // errno
20 : #include <stdlib.h> // strto* functions
21 :
22 : /**
23 : * Structure for registered key variable pairs
24 : * @internal
25 : */
26 : struct _KeyRegistration
27 : {
28 : char * name;
29 : char * lastValue;
30 : int sameOrBelow;
31 : int freeContext;
32 : ElektraNotificationChangeCallback callback;
33 : void * context;
34 : struct _KeyRegistration * next;
35 : };
36 : typedef struct _KeyRegistration KeyRegistration;
37 :
38 : /**
39 : * Structure for internal plugin state
40 : * @internal
41 : */
42 : struct _PluginState
43 : {
44 : KeyRegistration * head;
45 : KeyRegistration * last;
46 : ElektraNotificationConversionErrorCallback conversionErrorCallback;
47 : void * conversionErrorCallbackContext;
48 : };
49 : typedef struct _PluginState PluginState;
50 :
51 : /**
52 : * @see kdbnotificationinternal.h ::ElektraNotificationSetConversionErrorCallback
53 : */
54 2 : static void elektraInternalnotificationSetConversionErrorCallback (Plugin * handle, ElektraNotificationConversionErrorCallback callback,
55 : void * context)
56 : {
57 2 : ELEKTRA_NOT_NULL (handle);
58 2 : ELEKTRA_NOT_NULL (callback);
59 2 : PluginState * data = elektraPluginGetData (handle);
60 2 : ELEKTRA_NOT_NULL (data);
61 :
62 2 : data->conversionErrorCallback = callback;
63 2 : data->conversionErrorCallbackContext = context;
64 2 : }
65 :
66 : /**
67 : * @internal
68 : * Check if two keys have the same name.
69 : * If one of the keys is cascading only the cascading names are compared.
70 : *
71 : * @param key key
72 : * @param check check
73 : * @retval 1 if keys have the same name
74 : * @retval 0 otherwise
75 : */
76 6 : static int checkKeyIsSame (Key * key, Key * check)
77 : {
78 6 : int result = 0;
79 6 : if (keyGetNamespace (check) == KEY_NS_CASCADING || keyGetNamespace (key) == KEY_NS_CASCADING)
80 : {
81 0 : const char * cascadingCheck = strrchr (keyName (check), '/');
82 0 : const char * cascadingKey = strrchr (keyName (key), '/');
83 0 : if (cascadingCheck != NULL && cascadingKey != NULL)
84 : {
85 0 : result = elektraStrCmp (cascadingKey, cascadingCheck) == 0;
86 : }
87 : else
88 : {
89 : if (cascadingCheck == NULL)
90 : {
91 : ELEKTRA_LOG_WARNING ("invalid key given: '%s' is not a valid key", cascadingCheck);
92 : }
93 : if (cascadingKey == NULL)
94 : {
95 : ELEKTRA_LOG_WARNING ("invalid key given: '%s' is not a valid key", cascadingKey);
96 : }
97 : }
98 : }
99 : else
100 : {
101 6 : result = elektraStrCmp (keyName (check), keyName (key)) == 0;
102 : }
103 6 : return result;
104 : }
105 :
106 : /**
107 : * @internal
108 : * Check if a key has the same name or is below a given key.
109 : *
110 : * @param key key
111 : * @param check check
112 : * @retval 1 if key has the same name or is below
113 : * @retval 0 otherwise
114 : */
115 10 : static int checkKeyIsBelowOrSame (Key * key, Key * check)
116 : {
117 10 : int result = 0;
118 10 : if (keyIsBelow (key, check))
119 : {
120 : result = 1;
121 : }
122 : else
123 : {
124 6 : result = checkKeyIsSame (key, check);
125 : }
126 :
127 10 : return result;
128 : }
129 :
130 : /**
131 : * @internal
132 : * Call kdbGet if there are registrations below the changed key.
133 : *
134 : * On kdbGet this plugin implicitly updates registered keys.
135 : *
136 : * @see ElektraNotificationChangeCallback (kdbnotificationinternal.h)
137 : * @param key changed key
138 : * @param context callback context
139 : */
140 10 : void elektraInternalnotificationDoUpdate (Key * changedKey, ElektraNotificationCallbackContext * context)
141 : {
142 10 : ELEKTRA_NOT_NULL (changedKey);
143 10 : ELEKTRA_NOT_NULL (context);
144 :
145 10 : Plugin * plugin = context->notificationPlugin;
146 :
147 10 : PluginState * pluginState = elektraPluginGetData (plugin);
148 10 : ELEKTRA_NOT_NULL (pluginState);
149 :
150 10 : int kdbChanged = 0;
151 10 : KeyRegistration * keyRegistration = pluginState->head;
152 28 : while (keyRegistration != NULL)
153 : {
154 8 : Key * registeredKey = keyNew (keyRegistration->name, KEY_END);
155 :
156 : // check if registered key is same or below changed/commit key
157 8 : kdbChanged |= checkKeyIsBelowOrSame (changedKey, registeredKey);
158 :
159 8 : if (keyRegistration->sameOrBelow)
160 : {
161 : // check if registered key is also above changed/commit key
162 2 : kdbChanged |= checkKeyIsBelowOrSame (registeredKey, changedKey);
163 : }
164 :
165 8 : keyRegistration = keyRegistration->next;
166 8 : keyDel (registeredKey);
167 : }
168 :
169 10 : if (kdbChanged)
170 : {
171 6 : context->kdbUpdate (context->kdb, changedKey);
172 : }
173 10 : keyDel (changedKey);
174 10 : }
175 :
176 : /**
177 : * Creates a new KeyRegistration structure and appends it at the end of the registration list
178 : * @internal
179 : *
180 : * @param pluginState internal plugin data structure
181 : * @param key key
182 : * @param callback callback for changes
183 : * @param context context for callback
184 : * @param freeContext context needs to be freed on close
185 : *
186 : * @return pointer to created KeyRegistration structure or NULL if memory allocation failed
187 : */
188 106 : static KeyRegistration * elektraInternalnotificationAddNewRegistration (PluginState * pluginState, Key * key,
189 : ElektraNotificationChangeCallback callback, void * context,
190 : int freeContext)
191 : {
192 106 : KeyRegistration * item = elektraMalloc (sizeof *item);
193 106 : if (item == NULL)
194 : {
195 : return NULL;
196 : }
197 106 : item->next = NULL;
198 106 : item->lastValue = NULL;
199 106 : item->name = elektraStrDup (keyName (key));
200 106 : item->callback = callback;
201 106 : item->context = context;
202 106 : item->sameOrBelow = 0;
203 106 : item->freeContext = freeContext;
204 :
205 106 : if (pluginState->head == NULL)
206 : {
207 : // Initialize list
208 106 : pluginState->head = pluginState->last = item;
209 : }
210 : else
211 : {
212 : // Make new item end of list
213 0 : pluginState->last->next = item;
214 0 : pluginState->last = item;
215 : }
216 :
217 : return item;
218 : }
219 :
220 : /**
221 : * @internal
222 : * Check if a key set contains a key that is same or below a given key.
223 : *
224 : * @param key key
225 : * @param ks key set
226 : * @retval 1 if the key set contains the key
227 : * @retval 0 otherwise
228 : */
229 0 : static int keySetContainsSameOrBelow (Key * check, KeySet * ks)
230 : {
231 : Key * current;
232 0 : ksRewind (ks);
233 0 : while ((current = ksNext (ks)) != NULL)
234 : {
235 0 : if (checkKeyIsBelowOrSame (check, current))
236 : {
237 : return 1;
238 : }
239 : }
240 : return 0;
241 : }
242 :
243 : /**
244 : * Updates all KeyRegistrations according to data from the given KeySet
245 : * @internal
246 : *
247 : * @param plugin internal plugin handle
248 : * @param keySet key set retrieved from hooks
249 : * e.g. elektraInternalnotificationGet or elektraInternalnotificationSet)
250 : *
251 : */
252 104 : void elektraInternalnotificationUpdateRegisteredKeys (Plugin * plugin, KeySet * keySet)
253 : {
254 104 : PluginState * pluginState = elektraPluginGetData (plugin);
255 104 : ELEKTRA_ASSERT (pluginState != NULL, "plugin state was not initialized properly");
256 :
257 104 : KeyRegistration * registeredKey = pluginState->head;
258 308 : while (registeredKey != NULL)
259 : {
260 100 : int changed = 0;
261 : Key * key;
262 100 : if (registeredKey->sameOrBelow)
263 : {
264 0 : Key * checkKey = keyNew (registeredKey->name, KEY_END);
265 0 : if (keySetContainsSameOrBelow (checkKey, keySet))
266 : {
267 : changed = 1;
268 : key = checkKey;
269 : }
270 : else
271 : {
272 0 : keyDel (checkKey);
273 : }
274 : }
275 : else
276 : {
277 100 : key = ksLookupByName (keySet, registeredKey->name, 0);
278 100 : if (key != NULL)
279 : {
280 : // Detect changes for string keys
281 100 : if (!keyIsString (key))
282 : {
283 : // always notify for binary keys
284 : changed = 1;
285 : }
286 : else
287 : {
288 100 : const char * currentValue = keyString (key);
289 100 : changed = registeredKey->lastValue == NULL || strcmp (currentValue, registeredKey->lastValue) != 0;
290 :
291 100 : if (changed)
292 : {
293 : // Save last value
294 98 : char * buffer = elektraStrDup (currentValue);
295 98 : if (buffer)
296 : {
297 98 : if (registeredKey->lastValue != NULL)
298 : {
299 : // Free previous value
300 0 : elektraFree (registeredKey->lastValue);
301 : }
302 98 : registeredKey->lastValue = buffer;
303 : }
304 : }
305 : }
306 : }
307 : }
308 :
309 100 : if (changed)
310 : {
311 : ELEKTRA_LOG_DEBUG ("found changed registeredKey=%s with string value \"%s\". using context or variable=%p",
312 : registeredKey->name, keyString (key), registeredKey->context);
313 :
314 : // Invoke callback
315 98 : ElektraNotificationChangeCallback callback = *(ElektraNotificationChangeCallback) registeredKey->callback;
316 98 : callback (key, registeredKey->context);
317 98 : if (registeredKey->sameOrBelow)
318 : {
319 0 : keyDel (key);
320 : }
321 : }
322 :
323 : // proceed with next registered key
324 100 : registeredKey = registeredKey->next;
325 : }
326 104 : }
327 :
328 : // Generate register and conversion functions
329 : // for built-in C types
330 : #define TYPE int
331 : #define VALUE_TYPE long int
332 : #define TYPE_NAME Int
333 : #define TO_VALUE (strtol (string, &end, 10))
334 : #define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION_RANGE (value <= INT_MAX && value >= INT_MIN)
335 : #include "macros/add_type.h"
336 :
337 : #define TYPE unsigned int
338 : #define VALUE_TYPE unsigned long int
339 : #define TYPE_NAME UnsignedInt
340 : #define TO_VALUE (strtoul (string, &end, 10))
341 : #define PRE_CHECK_BLOCK ELEKTRA_TYPE_NEGATIVE_PRE_CHECK_BLOCK
342 : #define PRE_CHECK_CONVERSION ELEKTRA_TYPE_NEGATIVE_PRE_CHECK
343 : #define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION_RANGE (value <= UINT_MAX)
344 : #include "macros/add_type.h"
345 :
346 : #define TYPE long
347 : #define TYPE_NAME Long
348 : #define TO_VALUE (strtol (string, &end, 10))
349 : #define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION
350 : #include "macros/add_type.h"
351 :
352 : #define TYPE unsigned long
353 : #define TYPE_NAME UnsignedLong
354 : #define TO_VALUE (strtoul (string, &end, 10))
355 : #define PRE_CHECK_BLOCK ELEKTRA_TYPE_NEGATIVE_PRE_CHECK_BLOCK
356 : #define PRE_CHECK_CONVERSION ELEKTRA_TYPE_NEGATIVE_PRE_CHECK
357 : #define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION
358 : #include "macros/add_type.h"
359 :
360 : #define TYPE long long
361 : #define TYPE_NAME LongLong
362 : #define TO_VALUE (strtoll (string, &end, 10))
363 : #define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION
364 : #include "macros/add_type.h"
365 :
366 : #define TYPE unsigned long long
367 : #define TYPE_NAME UnsignedLongLong
368 : #define TO_VALUE (strtoull (string, &end, 10))
369 : #define PRE_CHECK_BLOCK ELEKTRA_TYPE_NEGATIVE_PRE_CHECK_BLOCK
370 : #define PRE_CHECK_CONVERSION ELEKTRA_TYPE_NEGATIVE_PRE_CHECK
371 : #define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION
372 : #include "macros/add_type.h"
373 :
374 : #define TYPE float
375 : #define TYPE_NAME Float
376 : #define TO_VALUE (strtof (string, &end))
377 : #define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION
378 : #include "macros/add_type.h"
379 :
380 : #define TYPE double
381 : #define TYPE_NAME Double
382 : #define TO_VALUE (strtod (string, &end))
383 : #define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION
384 : #include "macros/add_type.h"
385 :
386 : // for kdb_*_t Types
387 : #define TYPE kdb_boolean_t
388 : #define TYPE_NAME KdbBoolean
389 : #define TO_VALUE (!strcmp (string, "1"))
390 : #include "macros/add_type.h"
391 :
392 : #define TYPE kdb_char_t
393 : #define TYPE_NAME KdbChar
394 : #define TO_VALUE (string[0])
395 : #include "macros/add_type.h"
396 :
397 : #define TYPE kdb_octet_t
398 : #define VALUE_TYPE unsigned int
399 : #define TYPE_NAME KdbOctet
400 : #define TO_VALUE (strtoul (string, &end, 10))
401 : #define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION_RANGE (value <= 255)
402 : #include "macros/add_type.h"
403 :
404 : #define TYPE kdb_short_t
405 : #define VALUE_TYPE int
406 : #define TYPE_NAME KdbShort
407 : #define TO_VALUE (strtol (string, &end, 10))
408 : #define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION_RANGE (value <= SHRT_MAX && value >= SHRT_MIN)
409 : #include "macros/add_type.h"
410 :
411 : #define TYPE kdb_unsigned_short_t
412 : #define VALUE_TYPE unsigned int
413 : #define TYPE_NAME KdbUnsignedShort
414 : #define TO_VALUE (strtoul (string, &end, 10))
415 : #define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION_RANGE (value <= USHRT_MAX)
416 : #include "macros/add_type.h"
417 :
418 : #define TYPE kdb_long_t
419 : #define TYPE_NAME KdbLong
420 : #define TO_VALUE (strtol (string, &end, 10))
421 : #define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION
422 : #include "macros/add_type.h"
423 :
424 : #define TYPE kdb_unsigned_long_t
425 : #define TYPE_NAME KdbUnsignedLong
426 : #define TO_VALUE (strtoul (string, &end, 10))
427 : #define PRE_CHECK_BLOCK ELEKTRA_TYPE_NEGATIVE_PRE_CHECK_BLOCK
428 : #define PRE_CHECK_CONVERSION ELEKTRA_TYPE_NEGATIVE_PRE_CHECK
429 : #define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION
430 : #include "macros/add_type.h"
431 :
432 : #define TYPE kdb_long_long_t
433 : #define TYPE_NAME KdbLongLong
434 : #define TO_VALUE (ELEKTRA_LONG_LONG_S (string, &end, 10))
435 : #define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION
436 : #include "macros/add_type.h"
437 :
438 : #define TYPE kdb_unsigned_long_long_t
439 : #define TYPE_NAME KdbUnsignedLongLong
440 : #define TO_VALUE (ELEKTRA_UNSIGNED_LONG_LONG_S (string, &end, 10))
441 : #define PRE_CHECK_BLOCK ELEKTRA_TYPE_NEGATIVE_PRE_CHECK_BLOCK
442 : #define PRE_CHECK_CONVERSION ELEKTRA_TYPE_NEGATIVE_PRE_CHECK
443 : #define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION
444 : #include "macros/add_type.h"
445 :
446 : #define TYPE kdb_float_t
447 : #define TYPE_NAME KdbFloat
448 : #define TO_VALUE (strtof (string, &end))
449 : #define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION
450 : #include "macros/add_type.h"
451 :
452 : #define TYPE kdb_double_t
453 : #define TYPE_NAME KdbDouble
454 : #define TO_VALUE (strtod (string, &end))
455 : #define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION
456 : #include "macros/add_type.h"
457 :
458 : #define TYPE kdb_long_double_t
459 : #define TYPE_NAME KdbLongDouble
460 : #define TO_VALUE (strtold (string, &end))
461 : #define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION
462 : #include "macros/add_type.h"
463 :
464 : /**
465 : * @see kdbnotificationinternal.h ::ElektraNotificationPluginRegisterCallback
466 : */
467 12 : int elektraInternalnotificationRegisterCallback (Plugin * handle, Key * key, ElektraNotificationChangeCallback callback, void * context)
468 : {
469 12 : PluginState * pluginState = elektraPluginGetData (handle);
470 12 : ELEKTRA_ASSERT (pluginState != NULL, "plugin state was not initialized properly");
471 :
472 12 : KeyRegistration * registeredKey = elektraInternalnotificationAddNewRegistration (pluginState, key, callback, context, 0);
473 12 : if (registeredKey == NULL)
474 : {
475 : return 0;
476 : }
477 :
478 12 : return 1;
479 : }
480 :
481 : /**
482 : * @see kdbnotificationinternal.h ::ElektraNotificationPluginRegisterCallbackSameOrBelow
483 : */
484 2 : int elektraInternalnotificationRegisterCallbackSameOrBelow (Plugin * handle, Key * key, ElektraNotificationChangeCallback callback,
485 : void * context)
486 : {
487 2 : PluginState * pluginState = elektraPluginGetData (handle);
488 2 : ELEKTRA_ASSERT (pluginState != NULL, "plugin state was not initialized properly");
489 :
490 2 : KeyRegistration * registeredKey = elektraInternalnotificationAddNewRegistration (pluginState, key, callback, context, 0);
491 2 : if (registeredKey == NULL)
492 : {
493 : return 0;
494 : }
495 2 : registeredKey->sameOrBelow = 1;
496 :
497 2 : return 1;
498 : }
499 :
500 : /**
501 : * Updates registrations with current data from storage.
502 : * Part of elektra plugin contract.
503 : *
504 : * @param handle plugin handle
505 : * @param returned key set containing current data from storage
506 : * @param parentKey key for errors
507 : *
508 : * @retval 1 on success
509 : * @retval -1 on failure
510 : */
511 1032 : int elektraInternalnotificationGet (Plugin * handle, KeySet * returned, Key * parentKey)
512 : {
513 1032 : if (!elektraStrCmp (keyName (parentKey), "system/elektra/modules/internalnotification"))
514 : {
515 1024 : KeySet * contract = ksNew (
516 : 30,
517 : keyNew ("system/elektra/modules/internalnotification", KEY_VALUE,
518 : "internalnotification plugin waits for your orders", KEY_END),
519 : keyNew ("system/elektra/modules/internalnotification/exports", KEY_END),
520 : keyNew ("system/elektra/modules/internalnotification/exports/get", KEY_FUNC, elektraInternalnotificationGet,
521 : KEY_END),
522 : keyNew ("system/elektra/modules/internalnotification/exports/set", KEY_FUNC, elektraInternalnotificationSet,
523 : KEY_END),
524 : keyNew ("system/elektra/modules/internalnotification/exports/open", KEY_FUNC, elektraInternalnotificationOpen,
525 : KEY_END),
526 : keyNew ("system/elektra/modules/internalnotification/exports/close", KEY_FUNC, elektraInternalnotificationClose,
527 : KEY_END),
528 :
529 : keyNew ("system/elektra/modules/internalnotification/exports/notificationCallback", KEY_FUNC,
530 : elektraInternalnotificationDoUpdate, KEY_END),
531 :
532 : // Export register* functions
533 : INTERNALNOTIFICATION_EXPORT_FUNCTION (Int), INTERNALNOTIFICATION_EXPORT_FUNCTION (UnsignedInt),
534 : INTERNALNOTIFICATION_EXPORT_FUNCTION (Long), INTERNALNOTIFICATION_EXPORT_FUNCTION (UnsignedLong),
535 : INTERNALNOTIFICATION_EXPORT_FUNCTION (LongLong), INTERNALNOTIFICATION_EXPORT_FUNCTION (UnsignedLongLong),
536 : INTERNALNOTIFICATION_EXPORT_FUNCTION (Float), INTERNALNOTIFICATION_EXPORT_FUNCTION (Double),
537 :
538 : // Export register* functions for kdb_*_t types
539 : INTERNALNOTIFICATION_EXPORT_FUNCTION (KdbBoolean), INTERNALNOTIFICATION_EXPORT_FUNCTION (KdbChar),
540 : INTERNALNOTIFICATION_EXPORT_FUNCTION (KdbOctet), INTERNALNOTIFICATION_EXPORT_FUNCTION (KdbShort),
541 : INTERNALNOTIFICATION_EXPORT_FUNCTION (KdbUnsignedShort), INTERNALNOTIFICATION_EXPORT_FUNCTION (KdbLong),
542 : INTERNALNOTIFICATION_EXPORT_FUNCTION (KdbUnsignedLong), INTERNALNOTIFICATION_EXPORT_FUNCTION (KdbLongLong),
543 : INTERNALNOTIFICATION_EXPORT_FUNCTION (KdbUnsignedLongLong), INTERNALNOTIFICATION_EXPORT_FUNCTION (KdbFloat),
544 : INTERNALNOTIFICATION_EXPORT_FUNCTION (KdbDouble), INTERNALNOTIFICATION_EXPORT_FUNCTION (KdbLongDouble),
545 :
546 : keyNew ("system/elektra/modules/internalnotification/exports/registerCallback", KEY_FUNC,
547 : elektraInternalnotificationRegisterCallback, KEY_END),
548 : keyNew ("system/elektra/modules/internalnotification/exports/registerCallbackSameOrBelow", KEY_FUNC,
549 : elektraInternalnotificationRegisterCallbackSameOrBelow, KEY_END),
550 : keyNew ("system/elektra/modules/internalnotification/exports/setConversionErrorCallback", KEY_FUNC,
551 : elektraInternalnotificationSetConversionErrorCallback, KEY_END),
552 :
553 : #include ELEKTRA_README
554 :
555 : keyNew ("system/elektra/modules/internalnotification/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END);
556 1024 : ksAppend (returned, contract);
557 1024 : ksDel (contract);
558 :
559 1024 : return 1;
560 : }
561 :
562 8 : elektraInternalnotificationUpdateRegisteredKeys (handle, returned);
563 :
564 8 : return 1;
565 : }
566 :
567 : /**
568 : * Updates registrations with data written by the application.
569 : * Part of elektra plugin contract.
570 : *
571 : * @param handle plugin handle
572 : * @param returned key set containing current data from the application
573 : * @param parentKey key for errors
574 :
575 : * @retval 1 on success
576 : * @retval -1 on failure
577 : */
578 4 : int elektraInternalnotificationSet (Plugin * handle, KeySet * returned, Key * parentKey ELEKTRA_UNUSED)
579 : {
580 4 : elektraInternalnotificationUpdateRegisteredKeys (handle, returned);
581 :
582 4 : return 1;
583 : }
584 :
585 : /**
586 : * Initialize data plugin data structures.
587 : * Part of elektra plugin contract.
588 : *
589 : * @param handle plugin handle
590 : * @param parentKey key for errors
591 : *
592 : * @retval 1 on success
593 : * @retval -1 on failure
594 : */
595 136 : int elektraInternalnotificationOpen (Plugin * handle, Key * parentKey ELEKTRA_UNUSED)
596 : {
597 136 : PluginState * pluginState = elektraPluginGetData (handle);
598 136 : if (pluginState == NULL)
599 : {
600 134 : pluginState = elektraMalloc (sizeof *pluginState);
601 134 : if (pluginState == NULL)
602 : {
603 : return -1;
604 : }
605 134 : elektraPluginSetData (handle, pluginState);
606 :
607 : // Initialize list pointers for registered keys
608 134 : pluginState->head = NULL;
609 134 : pluginState->last = NULL;
610 134 : pluginState->conversionErrorCallback = NULL;
611 134 : pluginState->conversionErrorCallbackContext = NULL;
612 : }
613 :
614 : return 1;
615 : }
616 :
617 : /**
618 : * Free used memory.
619 : * Part of elektra plugin contract.
620 : *
621 : * @param handle plugin handle
622 : * @param parentKey key for errors
623 : *
624 : * @retval 1 on success
625 : * @retval -1 on failure
626 : */
627 136 : int elektraInternalnotificationClose (Plugin * handle, Key * parentKey ELEKTRA_UNUSED)
628 : {
629 136 : PluginState * pluginState = elektraPluginGetData (handle);
630 136 : if (pluginState != NULL)
631 : {
632 : // Free registrations
633 134 : KeyRegistration * current = pluginState->head;
634 : KeyRegistration * next;
635 374 : while (current != NULL)
636 : {
637 106 : next = current->next;
638 106 : elektraFree (current->name);
639 106 : if (current->lastValue != NULL)
640 : {
641 98 : elektraFree (current->lastValue);
642 : }
643 106 : if (current->freeContext)
644 : {
645 92 : elektraFree (current->context);
646 : }
647 106 : elektraFree (current);
648 :
649 106 : current = next;
650 : }
651 :
652 : // Free list pointer
653 134 : elektraFree (pluginState);
654 134 : elektraPluginSetData (handle, NULL);
655 : }
656 :
657 136 : return 1;
658 : }
659 :
660 134 : Plugin * ELEKTRA_PLUGIN_EXPORT
661 : {
662 : // clang-format off
663 134 : return elektraPluginExport ("internalnotification",
664 : ELEKTRA_PLUGIN_GET, &elektraInternalnotificationGet,
665 : ELEKTRA_PLUGIN_SET, &elektraInternalnotificationSet,
666 : ELEKTRA_PLUGIN_OPEN, &elektraInternalnotificationOpen,
667 : ELEKTRA_PLUGIN_CLOSE, &elektraInternalnotificationClose,
668 : ELEKTRA_PLUGIN_END);
669 : }
|