Home | History | Annotate | Download | only in inc
      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