summaryrefslogtreecommitdiff
path: root/para.h
blob: ec771af3fd7d538bc4fd09c6c0c3eb12eae09a84 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
/* SPDX-License-Identifier: GPL-2.0 */

/** \file para.h global paraslash definitions */

#include "config.h"

#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h> /* time(), localtime() */
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <ctype.h>
#include <string.h>
#include <assert.h>
#include <stdbool.h>
#include <inttypes.h>
#include <sys/uio.h>
#include <poll.h>
#include <regex.h>

/** used in various contexts */
#define MAXLINE 255

/** Compute the minimum of \a x and \a y. */
#define PARA_MIN(x, y) ({ \
	typeof(x) _min1 = (x); \
	typeof(y) _min2 = (y); \
	(void) (&_min1 == &_min2); \
	_min1 < _min2 ? _min1 : _min2; })

/** Compute the maximum of \a x and \a y. */
#define PARA_MAX(x, y) ({ \
	typeof(x) _max1 = (x); \
	typeof(y) _max2 = (y); \
	(void) (&_max1 == &_max2); \
	_max1 < _max2 ? _max2 : _max1; })

/** Compute the absolute value of \a x. */
#define PARA_ABS(x) ({ \
	typeof(x) _x = (x); \
	_x > 0? _x : -_x; })

/** \cond doxygen_ignore */
#define __noreturn __attribute__ ((noreturn))
#define __malloc __attribute__ ((malloc))
#define __a_unused __attribute__ ((unused))
#define __a_aligned(alignment) __attribute__((__aligned__(alignment)))

/*
 * p is the number of the "format string" parameter, and q is the number of the
 * first variadic parameter. If q is specified as zero, the compiler only
 * checks the format string for consistency.
 */
#define __printf(p,q) __attribute__ ((format (printf, p, q)))
#define __a_const __attribute__ ((const))

/*
 * As direct use of __printf(p,q) confuses doxygen, here are some extra macros
 * for those values p,q that are actually used.
 */
#define __printf_2_0 __printf(2,0)
#define __printf_1_2 __printf(1,2)
#define __printf_2_3 __printf(2,3)
#define __printf_3_4 __printf(3,4)

#define __must_check __attribute__ ((warn_unused_result))
#define _static_inline_ static inline
/** \endcond */

extern __printf_2_3 void (*para_log)(int, const char*, ...);

/**
 * Define a standard log function that always writes to stderr.
 *
 * \param funcname The name of the function to be defined.
 *
 * \param loglevel_barrier If the loglevel of the current message
 * is less than that, the message is going to be ignored.
 *
 */
#define DEFINE_STDERR_LOGGER(funcname, loglevel_barrier) \
	static __printf_2_3 void funcname(int ll, const char* fmt,...) \
	{ \
		va_list argp; \
		if (ll < loglevel_barrier) \
			return; \
		va_start(argp, fmt); \
		vfprintf(stderr, fmt, argp); \
		va_end(argp); \
	}
/**
 * Define the standard log function and activate it.
 *
 * \param loglevel_barrier See \ref DEFINE_STDERR_LOGGER.
 */
#define INIT_STDERR_LOGGING(loglevel_barrier) \
	DEFINE_STDERR_LOGGER(stderr_log, loglevel_barrier); \
	__printf_2_3 void (*para_log)(int, const char*, ...) = stderr_log;

/** Sent by para_client to initiate the authentication procedure. */
#define AUTH_REQUEST_MSG "auth rsa "

/* exec */
int xexec(pid_t *pid, const char *cmdline, int *fds);

/* time */
int tv_diff(const struct timeval *b, const struct timeval *a,
		struct timeval *diff);
long unsigned tv2ms(const struct timeval *tv);
void tv_add(const struct timeval *a, const struct timeval *b,
		struct timeval *sum);
void tv_scale(const unsigned long mult, const struct timeval *tv,
		struct timeval *result);
