LCOV - code coverage report
Current view: top level - src/plugins/internalnotification - internalnotification.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 124 139 89.2 %
Date: 2019-09-12 12:28:41 Functions: 13 15 86.7 %

          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             : }

Generated by: LCOV version 1.13