<commit_before>/**
 * @file
 *
 * @brief Methods for Key name manipulation.
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 */

/** @class doxygenNamespaces
 *
 * @brief .
 *
 * .
 *
 * - @p spec:/something for specification of other keys.
 * - @p proc:/something for in-memory keys, e.g. commandline.
 * - @p dir:/something for dir keys in current working directory
 * - @p system:/something for system keys in /etc or /
 * - @p user:/something for user keys in home directory
 * - @p user:username/something for other users (deprecated: kdbGet() + kdbSet() currently unsupported)
 * - @p /something for cascading keys (actually refers to one of the above, see also ksLookup())
 *
 */


/**
 * @defgroup keyname Name Manipulation Methods
 * @ingroup key
 * @brief Methods to do various operations on Key names.
 *
 * To use them:
 * @code
#include <kdb.h>
* @endcode
 *
 * These functions make it easier for C programmers to work with key names.
 *
 *
 * @par Terminology of Key Names
 * - A *key name* (see keySetName() and keyName()) defines the
 *   place of a key within the key database.
 *   To be unique, it is always absolute and canonical.
 * - Key names are composed out of many *key name parts* split by a
 *   separator. These *key name parts* do not contain an unescaped
 *   separator.
 * - A *key base name* (see keySetBaseName() and keyAddBaseName()) is
 *   the last part of the key name.
 * - A *C-String* is a null terminated sequence of characters.
 *   So \\0 (null-character) must not occur within a C-String.
 *
 * @par Namespaces
 * A namespace denotes the place the key comes from:
 *
 * @copydetails doxygenNamespaces
 *
 *
 * @note The rules are currently not formally specified and are subject
 * of change in the next major release.
 * So, always prefer:
 * - To use keySetName() and keyAddName() to get the canonified version of the keyname
 * - To use keySetBaseName() and keyAddBaseName() to get an escaped key
 *   name part.
 * - Not to escape or canonify with your own algorithms!
 * - To use keyUnescapedName() and keyBaseName() to have access to the
 *   key name without escape sequences (key name parts are null
 *   terminated)
 * - Not to unescape the strings yourself!
 *
 *
 * @par Syntax for Key Names
 * Key names and key name parts have following goals:
 * - The C-String passed to keySetName() and keyAddName() may be any
 *   C-String.
 * - The *key name parts* (e.g. keySetBaseName(), keyBaseName()) may
 *   be any C-String.
 * Escaping is needed to achieve both goals.
 *
 *
 * @par Semantics for Key Name Parts
 * - \% denotes an empty key name part.
 *
 *
 * @par Canonicalization for Key Names
 * - / (slash) is the separator between key name parts.
 * - // is shortened to /
 * - trailing / (slashes) are removed
 * - . (dot) and .. (dot-dot) is removed in an canonical key name, with
 *   following rules:
 *   - /./ is shortened to /
 *   - _/../ is shortened to _
 *
 *
 * @par Conventions for key names
 * - Key name parts starting with \# are array elements.
 *   Then only _ (underscore) followed by 0-9 is allowed.
 *   So we have the regular expression #[_]*[0-9]+ with the further
 *   limitation that the number of _ is defined by the number of
 *   digits-1.
 * - Key name parts starting with _ are reserved for special purposes
 *   (if you use this within a plugin you still have to make sure _ is
 *   escaped properly)
 * - Key name parts starting with @ are reserved for special purposes
 *   (if you use this within a plugin you still have to make sure @ is
 *   escaped properly)
 *
 *
 * @par Escaping rules
 * - \\ (backslash) is the escape character for the situations as
 *   described here (and only these).
 *   The \\ character must only be escaped, when one of the following
 *   rules apply.
 * - Stray escape characters are only possible in the end of the string.
 * - \\/ allows one to escape / (any uneven number of \\).
 *   Does not introduce a new part.
 * - Any uneven number N of \\ before / allows you to escape / with the
 *   N/2 of \\ prefixed.
 *   Does not introduce a new part.
 * - \\\\/ allows one to use \\ as character before / and introduces a new
 *   part.
 * - Any even number N of \\ before / allows you to have N/2 of \\
 *   prefixed before a / which introduces a new part.
 * - Use \\. and \\.. if you want your key name part to represent . and ..
 * - \\\\. and \\\\.. allows us to use \\ as character before . and .. (and so on)
 * - Use \\% if you want your key name part to start with \% (and does
 *   not represent an empty name)
 * - Using \\\\% allows one to use \\ as character before \% (and so on)

 *
 *
 * @par Semantics for Key Name Specifications
 * - _ denotes that the key name part is
 *   arbitrary (syntax as described above).
 * - \# denotes that the key name part
 *   has array syntax.
 * - names surrounded by \% (e.g. \%profile\%)
 *   denotes a placeholder.
 *
 *
 * @{
 */


