Skip to content
This repository has been archived by the owner on Oct 15, 2024. It is now read-only.

Commit

Permalink
type conversion: added supermacro for type to value conversion functions
Browse files Browse the repository at this point in the history
  • Loading branch information
waht committed Apr 6, 2018
1 parent f2b03c8 commit 0b61024
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 32 deletions.
98 changes: 98 additions & 0 deletions src/include/macros/type_create_to_value.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/**
* Create key to type conversion function.
*
* This supermacro creates the following functions:
* - int NAME_MACRO (TYPE_NAME) (Key * key, TYPE * variable)
*
* @param TYPE valid C type (e.g. int or kdb_short_t)
* @param TYPE_NAME name suffix for the functions (e.g. Int or UnsignedLong)
* @param VALUE_TYPE optional, defaults to TYPE. Ideally a larger type assigned to variable `value` for
* checking the range before the variable is updated
* @param TO_VALUE expression for converting `string` (variable containing the key value) to VALUE_TYPE
* @param CHECK_CONVERSION optional, defaults to true. A boolean expression. Allows to check the range after
* conversion. Use ELEKTRA_TYPE_CHECK_CONVERSION to check if a conversion using
* strto*()-functions was successful and ELEKTRA_TYPE_CHECK_CONVERSION_RANGE (RANGE)
* to check additionally for a specified range.
* @param DISABLE_UNDEF_PARAMETERS define to disable undefining of parameters after the macro. Use if parameters
* are used within another supermacro.
*/
#ifndef TYPE
#error "You have to #define TYPE, TYPE_NAME, TO_VALUE and NAME_MACRO before including the type_create_to_value supermacro"
#endif
#ifndef VALUE_TYPE
// use type as default if not set
#define VALUE_TYPE TYPE
#endif
#ifndef TYPE_NAME
#error "You have to #define TYPE, TYPE_NAME, TO_VALUE and NAME_MACRO before including the type_create_to_value supermacro"
#endif
#ifndef NAME_MACRO
#error "You have to #define TYPE, TYPE_NAME, TO_VALUE and NAME_MACRO before including the type_create_to_value supermacro"
#endif
#ifndef TO_VALUE
#error "You have to #define TYPE, TYPE_NAME, TO_VALUE and NAME_MACRO before including the type_create_to_value supermacro"
#endif
#ifndef CHECK_CONVERSION
#define CHECK_CONVERSION 1
#endif

#ifndef ELEKTRA_TYPE_CONVERSION_MACROS
#define ELEKTRA_TYPE_CONVERSION_MACROS
#define ELEKTRA_TYPE_CHECK_CONVERSION (*end == 0 && errno == 0)
#define ELEKTRA_TYPE_CHECK_CONVERSION_RANGE(CHECK_RANGE) (ELEKTRA_TYPE_CHECK_CONVERSION && CHECK_RANGE)
#endif

#include <errno.h> // errno

#define TYPE_CONVERSION_SIGNATURE(TYPE, TYPE_NAME, NAME_MACRO) int NAME_MACRO (TYPE_NAME) (Key * key, TYPE * variable)

/**
* Convert string to TYPE.
*
* The variable is only changed if no conversion error occured
*
* Example:
* int variable = 1234;
* if (!NAME_MACRO (TYPE_NAME) (key, &variable))
* {
* // conversion failed
* // variable == 1234
* }
* // variable was changed
*
* @param key key
* @param variable pointer to variable
* @retval 1 on success
* @retval 0 on conversion error
*/
TYPE_CONVERSION_SIGNATURE (TYPE, TYPE_NAME, NAME_MACRO)
{
char * end ELEKTRA_UNUSED;
const char * string = keyValue (key);
errno = 0;
// convert string to target type
VALUE_TYPE value = TO_VALUE;
if (CHECK_CONVERSION)
{
// only update if conversion was successful
*(variable) = value;
return 1;
}
else
{
ELEKTRA_LOG_WARNING ("type conversion failed! string=%s, stopped=%c errno=%d", keyString (key), *end, errno);
return 0;
}
}

#undef TYPE_CONVERSION_SIGNATURE

