1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12
13#pragma once
14
15#include <utils/attribute.h>
16
17#if (defined(__clang__) && __has_feature(c_generic_selections)) || \
18    (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) && __STDC_VERSION__ >= 201112L)
19
20    /* On a fully-compliant C11 compiler, we provide a generic mechanism for printing a variable.
21     *
22     * Example usage:
23     *
24     *     int i = 42;
25     *     printf(FORMAT_STRING(i), i);
26     *
27     * Some known gotchas:
28     *  - Character literals are ints, so you will need to cast them to get sensible results:
29     *      FORMAT_STRING((char)'a')
30     *  - String literals are character arrays, so you will need to also cast them:
31     *      FORMAT_STRING((char*)"hello world")
32     */
33
34    #define FORMAT_STRING(x) _Generic((x), \
35        char:               "%c",   \
36        signed char:        "%hhd", \
37        unsigned char:      "%hhu", \
38        short:              "%hd",  \
39        unsigned short:     "%hu",  \
40        int:                "%d",   \
41        unsigned int:       "%u",   \
42        long:               "%ld",  \
43        unsigned long:      "%lu",  \
44        long long:          "%lld", \
45        unsigned long long: "%llu", \
46        double:             "%f",   \
47        long double:        "%Lf",  \
48        float:              "%f",   \
49        char*:              "%s",   \
50        void*:              "%p",   \
51                                    \
52        /* The remaining cases are not necessary on GCC, where lvalue conversion is performed, */ \
53        /* but are needed for Clang, which does not do this conversion.                        */ \
54                                    \
55        const char:               "%c",   \
56        const signed char:        "%hhd", \
57        const unsigned char:      "%hhu", \
58        const short:              "%hd",  \
59        const unsigned short:     "%hu",  \
60        const int:                "%d",   \
61        const unsigned int:       "%u",   \
62        const long:               "%ld",  \
63        const unsigned long:      "%lu",  \
64        const long long:          "%lld", \
65        const unsigned long long: "%llu", \
66        const double:             "%f",   \
67        const long double:        "%Lf",  \
68        const float:              "%f",   \
69        const char*:              "%s",   \
70        const void*:              "%p",   \
71        volatile char:               "%c",   \
72        volatile signed char:        "%hhd", \
73        volatile unsigned char:      "%hhu", \
74        volatile short:              "%hd",  \
75        volatile unsigned short:     "%hu",  \
76        volatile int:                "%d",   \
77        volatile unsigned int:       "%u",   \
78        volatile long:               "%ld",  \
79        volatile unsigned long:      "%lu",  \
80        volatile long long:          "%lld", \
81        volatile unsigned long long: "%llu", \
82        volatile double:             "%f",   \
83        volatile long double:        "%Lf",  \
84        volatile float:              "%f",   \
85        volatile char*:              "%s",   \
86        volatile void*:              "%p"    \
87                                             \
88        /* We assume that no one needs to print a const- *and* volatile-qualified variable. */ \
89                                             )
90
91#else
92
93    /* In an unsupported compiler configuration, trigger a compile-time error if the user has
94     * attempted to use FORMAT_STRING.
95     */
96
97    extern const char *FORMAT_STRING(void *dummy, ...)
98        ERROR("FORMAT_STRING requires full C11 compiler support");
99
100#endif
101