1 /** @addtogroup MC_RTM
2  * @{
3  * MobiCore Version Helper Macros
4  *
5  * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote
16  *    products derived from this software without specific prior
17  *    written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
20  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
25  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 #include <stdio.h>
32 
33 //lint -emacro(*,MC_CHECK_VERSION) Disable all warnings for this macro.
34 //lint -emacro(*,MC_MAKE_VERSION) Disable all warnings for this macro.
35 //lint -emacro(*,MC_GET_MAJOR_VERSION) Disable all warnings for this macro.
36 //lint -emacro(*,MC_GET_MINOR_VERSION) Disable all warnings for this macro.
37 //lint -emacro(*,MC_GET_MINOR_VERSION) Disable all warnings for this macro.
38 //lint -emacro(*,ASSERT_VERSION_IMPLEMENTATION) Disable all warnings for this macro.
39 //lint -esym(*,Actual_*) Disable all warnings for these functions.
40 
41 /** Create a version number given major and minor numbers. */
42 #define MC_MAKE_VERSION(major,minor) \
43     (   (((major) & 0xffff) << 16) |\
44         ((minor) & 0xffff))
45 
46 /** Get major version number from complete version. */
47 #define MC_GET_MAJOR_VERSION(version) ((version) >> 16)
48 
49 /** Get minor version number from complete version. */
50 #define MC_GET_MINOR_VERSION(version) ((version) & 0xffff)
51 
52 // Asserts expression at compile-time (to be used outside a function body).
53 #define ASSERT_VERSION_IMPLEMENTATION(comp, versionpart, requiredV, actualV, expression) \
54     extern int Actual_##comp##_##versionpart##_VERSION_##actualV##_does_not_match_required_version_##requiredV[(expression) ? 0:-1]
55 
56 #define ASSERT_VERSION_EVALUATOR(comp, versionpart, requiredV, actualV, expression) \
57         ASSERT_VERSION_IMPLEMENTATION(comp, versionpart, requiredV, actualV, expression)
58 
59 #define ASSERT_VERSION(required, comparator, comp, versionpart) \
60     ASSERT_VERSION_EVALUATOR(comp, versionpart, required, comp ##_VERSION_## versionpart, required comparator comp ##_VERSION_## versionpart)
61 
62 /** Checks at compile-time that an interface version provided by component
63  * 'comp' is identical to the required version of a component using this interface.
64  * Note! This check is useful for components that IMPLEMENT a particular
65  * interface to be alerted of changes to the interface which are likely to
66  * require adaptations in the implementation. */
67 #define MC_CHECK_VERSION_EQUALS(comp, major, minor) \
68     ASSERT_VERSION(major, ==, comp, MAJOR); \
69     ASSERT_VERSION(minor, ==, comp, MINOR);
70 
71 /** Checks at compile-time that an interface version provided by component 'comp' meets the
72  * required version of a component using this interface. */
73 #define MC_CHECK_VERSION_STATIC(comp, majorRequired, minorRequired) \
74     ASSERT_VERSION(majorRequired, ==, comp, MAJOR); \
75     ASSERT_VERSION(minorRequired, <=, comp, MINOR);
76 
77 /** Version check helper macro for an interface consumer against an interface
78  * provider.
79  * @param comp          Name of Interface to check.
80  * @param majorRequired Required major version of interface provider.
81  * @param minorRequired Required minor version of interface provider.
82  * Performs a compile-time interface version check that comp_VERSION_MAJOR
83  * equals majorRequired and that comp_VERSION_MINOR is at least minorRequired.
84  * On success, compilation goes through.
85  * On error, compilation breaks, telling the component that did not match in the
86  * error message.
87  *
88  * Additionally, a function is created:
89  *
90  * checkVersionOk##component(uint32_t version, char** errmsg)
91  *
92  * Compares version against majorRequired and minorRequired.
93  * Additionally, it creates a message string that can be printed out using printf("%s", errmsg).
94  * It returns either only the actual version, or on mismatch, actual and required version.
95  *
96  * @param version[in] component version as returned by layer-specific getVersion.
97  * @param errmsg[out] a message string that contains a log.
98  *
99  */
100 #if !defined(NDEBUG)
101 #define MC_CHECK_VERSION(comp, majorRequired, minorRequired) \
102     MC_CHECK_VERSION_STATIC(comp, majorRequired, minorRequired) \
103     static uint32_t checkVersionOk##comp(uint32_t version, char** errmsg) { \
104         static char msgBuf[100]; \
105         uint32_t major = MC_GET_MAJOR_VERSION(version); \
106         uint32_t minor = MC_GET_MINOR_VERSION(version); \
107         uint32_t ret = 0; \
108         *errmsg = msgBuf; \
109         if ((major == majorRequired) && (minor >= minorRequired)) { \
110             snprintf(msgBuf, sizeof(msgBuf), \
111                 #comp " version is %u.%u", major, minor); \
112             ret = 1; \
113         } else { \
114             snprintf(msgBuf, sizeof(msgBuf), \
115                 #comp " version error. Got: %u.%u, want >= %u.%u", major, minor, majorRequired, minorRequired); \
116         } \
117         msgBuf[sizeof(msgBuf) - 1] = '\0'; \
118         return ret; \
119     }
120 #else
121 #define MC_CHECK_VERSION(comp, majorRequired, minorRequired) \
122     MC_CHECK_VERSION_STATIC(comp, majorRequired, minorRequired) \
123     static uint32_t checkVersionOk##comp(uint32_t version, char** errmsg) { \
124         uint32_t major = MC_GET_MAJOR_VERSION(version); \
125         uint32_t minor = MC_GET_MINOR_VERSION(version); \
126         *errmsg = NULL; \
127         if ((major == majorRequired) && (minor >= minorRequired)) { \
128             return 1; \
129         }; \
130         return 0; \
131     }
132 #endif
133 
134 /** Version check helper macro for version checks of a data object version
135  * against an data object consumer.
136  *
137  * @param comp           Name of Interface to check.
138  * @param majorRequired Major data object version supported by component.
139  * @param minorRequired Minor data object version supported by component.
140  * Performs a compile-time interface version check that comp_VERSION_MAJOR
141  * equals majorRequired and that comp_VERSION_MINOR is at least minorRequired.
142  * On success, compilation goes through.
143  * On error, compilation breaks, telling the component that did not match in the
144  * error message.
145  *
146  * Additionally, the following function is created:
147  *
148  * checkVersionOkDataObject##component(uint32_t version, char** errmsg)
149  *
150  * This function checks that the data object version is compatible with the
151  * interface version; that is, the major version of the data object must match
152  * exactly and the minor version of the data object MUST BE LESS OR EQUAL to the
153  * required interface version.
154  * Additionally, it creates a message string that can be printed out using printf("%s", errmsg).
155  * It returns either only the actual version, or on mismatch, actual and
156  * provided version.
157  *
158  * @param version[in] Data object version of data object.
159  * @param errmsg[out] a message string that contains a log.
160  *
161  */
162 #if !defined(NDEBUG)
163 #define MC_CHECK_DATA_OBJECT_VERSION(comp, majorRequired, minorRequired) \
164     MC_CHECK_VERSION_STATIC(comp, majorRequired, minorRequired) \
165     static uint32_t checkVersionOkDataObject##comp(uint32_t version, char** errmsg) { \
166         static char msgBuf[100]; \
167         uint32_t major = MC_GET_MAJOR_VERSION(version); \
168         uint32_t minor = MC_GET_MINOR_VERSION(version); \
169         uint32_t ret = 0; \
170         *errmsg = msgBuf; \
171         if ((major == majorRequired) && (minor <= minorRequired)) { \
172             snprintf(msgBuf, sizeof(msgBuf), \
173                 #comp " version is %u.%u", major, minor); \
174             ret = 1; \
175         } else { \
176             snprintf(msgBuf, sizeof(msgBuf), \
177                 #comp " version error. Got: %u.%u, want <= %u.%u", major, minor, majorRequired, minorRequired); \
178         } \
179         msgBuf[sizeof(msgBuf) - 1] = '\0'; \
180         return ret; \
181     }
182 #else
183 #define MC_CHECK_DATA_OBJECT_VERSION(comp, majorRequired, minorRequired) \
184     MC_CHECK_VERSION_STATIC(comp, majorRequired, minorRequired) \
185     static uint32_t checkVersionOkDataObject##comp(uint32_t version, char** errmsg) { \
186         uint32_t major = MC_GET_MAJOR_VERSION(version); \
187         uint32_t minor = MC_GET_MINOR_VERSION(version); \
188         *errmsg = NULL; \
189         if ((major == majorRequired) && (minor <= minorRequired)) { \
190             return 1; \
191         }; \
192         return 0; \
193     }
194 #endif
195