#include "kdbprivate.h"
#ifdef HAVE_KDBCONFIG_H
#include "kdbconfig.h"
#endif

#include <kdbassert.h>

#ifdef HAVE_STDARG_H
#include <stdarg.h>
#endif

#ifdef HAVE_STRING_H
#include <string.h>
#endif

#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif

#include <ctype.h>

#include "kdb.h"
#include "kdbhelper.h"
#include "kdbinternal.h"

/**
 * Helper method: returns a pointer to the start of the last part of the given key name
 *
 * @param name a canonical key name
 * @param len the length of the key name
 *
 * @returns pointer to the start of the last part within @p name
 */
static char * findStartOfLastPart (char * name, size_t len)
{
	char * colon = strchr (name, ':');
	char * start = colon == NULL ? name : colon + 1;
	++start; // start after first slash

	char * cur = start + len - (start - name) - 1;

	if (cur == start) return NULL; // no base name

	while (cur >= start)
	{
		--cur;
		while (cur >= start && *cur != '/')
		{
			--cur;
		}

		size_t backslashes = 0;
		while (cur - backslashes > start && *(cur - backslashes - 1) == '\\')
		{
			++backslashes;
		}

		if (backslashes % 2 == 0)
		{
			break;
		}
	}

	return cur < start - 1 ? NULL : cur;
}


/*******************************************
 *    General name manipulation methods    *
 *******************************************/


/**
 * Returns a pointer to the abbreviated real internal @p key name.
 *
 * This is a much more efficient version of keyGetName() and can use
 * it if you are responsible enough to not mess up things. You are not allowed
 * to change anything in the returned array. The content of that string
 * may change after keySetName() and similar functions. If you need a copy of the name,
 * consider using keyGetName().
 *
 *
 * @retval "" when there is no keyName. The reason is
 * @code
key=keyNew(0);
keySetName(key,"");
keyName(key); // you would expect "" here
keyDel(key);
 * @endcode
 *
 * Valid key names are:
 *
 * @copydetails doxygenNamespaces
 *
 * @note Note that the Key structure keeps its own size field that is calculated
 * by library internal calls, so to avoid inconsistencies, you
 * must never use the pointer returned by keyName() method to set a new
 * value. Use keySetName() instead.
 *
 * @param key the Key you want to get the name from
 *
 * @return a pointer to the Key's name which must not be changed.
 * @retval "" when Key's name is empty
 * @retval 0 on NULL pointer
 *
 * @since 1.0.0
 * @ingroup keyname
 * @see keyGetNameSize() for the string length
 * @see keyGetName() as alternative to get a copy
 * @see keyUnescapedName to get an unescaped key name
 */
const char * keyName (const Key * key)
{
	if (!key) return 0;

	ELEKTRA_ASSERT (key->key != NULL, "invalid name");
	return key->key;
}

/**
 * Bytes needed to store the Key's name (excluding owner).
 *
 * For an empty Key name you need one byte to store the ending NULL.
 * For that reason, 1 is returned when the name is empty.
 *
 * @param key the Key to get the name size from
 *
 * @return number of bytes needed, including NULL terminator, to store Key's name
 * 	(excluding owner)
 * @retval 1 if Key has no name
 * @retval -1 on NULL pointer
 *
 * @since 1.0.0
 * @ingroup keyname
 * @see keyGetName() for getting the Key's name
 * @see keyGetUnescapedNameSize() for getting the size of the unescaped name
 */
ssize_t keyGetNameSize (const Key * key)
{
	if (!key) return -1;

	return key->keySize;
}


