LCOV - code coverage report
Current view: top level - src/plugins/type - type.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 156 181 86.2 %
Date: 2019-09-12 12:28:41 Functions: 12 13 92.3 %

          Line data    Source code
       1             : /**
       2             :  * @file
       3             :  *
       4             :  * @brief
       5             :  *
       6             :  * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
       7             :  *
       8             :  */
       9             : 
      10             : 
      11             : #include "type.h"
      12             : #include "types.h"
      13             : 
      14             : #include <kdbease.h>
      15             : #include <kdberrors.h>
      16             : 
      17             : struct _Type
      18             : {
      19             :         const char * name;
      20             :         bool (*normalize) (Plugin * handle, Key * key);
      21             :         bool (*check) (const Key * key);
      22             :         bool (*restore) (Plugin * handle, Key * key);
      23             :         void (*setError) (Plugin * handle, Key * errorKey, const Key * key);
      24             : };
      25             : 
      26             : static void elektraTypeSetDefaultError (Plugin * handle, Key * errorKey, const Key * key);
      27             : 
      28             : static const Type elektraTypesList[] = {
      29             :         { "any", NULL, &elektraTypeCheckAny, NULL, &elektraTypeSetDefaultError },
      30             :         { "string", NULL, &elektraTypeCheckString, NULL, &elektraTypeSetDefaultError },
      31             :         { "wstring", NULL, &elektraTypeCheckWString, NULL, &elektraTypeSetDefaultError },
      32             :         { "char", NULL, &elektraTypeCheckChar, NULL, &elektraTypeSetDefaultError },
      33             :         { "wchar", NULL, &elektraTypeCheckWChar, NULL, &elektraTypeSetDefaultError },
      34             :         { "octet", NULL, &elektraTypeCheckChar, NULL, &elektraTypeSetDefaultError },
      35             :         { "short", NULL, &elektraTypeCheckShort, NULL, &elektraTypeSetDefaultError },
      36             :         { "long", NULL, &elektraTypeCheckLong, NULL, &elektraTypeSetDefaultError },
      37             :         { "long_long", NULL, &elektraTypeCheckLongLong, NULL, &elektraTypeSetDefaultError },
      38             :         { "unsigned_short", NULL, &elektraTypeCheckUnsignedShort, NULL, &elektraTypeSetDefaultError },
      39             :         { "unsigned_long", NULL, &elektraTypeCheckUnsignedLong, NULL, &elektraTypeSetDefaultError },
      40             :         { "unsigned_long_long", NULL, &elektraTypeCheckUnsignedLongLong, NULL, &elektraTypeSetDefaultError },
      41             :         { "float", NULL, &elektraTypeCheckFloat, NULL, &elektraTypeSetDefaultError },
      42             :         { "double", NULL, &elektraTypeCheckDouble, NULL, &elektraTypeSetDefaultError },
      43             : #ifdef ELEKTRA_HAVE_KDB_LONG_DOUBLE
      44             :         { "long_double", NULL, &elektraTypeCheckLongDouble, NULL, &elektraTypeSetDefaultError },
      45             : #endif
      46             :         { "boolean", &elektraTypeNormalizeBoolean, &elektraTypeCheckBoolean, &elektraTypeRestoreBoolean, &elektraTypeSetDefaultError },
      47             :         { "enum", &elektraTypeNormalizeEnum, &elektraTypeCheckEnum, &elektraTypeRestoreEnum, &elektraTypeSetErrorEnum },
      48             :         { NULL, NULL, NULL, NULL, NULL }
      49             : };
      50             : 
      51             : static const Type * findType (const char * name)
      52             : {
      53             :         const Type * cur = &elektraTypesList[0];
      54      670502 :         while (cur->name != NULL)
      55             :         {
      56      670502 :                 if (strcmp (cur->name, name) == 0)
      57             :                 {
      58             :                         return cur;
      59             :                 }
      60      537730 :                 ++cur;
      61             :         }
      62             :         return NULL;
      63             : }
      64             : 
      65      132884 : static const char * getTypeName (const Key * key)
      66             : {
      67      132884 :         const Key * meta = keyGetMeta (key, "check/type");
      68      132884 :         if (meta == NULL)
      69             :         {
      70         368 :                 meta = keyGetMeta (key, "type");
      71             :         }
      72             : 
      73      132884 :         if (meta == NULL)
      74             :         {
      75             :                 return NULL;
      76             :         }
      77             : 
      78      132776 :         const char * type = keyString (meta);
      79      132776 :         return strlen (type) == 0 ? NULL : type;
      80             : }
      81             : 
      82      132208 : bool elektraTypeCheckType (const Key * key)
      83             : {
      84      132208 :         const char * typeName = getTypeName (key);
      85      132208 :         if (typeName == NULL)
      86             :         {
      87             :                 return true;
      88             :         }
      89             : 
      90      132198 :         const Type * type = findType (typeName);
      91      132198 :         return type != NULL && type->check (key);
      92             : }
      93             : 
      94           4 : static void elektraTypeSetDefaultError (Plugin * handle ELEKTRA_UNUSED, Key * errorKey, const Key * key)
      95             : {
      96           4 :         ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (errorKey, "The type '%s' failed to match for '%s' with string '%s'", getTypeName (key),
      97             :                                                 keyName (key), keyString (key));
      98           4 : }
      99             : 
     100           4 : bool elektraTypeValidateKey (Plugin * handle, Key * key, Key * errorKey)
     101             : {
     102           4 :         const char * typeName = getTypeName (key);
     103           4 :         if (typeName == NULL)
     104             :         {
     105             :                 return true;
     106             :         }
     107             : 
     108           4 :         const Type * type = findType (typeName);
     109           4 :         if (type == NULL)
     110             :         {
     111           0 :                 ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (errorKey, "Unknown type '%s' for key '%s'", typeName, keyName (key));
     112           0 :                 return false;
     113             :         }
     114             : 
     115           4 :         if (type->normalize != NULL && !type->normalize (handle, key))
     116             :         {
     117           0 :                 ELEKTRA_SET_VALIDATION_SYNTACTIC_ERRORF (errorKey, "The value '%s' of key '%s' could not be normalized (type is '%s')",
     118             :                                                          keyString (key), keyName (key), typeName);
     119           0 :                 return false;
     120             :         }
     121             : 
     122           4 :         if (!type->check (key))
     123             :         {
     124           2 :                 type->setError (handle, errorKey, key);
     125           2 :                 return false;
     126             :         }
     127             : 
     128           2 :         if (type->restore != NULL && !type->restore (handle, key))
     129             :         {
     130           0 :                 ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (errorKey,
     131             :                                                         "The normalized value '%s' of key '%s' could not be restored (type is '%s')",
     132             :                                                         keyString (key), keyName (key), typeName);
     133           0 :                 return false;
     134             :         }
     135             : 
     136             :         return true;
     137             : }
     138             : 
     139         701 : static kdb_long_long_t readBooleans (KeySet * config, struct boolean_pair ** result, Key * errorKey)
     140             : {
     141         701 :         Key * parent = ksLookupByName (config, "/booleans", 0);
     142         701 :         const char * max = keyString (parent);
     143         701 :         if (parent == NULL || strlen (max) == 0)
     144             :         {
     145         687 :                 *result = NULL;
     146         687 :                 return -1;
     147             :         }
     148             : 
     149          14 :         kdb_long_long_t index = 0;
     150             :         char buffer[10 + ELEKTRA_MAX_ARRAY_SIZE + 6];
     151          14 :         strcpy (buffer, "/booleans/");
     152          14 :         char * indexPos = &buffer[10];
     153          14 :         elektraWriteArrayNumber (indexPos, index);
     154             : 
     155          14 :         if (strcmp (indexPos, max) > 0)
     156             :         {
     157           0 :                 *result = NULL;
     158           0 :                 return 0;
     159             :         }
     160             : 
     161          14 :         kdb_long_long_t size = 0;
     162          14 :         *result = elektraMalloc (sizeof (struct boolean_pair));
     163          56 :         while (strcmp (indexPos, max) <= 0)
     164             :         {
     165          30 :                 char * subPos = &buffer[strlen (buffer)];
     166          30 :                 strcpy (subPos, "/true");
     167          30 :                 Key * trueKey = ksLookupByName (config, buffer, 0);
     168          30 :                 strcpy (subPos, "/false");
     169          30 :                 Key * falseKey = ksLookupByName (config, buffer, 0);
     170             : 
     171          30 :                 *subPos = '\0';
     172          30 :                 if ((trueKey == NULL) != (falseKey == NULL))
     173             :                 {
     174           2 :                         ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (
     175             :                                 errorKey, "You must set both true and false for a boolean pair (config key: '%s')", buffer);
     176           2 :                         elektraFree (*result);
     177           2 :                         *result = NULL;
     178           2 :                         return -2;
     179             :                 }
     180             : 
     181             : 
     182          28 :                 elektraRealloc ((void **) result, (size + 1) * sizeof (struct boolean_pair));
     183             : 
     184          28 :                 (*result)[size].trueValue = keyString (trueKey);
     185          28 :                 (*result)[size].falseValue = keyString (falseKey);
     186          28 :                 ++size;
     187             : 
     188          28 :                 ++index;
     189          28 :                 elektraWriteArrayNumber (indexPos, index);
     190             :         }
     191             : 
     192             :         return size;
     193             : }
     194             : 
     195             : /**
     196             :  * Reads the value of the config key /boolean/restoreas.
     197             :  *
     198             :  * @p config The config KeySet obtained from elektraPluginGetConfig().
     199             :  *
     200             :  * @retval -3 on error
     201             :  * @retval -2 if /boolean/restoreas = none
     202             :  * @retval -1 if /boolean/restoreas is unset
     203             :  * @retval >= 0 index of chosen boolean pair
     204             :  */
     205         686 : static kdb_long_long_t readBooleanRestore (KeySet * config)
     206             : {
     207         686 :         Key * restore = ksLookupByName (config, "/boolean/restoreas", 0);
     208         686 :         if (restore == NULL)
     209             :         {
     210             :                 return -1;
     211             :         }
     212             : 
     213          32 :         const char * restoreString = keyString (restore);
     214             : 
     215          32 :         if (strcmp (restoreString, "none") == 0)
     216             :         {
     217             :                 return -2;
     218             :         }
     219             : 
     220          28 :         int digitStart = elektraArrayValidateBaseNameString (restoreString);
     221          28 :         if (digitStart <= 0)
     222             :         {
     223             :                 return -3;
     224             :         }
     225             : 
     226          28 :         Key * restoreKey = keyNew ("", KEY_VALUE, &restoreString[digitStart], KEY_END);
     227             : 
     228             :         kdb_long_long_t size;
     229          28 :         if (!elektraKeyToLongLong (restoreKey, &size))
     230             :         {
     231           0 :                 keyDel (restoreKey);
     232           0 :                 return -3;
     233             :         }
     234             : 
     235          28 :         keyDel (restoreKey);
     236             : 
     237          28 :         return size;
     238             : }
     239             : 
     240         688 : int elektraTypeOpen (Plugin * handle, Key * errorKey)
     241             : {
     242         688 :         KeySet * conf = elektraPluginGetConfig (handle);
     243         688 :         TypeData * data = elektraMalloc (sizeof (TypeData));
     244             : 
     245         688 :         kdb_long_long_t result = readBooleans (conf, &data->booleans, errorKey);
     246         688 :         if (result < -1)
     247             :         {
     248           2 :                 elektraFree (data);
     249           2 :                 return ELEKTRA_PLUGIN_STATUS_ERROR;
     250             :         }
     251             : 
     252         686 :         if (result == -1)
     253             :         {
     254         674 :                 data->booleans = elektraMalloc (sizeof (struct boolean_pair) * 5);
     255         674 :                 data->booleans[0] = (struct boolean_pair){ "yes", "no" };
     256         674 :                 data->booleans[1] = (struct boolean_pair){ "true", "false" };
     257         674 :                 data->booleans[2] = (struct boolean_pair){ "on", "off" };
     258         674 :                 data->booleans[3] = (struct boolean_pair){ "enabled", "disabled" };
     259         674 :                 data->booleans[4] = (struct boolean_pair){ "enable", "disable" };
     260         674 :                 data->booleanCount = 5;
     261             :         }
     262             :         else
     263             :         {
     264          12 :                 data->booleanCount = result;
     265             :         }
     266             : 
     267         686 :         data->booleanRestore = readBooleanRestore (conf);
     268         686 :         if (data->booleanRestore < -2 || data->booleanRestore >= data->booleanCount)
     269             :         {
     270           0 :                 ELEKTRA_SET_VALIDATION_SEMANTIC_ERROR (errorKey, "The value of the config key /boolean/restoreas was invalid");
     271           0 :                 elektraFree (data);
     272           0 :                 return ELEKTRA_PLUGIN_STATUS_ERROR;
     273             :         }
     274             : 
     275         686 :         elektraPluginSetData (handle, data);
     276             : 
     277         686 :         return ELEKTRA_PLUGIN_STATUS_SUCCESS;
     278             : }
     279             : 
     280         474 : int elektraTypeGet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned, Key * parentKey)
     281             : {
     282         474 :         if (!elektraStrCmp (keyName (parentKey), "system/elektra/modules/type"))
     283             :         {
     284         162 :                 KeySet * contract =
     285         162 :                         ksNew (30, keyNew ("system/elektra/modules/type", KEY_VALUE, "type plugin waits for your orders", KEY_END),
     286             :                                keyNew ("system/elektra/modules/type/exports", KEY_END),
     287             :                                keyNew ("system/elektra/modules/type/exports/open", KEY_FUNC, elektraTypeOpen, KEY_END),
     288             :                                keyNew ("system/elektra/modules/type/exports/get", KEY_FUNC, elektraTypeGet, KEY_END),
     289             :                                keyNew ("system/elektra/modules/type/exports/set", KEY_FUNC, elektraTypeSet, KEY_END),
     290             :                                keyNew ("system/elektra/modules/type/exports/close", KEY_FUNC, elektraTypeClose, KEY_END),
     291             :                                keyNew ("system/elektra/modules/type/exports/checkconf", KEY_FUNC, elektraTypeCheckConf, KEY_END),
     292             :                                keyNew ("system/elektra/modules/type/exports/validateKey", KEY_FUNC, elektraTypeValidateKey, KEY_END),
     293             : #include ELEKTRA_README
     294             :                                keyNew ("system/elektra/modules/type/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END);
     295         162 :                 ksAppend (returned, contract);
     296         162 :                 ksDel (contract);
     297             : 
     298         162 :                 return ELEKTRA_PLUGIN_STATUS_SUCCESS;
     299             :         }
     300             : 
     301         312 :         cursor_t cursor = ksGetCursor (returned);
     302             : 
     303         312 :         ksRewind (returned);
     304             : 
     305         312 :         Key * cur = NULL;
     306         996 :         while ((cur = ksNext (returned)))
     307             :         {
     308         380 :                 const char * typeName = getTypeName (cur);
     309         380 :                 if (typeName == NULL)
     310             :                 {
     311          76 :                         continue;
     312             :                 }
     313             : 
     314         304 :                 const Type * type = findType (typeName);
     315         304 :                 if (type == NULL)
     316             :                 {
     317           0 :                         ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (parentKey, "Unknown type '%s' for key '%s'", typeName, keyName (cur));
     318           0 :                         ksSetCursor (returned, cursor);
     319           0 :                         return ELEKTRA_PLUGIN_STATUS_ERROR;
     320             :                 }
     321             : 
     322         304 :                 if (type->normalize != NULL)
     323             :                 {
     324         295 :                         const Key * orig = keyGetMeta (cur, "origvalue");
     325         295 :                         if (orig != NULL)
     326             :                         {
     327           0 :                                 ELEKTRA_SET_INSTALLATION_ERRORF (
     328             :                                         parentKey,
     329             :                                         "The key '%s' was already normalized by a different plugin. Please ensure that there is "
     330             :                                         "only one plugin active that will normalize this key",
     331             :                                         keyName (cur));
     332           0 :                                 ksSetCursor (returned, cursor);
     333           0 :                                 return ELEKTRA_PLUGIN_STATUS_ERROR;
     334             :                         }
     335             : 
     336         295 :                         if (!type->normalize (handle, cur))
     337             :                         {
     338           4 :                                 ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (parentKey,
     339             :                                                                         "The value '%s' of key '%s' could not be normalized (type is '%s')",
     340             :                                                                         keyString (cur), keyName (cur), typeName);
     341           4 :                                 ksSetCursor (returned, cursor);
     342           4 :                                 return ELEKTRA_PLUGIN_STATUS_ERROR;
     343             :                         }
     344             :                 }
     345             : 
     346         300 :                 if (!type->check (cur))
     347             :                 {
     348           4 :                         type->setError (handle, parentKey, cur);
     349           4 :                         ksSetCursor (returned, cursor);
     350           4 :                         return ELEKTRA_PLUGIN_STATUS_ERROR;
     351             :                 }
     352             :         }
     353             : 
     354         304 :         ksSetCursor (returned, cursor);
     355             : 
     356         304 :         return ELEKTRA_PLUGIN_STATUS_SUCCESS;
     357             : }
     358             : 
     359         200 : int elektraTypeSet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned, Key * parentKey)
     360             : {
     361         200 :         cursor_t cursor = ksGetCursor (returned);
     362             : 
     363         200 :         ksRewind (returned);
     364             : 
     365         200 :         Key * cur = NULL;
     366         675 :         while ((cur = ksNext (returned)))
     367             :         {
     368         288 :                 const char * typeName = getTypeName (cur);
     369         288 :                 if (typeName == NULL)
     370             :                 {
     371          22 :                         continue;
     372             :                 }
     373             : 
     374         266 :                 const Type * type = findType (typeName);
     375         266 :                 if (type == NULL)
     376             :                 {
     377           0 :                         ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (parentKey, "Unknown type '%s' for key '%s'", typeName, keyName (cur));
     378           0 :                         ksSetCursor (returned, cursor);
     379           0 :                         return ELEKTRA_PLUGIN_STATUS_ERROR;
     380             :                 }
     381             : 
     382         266 :                 if (type->normalize != NULL)
     383             :                 {
     384         261 :                         const Key * orig = keyGetMeta (cur, "origvalue");
     385             :                         // skip normalization origvalue already set
     386         261 :                         if (orig == NULL && !type->normalize (handle, cur))
     387             :                         {
     388           5 :                                 ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (parentKey,
     389             :                                                                         "The value '%s' of key '%s' could not be normalized (type is '%s')",
     390             :                                                                         keyString (cur), keyName (cur), typeName);
     391           5 :                                 ksSetCursor (returned, cursor);
     392           5 :                                 return ELEKTRA_PLUGIN_STATUS_ERROR;
     393             :                         }
     394             :                 }
     395             : 
     396         261 :                 if (!type->check (cur))
     397             :                 {
     398           8 :                         type->setError (handle, parentKey, cur);
     399           8 :                         ksSetCursor (returned, cursor);
     400           8 :                         return ELEKTRA_PLUGIN_STATUS_ERROR;
     401             :                 }
     402             : 
     403         253 :                 if (type->restore != NULL && !type->restore (handle, cur))
     404             :                 {
     405           0 :                         ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (
     406             :                                 parentKey, "The normalized value '%s' of key '%s' could not be restored (type is '%s')", keyString (cur),
     407             :                                 keyName (cur), typeName);
     408           0 :                         ksSetCursor (returned, cursor);
     409           0 :                         return ELEKTRA_PLUGIN_STATUS_ERROR;
     410             :                 }
     411             :         }
     412             : 
     413         187 :         ksSetCursor (returned, cursor);
     414             : 
     415         187 :         return ELEKTRA_PLUGIN_STATUS_SUCCESS;
     416             : }
     417             : 
     418             : 
     419         688 : int elektraTypeClose (Plugin * handle, Key * errorKey ELEKTRA_UNUSED)
     420             : {
     421         688 :         TypeData * data = elektraPluginGetData (handle);
     422         688 :         if (data != NULL)
     423             :         {
     424         686 :                 if (data->booleans != NULL)
     425             :                 {
     426         686 :                         elektraFree (data->booleans);
     427             :                 }
     428         686 :                 elektraFree (data);
     429             :         }
     430         688 :         elektraPluginSetData (handle, NULL);
     431         688 :         return ELEKTRA_PLUGIN_STATUS_SUCCESS;
     432             : }
     433             : 
     434          13 : int elektraTypeCheckConf (Key * errorKey, KeySet * conf)
     435             : {
     436             :         struct boolean_pair * pairs;
     437          13 :         if (readBooleans (conf, &pairs, errorKey) < -1)
     438             :         {
     439             :                 return ELEKTRA_PLUGIN_STATUS_ERROR;
     440             :         }
     441          13 :         elektraFree (pairs);
     442          13 :         return ELEKTRA_PLUGIN_STATUS_SUCCESS;
     443             : }
     444             : 
     445         688 : Plugin * ELEKTRA_PLUGIN_EXPORT
     446             : {
     447             :         // clang-format off
     448         688 :         return elektraPluginExport("type",
     449             :                 ELEKTRA_PLUGIN_OPEN,    &elektraTypeOpen,
     450             :                 ELEKTRA_PLUGIN_GET,     &elektraTypeGet,
     451             :                 ELEKTRA_PLUGIN_SET,     &elektraTypeSet,
     452             :                 ELEKTRA_PLUGIN_CLOSE,   &elektraTypeClose,
     453             :                 ELEKTRA_PLUGIN_END);
     454             :         // clang-format on
     455             : }

Generated by: LCOV version 1.13