/* macros.h - collection of useful macros */ #ifndef MACROS_H #define MACROS_H /****************************************************************************** * Macros ******************************************************************************/ /*=* General purpose macros *=*/ /* get number of elements in an array */ #define NR(x) (sizeof(x)/sizeof*(x)) #ifndef NDEBUG #include /* initialize with junk - used to find unitialized values */ # define JUNKINIT(ptr, len) memset((ptr), 0x99, (len)); #else # define JUNKINIT(ptr, len) /* do nothing */ #endif /* round up/down on a boundry */ #define ROUNDUP(a,n) (((a)+(n)-1)/(n)*(n)) #define ROUNDDOWN(a,n) ((a)-((a)%(n))) /* make four ASCII characters into a 32-bit integer */ #define FOURCC(a,b,c,d) ( \ ((uint_least32_t)(d)<<24) \ |((uint_least32_t)(c)<<16) \ |((uint_least32_t)(b)<<8) \ |(a)) /* used by var */ #define _make_name2(x,y) x##y #define _make_name(x,y) _make_name2(x,y) /* VAR() is used for making temp variables in macros */ #define VAR(x) _make_name(x,__LINE__) /* controls how external functions are exported */ #ifndef NDEBUG #define EXPORT #else /* fake out the export and keep the functions internal */ #define EXPORT static #endif /*=* Byte-order functions *=*/ /* WRite Big-Endian 32-bit value */ #define WR_BE32(dest, offset, value) do { \ unsigned VAR(tmp)=value; \ (dest)[offset]=(VAR(tmp)/16777216L)%256; \ (dest)[(offset)+1]=(VAR(tmp)/65536L)%256; \ (dest)[(offset)+2]=(VAR(tmp)/256)%256; \ (dest)[(offset)+3]=VAR(tmp)%256; \ } while(0) /* WRite Big-Endian 16-bit value */ #define WR_BE16(dest, offset, value) do { \ unsigned VAR(tmp)=value; \ (dest)[offset]=(VAR(tmp)/256)%256; \ (dest)[(offset)+1]=VAR(tmp)%256; \ } while(0) /* WRite Big-Endian 64-bit value */ #define WR_BE64(dest, offset, value) do { \ unsigned long long VAR(tmp)=value; \ (dest)[offset]=((VAR(tmp))>>56)&255; \ (dest)[(offset)+1]=((VAR(tmp))>>48)&255; \ (dest)[(offset)+2]=((VAR(tmp))>>40)&255; \ (dest)[(offset)+3]=((VAR(tmp))>>32)&255; \ (dest)[(offset)+4]=((VAR(tmp))>>24)&255; \ (dest)[(offset)+5]=((VAR(tmp))>>16)&255; \ (dest)[(offset)+6]=((VAR(tmp))>>8)&255; \ (dest)[(offset)+7]=(VAR(tmp))&255; \ } while(0) /* ReaD Big-Endian 16-bit value */ #define RD_BE16(src, offset) ((((src)[offset]&255u)<<8)|((src)[(offset)+1]&255u)) /* ReaD Big-Endian 32-bit value */ #define RD_BE32(src, offset) (\ (((src)[offset]&255ul)<<24) \ |(((src)[(offset)+1]&255ul)<<16) \ |(((src)[(offset)+2]&255ul)<<8) \ |((src)[(offset)+3]&255ul)) /* ReaD Big-Endian 64-bit value */ #define RD_BE64(src, offset) (\ (((src)[offset]&255ull)<<56) \ |(((src)[(offset)+1]&255ull)<<48) \ |(((src)[(offset)+2]&255ull)<<40) \ |(((src)[(offset)+3]&255ull)<<32) \ |(((src)[(offset)+4]&255ull)<<24) \ |(((src)[(offset)+5]&255ull)<<16) \ |(((src)[(offset)+6]&255ull)<<8) \ |((src)[(offset)+7]&255ull)) /*=* Rotate operations *=*/ #define ROL8(a,b) (((uint_least8_t)(a)<<(b))|((uint_least8_t)(a)>>(8-(b)))) #define ROL16(a,b) (((uint_least16_t)(a)<<(b))|((uint_least16_t)(a)>>(16-(b)))) #define ROL32(a,b) (((uint_least32_t)(a)<<(b))|((uint_least32_t)(a)>>(32-(b)))) #define ROL64(a,b) (((uint_least64_t)(a)<<(b))|((uint_least64_t)(a)>>(64-(b)))) #define ROR8(a,b) (((uint_least8_t)(a)>>(b))|((uint_least8_t)(a)<<(8-(b)))) #define ROR16(a,b) (((uint_least16_t)(a)>>(b))|((uint_least16_t)(a)<<(16-(b)))) #define ROR32(a,b) (((uint_least32_t)(a)>>(b))|((uint_least32_t)(a)<<(32-(b)))) #define ROR64(a,b) (((uint_least64_t)(a)>>(b))|((uint_least64_t)(a)<<(64-(b)))) /*=* Bitfield operations *=*/ /* return in type sized elements to create a bitfield of 'bits' bits */ #define BITFIELD(bits, type) (((bits)+(CHAR_BIT*sizeof(type))-1)/(CHAR_BIT*sizeof(type))) /* set bit position 'bit' in bitfield x */ #define BITSET(x, bit) (x)[(bit)/((CHAR_BIT*sizeof *(x)))]|=1<<((bit)&((CHAR_BIT*sizeof *(x))-1)) /* clear bit position 'bit' in bitfield x */ #define BITCLR(x, bit) (x)[(bit)/((CHAR_BIT*sizeof *(x)))]&=~(1<<((bit)&((CHAR_BIT*sizeof *(x))-1))) /* toggle bit position 'bit' in bitfield x */ #define BITINV(x, bit) (x)[(bit)/((CHAR_BIT*sizeof *(x)))]^=1<<((bit)&((CHAR_BIT*sizeof *(x))-1)) /* return a large non-zero number if the bit is set, zero if clear */ #define BITTEST(x, bit) ((x)[(bit)/((CHAR_BIT*sizeof *(x)))]&(1<<((bit)&((CHAR_BIT*sizeof *(x))-1)))) /* checks that bit is in range for bitfield x */ #define BITRANGE(x, bit) ((bit)<(sizeof(x)*CHAR_BIT)) /*=* DEBUG MACROS *=*/ /* VERBOSE(), DEBUG() and TRACE() macros. * DEBUG() does nothing if NDEBUG is defined * TRACE() does nothing if NTRACE is defined */ #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) # define VERBOSE(...) fprintf(stderr, __VA_ARGS__) # ifdef NDEBUG # define DEBUG(...) /* DEBUG disabled */ # define DEBUG_MSG(msg) /* DEBUG_MSG disabled */ # define HEXDUMP(data, len, ...) /* HEXDUMP disabled */ # else # define DEBUG(msg, ...) fprintf(stderr, "DEBUG:%s():%d:" msg, __func__, __LINE__, ## __VA_ARGS__) # define DEBUG_MSG(msg) fprintf(stderr, "DEBUG:%s():%d:" msg "\n", __func__, __LINE__) # define HEXDUMP(data, len, ...) do { fprintf(stderr, __VA_ARGS__); hexdump(stderr, data, len); } while(0) # endif # ifdef NTRACE # define TRACE(...) /* TRACE disabled */ # define HEXDUMP_TRACE(data, len, ...) /* HEXDUMP_TRACE disabled */ # else # define TRACE(msg, ...) fprintf(stderr, "TRACE:%s():%d:" msg, __func__, __LINE__, ## __VA_ARGS__) # define TRACE_MSG(msg) fprintf(stderr, "TRACE:%s():%d:" msg "\n", __func__, __LINE__) # define HEXDUMP_TRACE(data, len, ...) HEXDUMP(data, len, __VA_ARGS__) # endif # define ERROR_FMT(msg, ...) fprintf(stderr, "ERROR:%s():%d:" msg, __func__, __LINE__, __VA_ARGS__) #else /* TODO: prepare a solution for C89 */ # error Requires C99. #endif #define PERROR(reason) fprintf(stderr, "ERROR:%s():%d:%s:%s\n", __func__, __LINE__, reason, strerror(errno)); #define ERROR_MSG(reason) fprintf(stderr, "ERROR:%s():%d:%s\n", __func__, __LINE__, reason); /* macro to report unfinished code */ #define TODO(msg) fprintf(stderr, "TODO:%s():%d:" msg "\n", __func__, __LINE__); /* macro to mark unfinished code and refuse to go further until it is complete */ #define TODO_abort(msg) do { TODO(msg); abort(); } while(0) #define TRACE_ENTER TRACE_MSG("ENTER") #define TRACE_EXIT TRACE_MSG("EXIT") #define FAILON_perror(e, reason, label) do { if(e) { fprintf(stderr, "FAILED:%s:%s\n", reason, strerror(errno)); goto label; } } while(0) #define FAILON_socket FAILON_perror #define FAILON_generic(e, reason, label) do { if(e) { fprintf(stderr, "FAILED:%s\n", reason); goto label; } } while(0) /*=* reference counting macros *=*/ #define REFCOUNT_TYPE int #define REFCOUNT_NAME _referencecount #define REFCOUNT_INIT(obj) ((obj)->REFCOUNT_NAME=0) #define REFCOUNT_TAKE(obj) ((obj)->REFCOUNT_NAME++) #define REFCOUNT_PUT(obj, free_func) do { \ assert((obj)->REFCOUNT_NAME>0); \ if(--(obj)->REFCOUNT_NAME<=0) \ free_func((obj)); \ } while(0) /*=* Compiler macros *=*/ #ifdef __GNUC__ /* using GCC, enable special GCC options */ #define GCC_ONLY(x) x #else /* not using GCC */ #define GCC_ONLY(x) #endif #define UNUSED GCC_ONLY(__attribute__((unused))) #endif /* MACROS_H */