/**
 * Returns a Key's name, separated by NULL bytes and without backslashes for
 * escaping
 *
 * Slashes are replaced with NULL bytes.
 * Therefore unescaped names of cascading Keys start with a NULL byte.
 * Otherwise escaped characters, e.g. non-hierarchy slashes, will be unescaped.
 *
 * This name is essential if you want to iterate over parts of the Key's
 * name, compare Key names or check relations of Keys in the hierarchy.
 *
 * @param key the Key whose unescaped name to get
 *
 * @return the name in its unescaped form
 * @retval 0 on NULL pointers
 * @retval "" if Key's name is empty
 *
 * @since 1.0.0
 * @ingroup keyname
 * @see keyGetUnescapedName() for getting a copy of the unescaped name
 * @see keyGetUnescapedNameSize() for getting the size of the unescaped name
 * @see keyName() for getting the escaped name of the Key
 */
const void * keyUnescapedName (const Key * key)
{
	if (!key) return 0;
	ELEKTRA_ASSERT (key->ukey != NULL, "invalid name");
	return key->ukey;
}


/**
 * @brief Returns the size of the Key's unescaped name including embedded and
 * terminating NULL characters
 *
 * @param key the Key where to get the size of the unescaped name from
 *
 * @return The size of the Key's unescaped name
 * @retval -1 on NULL pointer
 * @retval 0 if Key has no name
 *
 * @since 1.0.0
 * @ingroup keyname
 * @see keyUnescapedName() for getting a pointer to the unescaped name
 * @see keyGetUnescapedName() for getting a copy of the unescaped name
 * @see keyGetNameSize() for getting the size of the escaped name
 */
ssize_t keyGetUnescapedNameSize (const Key * key)
{
	if (!key) return -1;

	return key->keyUSize;
}


/**
 * Get abbreviated Key name (excluding owner).
 *
 * When there is not enough space to write the name,
 * nothing will be written and -1 will be returned.
 *
 * @p maxSize is limited to SSIZE_MAX. When this value
 * is exceeded, -1 will be returned. The reason for that
 * is, that any value higher is just a negative return
 * value passed by accident. elektraMalloc() is not
 * as failure tolerant and would try to allocate memory
 * accordingly.
 *
 * @code
char *getBack = elektraMalloc (keyGetNameSize(key));
keyGetName(key, getBack, keyGetNameSize(key));
 * @endcode
 *
 * @param key the Key to get the name from
 * @param returnedName pre-allocated buffer to write the Key's name
 * @param maxSize maximum number of bytes that will fit in returnedName,
 * including the NULL terminator
 *
 * @return number of bytes written to @p returnedName
 * @retval 1 when only NULL terminator was written
 * @retval -1 when Key's name is longer than maxSize or maxSize is 0 or maxSize
 * is greater than SSIZE_MAX
 * @retval -1 @p key or @p returnedName is NULL pointer
 *
 * @since 1.0.0
 * @ingroup keyname
 * @see keyGetNameSize() for getting the size of a Key's name
 * @see keyName() for getting a pointer to a Key's name
 * @see keyGetBaseName() for getting a Key's base name
 * @see keyGetNamespace() for getting the namespace of a Key's name
 */
ssize_t keyGetName (const Key * key, char * returnedName, size_t maxSize)
{
	if (!key) return -1;

	if (!returnedName) return -1;

	if (!maxSize) return -1;

	if (maxSize > SSIZE_MAX) return -1;

	if (!key->key)
	{
		returnedName[0] = 0;
		return 1;
	}

	if (key->keySize > maxSize)
	{
		return -1;
	}

	memcpy (returnedName, key->key, key->keySize);

	return key->keySize;
}

/**
 * Copies the unescaped name of a Key into @p returnedName.
 *
 * It will only copy the whole name. If the buffer is too small,
 * an error code will be returned.
 *
 * To ensure the buffer is big enough, you can use keyGetUnescapedNameSize()
 * to get the correct size.
 *
 * @param key          the Key to extract the unescaped name from
 * @param returnedName the buffer to write the unescaped name into
 * @param maxSize      maximum number of bytes that can be copied
 * into @p returnedName
 *
 * @pre @p key MUST be a valid #Key and `key != NULL`
 * @pre @p returnedName MUST be allocated to be at least @p maxSize bytes big
 * @pre @p returnedName must not be NULL
 *
 * @returns the actual size of the Key's unescaped name, i.e. the number of
 * bytes copied into @p returnedName
 * @retval -1 Precondition error
 * @retval -2 the size of the unescaped name is greater than @p maxSize
 *
 * @since 1.0.0
 * @ingroup keyname
 * @see keyGetUnescapedNameSize() for getting the size of the unescaped name
 * @see keyGetName() for getting the Key's escaped name
 */
