// keyRel2 helper, returns how many levels check is below key, or 0 if check isn't below int keyGetLevelsBelow (const Key * key, const Key * check) { const char * keyUName = keyUnescapedName (key); size_t keyUSize = keyGetUnescapedNameSize (key); const char * keyUNameEnd = keyUName + keyUSize; const char * checkUName = keyUnescapedName (check); size_t checkUSize = keyGetUnescapedNameSize (check); const char * checkUNameEnd = checkUName + checkUSize; while (strcmp (keyUName, checkUName) == 0) { keyUName = strchr (keyUName, '\0') + 1; checkUName = strchr (checkUName, '\0') + 1; if (keyUName >= keyUNameEnd) { int levels = 0; while (checkUName < checkUNameEnd) { checkUName = strchr (checkUName, '\0') + 1; ++levels; } return levels; } if (checkUName >= checkUNameEnd) { break; } } return 0; }
/** * Check if the key check is direct below the key key or not. * @verbatim Example: key user/sw/app check user/sw/app/key returns true because check is below key Example: key user/sw/app check user/sw/app/folder/key does not return true, because there is only a indirect relation @endverbatim * * @param key the key object to work with * @param check the key to find the relative position of * @retval 1 if check is below key * @retval 0 if it is not below or if it is the same key * @retval -1 on null pointer * @see keyIsBelow(), keySetName(), keyGetName() * @ingroup keytest * */ int keyIsDirectBelow (const Key * key, const Key * check) { if (!key || !check) return -1; if (!keyIsBelow (key, check)) return 0; const char * checkname = keyUnescapedName (check); ssize_t keysize = keyGetUnescapedNameSize (key); ssize_t checksize = keyGetUnescapedNameSize (check); char * startPtr = NULL; if (keyName (key)[0] != '/') { startPtr = strrchr (checkname + keysize, '\0'); } else { if (keyName (check)[0] != '/') { startPtr = strrchr (checkname, '\0'); startPtr = strrchr (startPtr + keysize, '\0'); } else { startPtr = strrchr (checkname + keysize, '\0'); } } if (startPtr == checkname + checksize - 1) return 1; return 0; }
/** * Check if the key check is direct below the key key or not. * @verbatim Example: key user/sw/app check user/sw/app/key returns true because check is below key Example: key user/sw/app check user/sw/app/folder/key does not return true, because there is only a indirect relation @endverbatim * * @param key the key object to work with * @param check the key to find the relative position of * @retval 1 if check is below key * @retval 0 if it is not below or if it is the same key * @retval -1 on null pointer * @see keyIsBelow(), keySetName(), keyGetName() * @ingroup keytest * */ int keyIsDirectBelow(const Key *key, const Key *check) { if (!key || !check) return -1; if (!keyIsBelow(key, check)) return 0; const char * checkname = keyUnescapedName(check); ssize_t keysize = keyGetUnescapedNameSize(key); ssize_t checksize = keyGetUnescapedNameSize(check); if (strchr(checkname + keysize, '\0') == checkname + checksize - 1) return 1; return 0; }
int keyIsBelow (const Key * key, const Key * check) { const char * keyname = 0; const char * checkname = 0; const char * ukeyname = 0; const char * ucheckname = 0; ssize_t keysize = 0; ssize_t checksize = 0; ssize_t ukeysize = 0; ssize_t uchecksize = 0; if (!key || !check) return -1; keyname = keyName (key); checkname = keyName (check); ukeyname = keyUnescapedName (key); ucheckname = keyUnescapedName (check); keysize = keyGetNameSize (key); checksize = keyGetNameSize (check); ukeysize = keyGetUnescapedNameSize (key); uchecksize = keyGetUnescapedNameSize (check); if (!strcmp (checkname, "/")) return 0; if (!strcmp (keyname, "/")) { if (checkname[0] == '/') return 1; if (strchr (checkname, '/')) return 1; } else if (checkname[0] == '/') { if (keyname[0] == '/') { if (!strncmp (keyname, checkname, keysize - 1)) { if (ucheckname[ukeysize - 1] == '\0' && uchecksize > ukeysize) { return 1; } } } else { size_t size = 0; char * ptr = (char *)keyname; ptr = keyNameGetOneLevel (ptr, &size); if (size == (size_t)keysize) { return 1; } keyname += size; keysize = elektraStrLen (keyname); ptr = strrchr (ukeyname, '\0'); ukeysize -= (ptr - ukeyname); if (!strncmp (keyname, checkname, keysize - 1)) { if (ucheckname[ukeysize - 1] == '\0' && uchecksize > ukeysize) { return 1; } } } } else if (keyname[0] == '/') { size_t size = 0; char * ptr = (char *)checkname; ptr = keyNameGetOneLevel (ptr, &size); if (size == (size_t)checksize) { return 0; } checkname += size; checksize = elektraStrLen (checkname); ptr = strrchr (ucheckname, '\0'); uchecksize -= (ptr - ucheckname); ucheckname = ptr; if (!strncmp (keyname, checkname, keysize - 1)) { if (ucheckname[ukeysize - 1] == '\0' && uchecksize > ukeysize) { return 1; } } } else if (!strncmp (keyname, checkname, keysize - 1)) { if ((ucheckname[ukeysize - 1] == '\0') && (uchecksize > ukeysize)) return 1; } return 0; }