void tv_divide(const unsigned long divisor, const struct timeval *tv,
		struct timeval *result);
int tv_convex_combination(const long a, const struct timeval *tv1,
		const long b, const struct timeval *tv2,
		struct timeval *result);
void ms2tv(long unsigned n, struct timeval *tv);
void compute_chunk_time(long unsigned chunk_num,
		struct timeval *chunk_tv, struct timeval *stream_start,
		struct timeval *result);
struct timeval *clock_get_realtime(struct timeval *tv);

/**
 * Return a random non-negative integer in an interval.
 *
 * \param max Determines maximal possible return value.
 *
 * \return An integer between zero and \p max - 1, inclusively.
 */
_static_inline_ long int para_random(unsigned max)
{
	return ((max + 0.0) * (random() / (RAND_MAX + 1.0)));
}

/** Round up x to next multiple of y. */
#define ROUND_UP(x, y) ({ \
	const typeof(y) _divisor = y; \
	((x) + _divisor - 1) / _divisor * _divisor; })

/** Round down x to multiple of y. */
#define ROUND_DOWN(x, y) ({ \
	const typeof(y) _divisor = y; \
	(x) / _divisor * _divisor; })

/** Divide and round up to next integer. */
#define DIV_ROUND_UP(x, y) ({ \
	typeof(y) _divisor = y; \
	((x) + _divisor - 1) / _divisor; })

/**
 * Assert a build-time dependency, as an expression.
 *
 * \param cond The compile-time condition which must be true.
 *
 * Compilation will fail if the condition isn't true, or can't be evaluated by
 * the compiler. This can be used in an expression: its value is "0".
 *
 * Taken from ccan.
 */
#define EXPR_BUILD_ASSERT(cond) (sizeof(char [1 - 2 * !(cond)]) - 1)

/** &a[0] degrades to a pointer: a different type from an array */
#define _array_size_chk(arr) EXPR_BUILD_ASSERT(\
	!__builtin_types_compatible_p(typeof(arr), typeof(&(arr)[0])))
/** Get the size of an array */
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + _array_size_chk(arr))

/**
 * Wrapper for isspace.
 * NetBSD needs this.
 */
/*
 * The values should be cast to an unsigned char first, then to int.
 * Why? Because the isdigit (as do all other is/to functions/macros)
 * expect a number from 0 upto and including 255 as their (int) argument.
 * Because char is signed on most systems, casting it to int immediately
 * gives the functions an argument between -128 and 127 (inclusive),
 * which they will use as an array index, and which will thus fail
 * horribly for characters which have their most significant bit set.
 */
#define para_isspace(c) isspace((int)(unsigned char)(c))

/** Used to avoid a shortcoming in vim's syntax highlighting. */
#define EMBRACE(...) { __VA_ARGS__}

/** A nice cup of STFU for Mr gcc. */
#define do_nothing do {/* nothing */} while (0)

/**
 * The sample formats supported by paraslash.
 *
 * It may be determined by one of the following sources:
 *
 *	1. The decoding filter (para_audiod only). In this case, it is always
 *	\p SF_S16_LE which is the canonical format used within decoders.
 *
 *	2. The wav header (para_write only).
 *
 *	3. The --sample-format option of para_write.
 */
#define SAMPLE_FORMATS \
	SAMPLE_FORMAT(SF_S8, "8 bit signed"), \
	SAMPLE_FORMAT(SF_U8, "8 bit unsigned"), \
	SAMPLE_FORMAT(SF_S16_LE, "16 bit signed, little endian"), \
	SAMPLE_FORMAT(SF_S16_BE, "16 bit signed, big endian"), \
	SAMPLE_FORMAT(SF_U16_LE, "16 bit unsigned, little endian"), \
	SAMPLE_FORMAT(SF_U16_BE, "16 bit unsigned, big endian"), \
	SAMPLE_FORMAT(SF_FLOAT_LE, "32 bit float, little endian"), \
	SAMPLE_FORMAT(SF_FLOAT_BE, "32 bit float, big endian"), \