ssize_t keyGetUnescapedName (const Key * key, char * returnedName, size_t maxSize)
{
	if (!key) return -1;
	if (!returnedName) return -1;

	if (!key->ukey)
	{
		returnedName[0] = 0;
		return 1;
	}

	if (key->keyUSize > maxSize)
	{
		return -2;
	}

	memcpy (returnedName, key->ukey, maxSize);

	return key->keyUSize;
}

/**
 * Set a new name to a Key.
 *
 * A valid name is one of the forms:
 * @copydetails doxygenNamespaces
 *
 * An invalid name either has an invalid namespace or
 * a wrongly escaped \\ at the end of the name.
 *
 * See @link keyname key names @endlink for the exact rules.
 *
 * The last form has explicitly set the owner, to let the library
 * know in which user folder to save the Key. A owner is a user name.
 * If it is not defined (the second form), current user is used.
 *
 * You should always follow the guidelines for Key tree structure creation.
 *
 * A private copy of the Key name will be stored, and the @p newName
 * parameter can be freed after this call.
 *
 * .., . and / will be handled as in filesystem paths. A valid name will be build
 * out of the (valid) name what you pass, e.g. user:///sw/../sw//././MyApp -> user:/sw/MyApp
 * 
 * Trailing slashes will be stripped.
 *
 * On invalid names, the name stays unchanged.
 *
 * @return size of the new Key name in bytes, including NULL terminator
 * @retval -1 if @p key or @p keyName is NULL or @p keyName is empty or invalid
 * @retval -1 if Key was inserted to a KeySet before
 * @retval -1 if Key name is read-only
 *
 * @param key the Key whose name to set
 * @param newName the new name for the Key<commit_msg>fix formatting<commit_after>/**
 * @file
 *
 * @brief Methods for Key name manipulation.
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 */

/** @class doxygenNamespaces
 *
 * @brief .
 *
 * .
 *
 * - @p spec:/something for specification of other keys.
 * - @p proc:/something for in-memory keys, e.g. commandline.
 * - @p dir:/something for dir keys in current working directory
 * - @p system:/something for system keys in /etc or /
 * - @p user:/something for user keys in home directory
 * - @p user:username/something for other users (deprecated: kdbGet() + kdbSet() currently unsupported)
 * - @p /something for cascading keys (actually refers to one of the above, see also ksLookup())
 *
 */


