Permalink
Browse files

hexnumber: initial version of hex plugin

  • Loading branch information...
kodebach committed Apr 12, 2018
1 parent e3f04a7 commit 1a6a8a3ee98d239d3f4557c2c6a74c3dd69f1c51
@@ -12,6 +12,7 @@
#ignore all build directories of cmake
build*/
cmake-build*/
#ignore ctags + gdb history files
.ctags
@@ -554,7 +554,7 @@ function (generate_readme p) # rerun cmake when README.md is changed also allow
contents
"${contents}")
string (REGEX
REPLACE "\"- +infos/author *= *([.@<>a-zéA-Z0-9 %_-]*)\\\\n\""
REPLACE "\"- +infos/author *= *([^\\\\]*)\\\\n\""
"keyNew(\"system/elektra/modules/${p}/infos/author\",\nKEY_VALUE, \"\\1\", KEY_END),"
contents
"${contents}")
@@ -0,0 +1,9 @@
include (LibAddMacros)
add_plugin (hexnumber
SOURCES
hexnumber.h
hexnumber.c
ADD_TEST
TEST_README
)
@@ -0,0 +1,30 @@
- infos = Information about the template plugin is in keys below
- infos/author = Klemens Böswirth <k.boeswirth+git@gmail.com>
- infos/licence = BSD
- infos/needs =
- infos/provides =
- infos/recommends =
- infos/placements = postgetstorage presetstorage
- infos/status = nodep experimental unfinished
- infos/metadata =
- infos/description = interprets strings with prefix 0x as hexadecimal numbers
## Introduction
TODO
## Usage
TODO
## Dependencies
None.
## Examples
TODO
## Limitations
None.
@@ -0,0 +1,213 @@
/**
* @file
*
* @brief Source for hexnumber plugin
*
* @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
*
*/
#include "hexnumber.h"
#include <kdbhelper.h>
#include <kdberrors.h>
#include <stdlib.h>
#include <stdio.h>
#include <kdbprivate.h>
#include <stdbool.h>
static KeySet * elektraContract (void)
{
return ksNew (
30, keyNew ("system/elektra/modules/hexnumber", KEY_VALUE, "hexnumber plugin waits for your orders", KEY_END),
keyNew ("system/elektra/modules/hexnumber/exports", KEY_END),
keyNew ("system/elektra/modules/hexnumber/exports/get", KEY_FUNC, elektraHexnumberGet, KEY_END),
keyNew ("system/elektra/modules/hexnumber/exports/set", KEY_FUNC, elektraHexnumberSet, KEY_END),
#include ELEKTRA_README (hexnumber)
keyNew ("system/elektra/modules/hexnumber/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END);
}
static int convertHexToDec (Key * key, Key * parentKey)
{
// get hex string from key
const char * hexValue = keyString (key);
int errnoSaved = errno;
// convert hex string to long long int
errno = 0;
char * endPtr;
unsigned long long int value = strtoull (hexValue, &endPtr, 16);
if (errno == ERANGE && value == ULLONG_MAX)
{
errno = errnoSaved;
ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_INVALID_RANGE, parentKey, "Hexadecimal number %s out of range 0 to %llu", hexValue,
ULLONG_MAX);
return ELEKTRA_PLUGIN_STATUS_ERROR;
}
else if ((errno != 0 && value == 0) || endPtr == hexValue)
{
errno = errnoSaved;
ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_INVALID_FORMAT, parentKey, "Hexadecimal number '%s' could not be read", hexValue);
return ELEKTRA_PLUGIN_STATUS_ERROR;
}
errno = errnoSaved;
// convert long long int back to string (formatted as decimal)
int result = snprintf (NULL, 0, "%llu", value);
if (result < 0)
{
return ELEKTRA_PLUGIN_STATUS_ERROR;
}
size_t length = (size_t) result + 1;
char * decValue = elektraMalloc (length);
if (!decValue)
{
ELEKTRA_MALLOC_ERROR (parentKey, length);
return ELEKTRA_PLUGIN_STATUS_ERROR;
}
result = snprintf (decValue, length, "%llu", value);
if (result < 0)
{
elektraFree (decValue);
return ELEKTRA_PLUGIN_STATUS_ERROR;
}
// set decimal string in key and set type in metadata
keySetString (key, decValue);
keySetMeta (key, "type", ELEKTRA_HEXNUMBER_META_TYPE);
elektraFree (decValue);
return ELEKTRA_PLUGIN_STATUS_SUCCESS;
}
static int convertDecToHex (Key * key, Key * parentKey)
{
// get decimal string from key
const char * decValue = keyString (key);
int errnoSaved = errno;
// convert hex string to long long int
errno = 0;
char * endPtr;
unsigned long long int value = strtoull (decValue, &endPtr, 10);
if (errno == ERANGE && value == ULLONG_MAX)
{
errno = errnoSaved;
ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_INVALID_RANGE, parentKey, "Decimal number %s out of range 0 to %llu", decValue,
ULLONG_MAX);
return ELEKTRA_PLUGIN_STATUS_ERROR;
}
else if ((errno != 0 && value == 0) || endPtr == decValue)
{
errno = errnoSaved;
ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_INVALID_FORMAT, parentKey, "Decimal number '%s' could not be read", decValue);
return ELEKTRA_PLUGIN_STATUS_ERROR;
}
errno = errnoSaved;
// convert long long int back to string (formatted as hexadecimal)
int result = snprintf (NULL, 0, "0x%llx", value);
if (result < 0)
{
return ELEKTRA_PLUGIN_STATUS_ERROR;
}
size_t length = (size_t) result;
char * hexValue = elektraMalloc (length);
if (!hexValue)
{
ELEKTRA_MALLOC_ERROR (parentKey, length);
return ELEKTRA_PLUGIN_STATUS_ERROR;
}
result = snprintf (hexValue, length, "0x%llx", value);
if (result < 0)
{
elektraFree (hexValue);
return ELEKTRA_PLUGIN_STATUS_ERROR;
}
// set hex string in key
keySetString (key, hexValue);
elektraFree (hexValue);
return ELEKTRA_PLUGIN_STATUS_SUCCESS;
}
/**
* Checks whether a given Key's value is a hexadecimal number.
*
* @param key The Key that should be checked.
* @param checkPrefix Set to true to indicate that a Key containing a string starting with 0x counts as hexadecimal.
*
* @retval true If the Key's value is a hexadecimal number.
* @retval false If the Key's value is not a hexadecimal number.
*/
static bool isHexNumber (const Key * key, const bool checkPrefix)
{
const Key * typeMeta = keyGetMeta (key, "type");
if (typeMeta)
{
ELEKTRA_LOG_DEBUG ("Meta key “type” contains value “%s", keyString (typeMeta));
return !strcmp (keyString (typeMeta), ELEKTRA_HEXNUMBER_META_TYPE);
}
typeMeta = keyGetMeta (key, "check/type");
if (typeMeta && !strcmp (keyString (typeMeta), ELEKTRA_HEXNUMBER_META_TYPE)) { return true; }
return checkPrefix && strncasecmp (keyString (key), "0x", 2) == 0;
}
int elektraHexnumberGet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned, Key * parentKey)
{
if (!elektraStrCmp (keyName (parentKey), "system/elektra/modules/hexnumber"))
{
KeySet * contract = elektraContract ();
ksAppend (returned, contract);
ksDel (contract);
return ELEKTRA_PLUGIN_STATUS_SUCCESS;
}
Key * cur;
ksRewind (returned);
int status = ELEKTRA_PLUGIN_STATUS_NO_UPDATE;
while ((cur = ksNext (returned)) != NULL)
{
if (!keyIsString (cur) || !isHexNumber (cur, true)) { continue; }
status |= convertHexToDec (cur, parentKey);
}
return status;
}
int elektraHexnumberSet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned ELEKTRA_UNUSED, Key * parentKey ELEKTRA_UNUSED)
{
Key * cur;
ksRewind (returned);
int status = ELEKTRA_PLUGIN_STATUS_NO_UPDATE;
while ((cur = ksNext (returned)) != NULL)
{
if (!keyIsString (cur) || !isHexNumber (cur, false)) { continue; }
status |= convertDecToHex (cur, parentKey);
}
return status;
}
Plugin * ELEKTRA_PLUGIN_EXPORT (hexnumber)
{
// clang-format off
return elektraPluginExport ("hexnumber",
ELEKTRA_PLUGIN_GET, &elektraHexnumberGet,
ELEKTRA_PLUGIN_SET, &elektraHexnumberSet,
ELEKTRA_PLUGIN_END);
}
@@ -0,0 +1,23 @@
/**
* @file
*
* @brief Header for hexnumber plugin
*
* @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
*
*/
#ifndef ELEKTRA_HEXNUMBER_H
#define ELEKTRA_HEXNUMBER_H
#include <kdbplugin.h>
#define ELEKTRA_HEXNUMBER_META_TYPE "hexnumber"
int elektraHexnumberGet (Plugin * handle, KeySet * ks, Key * parentKey);
int elektraHexnumberSet (Plugin * handle, KeySet * ks, Key * parentKey);
Plugin * ELEKTRA_PLUGIN_EXPORT (hexnumber);
#endif //ELEKTRA_HEXNUMBER_H
@@ -0,0 +1,79 @@
/**
* @file
*
* @brief Tests for hexnumber plugin
*
* @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
*
*/
#include <stdlib.h>
#include <string.h>
#include <kdbconfig.h>
#include <tests_plugin.h>
#define ELEKTRA_HEXNUMBER_META_TYPE "hexnumber"
#define CREATE_TEST_KEY(HEX) \
(keyNew ("user/tests/hexnumber/" #HEX, KEY_VALUE, #HEX, KEY_META, "type", ELEKTRA_HEXNUMBER_META_TYPE, KEY_END))
#define CHECK_TEST_KEY(HEX, DEC) \
succeed_if_same_string (keyString (ksLookupByName (ks, "user/tests/hexnumber/" #HEX, 0)), #DEC)\
static void test_basics (void)
{
Key * parentKey = keyNew ("user/tests/hexnumber", KEY_END);
KeySet * conf = ksNew (0, KS_END);
PLUGIN_OPEN ("hexnumber");
KeySet * ks = ksNew (0, KS_END);
succeed_if (plugin->kdbGet (plugin, ks, parentKey) == ELEKTRA_PLUGIN_STATUS_NO_UPDATE, "call to kdbGet was not successful");
succeed_if (plugin->kdbSet (plugin, ks, parentKey) == ELEKTRA_PLUGIN_STATUS_NO_UPDATE, "call to kdbSet was not successful");
keyDel (parentKey);
ksDel (ks);
PLUGIN_CLOSE ();
}
static void test_default (void)
{
Key * parentKey = keyNew ("user/tests/hexnumber", KEY_END);
KeySet * conf = ksNew (0, KS_END);
PLUGIN_OPEN ("hexnumber");
KeySet * ks = ksNew (30, CREATE_TEST_KEY (0xF), CREATE_TEST_KEY (0xf), CREATE_TEST_KEY (0x14), CREATE_TEST_KEY (0xFFFFFFFFFFFFFFFF),
CREATE_TEST_KEY (0x0), CREATE_TEST_KEY (0x2), CREATE_TEST_KEY (-0x2), CREATE_TEST_KEY (-0x1), KS_END);
succeed_if (plugin->kdbGet (plugin, ks, parentKey) >= 1, "call to kdbGet was not successful");
CHECK_TEST_KEY (0xF, 15);
CHECK_TEST_KEY (0xf, 15);
CHECK_TEST_KEY (0x14, 20);
CHECK_TEST_KEY (0xFFFFFFFFFFFFFFFF, 18446744073709551615);
CHECK_TEST_KEY (0x0, 0);
CHECK_TEST_KEY (0x2, 2);
CHECK_TEST_KEY (-0x2, 18446744073709551614);
CHECK_TEST_KEY (-0x1, 18446744073709551615);
ksDel (ks);
keyDel (parentKey);
PLUGIN_CLOSE ();
}
int main (int argc, char ** argv)
{
printf ("HEXNUMBER TESTS\n");
printf ("==================\n\n");
init (argc, argv);
test_basics ();
test_default ();
print_result ("testmod_hexnumber");
return nbError;
}

0 comments on commit 1a6a8a3

Please sign in to comment.