#ifndef DISABLE_UNDEF_PARAMETERS
#undef TYPE
#undef VALUE_TYPE
#undef TYPE_NAME
#undef NAME_MACRO
#undef TO_VALUE
#undef CHECK_CONVERSION
#endif
#undef DISABLE_UNDEF_PARAMETERS
32 changes: 16 additions & 16 deletions src/plugins/internalnotification/internalnotification.c
Original file line number Diff line number Diff line change
Expand Up @@ -326,38 +326,38 @@ void elektraInternalnotificationUpdateRegisteredKeys (Plugin * plugin, KeySet *
#define VALUE_TYPE long int
#define TYPE_NAME Int
#define TO_VALUE (strtol (string, &end, 10))
#define CHECK_CONVERSION INTERNALNOTIFICATION_CHECK_CONVERSION_RANGE (value <= INT_MAX && value >= INT_MIN)
#define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION_RANGE (value <= INT_MAX && value >= INT_MIN)
#include "macros/add_type.h"

#define TYPE unsigned int
#define VALUE_TYPE unsigned long int
#define TYPE_NAME UnsignedInt
#define TO_VALUE (strtoul (string, &end, 10))
#define CHECK_CONVERSION INTERNALNOTIFICATION_CHECK_CONVERSION_RANGE (value <= UINT_MAX)
#define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION_RANGE (value <= UINT_MAX)
#include "macros/add_type.h"

#define TYPE long
#define TYPE_NAME Long
#define TO_VALUE (strtol (string, &end, 10))
#define CHECK_CONVERSION INTERNALNOTIFICATION_CHECK_CONVERSION
#define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION
#include "macros/add_type.h"

#define TYPE unsigned long
#define TYPE_NAME UnsignedLong
#define TO_VALUE (strtoul (string, &end, 10))
#define CHECK_CONVERSION INTERNALNOTIFICATION_CHECK_CONVERSION
#define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION
#include "macros/add_type.h"

#define TYPE float
#define TYPE_NAME Float
#define TO_VALUE (strtof (string, &end))
#define CHECK_CONVERSION INTERNALNOTIFICATION_CHECK_CONVERSION
#define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION
#include "macros/add_type.h"

#define TYPE double
#define TYPE_NAME Double
#define TO_VALUE (strtod (string, &end))
#define CHECK_CONVERSION INTERNALNOTIFICATION_CHECK_CONVERSION
#define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION
#include "macros/add_type.h"

// for kdb_*_t Types
Expand All @@ -375,63 +375,63 @@ void elektraInternalnotificationUpdateRegisteredKeys (Plugin * plugin, KeySet *
#define VALUE_TYPE unsigned int
#define TYPE_NAME KdbOctet
#define TO_VALUE (strtoul (string, &end, 10))
#define CHECK_CONVERSION INTERNALNOTIFICATION_CHECK_CONVERSION_RANGE (value <= 255)
#define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION_RANGE (value <= 255)
#include "macros/add_type.h"

#define TYPE kdb_short_t
#define VALUE_TYPE int
#define TYPE_NAME KdbShort
#define TO_VALUE (strtol (string, &end, 10))
#define CHECK_CONVERSION INTERNALNOTIFICATION_CHECK_CONVERSION_RANGE (value <= SHRT_MAX && value >= SHRT_MIN)
#define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION_RANGE (value <= SHRT_MAX && value >= SHRT_MIN)
#include "macros/add_type.h"

#define TYPE kdb_unsigned_short_t
#define VALUE_TYPE unsigned int
#define TYPE_NAME KdbUnsignedShort
#define TO_VALUE (strtoul (string, &end, 10))
#define CHECK_CONVERSION INTERNALNOTIFICATION_CHECK_CONVERSION_RANGE (value <= USHRT_MAX)
#define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION_RANGE (value <= USHRT_MAX)
#include "macros/add_type.h"

#define TYPE kdb_long_t
#define TYPE_NAME KdbLong
#define TO_VALUE (strtol (string, &end, 10))
#define CHECK_CONVERSION INTERNALNOTIFICATION_CHECK_CONVERSION
#define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION
#include "macros/add_type.h"

#define TYPE kdb_unsigned_long_t
#define TYPE_NAME KdbUnsignedLong
#define TO_VALUE (strtoul (string, &end, 10))
#define CHECK_CONVERSION INTERNALNOTIFICATION_CHECK_CONVERSION
#define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION
#include "macros/add_type.h"

#define TYPE kdb_long_long_t
#define TYPE_NAME KdbLongLong
#define TO_VALUE (ELEKTRA_LONG_LONG_S (string, &end, 10))
#define CHECK_CONVERSION INTERNALNOTIFICATION_CHECK_CONVERSION
#define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION
#include "macros/add_type.h"

#define TYPE kdb_unsigned_long_long_t
#define TYPE_NAME KdbUnsignedLongLong
#define TO_VALUE (ELEKTRA_UNSIGNED_LONG_LONG_S (string, &end, 10))
#define CHECK_CONVERSION INTERNALNOTIFICATION_CHECK_CONVERSION
#define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION
#include "macros/add_type.h"

#define TYPE kdb_float_t
#define TYPE_NAME KdbFloat
#define TO_VALUE (strtof (string, &end))
#define CHECK_CONVERSION INTERNALNOTIFICATION_CHECK_CONVERSION
#define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION
#include "macros/add_type.h"

#define TYPE kdb_double_t
#define TYPE_NAME KdbDouble
#define TO_VALUE (strtod (string, &end))
#define CHECK_CONVERSION INTERNALNOTIFICATION_CHECK_CONVERSION
#define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION
#include "macros/add_type.h"

#define TYPE kdb_long_double_t
#define TYPE_NAME KdbLongDouble
#define TO_VALUE (strtold (string, &end))
#define CHECK_CONVERSION INTERNALNOTIFICATION_CHECK_CONVERSION
#define CHECK_CONVERSION ELEKTRA_TYPE_CHECK_CONVERSION
#include "macros/add_type.h"

/**
Expand Down
3 changes: 0 additions & 3 deletions src/plugins/internalnotification/internalnotification.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@ Plugin * ELEKTRA_PLUGIN_EXPORT (internalnotification);
void elektraInternalnotificationUpdateRegisteredKeys (Plugin * plugin, KeySet * keySet);
void elektraInternalnotificationDoUpdate (Key * changedKey, ElektraNotificationCallbackContext * context);

#define INTERNALNOTIFICATION_CHECK_CONVERSION_RANGE(CHECK_RANGE) (*end == 0 && errno == 0 && CHECK_RANGE)
#define INTERNALNOTIFICATION_CHECK_CONVERSION (*end == 0 && errno == 0)

#define INTERNALNOTIFICATION_REGISTER_NAME(TYPE_NAME) elektraInternalnotificationRegister##TYPE_NAME

#define INTERNALNOTIFICATION_EXPORT_FUNCTION(TYPE_NAME) \
Expand Down
22 changes: 9 additions & 13 deletions src/plugins/internalnotification/macros/add_type.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,31 +41,25 @@
#define ELEKTRA_CONCAT(X, Y) ELEKTRA_CONCAT2 (X, Y)
#define ELEKTRA_CONCAT2(X, Y) X##Y

#define INTERNALNOTIFICATION_CONVERSION_CALLBACK_NAME(TYPE_NAME) ELEKTRA_CONCAT (elektraInternalnotificationConvert, TYPE_NAME)
#define INTERNALNOTIFICATION_CONVERSION_FUNCTION_NAME(TYPE_NAME) ELEKTRA_CONCAT (elektraInternalnotificationConvert, TYPE_NAME)
#define INTERNALNOTIFICATION_CONVERSION_CALLBACK_NAME(TYPE_NAME) ELEKTRA_CONCAT (elektraInternalnotificationConvertCallback, TYPE_NAME)

#define INTERNALNOTIFICATION_REGISTER_SIGNATURE(TYPE, TYPE_NAME) \
int INTERNALNOTIFICATION_REGISTER_NAME (TYPE_NAME) (Plugin * handle, Key * key, TYPE * variable)

#define INTERNALNOTIFICATION_CONVERSION_CALLBACK_SIGNATURE(TYPE_NAME) \
void INTERNALNOTIFICATION_CONVERSION_CALLBACK_NAME (TYPE_NAME) (Key * key, void * context)

#define DISABLE_UNDEF_PARAMETERS
#define NAME_MACRO INTERNALNOTIFICATION_CONVERSION_FUNCTION_NAME
#include <macros/type_create_to_value.h>

INTERNALNOTIFICATION_CONVERSION_CALLBACK_SIGNATURE (TYPE_NAME)
{
_ElektraInternalnotificationConversionContext * ctx = (_ElektraInternalnotificationConversionContext *) context;
TYPE * variable = (TYPE *) ctx->variable;
char * end ELEKTRA_UNUSED;
const char * string = keyValue (key);
errno = 0;
/* convert string to target type */
VALUE_TYPE value = TO_VALUE;
/* only update if conversion was successful */
if (CHECK_CONVERSION)
{
*(variable) = value;
}
else
if (!INTERNALNOTIFICATION_CONVERSION_FUNCTION_NAME (TYPE_NAME) (key, variable))
{
ELEKTRA_LOG_WARNING ("conversion failed! string=%s, stopped=%c errno=%d", keyString (key), *end, errno);
if (ctx->errorCallback)
{
ctx->errorCallback (key, ctx->errorCallbackContext);
Expand Down Expand Up @@ -99,8 +93,10 @@ INTERNALNOTIFICATION_REGISTER_SIGNATURE (TYPE, TYPE_NAME)
#undef ELEKTRA_CONCAT
#undef ELEKTRA_CONCAT2
#undef INTERNALNOTIFICATION_CONVERSION_CALLBACK_NAME
#undef INTERNALNOTIFICATION_CONVERSION_FUNCTION_NAME_SIGNATURE
#undef INTERNALNOTIFICATION_CONVERSION_CALLBACK_SIGNATURE
#undef INTERNALNOTIFICATION_REGISTER_SIGNATURE
#undef NAME_MACRO

#undef TYPE
#undef VALUE_TYPE
Expand Down

0 comments on commit 0b61024

Please sign in to comment.