/**
 * @defgroup keyname Name Manipulation Methods
 * @ingroup key
 * @brief Methods to do various operations on Key names.
 *
 * To use them:
 * @code
#include <kdb.h>
* @endcode
 *
 * These functions make it easier for C programmers to work with key names.
 *
 *
 * @par Terminology of Key Names
 * - A *key name* (see keySetName() and keyName()) defines the
 *   place of a key within the key database.
 *   To be unique, it is always absolute and canonical.
 * - Key names are composed out of many *key name parts* split by a
 *   separator. These *key name parts* do not contain an unescaped
 *   separator.
 * - A *key base name* (see keySetBaseName() and keyAddBaseName()) is
 *   the last part of the key name.
 * - A *C-String* is a null terminated sequence of characters.
 *   So \\0 (null-character) must not occur within a C-String.
 *
 * @par Namespaces
 * A namespace denotes the place the key comes from:
 *
 * @copydetails doxygenNamespaces
 *
 *
 * @note The rules are currently not formally specified and are subject
 * of change in the next major release.
 * So, always prefer:
 * - To use keySetName() and keyAddName() to get the canonified version of the keyname
 * - To use keySetBaseName() and keyAddBaseName() to get an escaped key
 *   name part.
 * - Not to escape or canonify with your own algorithms!
 * - To use keyUnescapedName() and keyBaseName() to have access to the
 *   key name without escape sequences (key name parts are null
 *   terminated)
 * - Not to unescape the strings yourself!
 *
 *
 * @par Syntax for Key Names
 * Key names and key name parts have following goals:
 * - The C-String passed to keySetName() and keyAddName() may be any
 *   C-String.
 * - The *key name parts* (e.g. keySetBaseName(), keyBaseName()) may
 *   be any C-String.
 * Escaping is needed to achieve both goals.
 *
 *
 * @par Semantics for Key Name Parts
 * - \% denotes an empty key name part.
 *
 *
 * @par Canonicalization for Key Names
 * - / (slash) is the separator between key name parts.
 * - // is shortened to /
 * - trailing / (slashes) are removed
 * - . (dot) and .. (dot-dot) is removed in an canonical key name, with
 *   following rules:
 *   - /./ is shortened to /
 *   - _/../ is shortened to _
 *
 *
 * @par Conventions for key names
 * - Key name parts starting with \# are array elements.
 *   Then only _ (underscore) followed by 0-9 is allowed.
 *   So we have the regular expression #[_]*[0-9]+ with the further
 *   limitation that the number of _ is defined by the number of
 *   digits-1.
 * - Key name parts starting with _ are reserved for special purposes
 *   (if you use this within a plugin you still have to make sure _ is
 *   escaped properly)
 * - Key name parts starting with @ are reserved for special purposes
 *   (if you use this within a plugin you still have to make sure @ is
 *   escaped properly)
 *
 *
 * @par Escaping rules
 * - \\ (backslash) is the escape character for the situations as
 *   described here (and only these).
 *   The \\ character must only be escaped, when one of the following
 *   rules apply.
 * - Stray escape characters are only possible in the end of the string.
 * - \\/ allows one to escape / (any uneven number of \\).
 *   Does not introduce a new part.
 * - Any uneven number N of \\ before / allows you to escape / with the
 *   N/2 of \\ prefixed.
 *   Does not introduce a new part.
 * - \\\\/ allows one to use \\ as character before / and introduces a new
 *   part.
 * - Any even number N of \\ before / allows you to have N/2 of \\
 *   prefixed before a / which introduces a new part.
 * - Use \\. and \\.. if you want your key name part to represent . and ..
 * - \\\\. and \\\\.. allows us to use \\ as character before . and .. (and so on)
 * - Use \\% if you want your key name part to start with \% (and does
 *   not represent an empty name)
 * - Using \\\\% allows one to use \\ as character before \% (and so on)

 *
 *
 * @par Semantics for Key Name Specifications
 * - _ denotes that the key name part is
 *   arbitrary (syntax as described above).
 * - \# denotes that the key name part
 *   has array syntax.
 * - names surrounded by \% (e.g. \%profile\%)
 *   denotes a placeholder.
 *
 *
 * @{
 */


#include "kdbprivate.h"
#ifdef HAVE_KDBCONFIG_H
#include "kdbconfig.h"
#endif

#include <kdbassert.h>

#ifdef HAVE_STDARG_H
#include <stdarg.h>
#endif

#ifdef HAVE_STRING_H
#include <string.h>
#endif

#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif

#include <ctype.h>

#include "kdb.h"
#include "kdbhelper.h"
#include "kdbinternal.h"

/**
 * Helper method: returns a pointer to the start of the last part of the given key name
 *
 * @param name a canonical key name
 * @param len the length of the key name
 *
 * @returns pointer to the start of the last part within @p name
 */
static char * findStartOfLastPart (char * name, size_t len)
{
	char * colon = strchr (name, ':');
	char * start = colon == NULL ? name : colon + 1;
	++start; // start after first slash

	char * cur = start + len - (start - name) - 1;

	if (cur == start) return NULL; // no base name

	while (cur >= start)
	{
		--cur;
		while (cur >= start && *cur != '/')
		{
			--cur;
		}

		size_t backslashes = 0;
		while (cur - backslashes > start && *(cur - backslashes - 1) == '\\')
		{
			++backslashes;
		}

		if (backslashes % 2 == 0)
		{
			break;
		}
	}

	return cur < start - 1 ? NULL : cur;
}


/*******************************************
 *    General name manipulation methods    *
 *******************************************/