/** \cond sample_format */
#define SAMPLE_FORMAT(a, b) a
enum sample_format {SAMPLE_FORMATS};
#undef SAMPLE_FORMAT
#define SAMPLE_FORMAT(a, b) b
/** \endcond sample_format */

/** Debug, Info, etc. */
enum loglevels {LOGLEVELS, NUM_LOGLEVELS};

#define PARA_DEBUG_LOG(f,...) para_log(LL_DEBUG, "%s: " f, __func__, ## __VA_ARGS__)
#define PARA_INFO_LOG(f,...) para_log(LL_INFO, "%s: " f, __func__, ## __VA_ARGS__)
#define PARA_NOTICE_LOG(f,...) para_log(LL_NOTICE, "%s: " f, __func__, ## __VA_ARGS__)
#define PARA_WARNING_LOG(f,...) para_log(LL_WARNING, "%s: " f, __func__, ##  __VA_ARGS__)
#define PARA_ERROR_LOG(f,...) para_log(LL_ERROR, "%s: " f, __func__, ## __VA_ARGS__)
#define PARA_CRIT_LOG(f,...) para_log(LL_CRIT, "%s: " f, __func__, ## __VA_ARGS__)
#define PARA_EMERG_LOG(f,...) para_log(LL_EMERG, "%s: " f, __func__, ## __VA_ARGS__)

/** \cond status_items */
#define STATUS_ITEMS \
	STATUS_ITEM(basename) \
	STATUS_ITEM(status) \
	STATUS_ITEM(num_played) \
	STATUS_ITEM(mtime) \
	STATUS_ITEM(bitrate) \
	STATUS_ITEM(frequency) \
	STATUS_ITEM(file_size) \
	STATUS_ITEM(status_flags) \
	STATUS_ITEM(format) \
	STATUS_ITEM(score) \
	STATUS_ITEM(techinfo) \
	STATUS_ITEM(afs_mode) \
	STATUS_ITEM(attributes_txt) \
	STATUS_ITEM(decoder_flags) \
	STATUS_ITEM(audiod_status) \
	STATUS_ITEM(play_time) \
	STATUS_ITEM(attributes_bitmap) \
	STATUS_ITEM(offset) \
	STATUS_ITEM(seconds_total) \
	STATUS_ITEM(stream_start) \
	STATUS_ITEM(current_time) \
	STATUS_ITEM(audiod_uptime) \
	STATUS_ITEM(image_id) \
	STATUS_ITEM(lyrics_id) \
	STATUS_ITEM(duration) \
	STATUS_ITEM(directory) \
	STATUS_ITEM(lyrics_name) \
	STATUS_ITEM(image_name) \
	STATUS_ITEM(path) \
	STATUS_ITEM(hash) \
	STATUS_ITEM(channels) \
	STATUS_ITEM(last_played) \
	STATUS_ITEM(num_chunks) \
	STATUS_ITEM(chunk_time) \
	STATUS_ITEM(amplification) \
	STATUS_ITEM(artist) \
	STATUS_ITEM(title) \
	STATUS_ITEM(year) \
	STATUS_ITEM(album) \
	STATUS_ITEM(comment) \
	STATUS_ITEM(max_chunk_size) \

#define STATUS_ITEM(_name) SI_ ##_name,
enum status_items {STATUS_ITEMS NUM_STAT_ITEMS};
#undef STATUS_ITEM
#define STATUS_ITEM(_name) #_name,
/** \endcond status items */

extern const char *status_item_list[];
/** Loop over each status item. */
#define FOR_EACH_STATUS_ITEM(i) for (i = 0; i < NUM_STAT_ITEMS; i++)
uint64_t parse_status_items(char *item_buf, size_t num_bytes, char **items);
static inline bool status_item_bit_set(int item_num, uint64_t mask)
{
	return mask & ((uint64_t)1 << item_num);
}