1 /*
2  *  libzvbi -- Miscellaneous cows and chickens
3  *
4  *  Copyright (C) 2000-2003 Iñaki García Etxebarria
5  *  Copyright (C) 2002-2007 Michael H. Schimek
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Library General Public
9  *  License as published by the Free Software Foundation; either
10  *  version 2 of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Library General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Library General Public
18  *  License along with this library; if not, write to the
19  *  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  *  Boston, MA  02110-1301  USA.
21  */
22 
23 /* $Id: misc.h,v 1.24 2013-07-02 02:32:31 mschimek Exp $ */
24 
25 #ifndef MISC_H
26 #define MISC_H
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <stddef.h>
31 #include <stdarg.h>
32 #include <string.h>
33 #include <inttypes.h>		/* (u)intXX_t */
34 #include <sys/types.h>		/* (s)size_t */
35 #include <float.h>		/* DBL_MAX */
36 #include <limits.h>		/* (S)SIZE_MAX */
37 #include <assert.h>
38 #include <glib.h>
39 #include <gst/gst.h>
40 
41 #include "macros.h"
42 
43 #define N_ELEMENTS(array) (sizeof (array) / sizeof (*(array)))
44 
45 #ifdef __GNUC__
46 
47 #if __GNUC__ < 3
48 /* Expect expression usually true/false, schedule accordingly. */
49 #  define likely(expr) (expr)
50 #  define unlikely(expr) (expr)
51 #else
52 #  define likely(expr) __builtin_expect(expr, 1)
53 #  define unlikely(expr) __builtin_expect(expr, 0)
54 #endif
55 
56 #undef __i386__
57 #undef __i686__
58 /* FIXME #cpu is deprecated
59 #if #cpu (i386)
60 #  define __i386__ 1
61 #endif
62 #if #cpu (i686)
63 #  define __i686__ 1
64 #endif
65 */
66 
67 /* &x == PARENT (&x.tm_min, struct tm, tm_min),
68    safer than &x == (struct tm *) &x.tm_min. A NULL _ptr is safe and
69    will return NULL, not -offsetof(_member). */
70 #undef PARENT
71 #define PARENT(_ptr, _type, _member) ({					\
72 	__typeof__ (&((_type *) 0)->_member) _p = (_ptr);		\
73 	(_p != 0) ? (_type *)(((char *) _p) - offsetof (_type,		\
74 	  _member)) : (_type *) 0;					\
75 })
76 
77 /* Like PARENT(), to be used with const _ptr. */
78 #define CONST_PARENT(_ptr, _type, _member) ({				\
79 	__typeof__ (&((const _type *) 0)->_member) _p = (_ptr);		\
80 	(_p != 0) ? (const _type *)(((const char *) _p) - offsetof	\
81 	 (const _type, _member)) : (const _type *) 0;			\
82 })
83 
84 /* Note the following macros have no side effects only when you
85    compile with GCC, so don't expect this. */
86 
87 /* Absolute value of int, long or long long without a branch.
88    Note ABS (INT_MIN) -> INT_MAX + 1. */
89 #undef ABS
90 #define ABS(n) ({							\
91 	register __typeof__ (n) _n = (n), _t = _n;			\
92 	if (-1 == (-1 >> 1)) { /* do we have signed shifts? */		\
93 		_t >>= sizeof (_t) * 8 - 1;				\
94 		_n ^= _t;						\
95 		_n -= _t;						\
96 	} else if (_n < 0) { /* also warns if n is unsigned type */	\
97 		_n = -_n;						\
98 	}								\
99 	/* return */ _n;						\
100 })
101 
102 #undef MIN
103 #define MIN(x, y) ({							\
104 	__typeof__ (x) _x = (x);					\
105 	__typeof__ (y) _y = (y);					\
106 	(void)(&_x == &_y); /* warn if types do not match */		\
107 	/* return */ (_x < _y) ? _x : _y;				\
108 })
109 
110 #undef MAX
111 #define MAX(x, y) ({							\
112 	__typeof__ (x) _x = (x);					\
113 	__typeof__ (y) _y = (y);					\
114 	(void)(&_x == &_y); /* warn if types do not match */		\
115 	/* return */ (_x > _y) ? _x : _y;				\
116 })
117 
118 /* Note other compilers may swap only int, long or pointer. */
119 #undef SWAP
120 #define SWAP(x, y)							\
121 do {									\
122 	__typeof__ (x) _x = x;						\
123 	x = y;								\
124 	y = _x;								\
125 } while (0)
126 
127 #undef SATURATE
128 #ifdef __i686__ /* has conditional move */
129 #define SATURATE(n, min, max) ({					\
130 	__typeof__ (n) _n = (n);					\
131 	__typeof__ (n) _min = (min);					\
132 	__typeof__ (n) _max = (max);					\
133 	(void)(&_n == &_min); /* warn if types do not match */		\
134 	(void)(&_n == &_max);						\
135 	if (_n < _min)							\
136 		_n = _min;						\
137 	if (_n > _max)							\
138 		_n = _max;						\
139 	/* return */ _n;						\
140 })
141 #else
142 #define SATURATE(n, min, max) ({					\
143 	__typeof__ (n) _n = (n);					\
144 	__typeof__ (n) _min = (min);					\
145 	__typeof__ (n) _max = (max);					\
146 	(void)(&_n == &_min); /* warn if types do not match */		\
147 	(void)(&_n == &_max);						\
148 	if (_n < _min)							\
149 		_n = _min;						\
150 	else if (_n > _max)						\
151 		_n = _max;						\
152 	/* return */ _n;						\
153 })
154 #endif
155 
156 #else /* !__GNUC__ */
157 
158 #define likely(expr) (expr)
159 #define unlikely(expr) (expr)
160 #undef __i386__
161 #undef __i686__
162 
163 static char *
PARENT_HELPER(char * p,unsigned int offset)164 PARENT_HELPER (char *p, unsigned int offset)
165 { return (0 == p) ? ((char *) 0) : p - offset; }
166 
167 static const char *
CONST_PARENT_HELPER(const char * p,unsigned int offset)168 CONST_PARENT_HELPER (const char *p, unsigned int offset)
169 { return (0 == p) ? ((char *) 0) : p - offset; }
170 
171 #define PARENT(_ptr, _type, _member)					\
172 	((0 == offsetof (_type, _member)) ? (_type *)(_ptr)		\
173 	 : (_type *) PARENT_HELPER ((char *)(_ptr), offsetof (_type, _member)))
174 #define CONST_PARENT(_ptr, _type, _member)				\
175 	((0 == offsetof (const _type, _member)) ? (const _type *)(_ptr)	\
176 	 : (const _type *) CONST_PARENT_HELPER ((const char *)(_ptr),	\
177 	  offsetof (const _type, _member)))
178 
179 #undef ABS
180 #define ABS(n) (((n) < 0) ? -(n) : (n))
181 
182 #undef MIN
183 #define MIN(x, y) (((x) < (y)) ? (x) : (y))
184 
185 #undef MAX
186 #define MAX(x, y) (((x) > (y)) ? (x) : (y))
187 
188 #undef SWAP
189 #define SWAP(x, y)							\
190 do {									\
191 	long _x = x;							\
192 	x = y;								\
193 	y = _x;								\
194 } while (0)
195 
196 #undef SATURATE
197 #define SATURATE(n, min, max) MIN (MAX (min, n), max)
198 
199 #endif /* !__GNUC__ */
200 
201 /* 32 bit constant byte reverse, e.g. 0xAABBCCDD -> 0xDDCCBBAA. */
202 #define SWAB32(m)							\
203 	(+ (((m) & 0xFF000000) >> 24)					\
204 	 + (((m) & 0xFF0000) >> 8)					\
205 	 + (((m) & 0xFF00) << 8)					\
206 	 + (((m) & 0xFF) << 24))
207 
208 #ifdef HAVE_BUILTIN_POPCOUNT
209 #  define popcnt(x) __builtin_popcount ((uint32_t)(x))
210 #else
211 #  define popcnt(x) _vbi_popcnt (x)
212 #endif
213 
214 extern unsigned int
215 _vbi_popcnt			(uint32_t		x);
216 
217 /* NB GCC inlines and optimizes these functions when size is const. */
218 #define SET(var) memset (&(var), ~0, sizeof (var))
219 
220 #define CLEAR(var) memset (&(var), 0, sizeof (var))
221 
222 /* Useful to copy arrays, otherwise use assignment. */
223 #define COPY(d, s)							\
224 	(assert (sizeof (d) == sizeof (s)), memcpy (d, s, sizeof (d)))
225 
226 /* Copy string const into char array. */
227 #define STRACPY(array, s)						\
228 do {									\
229 	/* Complain if s is no string const or won't fit. */		\
230 	const char t_[sizeof (array) - 1] _vbi_unused = s;		\
231 									\
232 	memcpy (array, s, sizeof (s));					\
233 } while (0)
234 
235 /* Copy bits through mask. */
236 #define COPY_SET_MASK(dest, from, mask)					\
237 	(dest ^= (from) ^ (dest & (mask)))
238 
239 /* Set bits if cond is TRUE, clear if FALSE. */
240 #define COPY_SET_COND(dest, bits, cond)					\
241 	 ((cond) ? (dest |= (bits)) : (dest &= ~(bits)))
242 
243 /* Set and clear bits. */
244 #define COPY_SET_CLEAR(dest, set, clear)				\
245 	(dest = (dest & ~(clear)) | (set))
246 
247 /* For applications, debugging and fault injection during unit tests. */
248 
249 #define vbi_malloc malloc
250 #define vbi_realloc realloc
251 #define vbi_strdup strdup
252 #define vbi_free free
253 
254 #define vbi_cache_malloc vbi_malloc
255 #define vbi_cache_free vbi_free
256 
257 /* Helper functions. */
258 
259 _vbi_inline int
_vbi_to_ascii(int c)260 _vbi_to_ascii			(int			c)
261 {
262 	if (c < 0)
263 		return '?';
264 
265 	c &= 0x7F;
266 
267 	if (c < 0x20 || c >= 0x7F)
268 		return '.';
269 
270 	return c;
271 }
272 
273 typedef struct {
274 	const char *		key;
275 	int			value;
276 } _vbi_key_value_pair;
277 
278 extern vbi_bool
279 _vbi_keyword_lookup		(int *			value,
280 				 const char **		inout_s,
281 				 const _vbi_key_value_pair * table,
282 				 unsigned int		n_pairs)
283   _vbi_nonnull ((1, 2, 3));
284 
285 extern void
286 _vbi_shrink_vector_capacity	(void **		vector,
287 				 size_t *		capacity,
288 				 size_t			min_capacity,
289 				 size_t			element_size)
290   _vbi_nonnull ((1, 2));
291 extern vbi_bool
292 _vbi_grow_vector_capacity	(void **		vector,
293 				 size_t *		capacity,
294 				 size_t			min_capacity,
295 				 size_t			element_size)
296   _vbi_nonnull ((1, 2));
297 
298 GST_DEBUG_CATEGORY_EXTERN (libzvbi_debug);
299 
300 #ifndef GST_DISABLE_GST_DEBUG
301 /* Logging stuff. */
302 #ifdef G_HAVE_ISO_VARARGS
303 #define VBI_CAT_LEVEL_LOG(level,object,...) G_STMT_START{		\
304   if (G_UNLIKELY ((level) <= GST_LEVEL_MAX && (level) <= _gst_debug_min)) {						\
305 	  gst_debug_log (libzvbi_debug, (level), __FILE__, GST_FUNCTION, __LINE__, \
306         (GObject *) (object), __VA_ARGS__);				\
307   }									\
308 }G_STMT_END
309 #else /* G_HAVE_GNUC_VARARGS */
310 #ifdef G_HAVE_GNUC_VARARGS
311 #define VBI_CAT_LEVEL_LOG(level,object,args...) G_STMT_START{	\
312   if (G_UNLIKELY ((level) <= GST_LEVEL_MAX && (level) <= _gst_debug_min)) {						\
313 	  gst_debug_log (libzvbi_debug, (level), __FILE__, GST_FUNCTION, __LINE__, \
314         (GObject *) (object), ##args );					\
315   }									\
316 }G_STMT_END
317 #else /* no variadic macros, use inline */
318 static inline void
VBI_CAT_LEVEL_LOG_valist(GstDebugCategory * cat,GstDebugLevel level,gpointer object,const char * format,va_list varargs)319 VBI_CAT_LEVEL_LOG_valist (GstDebugCategory * cat,
320     GstDebugLevel level, gpointer object, const char *format, va_list varargs)
321 {
322   if (G_UNLIKELY ((level) <= GST_LEVEL_MAX && (level) <= _gst_debug_min)) {
323     gst_debug_log_valist (cat, level, "", "", 0, (GObject *) object, format,
324         varargs);
325   }
326 }
327 
328 static inline void
VBI_CAT_LEVEL_LOG(GstDebugLevel level,gpointer object,const char * format,...)329 VBI_CAT_LEVEL_LOG (GstDebugLevel level,
330     gpointer object, const char *format, ...)
331 {
332   va_list varargs;
333 
334   va_start (varargs, format);
335   GST_CAT_LEVEL_LOG_valist (libzvbi_debug, level, object, format, varargs);
336   va_end (varargs);
337 }
338 #endif
339 #endif /* G_HAVE_ISO_VARARGS */
340 #else
341 static inline void
VBI_CAT_LEVEL_LOG(GstDebugLevel level,gpointer object,const char * format,...)342 VBI_CAT_LEVEL_LOG (GstDebugLevel level,
343     gpointer object, const char *format, ...)
344 {
345 }
346 #endif	/* GST_DISABLE_GST_DEBUG */
347 
348 #ifdef G_HAVE_GNUC_VARARGS
349 #define error(hook, templ, args...)					\
350 	VBI_CAT_LEVEL_LOG (GST_LEVEL_ERROR, NULL, templ , ##args)
351 #define warning(hook, templ, args...)					\
352 	VBI_CAT_LEVEL_LOG (GST_LEVEL_WARNING, NULL, templ , ##args)
353 #define notice(hook, templ, args...)					\
354 	VBI_CAT_LEVEL_LOG (GST_LEVEL_INFO, NULL, templ , ##args)
355 #define info(hook, templ, args...)					\
356 	VBI_CAT_LEVEL_LOG (GST_LEVEL_INFO, NULL, templ , ##args)
357 #define debug1(hook, templ, args...)					\
358 	VBI_CAT_LEVEL_LOG (GST_LEVEL_DEBUG, NULL, templ , ##args)
359 #define debug2(hook, templ, args...)					\
360 	VBI_CAT_LEVEL_LOG (GST_LEVEL_LOG, NULL, templ , ##args)
361 #define debug3(hook, templ, args...)					\
362 	VBI_CAT_LEVEL_LOG (GST_LEVEL_TRACE, NULL, templ , ##args)
363 #elif defined(G_HAVE_ISO_VARARGS)
364 #define error(hook, templ, ...)					\
365 	VBI_CAT_LEVEL_LOG (GST_LEVEL_ERROR, NULL, templ, __VA_ARGS__)
366 #define warning(hook, templ, ...)					\
367 	VBI_CAT_LEVEL_LOG (GST_LEVEL_WARNING, NULL, templ, __VA_ARGS__)
368 #define notice(hook, templ, ...)					\
369 	VBI_CAT_LEVEL_LOG (GST_LEVEL_INFO, NULL, templ, __VA_ARGS__)
370 #define info(hook, templ, ...)					\
371 	VBI_CAT_LEVEL_LOG (GST_LEVEL_INFO, NULL, templ, __VA_ARGS__)
372 #define debug1(hook, templ, ...)					\
373 	VBI_CAT_LEVEL_LOG (GST_LEVEL_DEBUG, NULL, templ, __VA_ARGS__)
374 #define debug2(hook, templ, ...)					\
375 	VBI_CAT_LEVEL_LOG (GST_LEVEL_LOG, NULL, templ, __VA_ARGS__)
376 #define debug3(hook, templ, ...)					\
377 	VBI_CAT_LEVEL_LOG (GST_LEVEL_TRACE, NULL, templ, __VA_ARGS__)
378 #else
379 /* if someone needs this, they can implement the inline functions for it */
380 #error "variadic macros are required"
381 #endif
382 
383 
384 #if 0				/* Replaced logging with GStreamer logging system */
385 extern _vbi_log_hook		_vbi_global_log;
386 
387 extern void
388 _vbi_log_vprintf		(vbi_log_fn *		log_fn,
389 				 void *			user_data,
390 				 vbi_log_mask		level,
391 				 const char *		source_file,
392 				 const char *		context,
393 				 const char *		templ,
394 				 va_list		ap)
395   _vbi_nonnull ((1, 4, 5, 6));
396 extern void
397 _vbi_log_printf		(vbi_log_fn *		log_fn,
398 				 void *			user_data,
399 				 vbi_log_mask		level,
400 				 const char *		source_file,
401 				 const char *		context,
402 				 const char *		templ,
403 				 ...)
404   _vbi_nonnull ((1, 4, 5, 6)) _vbi_format ((printf, 6, 7));
405 
406 #define _vbi_log(hook, level, templ, args...)				\
407 do {									\
408 	_vbi_log_hook *_h = hook;					\
409 									\
410 	if ((NULL != _h && 0 != (_h->mask & level))			\
411 	    || (_h = &_vbi_global_log, 0 != (_h->mask & level)))	\
412 		_vbi_log_printf (_h->fn, _h->user_data,		\
413 				  level, __FILE__, __FUNCTION__,	\
414 				  templ , ##args);			\
415 } while (0)
416 
417 #define _vbi_vlog(hook, level, templ, ap)				\
418 do {									\
419 	_vbi_log_hook *_h = hook;					\
420 									\
421 	if ((NULL != _h && 0 != (_h->mask & level))			\
422 	    || (_h = &_vbi_global_log, 0 != (_h->mask & level)))	\
423 		_vbi_log_vprintf (_h->fn, _h->user_data,		\
424 				  level, __FILE__, __FUNCTION__,	\
425 				  templ, ap);				\
426 } while (0)
427 #define error(hook, templ, args...)					\
428 	_vbi_log (hook, VBI_LOG_ERROR, templ , ##args)
429 #define warning(hook, templ, args...)					\
430 	_vbi_log (hook, VBI_LOG_ERROR, templ , ##args)
431 #define notice(hook, templ, args...)					\
432 	_vbi_log (hook, VBI_LOG_NOTICE, templ , ##args)
433 #define info(hook, templ, args...)					\
434 	_vbi_log (hook, VBI_LOG_INFO, templ , ##args)
435 #define debug1(hook, templ, args...)					\
436 	_vbi_log (hook, VBI_LOG_DEBUG, templ , ##args)
437 #define debug2(hook, templ, args...)					\
438 	_vbi_log (hook, VBI_LOG_DEBUG2, templ , ##args)
439 #define debug3(hook, templ, args...)					\
440 	_vbi_log (hook, VBI_LOG_DEBUG3, templ , ##args)
441 #endif
442 
443 /* Portability stuff. */
444 
445 /* These should be defined in inttypes.h. */
446 #ifndef PRId64
447 #  define PRId64 "lld"
448 #endif
449 #ifndef PRIu64
450 #  define PRIu64 "llu"
451 #endif
452 #ifndef PRIx64
453 #  define PRIx64 "llx"
454 #endif
455 
456 /* Should be defined in C99 limits.h? */
457 #ifndef SIZE_MAX
458 #  define SIZE_MAX ((size_t) -1)
459 #endif
460 
461 #ifndef TIME_MIN
462 #  define TIME_MIN (_vbi_time_min ())
463 _vbi_inline time_t
_vbi_time_min(void)464 _vbi_time_min			(void)
465 {
466 	const time_t t = (time_t) -1.25;
467 
468 	if (t < -1) {
469 		return (time_t)((sizeof (time_t) > 4) ? DBL_MIN : FLT_MIN);
470 	} else if (t < 0) {
471 		return ((uint64_t) 1) << (sizeof (time_t) * 8 - 1);
472 	} else {
473 		return 0;
474 	}
475 }
476 #endif
477 
478 #ifndef TIME_MAX
479 #  define TIME_MAX (_vbi_time_max ())
480 _vbi_inline time_t
_vbi_time_max(void)481 _vbi_time_max			(void)
482 {
483 	const time_t t = (time_t) -1.25;
484 
485 	if (t < -1) {
486 		return (time_t)((sizeof (time_t) > 4) ? DBL_MAX : FLT_MAX);
487 	} else if (t < 0) {
488 		/* Most likely signed 32 or 64 bit. */
489 		return (((uint64_t) 1) << (sizeof (time_t) * 8 - 1)) - 1;
490 	} else {
491 		return -1;
492 	}
493 }
494 #endif
495 
496 /* __va_copy is a GNU extension. */
497 #ifndef __va_copy
498 #  define __va_copy(ap1, ap2) do { ap1 = ap2; } while (0)
499 #endif
500 
501 #if 0
502 /* Use this instead of strncpy(). strlcpy() is a BSD extension. */
503 #ifndef HAVE_STRLCPY
504 #  define strlcpy _vbi_strlcpy
505 #endif
506 #undef strncpy
507 #define strncpy use_strlcpy_instead
508 
509 extern size_t
510 _vbi_strlcpy			(char *			dst,
511 				 const char *		src,
512 				 size_t			size)
513   _vbi_nonnull ((1, 2));
514 #endif
515 
516 /* /\* strndup() is a BSD/GNU extension. *\/ */
517 /* #ifndef HAVE_STRNDUP */
518 /* #  define strndup _vbi_strndup */
519 /* #endif */
520 
521 /* extern char * */
522 /* _vbi_strndup			(const char *		s, */
523 /* 				 size_t			len) */
524 /*   _vbi_nonnull ((1)); */
525 
526 /* vasprintf() is a GNU extension. */
527 #ifndef HAVE_VASPRINTF
528 #  define vasprintf _vbi_vasprintf
529 #endif
530 
531 extern int
532 _vbi_vasprintf			(char **		dstp,
533 				 const char *		templ,
534 				 va_list		ap)
535   _vbi_nonnull ((1, 2));
536 
537 /* asprintf() is a GNU extension. */
538 #ifndef HAVE_ASPRINTF
539 #  define asprintf _vbi_asprintf
540 #endif
541 
542 extern int
543 _vbi_asprintf			(char **		dstp,
544 				 const char *		templ,
545 				 ...)
546   _vbi_nonnull ((1, 2)) _vbi_format ((printf, 2, 3));
547 
548 #undef sprintf
549 #define sprintf use_snprintf_or_asprintf_instead
550 
551 #endif /* MISC_H */
552 
553 /*
554 Local variables:
555 c-set-style: K&R
556 c-basic-offset: 8
557 End:
558 */
559