/**
 * Returns a pointer to the abbreviated real internal @p key name.
 *
 * This is a much more efficient version of keyGetName() and can use
 * it if you are responsible enough to not mess up things. You are not allowed
 * to change anything in the returned array. The content of that string
 * may change after keySetName() and similar functions. If you need a copy of the name,
 * consider using keyGetName().
 *
 *
 * @retval "" when there is no keyName. The reason is
 * @code
key=keyNew(0);
keySetName(key,"");
keyName(key); // you would expect "" here
keyDel(key);
 * @endcode
 *
 * Valid key names are:
 *
 * @copydetails doxygenNamespaces
 *
 * @note Note that the Key structure keeps its own size field that is calculated
 * by library internal calls, so to avoid inconsistencies, you
 * must never use the pointer returned by keyName() method to set a new
 * value. Use keySetName() instead.
 *
 * @param key the Key you want to get the name from
 *
 * @return a pointer to the Key's name which must not be changed.
 * @retval "" when Key's name is empty
 * @retval 0 on NULL pointer
 *
 * @since 1.0.0
 * @ingroup keyname
 * @see keyGetNameSize() for the string length
 * @see keyGetName() as alternative to get a copy
 * @see keyUnescapedName to get an unescaped key name
 */
const char * keyName (const Key * key)
{
	if (!key) return 0;

	ELEKTRA_ASSERT (key->key != NULL, "invalid name");
	return key->key;
}

/**
 * Bytes needed to store the Key's name (excluding owner).
 *
 * For an empty Key name you need one byte to store the ending NULL.
 * For that reason, 1 is returned when the name is empty.
 *
 * @param key the Key to get the name size from
 *
 * @return number of bytes needed, including NULL terminator, to store Key's name
 * 	(excluding owner)
 * @retval 1 if Key has no name
 * @retval -1 on NULL pointer
 *
 * @since 1.0.0
 * @ingroup keyname
 * @see keyGetName() for getting the Key's name
 * @see keyGetUnescapedNameSize() for getting the size of the unescaped name
 */
ssize_t keyGetNameSize (const Key * key)
{
	if (!key) return -1;

	return key->keySize;
}


/**
 * Returns a Key's name, separated by NULL bytes and without backslashes for
 * escaping
 *
 * Slashes are replaced with NULL bytes.
 * Therefore unescaped names of cascading Keys start with a NULL byte.
 * Otherwise escaped characters, e.g. non-hierarchy slashes, will be unescaped.
 *
 * This name is essential if you want to iterate over parts of the Key's
 * name, compare Key names or check relations of Keys in the hierarchy.
 *
 * @param key the Key whose unescaped name to get
 *
 * @return the name in its unescaped form
 * @retval 0 on NULL pointers
 * @retval "" if Key's name is empty
 *
 * @since 1.0.0
 * @ingroup keyname
 * @see keyGetUnescapedName() for getting a copy of the unescaped name
 * @see keyGetUnescapedNameSize() for getting the size of the unescaped name
 * @see keyName() for getting the escaped name of the Key
 */
const void * keyUnescapedName (const Key * key)
{
	if (!key) return 0;
	ELEKTRA_ASSERT (key->ukey != NULL, "invalid name");
	return key->ukey;
}


/**
 * @brief Returns the size of the Key's unescaped name including embedded and
 * terminating NULL characters
 *
 * @param key the Key where to get the size of the unescaped name from
 *
 * @return The size of the Key's unescaped name
 * @retval -1 on NULL pointer
 * @retval 0 if Key has no name
 *
 * @since 1.0.0
 * @ingroup keyname
 * @see keyUnescapedName() for getting a pointer to the unescaped name
 * @see keyGetUnescapedName() for getting a copy of the unescaped name
 * @see keyGetNameSize() for getting the size of the escaped name
 */
ssize_t keyGetUnescapedNameSize (const Key * key)
{
	if (!key) return -1;

	return key->keyUSize;
}


