static KeySet * getGlobKeys (Key * parentKey, KeySet * keys, enum GlobDirection direction) { KeySet * glob = ksNew (0, KS_END); Key * k = 0; size_t parentsize = keyGetNameSize (parentKey); Key * userGlobConfig = 0; Key * systemGlobConfig = 0; Key * userDirGlobConfig = 0; Key * systemDirGlobConfig = 0; userGlobConfig = keyNew ("user/glob", KEY_END); systemGlobConfig = keyNew ("system/glob", KEY_END); switch (direction) { case GET: userDirGlobConfig = keyNew ("user/glob/get", KEY_END); systemDirGlobConfig = keyNew ("system/glob/get", KEY_END); break; case SET: userDirGlobConfig = keyNew ("user/glob/set", KEY_END); systemDirGlobConfig = keyNew ("system/glob/set", KEY_END); break; } while ((k = ksNext (keys)) != 0) { /* use only glob keys for the current direction */ if (keyIsDirectBelow (userGlobConfig, k) || keyIsDirectBelow (systemGlobConfig, k) || keyIsDirectBelow (userDirGlobConfig, k) || keyIsDirectBelow (systemDirGlobConfig, k)) { keySetMeta (k, "glob/flags", getGlobFlags (keys, k)); /* Look if we have a string */ size_t valsize = keyGetValueSize (k); if (valsize < 2) continue; /* We now know we want that key. Dup it to not change the configuration. */ Key * ins = keyDup (k); /* Now look if we want cascading for the key */ if (keyString (k)[0] == '/') { char * newstring = elektraMalloc (valsize + parentsize); strcpy (newstring, keyName (parentKey)); strcat (newstring, keyString (k)); keySetString (ins, newstring); elektraFree (newstring); } ksAppendKey (glob, ins); } } keyDel (userGlobConfig); keyDel (systemGlobConfig); keyDel (userDirGlobConfig); keyDel (systemDirGlobConfig); return glob; }
static void validateWildcardSubs (KeySet * ks, Key * key, Key * specKey) { const Key * requiredMeta = keyGetMeta (specKey, "required"); if (!requiredMeta) return; Key * tmpParent = keyDup (key); keySetBaseName (tmpParent, 0); Key * parent = ksLookup (ks, tmpParent, KDB_O_NONE); keyDel (tmpParent); if (parent == NULL) return; KeySet * ksCopy = ksDup (ks); KeySet * subKeys = ksCut (ksCopy, parent); Key * cur; long subCount = 0; while ((cur = ksNext (subKeys)) != NULL) { if (keyIsDirectBelow (parent, cur)) ++subCount; } long required = atol (keyString (requiredMeta)); if (required != subCount) { char buffer[MAX_CHARS_IN_LONG + 1]; snprintf (buffer, sizeof (buffer), "%ld", subCount); keySetMeta (parent, "conflict/invalid/subcount", buffer); } ksDel (subKeys); ksDel (ksCopy); }
/** * Information about the relation in the hierarchy between * two keys. * * Unlike keyCmp() the number gives information * about hierarchical information. * * * - If the keys are the same 0 is returned. * So it is the key itself. @verbatim user/key user/key @endverbatim * *@code keySetName (key, "user/key/folder"); keySetName (check, "user/key/folder"); succeed_if (keyRel (key, check) == 0, "should be same"); *@endcode * * @note this relation can be checked with keyCmp() too. * * * - If the key is direct below the other one 1 is returned. * That means that, in terms of hierarchy, no other key is * between them - it is a direct child. @verbatim user/key/folder user/key/folder/child @endverbatim * *@code keySetName (key, "user/key/folder"); keySetName (check, "user/key/folder/child"); succeed_if (keyRel (key, check) == 1, "should be direct below"); *@endcode * * * - If the key is below the other one, but not directly 2 is returned. * This is also called grand-child. @verbatim user/key/folder user/key/folder/any/depth/deeper/grand-child @endverbatim * * *@code keySetName (key, "user/key/folder"); keySetName (check, "user/key/folder/any/depth/deeper/grand-child"); succeed_if (keyRel (key, check) >= 2, "should be below (but not direct)"); succeed_if (keyRel (key, check) > 0, "should be below"); succeed_if (keyRel (key, check) >= 0, "should be the same or below"); *@endcode * * * - If a invalid or null ptr key is passed, -1 is returned * * * - If the keys have no relations, but are not invalid, -2 is returned. * * * - If the keys are in the same hierarchy, a value smaller then -2 is returned. * It means that the key is not below. @verbatim user/key/myself user/key/sibling @endverbatim * * @code keySetName (key, "user/key/folder"); keySetName (check, "user/notsame/folder"); succeed_if (keyRel (key, check) < -2, "key is not below, but same namespace"); * @endcode * * @code * @endcode * * * TODO Below is an idea how it could be extended: * It could continue the search into the other direction * if any (grand-)parents are equal. * * - If the keys are direct below a key which is next to the key, -2 is returned. * This is also called nephew. (TODO not implemented) * @verbatim user/key/myself user/key/sibling @endverbatim * * - If the keys are direct below a key which is next to the key, -2 is returned. * This is also called nephew. (TODO not implemented) * @verbatim user/key/myself user/key/sibling/nephew @endverbatim * * - If the keys are below a key which is next to the key, -3 is returned. * This is also called grand-nephew. (TODO not implemented) @verbatim user/key/myself user/key/sibling/any/depth/deeper/grand-nephew @endverbatim * * The same holds true for the other direction, but with negative values. * For no relation INT_MIN is returned. * * @note to check if the keys are the same, you must use * keyCmp() == 0! * keyRel() does not give you the information if it did not * find a relation or if it is the same key. * * @return depending on the relation * @retval 2 if below * @retval 1 if direct below * @retval 0 if the same * @retval -1 on null or invalid keys * @retval -2 if none of any other relation * @retval -3 if same hierarchy (none of those below) * @retval -4 if sibling (in same hierarchy) * @retval -5 if nephew (in same hierarchy) * * @param key the key object to work with * @param check the second key object to check the relation with * @ingroup keytest */ int keyRel (const Key * key, const Key * check) { if (!key || !check) return -1; if (!key->key || !check->key) return -1; if (!keyCmp (key, check)) return 0; if (keyIsDirectBelow (key, check)) return 1; if (keyIsBelow (key, check)) return 2; if (keyIsUser (key) && keyIsUser (check)) return -3; if (keyIsSystem (key) && keyIsSystem (check)) return -3; // if (keyIsSibling(key, check)) return -4; // if (keyIsNephew(key, check)) return -5; return -2; }
static void validateArray (KeySet * ks, Key * arrayKey, Key * specKey) { Key * tmpArrayParent = keyDup (arrayKey); keySetBaseName (tmpArrayParent, 0); Key * arrayParent = ksLookup (ks, tmpArrayParent, KDB_O_NONE); keyDel (tmpArrayParent); if (arrayParent == NULL) return; KeySet * ksCopy = ksDup (ks); KeySet * subKeys = ksCut (ksCopy, arrayParent); Key * cur; long validCount = 0; while ((cur = ksNext (subKeys)) != NULL) { if (!keyIsDirectBelow (arrayParent, cur)) continue; if (keyBaseName (cur)[0] == '#') { if (elektraArrayValidateName (cur) == 1) { ++validCount; keySetMeta (cur, "spec/internal/valid", ""); } else { KeySet * invalidCutKS = ksCut (subKeys, cur); Key * toMark; while ((toMark = ksNext (invalidCutKS)) != NULL) { if (strcmp (keyName (cur), keyName (toMark))) keySetMeta (toMark, "conflict/invalid", ""); elektraMetaArrayAdd (arrayParent, "conflict/invalid/hasmember", keyName (toMark)); } ksDel (invalidCutKS); } } } ksDel (subKeys); ksDel (ksCopy); validateArrayRange (arrayParent, validCount, specKey); }
int direct_below_a (Key *check) { return keyIsDirectBelow(global_a, check); }
/** * @internal * * Returns true (1) for all keys that are part of the array * identified by the supplied array parent. Only the array * eleements themself, but no subkeys of them will be filtered * * @pre The supplied argument has to be of type (const Key *) * and is the parent of the array to be extracted. For example * if the keys of the array comment/# are to be extracted, a key * with the name "comment" has to be supplied * * @param key the key to be checked against the array * @param argument the array parent * @return 1 if the key is part of the array identified by the * array parent, 0 otherwise * */ static int arrayFilter(const Key *key, void *argument) { const Key *arrayParent = (const Key *) argument; return keyIsDirectBelow(arrayParent, key) && elektraArrayValidateName(key); }