Line data Source code
1 : // lgtm [cpp/missing-header-guard]
2 :
3 : /**
4 : * @copyright BSD License (see doc/COPYING or http://www.libelektra.org)
5 : *
6 : * @brief Create key to type conversion function.
7 : *
8 : * This supermacro creates the following functions:
9 : * - int NAME_MACRO (TYPE_NAME) (Key * key, TYPE * variable)
10 : *
11 : * @param TYPE valid C type (e.g. int or kdb_short_t)
12 : * @param TYPE_NAME name suffix for the functions (e.g. Int or UnsignedLong)
13 : * @param VALUE_TYPE optional, defaults to TYPE. Ideally a larger type assigned to variable `value` for
14 : * checking the range before the variable is updated
15 : * @param TO_VALUE expression for converting `string` (variable containing the key value) to VALUE_TYPE
16 : * @param CHECK_CONVERSION optional, defaults to true. A boolean expression. Allows to check the range after
17 : * conversion. Use ELEKTRA_TYPE_CHECK_CONVERSION to check if a conversion using
18 : * strto*()-functions was successful and ELEKTRA_TYPE_CHECK_CONVERSION_RANGE (RANGE)
19 : * to check additionally for a specified range.
20 : * @param CHECK_FAIL_BLOCK optional, defaults to logging a warning in the key. The code to be executed (before returning 0), if
21 : * CHECK_CONVERSION evaluates to false.
22 : * @param PRE_CHECK_CONVERSION_BLOCK optional, defaults to empty. Allows to add additional code for pre-conversion checks
23 : * (e.g. ELEKTRA_TYPE_NEGATIVE_PRE_CHECK_BLOCK)
24 : * @param PRE_CHECK_CONVERSION optional, defaults to true. A boolean expression to check the contents of `string` before conversion
25 : * (e.g. ELEKTRA_TYPE_NEGATIVE_PRE_CHECK).
26 : * @param PRE_CHECK_FAIL_BLOCK optional, defaults to logging a warning in the key. The code to be executed (before returning 0), if
27 : * PRE_CHECK_CONVERSION evaluates to false.
28 : * @param DISABLE_UNDEF_PARAMETERS define to disable undefining of parameters after the macro. Use if parameters
29 : * are used within another supermacro.
30 : * @param CODE_ONLY optional, defaults to 0. Set to 1 to only generate the function body. This is useful, if you want to create a
31 : * function with a custom signature for example.
32 : * @param KEY_PARAM_NAME must be set, #if CODE_ONLY, will be set to 'key' otherwise. The name of the variable/parameter containing
33 : * the Key, whose value will be converted
34 : * @param VARIABLE_PARAM_NAME must be set, #if CODE_ONLY, will be set to 'variable' otherwise. The name of the variable/parameter
35 : * containing the pointer to where the result should be written
36 : */
37 : #ifndef TYPE
38 : #error "You have to #define TYPE, TYPE_NAME, TO_VALUE and NAME_MACRO before including the type_create_to_value supermacro"
39 : #endif
40 : #ifndef VALUE_TYPE
41 : // use type as default if not set
42 : #define VALUE_TYPE TYPE
43 : #endif
44 : #ifndef TYPE_NAME
45 : #error "You have to #define TYPE, TYPE_NAME, TO_VALUE and NAME_MACRO before including the type_create_to_value supermacro"
46 : #endif
47 : #ifndef NAME_MACRO
48 : #error "You have to #define TYPE, TYPE_NAME, TO_VALUE and NAME_MACRO before including the type_create_to_value supermacro"
49 : #endif
50 : #ifndef TO_VALUE
51 : #error "You have to #define TYPE, TYPE_NAME, TO_VALUE and NAME_MACRO before including the type_create_to_value supermacro"
52 : #endif
53 : #ifndef CHECK_CONVERSION
54 : #define CHECK_CONVERSION 1
55 : #endif
56 : #ifndef PRE_CHECK_CONVERSION
57 : #define PRE_CHECK_CONVERSION 1
58 : #endif
59 : #ifndef PRE_CHECK_BLOCK
60 : #define PRE_CHECK_BLOCK
61 : #endif
62 : #ifndef PRE_CHECK_FAIL_BLOCK
63 : #define PRE_CHECK_FAIL_BLOCK ELEKTRA_LOG_WARNING ("pre-check for type conversion failed! string=%s", keyString (key));
64 : #endif
65 : #ifndef CHECK_FAIL_BLOCK
66 : #define CHECK_FAIL_BLOCK ELEKTRA_LOG_WARNING ("type conversion failed! string=%s, stopped=%c errno=%d", keyString (key), *end, errno);
67 : #endif
68 : #ifndef CODE_ONLY
69 : #define CODE_ONLY 0
70 : #endif
71 :
72 : #if CODE_ONLY
73 : #if (!defined(KEY_PARAM_NAME) || !defined(VARIABLE_PARAM_NAME))
74 : #error "When CODE_ONLY is defined, you have to #define KEY_PARAM_NAME and VARIABLE_PARAM_NAME"
75 : #endif
76 : #else
77 : #undef KEY_PARAM_NAME
78 : #undef VARIABLE_PARAM_NAME
79 : #define KEY_PARAM_NAME key
80 : #define VARIABLE_PARAM_NAME variable
81 : #endif
82 :
83 : // These macros get defined at first inclusion
84 : #ifndef ELEKTRA_TYPE_CONVERSION_MACROS
85 : #define ELEKTRA_TYPE_CONVERSION_MACROS
86 : #define ELEKTRA_TYPE_CHECK_CONVERSION (*end == 0 && errno == 0)
87 : #define ELEKTRA_TYPE_CHECK_CONVERSION_RANGE(CHECK_RANGE) (ELEKTRA_TYPE_CHECK_CONVERSION && CHECK_RANGE)
88 : #define ELEKTRA_TYPE_NEGATIVE_PRE_CHECK_BLOCK \
89 : const char * test = string; \
90 : while (isspace (test[0]) || test[0] == 0) \
91 : { \
92 : test++; \
93 : }
94 : #define ELEKTRA_TYPE_NEGATIVE_PRE_CHECK (test[0] != '-')
95 : #endif
96 :
97 : #if !(CODE_ONLY)
98 : #include <errno.h> // errno
99 :
100 : #define TYPE_CONVERSION_SIGNATURE(TYPE, TYPE_NAME, NAME_MACRO) \
101 : int NAME_MACRO (TYPE_NAME) (const Key * KEY_PARAM_NAME, TYPE * VARIABLE_PARAM_NAME)
102 :
103 : /**
104 : * Convert string to TYPE.
105 : *
106 : * The variable is only changed if no conversion error occurred
107 : *
108 : * Example:
109 : * int variable = 1234;
110 : * if (!NAME_MACRO (TYPE_NAME) (key, &variable))
111 : * {
112 : * // conversion failed
113 : * // variable == 1234
114 : * }
115 : * // variable was changed
116 : *
117 : * @param key key
118 : * @param variable pointer to variable
119 : * @retval 1 on success
120 : * @retval 0 on conversion error
121 : */
122 138 : TYPE_CONVERSION_SIGNATURE (TYPE, TYPE_NAME, NAME_MACRO)
123 : {
124 : #endif
125 2670 : char * end ELEKTRA_UNUSED;
126 2670 : const char * string = keyValue (KEY_PARAM_NAME);
127 2670 : errno = 0;
128 400 : PRE_CHECK_BLOCK
129 677 : if (!PRE_CHECK_CONVERSION)
130 : {
131 : PRE_CHECK_FAIL_BLOCK
132 : return 0;
133 : }
134 : // convert string to target type
135 1932 : VALUE_TYPE value = TO_VALUE;
136 1932 : if (CHECK_CONVERSION)
137 : {
138 : // only update if conversion was successful
139 2532 : *(VARIABLE_PARAM_NAME) = (TYPE) value;
140 1989 : return 1;
141 : }
142 : else
143 : {
144 : CHECK_FAIL_BLOCK
145 : return 0;
146 : }
147 : #if !(CODE_ONLY)
148 : }
149 :
150 : #undef TYPE_CONVERSION_SIGNATURE
151 : #endif
152 :
153 : #ifndef DISABLE_UNDEF_PARAMETERS
154 : #undef TYPE
155 : #undef VALUE_TYPE
156 : #undef TYPE_NAME
157 : #undef NAME_MACRO
158 : #undef TO_VALUE
159 : #undef CHECK_CONVERSION
160 : #undef PRE_CHECK_BLOCK
161 : #undef PRE_CHECK_CONVERSION
162 : #undef PRE_CHECK_FAIL_BLOCK
163 : #undef CHECK_FAIL_BLOCK
164 : #undef CODE_ONLY
165 : #undef KEY_PARAM_NAME
166 : #undef VARIABLE_PARAM_NAME
167 : #endif
168 : #undef DISABLE_UNDEF_PARAMETERS
|