/**
 * Get abbreviated Key name (excluding owner).
 *
 * When there is not enough space to write the name,
 * nothing will be written and -1 will be returned.
 *
 * @p maxSize is limited to SSIZE_MAX. When this value
 * is exceeded, -1 will be returned. The reason for that
 * is, that any value higher is just a negative return
 * value passed by accident. elektraMalloc() is not
 * as failure tolerant and would try to allocate memory
 * accordingly.
 *
 * @code
char *getBack = elektraMalloc (keyGetNameSize(key));
keyGetName(key, getBack, keyGetNameSize(key));
 * @endcode
 *
 * @param key the Key to get the name from
 * @param returnedName pre-allocated buffer to write the Key's name
 * @param maxSize maximum number of bytes that will fit in returnedName,
 * including the NULL terminator
 *
 * @return number of bytes written to @p returnedName
 * @retval 1 when only NULL terminator was written
 * @retval -1 when Key's name is longer than maxSize or maxSize is 0 or maxSize
 * is greater than SSIZE_MAX
 * @retval -1 @p key or @p returnedName is NULL pointer
 *
 * @since 1.0.0
 * @ingroup keyname
 * @see keyGetNameSize() for getting the size of a Key's name
 * @see keyName() for getting a pointer to a Key's name
 * @see keyGetBaseName() for getting a Key's base name
 * @see keyGetNamespace() for getting the namespace of a Key's name
 */
ssize_t keyGetName (const Key * key, char * returnedName, size_t maxSize)
{
	if (!key) return -1;

	if (!returnedName) return -1;

	if (!maxSize) return -1;

	if (maxSize > SSIZE_MAX) return -1;

	if (!key->key)
	{
		returnedName[0] = 0;
		return 1;
	}

	if (key->keySize > maxSize)
	{
		return -1;
	}

	memcpy (returnedName, key->key, key->keySize);

	return key->keySize;
}

/**
 * Copies the unescaped name of a Key into @p returnedName.
 *
 * It will only copy the whole name. If the buffer is too small,
 * an error code will be returned.
 *
 * To ensure the buffer is big enough, you can use keyGetUnescapedNameSize()
 * to get the correct size.
 *
 * @param key          the Key to extract the unescaped name from
 * @param returnedName the buffer to write the unescaped name into
 * @param maxSize      maximum number of bytes that can be copied
 * into @p returnedName
 *
 * @pre @p key MUST be a valid #Key and `key != NULL`
 * @pre @p returnedName MUST be allocated to be at least @p maxSize bytes big
 * @pre @p returnedName must not be NULL
 *
 * @returns the actual size of the Key's unescaped name, i.e. the number of
 * bytes copied into @p returnedName
 * @retval -1 Precondition error
 * @retval -2 the size of the unescaped name is greater than @p maxSize
 *
 * @since 1.0.0
 * @ingroup keyname
 * @see keyGetUnescapedNameSize() for getting the size of the unescaped name
 * @see keyGetName() for getting the Key's escaped name
 */
ssize_t keyGetUnescapedName (const Key * key, char * returnedName, size_t maxSize)
{
	if (!key) return -1;
	if (!returnedName) return -1;

	if (!key->ukey)
	{
		returnedName[0] = 0;
		return 1;
	}

	if (key->keyUSize > maxSize)
	{
		return -2;
	}

	memcpy (returnedName, key->ukey, maxSize);

	return key->keyUSize;
}

/**
 * Set a new name to a Key.
 *
 * A valid name is one of the forms:
 * @copydetails doxygenNamespaces
 *
 * An invalid name either has an invalid namespace or
 * a wrongly escaped \\ at the end of the name.
 *
 * See @link keyname key names @endlink for the exact rules.
 *
 * The last form has explicitly set the owner, to let the library
 * know in which user folder to save the Key. A owner is a user name.
 * If it is not defined (the second form), current user is used.
 *
 * You should always follow the guidelines for Key tree structure creation.
 *
 * A private copy of the Key name will be stored, and the @p newName
 * parameter can be freed after this call.
 *
 * .., . and / will be handled as in filesystem paths. A valid name will be build
 * out of the (valid) name what you pass, e.g. user:///sw/../sw//././MyApp -> user:/sw/MyApp
 *
 * Trailing slashes will be stripped.
 *
 * On invalid names, the name stays unchanged.
 *
 * @return size of the new Key name in bytes, including NULL terminator
 * @retval -1 if @p key or @p keyName is NULL or @p keyName is empty or invalid
 * @retval -1 if Key was inserted to a KeySet before
 * @retval -1 if Key name is read-only
 *
 * @param key the Key whose name to set
 * @param newName the new name for the Key
{'fraction_non_alphanumeric': 0.1040871556449934, 'fraction_numerical': 0.004857400596766359, 'mean_word_length': 3.1370747811109516, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 59, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4197336', 'n_tokens_mistral': 9080, 'n_tokens_neox': 8703, 'n_words': 4088}