From 0b61024af2e98c8af68f9175eda1073a8b059bca Mon Sep 17 00:00:00 2001 From: Thomas Wahringer Date: Wed, 28 Mar 2018 17:28:26 +0200 Subject: [PATCH] type conversion: added supermacro for type to value conversion functions --- src/include/macros/type_create_to_value.h | 98 +++++++++++++++++++ .../internalnotification.c | 32 +++--- .../internalnotification.h | 3 - .../internalnotification/macros/add_type.h | 22 ++--- 4 files changed, 123 insertions(+), 32 deletions(-) create mode 100644 src/include/macros/type_create_to_value.h diff --git a/src/include/macros/type_create_to_value.h b/src/include/macros/type_create_to_value.h new file mode 100644 index 00000000000..5181e2a624e --- /dev/null +++ b/src/include/macros/type_create_to_value.h @@ -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 + +#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 diff --git a/src/plugins/internalnotification/internalnotification.c b/src/plugins/internalnotification/internalnotification.c index 4dbaa4783fb..7b9dad15cab 100644 --- a/src/plugins/internalnotification/internalnotification.c +++ b/src/plugins/internalnotification/internalnotification.c @@ -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 @@ -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" /** diff --git a/src/plugins/internalnotification/internalnotification.h b/src/plugins/internalnotification/internalnotification.h index a854b1a8eef..bb4da6cb099 100644 --- a/src/plugins/internalnotification/internalnotification.h +++ b/src/plugins/internalnotification/internalnotification.h @@ -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) \ diff --git a/src/plugins/internalnotification/macros/add_type.h b/src/plugins/internalnotification/macros/add_type.h index ac38a3fd54f..3391b9d2657 100644 --- a/src/plugins/internalnotification/macros/add_type.h +++ b/src/plugins/internalnotification/macros/add_type.h @@ -41,7 +41,8 @@ #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) @@ -49,23 +50,16 @@ #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 + 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); @@ -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