LCOV - code coverage report
Current view: top level - src/plugins/glob - glob.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 95 95 100.0 %
Date: 2019-09-12 12:28:41 Functions: 9 10 90.0 %

          Line data    Source code
       1             : /**
       2             :  * @file
       3             :  *
       4             :  * @brief A plugin that converts keys to metakeys and vice versa
       5             :  *
       6             :  * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
       7             :  *
       8             :  */
       9             : 
      10             : #include "glob.h"
      11             : 
      12             : #ifndef HAVE_KDBCONFIG
      13             : #include "kdbconfig.h"
      14             : #endif
      15             : 
      16             : #include <fnmatch.h>
      17             : #include <kdbhelper.h>
      18             : 
      19             : struct GlobFlagMap
      20             : {
      21             :         char * name;
      22             :         short flag;
      23             : };
      24             : 
      25             : struct GlobFlagMap flagMaps[] = { { "noescape", FNM_NOESCAPE }, { "pathname", FNM_PATHNAME }, { "period", FNM_PERIOD } };
      26             : 
      27          62 : int elektraGlobMatch (Key * key, const Key * match, const char * globFlags)
      28             : {
      29          62 :         char * tokenList = elektraStrDup (globFlags);
      30          62 :         char delimiter[] = ",";
      31          62 :         char * flagName = strtok (tokenList, delimiter);
      32             : 
      33          62 :         int flags = 0;
      34         168 :         while (flagName != NULL)
      35             :         {
      36         132 :                 for (size_t i = 0; i < sizeof (flagMaps) / sizeof (struct GlobFlagMap); i++)
      37             :                 {
      38         132 :                         if (!strcmp (flagName, flagMaps[i].name))
      39             :                         {
      40          44 :                                 flags |= flagMaps[i].flag;
      41             :                         }
      42             :                 }
      43          44 :                 flagName = strtok (NULL, delimiter);
      44             :         }
      45             : 
      46          62 :         free (tokenList);
      47             : 
      48          62 :         if (!fnmatch (keyString (match), keyName (key), flags))
      49             :         {
      50          34 :                 keyCopyAllMeta (key, match);
      51          34 :                 return 1;
      52             :         }
      53             : 
      54             :         return 0;
      55             : }
      56             : 
      57             : enum GlobDirection
      58             : {
      59             :         GET,
      60             :         SET,
      61             : };
      62             : 
      63          45 : static const char * getGlobFlags (KeySet * keys, Key * globKey)
      64             : {
      65          45 :         Key * flagKey = keyDup (globKey);
      66          45 :         keyAddBaseName (flagKey, "flags");
      67          45 :         Key * flagResult = ksLookup (keys, flagKey, KDB_O_NONE);
      68          45 :         keyDel (flagKey);
      69             : 
      70          45 :         if (flagResult)
      71             :         {
      72          10 :                 return keyString (flagResult);
      73             :         }
      74             : 
      75             :         return 0;
      76             : }
      77             : 
      78          33 : static KeySet * getGlobKeys (Key * parentKey, KeySet * keys, enum GlobDirection direction)
      79             : {
      80          33 :         KeySet * glob = ksNew (0, KS_END);
      81          33 :         Key * k = 0;
      82          33 :         size_t parentsize = keyGetNameSize (parentKey);
      83             : 
      84          33 :         Key * userGlobConfig = 0;
      85          33 :         Key * systemGlobConfig = 0;
      86          33 :         Key * userDirGlobConfig = 0;
      87          33 :         Key * systemDirGlobConfig = 0;
      88             : 
      89          33 :         userGlobConfig = keyNew ("user/glob", KEY_END);
      90          33 :         systemGlobConfig = keyNew ("system/glob", KEY_END);
      91          33 :         switch (direction)
      92             :         {
      93             :         case GET:
      94          23 :                 userDirGlobConfig = keyNew ("user/glob/get", KEY_END);
      95          23 :                 systemDirGlobConfig = keyNew ("system/glob/get", KEY_END);
      96          23 :                 break;
      97             :         case SET:
      98          10 :                 userDirGlobConfig = keyNew ("user/glob/set", KEY_END);
      99          10 :                 systemDirGlobConfig = keyNew ("system/glob/set", KEY_END);
     100          10 :                 break;
     101             :         }
     102             : 
     103         203 :         while ((k = ksNext (keys)) != 0)
     104             :         {
     105             :                 /* use only glob keys for the current direction */
     106         309 :                 if (keyIsDirectBelow (userGlobConfig, k) || keyIsDirectBelow (systemGlobConfig, k) ||
     107         274 :                     keyIsDirectBelow (userDirGlobConfig, k) || keyIsDirectBelow (systemDirGlobConfig, k))
     108             :                 {
     109          45 :                         keySetMeta (k, "glob/flags", getGlobFlags (keys, k));
     110             : 
     111             :                         /* Look if we have a string */
     112          45 :                         size_t valsize = keyGetValueSize (k);
     113          45 :                         if (valsize < 2) continue;
     114             : 
     115             :                         /* We now know we want that key.
     116             :                          Dup it to not change the configuration. */
     117          26 :                         Key * ins = keyDup (k);
     118             :                         /* Now look if we want cascading for the key */
     119          26 :                         if (keyString (k)[0] == '/')
     120             :                         {
     121          18 :                                 char * newstring = elektraMalloc (valsize + parentsize);
     122          18 :                                 strcpy (newstring, keyName (parentKey));
     123          18 :                                 strcat (newstring, keyString (k));
     124          18 :                                 keySetString (ins, newstring);
     125          18 :                                 elektraFree (newstring);
     126             :                         }
     127          26 :                         ksAppendKey (glob, ins);
     128             :                 }
     129             :         }
     130             : 
     131          33 :         keyDel (userGlobConfig);
     132          33 :         keyDel (systemGlobConfig);
     133          33 :         keyDel (userDirGlobConfig);
     134          33 :         keyDel (systemDirGlobConfig);
     135             : 
     136          33 :         return glob;
     137             : }
     138             : 
     139          33 : static void applyGlob (KeySet * returned, KeySet * glob)
     140             : {
     141             :         Key * cur;
     142          33 :         ksRewind (returned);
     143         164 :         while ((cur = ksNext (returned)) != 0)
     144             :         {
     145             :                 Key * match;
     146          98 :                 ksRewind (glob);
     147         224 :                 while ((match = ksNext (glob)) != 0)
     148             :                 {
     149          62 :                         const Key * flagKey = keyGetMeta (match, "glob/flags");
     150             :                         int matchApplied;
     151             : 
     152          62 :                         if (flagKey)
     153             :                         {
     154          24 :                                 matchApplied = elektraGlobMatch (cur, match, keyString (flagKey));
     155             :                         }
     156             :                         else
     157             :                         {
     158             :                                 /* if no flags were provided, default to FNM_PATHNAME behaviour */
     159          38 :                                 matchApplied = elektraGlobMatch (cur, match, "pathname");
     160             :                         }
     161             : 
     162          62 :                         if (matchApplied) break;
     163             :                 }
     164             :         }
     165          33 : }
     166             : 
     167         462 : int elektraGlobOpen (Plugin * handle ELEKTRA_UNUSED, Key * parentKey ELEKTRA_UNUSED)
     168             : {
     169             :         /* plugin initialization logic should be here */
     170             :         /* TODO: name of parentKey is not set...*/
     171             :         /* So rewriting cannot happen here (is in elektraGlobSet */
     172             : 
     173         462 :         return 1; /* success */
     174             : }
     175             : 
     176         462 : int elektraGlobClose (Plugin * handle ELEKTRA_UNUSED, Key * errorKey ELEKTRA_UNUSED)
     177             : {
     178             :         /* free all plugin resources and shut it down */
     179             : 
     180         462 :         KeySet * keys = elektraPluginGetData (handle);
     181         462 :         ksDel (keys);
     182             : 
     183         462 :         return 1; /* success */
     184             : }
     185             : 
     186             : 
     187         381 : int elektraGlobGet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned, Key * parentKey ELEKTRA_UNUSED)
     188             : {
     189         381 :         if (!strcmp (keyName (parentKey), "system/elektra/modules/glob"))
     190             :         {
     191             :                 // TODO: improve plugin contract
     192         358 :                 KeySet * config =
     193             : #include "contract.h"
     194         358 :                         ksAppend (returned, config);
     195         358 :                 ksDel (config);
     196         358 :                 return 1;
     197             :         }
     198             : 
     199          23 :         KeySet * keys = elektraPluginGetConfig (handle);
     200          23 :         ksRewind (keys);
     201             : 
     202          23 :         KeySet * glob = getGlobKeys (parentKey, keys, GET);
     203          23 :         applyGlob (returned, glob);
     204             : 
     205          23 :         ksDel (glob);
     206             : 
     207          23 :         return 1; /* success */
     208             : }
     209             : 
     210             : 
     211          10 : int elektraGlobSet (Plugin * handle, KeySet * returned, Key * parentKey)
     212             : {
     213          10 :         KeySet * keys = elektraPluginGetConfig (handle);
     214          10 :         ksRewind (keys);
     215             : 
     216          10 :         KeySet * glob = getGlobKeys (parentKey, keys, SET);
     217          10 :         applyGlob (returned, glob);
     218             : 
     219          10 :         ksDel (glob);
     220             : 
     221          10 :         return 1; /* success */
     222             : }
     223             : 
     224         462 : Plugin * ELEKTRA_PLUGIN_EXPORT
     225             : {
     226             :         // clang-format off
     227         462 :         return elektraPluginExport("glob",
     228             :                 ELEKTRA_PLUGIN_OPEN,    &elektraGlobOpen,
     229             :                 ELEKTRA_PLUGIN_CLOSE,   &elektraGlobClose,
     230             :                 ELEKTRA_PLUGIN_GET,     &elektraGlobGet,
     231             :                 ELEKTRA_PLUGIN_SET,     &elektraGlobSet,
     232             :                 ELEKTRA_PLUGIN_END);
     233             : }
     234             : 

Generated by: LCOV version 1.13