/* * libzvbi -- Miscellaneous cows and chickens * * Copyright (C) 2000-2003 Iñaki García Etxebarria * Copyright (C) 2002-2007 Michael H. Schimek * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. */ /* $Id: misc.h,v 1.24 2013-07-02 02:32:31 mschimek Exp $ */ #ifndef MISC_H #define MISC_H #include #include #include #include #include #include /* (u)intXX_t */ #include /* (s)size_t */ #include /* DBL_MAX */ #include /* (S)SIZE_MAX */ #include #include #include #include "macros.h" #define N_ELEMENTS(array) (sizeof (array) / sizeof (*(array))) #ifdef __GNUC__ #if __GNUC__ < 3 /* Expect expression usually true/false, schedule accordingly. */ # define likely(expr) (expr) # define unlikely(expr) (expr) #else # define likely(expr) __builtin_expect(expr, 1) # define unlikely(expr) __builtin_expect(expr, 0) #endif #undef __i386__ #undef __i686__ /* FIXME #cpu is deprecated #if #cpu (i386) # define __i386__ 1 #endif #if #cpu (i686) # define __i686__ 1 #endif */ /* &x == PARENT (&x.tm_min, struct tm, tm_min), safer than &x == (struct tm *) &x.tm_min. A NULL _ptr is safe and will return NULL, not -offsetof(_member). */ #undef PARENT #define PARENT(_ptr, _type, _member) ({ \ __typeof__ (&((_type *) 0)->_member) _p = (_ptr); \ (_p != 0) ? (_type *)(((char *) _p) - offsetof (_type, \ _member)) : (_type *) 0; \ }) /* Like PARENT(), to be used with const _ptr. */ #define CONST_PARENT(_ptr, _type, _member) ({ \ __typeof__ (&((const _type *) 0)->_member) _p = (_ptr); \ (_p != 0) ? (const _type *)(((const char *) _p) - offsetof \ (const _type, _member)) : (const _type *) 0; \ }) /* Note the following macros have no side effects only when you compile with GCC, so don't expect this. */ /* Absolute value of int, long or long long without a branch. Note ABS (INT_MIN) -> INT_MAX + 1. */ #undef ABS #define ABS(n) ({ \ register __typeof__ (n) _n = (n), _t = _n; \ if (-1 == (-1 >> 1)) { /* do we have signed shifts? */ \ _t >>= sizeof (_t) * 8 - 1; \ _n ^= _t; \ _n -= _t; \ } else if (_n < 0) { /* also warns if n is unsigned type */ \ _n = -_n; \ } \ /* return */ _n; \ }) #undef MIN #define MIN(x, y) ({ \ __typeof__ (x) _x = (x); \ __typeof__ (y) _y = (y); \ (void)(&_x == &_y); /* warn if types do not match */ \ /* return */ (_x < _y) ? _x : _y; \ }) #undef MAX #define MAX(x, y) ({ \ __typeof__ (x) _x = (x); \ __typeof__ (y) _y = (y); \ (void)(&_x == &_y); /* warn if types do not match */ \ /* return */ (_x > _y) ? _x : _y; \ }) /* Note other compilers may swap only int, long or pointer. */ #undef SWAP #define SWAP(x, y) \ do { \ __typeof__ (x) _x = x; \ x = y; \ y = _x; \ } while (0) #undef SATURATE #ifdef __i686__ /* has conditional move */ #define SATURATE(n, min, max) ({ \ __typeof__ (n) _n = (n); \ __typeof__ (n) _min = (min); \ __typeof__ (n) _max = (max); \ (void)(&_n == &_min); /* warn if types do not match */ \ (void)(&_n == &_max); \ if (_n < _min) \ _n = _min; \ if (_n > _max) \ _n = _max; \ /* return */ _n; \ }) #else #define SATURATE(n, min, max) ({ \ __typeof__ (n) _n = (n); \ __typeof__ (n) _min = (min); \ __typeof__ (n) _max = (max); \ (void)(&_n == &_min); /* warn if types do not match */ \ (void)(&_n == &_max); \ if (_n < _min) \ _n = _min; \ else if (_n > _max) \ _n = _max; \ /* return */ _n; \ }) #endif #else /* !__GNUC__ */ #define likely(expr) (expr) #define unlikely(expr) (expr) #undef __i386__ #undef __i686__ static char * PARENT_HELPER (char *p, unsigned int offset) { return (0 == p) ? ((char *) 0) : p - offset; } static const char * CONST_PARENT_HELPER (const char *p, unsigned int offset) { return (0 == p) ? ((char *) 0) : p - offset; } #define PARENT(_ptr, _type, _member) \ ((0 == offsetof (_type, _member)) ? (_type *)(_ptr) \ : (_type *) PARENT_HELPER ((char *)(_ptr), offsetof (_type, _member))) #define CONST_PARENT(_ptr, _type, _member) \ ((0 == offsetof (const _type, _member)) ? (const _type *)(_ptr) \ : (const _type *) CONST_PARENT_HELPER ((const char *)(_ptr), \ offsetof (const _type, _member))) #undef ABS #define ABS(n) (((n) < 0) ? -(n) : (n)) #undef MIN #define MIN(x, y) (((x) < (y)) ? (x) : (y)) #undef MAX #define MAX(x, y) (((x) > (y)) ? (x) : (y)) #undef SWAP #define SWAP(x, y) \ do { \ long _x = x; \ x = y; \ y = _x; \ } while (0) #undef SATURATE #define SATURATE(n, min, max) MIN (MAX (min, n), max) #endif /* !__GNUC__ */ /* 32 bit constant byte reverse, e.g. 0xAABBCCDD -> 0xDDCCBBAA. */ #define SWAB32(m) \ (+ (((m) & 0xFF000000) >> 24) \ + (((m) & 0xFF0000) >> 8) \ + (((m) & 0xFF00) << 8) \ + (((m) & 0xFF) << 24)) #ifdef HAVE_BUILTIN_POPCOUNT # define popcnt(x) __builtin_popcount ((uint32_t)(x)) #else # define popcnt(x) _vbi_popcnt (x) #endif extern unsigned int _vbi_popcnt (uint32_t x); /* NB GCC inlines and optimizes these functions when size is const. */ #define SET(var) memset (&(var), ~0, sizeof (var)) #define CLEAR(var) memset (&(var), 0, sizeof (var)) /* Useful to copy arrays, otherwise use assignment. */ #define COPY(d, s) \ (assert (sizeof (d) == sizeof (s)), memcpy (d, s, sizeof (d))) /* Copy string const into char array. */ #define STRACPY(array, s) \ do { \ /* Complain if s is no string const or won't fit. */ \ const char t_[sizeof (array) - 1] _vbi_unused = s; \ \ memcpy (array, s, sizeof (s)); \ } while (0) /* Copy bits through mask. */ #define COPY_SET_MASK(dest, from, mask) \ (dest ^= (from) ^ (dest & (mask))) /* Set bits if cond is TRUE, clear if FALSE. */ #define COPY_SET_COND(dest, bits, cond) \ ((cond) ? (dest |= (bits)) : (dest &= ~(bits))) /* Set and clear bits. */ #define COPY_SET_CLEAR(dest, set, clear) \ (dest = (dest & ~(clear)) | (set)) /* For applications, debugging and fault injection during unit tests. */ #define vbi_malloc malloc #define vbi_realloc realloc #define vbi_strdup strdup #define vbi_free free #define vbi_cache_malloc vbi_malloc #define vbi_cache_free vbi_free /* Helper functions. */ _vbi_inline int _vbi_to_ascii (int c) { if (c < 0) return '?'; c &= 0x7F; if (c < 0x20 || c >= 0x7F) return '.'; return c; } typedef struct { const char * key; int value; } _vbi_key_value_pair; extern vbi_bool _vbi_keyword_lookup (int * value, const char ** inout_s, const _vbi_key_value_pair * table, unsigned int n_pairs) _vbi_nonnull ((1, 2, 3)); extern void _vbi_shrink_vector_capacity (void ** vector, size_t * capacity, size_t min_capacity, size_t element_size) _vbi_nonnull ((1, 2)); extern vbi_bool _vbi_grow_vector_capacity (void ** vector, size_t * capacity, size_t min_capacity, size_t element_size) _vbi_nonnull ((1, 2)); GST_DEBUG_CATEGORY_EXTERN (libzvbi_debug); #ifndef GST_DISABLE_GST_DEBUG /* Logging stuff. */ #ifdef G_HAVE_ISO_VARARGS #define VBI_CAT_LEVEL_LOG(level,object,...) G_STMT_START{ \ if (G_UNLIKELY ((level) <= GST_LEVEL_MAX && (level) <= _gst_debug_min)) { \ gst_debug_log (libzvbi_debug, (level), __FILE__, GST_FUNCTION, __LINE__, \ (GObject *) (object), __VA_ARGS__); \ } \ }G_STMT_END #else /* G_HAVE_GNUC_VARARGS */ #ifdef G_HAVE_GNUC_VARARGS #define VBI_CAT_LEVEL_LOG(level,object,args...) G_STMT_START{ \ if (G_UNLIKELY ((level) <= GST_LEVEL_MAX && (level) <= _gst_debug_min)) { \ gst_debug_log (libzvbi_debug, (level), __FILE__, GST_FUNCTION, __LINE__, \ (GObject *) (object), ##args ); \ } \ }G_STMT_END #else /* no variadic macros, use inline */ static inline void VBI_CAT_LEVEL_LOG_valist (GstDebugCategory * cat, GstDebugLevel level, gpointer object, const char *format, va_list varargs) { if (G_UNLIKELY ((level) <= GST_LEVEL_MAX && (level) <= _gst_debug_min)) { gst_debug_log_valist (cat, level, "", "", 0, (GObject *) object, format, varargs); } } static inline void VBI_CAT_LEVEL_LOG (GstDebugLevel level, gpointer object, const char *format, ...) { va_list varargs; va_start (varargs, format); GST_CAT_LEVEL_LOG_valist (libzvbi_debug, level, object, format, varargs); va_end (varargs); } #endif #endif /* G_HAVE_ISO_VARARGS */ #else static inline void VBI_CAT_LEVEL_LOG (GstDebugLevel level, gpointer object, const char *format, ...) { } #endif /* GST_DISABLE_GST_DEBUG */ #ifdef G_HAVE_GNUC_VARARGS #define error(hook, templ, args...) \ VBI_CAT_LEVEL_LOG (GST_LEVEL_ERROR, NULL, templ , ##args) #define warn(hook, templ, args...) \ VBI_CAT_LEVEL_LOG (GST_LEVEL_WARNING, NULL, templ , ##args) #define notice(hook, templ, args...) \ VBI_CAT_LEVEL_LOG (GST_LEVEL_INFO, NULL, templ , ##args) #define info(hook, templ, args...) \ VBI_CAT_LEVEL_LOG (GST_LEVEL_INFO, NULL, templ , ##args) #define debug1(hook, templ, args...) \ VBI_CAT_LEVEL_LOG (GST_LEVEL_DEBUG, NULL, templ , ##args) #define debug2(hook, templ, args...) \ VBI_CAT_LEVEL_LOG (GST_LEVEL_LOG, NULL, templ , ##args) #define debug3(hook, templ, args...) \ VBI_CAT_LEVEL_LOG (GST_LEVEL_TRACE, NULL, templ , ##args) #elif defined(G_HAVE_ISO_VARARGS) #define error(hook, templ, ...) \ VBI_CAT_LEVEL_LOG (GST_LEVEL_ERROR, NULL, templ, __VA_ARGS__) #define warn(hook, templ, ...) \ VBI_CAT_LEVEL_LOG (GST_LEVEL_WARNING, NULL, templ, __VA_ARGS__) #define notice(hook, templ, ...) \ VBI_CAT_LEVEL_LOG (GST_LEVEL_INFO, NULL, templ, __VA_ARGS__) #define info(hook, templ, ...) \ VBI_CAT_LEVEL_LOG (GST_LEVEL_INFO, NULL, templ, __VA_ARGS__) #define debug1(hook, templ, ...) \ VBI_CAT_LEVEL_LOG (GST_LEVEL_DEBUG, NULL, templ, __VA_ARGS__) #define debug2(hook, templ, ...) \ VBI_CAT_LEVEL_LOG (GST_LEVEL_LOG, NULL, templ, __VA_ARGS__) #define debug3(hook, templ, ...) \ VBI_CAT_LEVEL_LOG (GST_LEVEL_TRACE, NULL, templ, __VA_ARGS__) #else /* if someone needs this, they can implement the inline functions for it */ #error "variadic macros are required" #endif #if 0 /* Replaced logging with GStreamer logging system */ extern _vbi_log_hook _vbi_global_log; extern void _vbi_log_vprintf (vbi_log_fn * log_fn, void * user_data, vbi_log_mask level, const char * source_file, const char * context, const char * templ, va_list ap) _vbi_nonnull ((1, 4, 5, 6)); extern void _vbi_log_printf (vbi_log_fn * log_fn, void * user_data, vbi_log_mask level, const char * source_file, const char * context, const char * templ, ...) _vbi_nonnull ((1, 4, 5, 6)) _vbi_format ((printf, 6, 7)); #define _vbi_log(hook, level, templ, args...) \ do { \ _vbi_log_hook *_h = hook; \ \ if ((NULL != _h && 0 != (_h->mask & level)) \ || (_h = &_vbi_global_log, 0 != (_h->mask & level))) \ _vbi_log_printf (_h->fn, _h->user_data, \ level, __FILE__, __FUNCTION__, \ templ , ##args); \ } while (0) #define _vbi_vlog(hook, level, templ, ap) \ do { \ _vbi_log_hook *_h = hook; \ \ if ((NULL != _h && 0 != (_h->mask & level)) \ || (_h = &_vbi_global_log, 0 != (_h->mask & level))) \ _vbi_log_vprintf (_h->fn, _h->user_data, \ level, __FILE__, __FUNCTION__, \ templ, ap); \ } while (0) #define error(hook, templ, args...) \ _vbi_log (hook, VBI_LOG_ERROR, templ , ##args) #define warning(hook, templ, args...) \ _vbi_log (hook, VBI_LOG_ERROR, templ , ##args) #define notice(hook, templ, args...) \ _vbi_log (hook, VBI_LOG_NOTICE, templ , ##args) #define info(hook, templ, args...) \ _vbi_log (hook, VBI_LOG_INFO, templ , ##args) #define debug1(hook, templ, args...) \ _vbi_log (hook, VBI_LOG_DEBUG, templ , ##args) #define debug2(hook, templ, args...) \ _vbi_log (hook, VBI_LOG_DEBUG2, templ , ##args) #define debug3(hook, templ, args...) \ _vbi_log (hook, VBI_LOG_DEBUG3, templ , ##args) #endif /* Portability stuff. */ /* These should be defined in inttypes.h. */ #ifndef PRId64 # define PRId64 "lld" #endif #ifndef PRIu64 # define PRIu64 "llu" #endif #ifndef PRIx64 # define PRIx64 "llx" #endif /* Should be defined in C99 limits.h? */ #ifndef SIZE_MAX # define SIZE_MAX ((size_t) -1) #endif #ifndef TIME_MIN # define TIME_MIN (_vbi_time_min ()) _vbi_inline time_t _vbi_time_min (void) { const time_t t = (time_t) -1.25; if (t < -1) { return (time_t)((sizeof (time_t) > 4) ? DBL_MIN : FLT_MIN); } else if (t < 0) { return ((uint64_t) 1) << (sizeof (time_t) * 8 - 1); } else { return 0; } } #endif #ifndef TIME_MAX # define TIME_MAX (_vbi_time_max ()) _vbi_inline time_t _vbi_time_max (void) { const time_t t = (time_t) -1.25; if (t < -1) { return (time_t)((sizeof (time_t) > 4) ? DBL_MAX : FLT_MAX); } else if (t < 0) { /* Most likely signed 32 or 64 bit. */ return (((uint64_t) 1) << (sizeof (time_t) * 8 - 1)) - 1; } else { return -1; } } #endif /* __va_copy is a GNU extension. */ #ifndef __va_copy # define __va_copy(ap1, ap2) do { ap1 = ap2; } while (0) #endif #if 0 /* Use this instead of strncpy(). strlcpy() is a BSD extension. */ #ifndef HAVE_STRLCPY # define strlcpy _vbi_strlcpy #endif #undef strncpy #define strncpy use_strlcpy_instead extern size_t _vbi_strlcpy (char * dst, const char * src, size_t size) _vbi_nonnull ((1, 2)); #endif /* /\* strndup() is a BSD/GNU extension. *\/ */ /* #ifndef HAVE_STRNDUP */ /* # define strndup _vbi_strndup */ /* #endif */ /* extern char * */ /* _vbi_strndup (const char * s, */ /* size_t len) */ /* _vbi_nonnull ((1)); */ /* vasprintf() is a GNU extension. */ #ifndef HAVE_VASPRINTF # define vasprintf _vbi_vasprintf #endif extern int _vbi_vasprintf (char ** dstp, const char * templ, va_list ap) _vbi_nonnull ((1, 2)); /* asprintf() is a GNU extension. */ #ifndef HAVE_ASPRINTF # define asprintf _vbi_asprintf #endif extern int _vbi_asprintf (char ** dstp, const char * templ, ...) _vbi_nonnull ((1, 2)) _vbi_format ((printf, 2, 3)); #undef sprintf #define sprintf use_snprintf_or_asprintf_instead #endif /* MISC_H */ /* Local variables: c-set-style: K&R c-basic-offset: 8 End: */