1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
11
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21
22 #ifndef PULSE_COMPAT_H
23 #define PULSE_COMPAT_H
24
25 #ifdef __cplusplus
26 extern "C" {
27 #else
28 #include <stdbool.h>
29 #endif
30
31 #include <stdio.h>
32 #include <stdarg.h>
33 #include <stdint.h>
34 #include <inttypes.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37
38 typedef struct pa_core pa_core;
39
40 typedef void *(*pa_copy_func_t)(const void *p);
41 typedef void (*pa_free_cb_t)(void *p);
42
43 #ifdef __GNUC__
44 #define PA_LIKELY(x) (__builtin_expect(!!(x),1))
45 #define PA_UNLIKELY(x) (__builtin_expect(!!(x),0))
46 #define PA_PRINTF_FUNC(fmt, arg1) __attribute__((format(printf, fmt, arg1)))
47 #else
48 #define PA_LIKELY(x) (x)
49 #define PA_UNLIKELY(x) (x)
50 #define PA_PRINTF_FUNC(fmt, arg1)
51 #endif
52
53 #define PA_MIN(a,b) \
54 ({ \
55 __typeof__(a) _a = (a); \
56 __typeof__(b) _b = (b); \
57 PA_LIKELY(_a < _b) ? _a : _b; \
58 })
59 #define PA_MAX(a,b) \
60 ({ \
61 __typeof__(a) _a = (a); \
62 __typeof__(b) _b = (b); \
63 PA_LIKELY(_a > _b) ? _a : _b; \
64 })
65 #define PA_CLAMP_UNLIKELY(v,low,high) \
66 ({ \
67 __typeof__(v) _v = (v); \
68 __typeof__(low) _low = (low); \
69 __typeof__(high) _high = (high); \
70 PA_MIN(PA_MAX(_v, _low), _high); \
71 })
72
73 #define PA_PTR_TO_UINT(p) ((unsigned int) ((uintptr_t) (p)))
74 #define PA_UINT_TO_PTR(u) ((void*) ((uintptr_t) (u)))
75
76 #include "array.h"
77 #include "llist.h"
78 #include "hashmap.h"
79 #include "dynarray.h"
80 #include "idxset.h"
81 #include "proplist.h"
82
83 typedef enum pa_direction {
84 PA_DIRECTION_OUTPUT = 0x0001U, /**< Output direction */
85 PA_DIRECTION_INPUT = 0x0002U /**< Input direction */
86 } pa_direction_t;
87
88 /* This enum replaces pa_port_available_t (defined in pulse/def.h) for
89 * internal use, so make sure both enum types stay in sync. */
90 typedef enum pa_available {
91 PA_AVAILABLE_UNKNOWN = 0,
92 PA_AVAILABLE_NO = 1,
93 PA_AVAILABLE_YES = 2,
94 } pa_available_t;
95
96 #define PA_RATE_MAX (48000U*8U)
97
98 typedef enum pa_sample_format {
99 PA_SAMPLE_U8, /**< Unsigned 8 Bit PCM */
100 PA_SAMPLE_ALAW, /**< 8 Bit a-Law */
101 PA_SAMPLE_ULAW, /**< 8 Bit mu-Law */
102 PA_SAMPLE_S16LE, /**< Signed 16 Bit PCM, little endian (PC) */
103 PA_SAMPLE_S16BE, /**< Signed 16 Bit PCM, big endian */
104 PA_SAMPLE_FLOAT32LE, /**< 32 Bit IEEE floating point, little endian (PC), range -1.0 to 1.0 */
105 PA_SAMPLE_FLOAT32BE, /**< 32 Bit IEEE floating point, big endian, range -1.0 to 1.0 */
106 PA_SAMPLE_S32LE, /**< Signed 32 Bit PCM, little endian (PC) */
107 PA_SAMPLE_S32BE, /**< Signed 32 Bit PCM, big endian */
108 PA_SAMPLE_S24LE, /**< Signed 24 Bit PCM packed, little endian (PC). \since 0.9.15 */
109 PA_SAMPLE_S24BE, /**< Signed 24 Bit PCM packed, big endian. \since 0.9.15 */
110 PA_SAMPLE_S24_32LE, /**< Signed 24 Bit PCM in LSB of 32 Bit words, little endian (PC). \since 0.9.15 */
111 PA_SAMPLE_S24_32BE, /**< Signed 24 Bit PCM in LSB of 32 Bit words, big endian. \since 0.9.15 */
112 PA_SAMPLE_MAX, /**< Upper limit of valid sample types */
113 PA_SAMPLE_INVALID = -1 /**< An invalid value */
114 } pa_sample_format_t;
115
pa_sample_format_valid(unsigned format)116 static inline int pa_sample_format_valid(unsigned format)
117 {
118 return format < PA_SAMPLE_MAX;
119 }
120
121 #ifdef WORDS_BIGENDIAN
122 #define PA_SAMPLE_S16NE PA_SAMPLE_S16BE
123 #define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32BE
124 #define PA_SAMPLE_S32NE PA_SAMPLE_S32BE
125 #define PA_SAMPLE_S24NE PA_SAMPLE_S24BE
126 #define PA_SAMPLE_S24_32NE PA_SAMPLE_S24_32BE
127 #define PA_SAMPLE_S16RE PA_SAMPLE_S16LE
128 #define PA_SAMPLE_FLOAT32RE PA_SAMPLE_FLOAT32LE
129 #define PA_SAMPLE_S32RE PA_SAMPLE_S32LE
130 #define PA_SAMPLE_S24RE PA_SAMPLE_S24LE
131 #define PA_SAMPLE_S24_32RE PA_SAMPLE_S24_32LE
132 #else
133 #define PA_SAMPLE_S16NE PA_SAMPLE_S16LE
134 #define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32LE
135 #define PA_SAMPLE_S32NE PA_SAMPLE_S32LE
136 #define PA_SAMPLE_S24NE PA_SAMPLE_S24LE
137 #define PA_SAMPLE_S24_32NE PA_SAMPLE_S24_32LE
138 #define PA_SAMPLE_S16RE PA_SAMPLE_S16BE
139 #define PA_SAMPLE_FLOAT32RE PA_SAMPLE_FLOAT32BE
140 #define PA_SAMPLE_S32RE PA_SAMPLE_S32BE
141 #define PA_SAMPLE_S24RE PA_SAMPLE_S24BE
142 #define PA_SAMPLE_S24_32RE PA_SAMPLE_S24_32BE
143 #endif
144
145 static const size_t pa_sample_size_table[] = {
146 [PA_SAMPLE_U8] = 1,
147 [PA_SAMPLE_ULAW] = 1,
148 [PA_SAMPLE_ALAW] = 1,
149 [PA_SAMPLE_S16LE] = 2,
150 [PA_SAMPLE_S16BE] = 2,
151 [PA_SAMPLE_FLOAT32LE] = 4,
152 [PA_SAMPLE_FLOAT32BE] = 4,
153 [PA_SAMPLE_S32LE] = 4,
154 [PA_SAMPLE_S32BE] = 4,
155 [PA_SAMPLE_S24LE] = 3,
156 [PA_SAMPLE_S24BE] = 3,
157 [PA_SAMPLE_S24_32LE] = 4,
158 [PA_SAMPLE_S24_32BE] = 4
159 };
160
pa_sample_format_to_string(pa_sample_format_t f)161 static inline const char *pa_sample_format_to_string(pa_sample_format_t f)
162 {
163 static const char* const table[]= {
164 [PA_SAMPLE_U8] = "u8",
165 [PA_SAMPLE_ALAW] = "aLaw",
166 [PA_SAMPLE_ULAW] = "uLaw",
167 [PA_SAMPLE_S16LE] = "s16le",
168 [PA_SAMPLE_S16BE] = "s16be",
169 [PA_SAMPLE_FLOAT32LE] = "float32le",
170 [PA_SAMPLE_FLOAT32BE] = "float32be",
171 [PA_SAMPLE_S32LE] = "s32le",
172 [PA_SAMPLE_S32BE] = "s32be",
173 [PA_SAMPLE_S24LE] = "s24le",
174 [PA_SAMPLE_S24BE] = "s24be",
175 [PA_SAMPLE_S24_32LE] = "s24-32le",
176 [PA_SAMPLE_S24_32BE] = "s24-32be",
177 };
178
179 if (!pa_sample_format_valid(f))
180 return NULL;
181 return table[f];
182 }
183
184 typedef struct pa_sample_spec {
185 pa_sample_format_t format;
186 uint32_t rate;
187 uint8_t channels;
188 } pa_sample_spec;
189
190 typedef uint64_t pa_usec_t;
191 #define PA_MSEC_PER_SEC ((pa_usec_t) 1000ULL)
192 #define PA_USEC_PER_SEC ((pa_usec_t) 1000000ULL)
193 #define PA_USEC_PER_MSEC ((pa_usec_t) 1000ULL)
194
pa_usec_to_bytes(pa_usec_t t,const pa_sample_spec * spec)195 static inline size_t pa_usec_to_bytes(pa_usec_t t, const pa_sample_spec *spec) {
196 return (size_t) (((t * spec->rate) / PA_USEC_PER_SEC)) *
197 (pa_sample_size_table[spec->format] * spec->channels);
198 }
199
pa_sample_rate_valid(uint32_t rate)200 static inline int pa_sample_rate_valid(uint32_t rate) {
201 return rate > 0 && rate <= PA_RATE_MAX * 101 / 100;
202 }
203
pa_frame_size(const pa_sample_spec * spec)204 static inline size_t pa_frame_size(const pa_sample_spec *spec) {
205 return pa_sample_size_table[spec->format] * spec->channels;
206 }
207
208 typedef enum pa_log_level {
209 PA_LOG_ERROR = 0, /* Error messages */
210 PA_LOG_WARN = 1, /* Warning messages */
211 PA_LOG_NOTICE = 2, /* Notice messages */
212 PA_LOG_INFO = 3, /* Info messages */
213 PA_LOG_DEBUG = 4, /* Debug messages */
214 PA_LOG_LEVEL_MAX
215 } pa_log_level_t;
216
217 extern int _acp_log_level;
218 extern acp_log_func _acp_log_func;
219 extern void * _acp_log_data;
220
221 #define pa_log_level_enabled(lev) (_acp_log_level >= (int)(lev))
222
223 #define pa_log_levelv_meta(lev,f,l,func,fmt,ap) \
224 ({ \
225 if (pa_log_level_enabled (lev) && _acp_log_func) \
226 _acp_log_func(_acp_log_data,lev,f,l,func,fmt,ap); \
227 })
228
pa_log_level_meta(enum pa_log_level level,const char * file,int line,const char * func,const char * fmt,...)229 static inline PA_PRINTF_FUNC(5, 6) void pa_log_level_meta(enum pa_log_level level,
230 const char *file, int line, const char *func,
231 const char *fmt, ...)
232 {
233 va_list args;
234 va_start(args,fmt);
235 pa_log_levelv_meta(level,file,line,func,fmt,args);
236 va_end(args);
237 }
238
239 #define pa_logl(lev,fmt,...) pa_log_level_meta(lev,__FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__)
240 #define pa_log_error(fmt,...) pa_logl(PA_LOG_ERROR, fmt, ##__VA_ARGS__)
241 #define pa_log_warn(fmt,...) pa_logl(PA_LOG_WARN, fmt, ##__VA_ARGS__)
242 #define pa_log_notice(fmt,...) pa_logl(PA_LOG_NOTICE, fmt, ##__VA_ARGS__)
243 #define pa_log_info(fmt,...) pa_logl(PA_LOG_INFO, fmt, ##__VA_ARGS__)
244 #define pa_log_debug(fmt,...) pa_logl(PA_LOG_DEBUG, fmt, ##__VA_ARGS__)
245 #define pa_log pa_log_error
246
247 #define pa_assert_se(expr) \
248 do { \
249 if (PA_UNLIKELY(!(expr))) { \
250 fprintf(stderr, "'%s' failed at %s:%u %s()\n", \
251 #expr , __FILE__, __LINE__, __func__); \
252 abort(); \
253 } \
254 } while (false)
255
256 #define pa_assert(expr) \
257 do { \
258 if (PA_UNLIKELY(!(expr))) { \
259 fprintf(stderr, "'%s' failed at %s:%u %s()\n", \
260 #expr , __FILE__, __LINE__, __func__); \
261 abort(); \
262 } \
263 } while (false)
264
265 #define pa_assert_not_reached() \
266 do { \
267 fprintf(stderr, "Code should not be reached at %s:%u %s()\n", \
268 __FILE__, __LINE__, __func__); \
269 abort(); \
270 } while (false)
271
272
273 #define pa_memzero(x,l) (memset((x), 0, (l)))
274 #define pa_zero(x) (pa_memzero(&(x), sizeof(x)))
275
276 #define PA_ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0]))
277
278 #define pa_streq(a,b) (!strcmp((a),(b)))
279 #define pa_strneq(a,b,n) (!strncmp((a),(b),(n)))
280 #define pa_strnull(s) ((s) ? (s) : "null")
281 #define pa_startswith(s,pfx) (strstr(s, pfx) == s)
282
283 PA_PRINTF_FUNC(3, 0)
pa_vsnprintf(char * str,size_t size,const char * format,va_list ap)284 static inline size_t pa_vsnprintf(char *str, size_t size, const char *format, va_list ap)
285 {
286 int ret;
287
288 pa_assert(str);
289 pa_assert(size > 0);
290 pa_assert(format);
291
292 ret = vsnprintf(str, size, format, ap);
293
294 str[size-1] = 0;
295
296 if (ret < 0)
297 return strlen(str);
298
299 if ((size_t) ret > size-1)
300 return size-1;
301
302 return (size_t) ret;
303 }
304
305 PA_PRINTF_FUNC(3, 4)
pa_snprintf(char * str,size_t size,const char * format,...)306 static inline size_t pa_snprintf(char *str, size_t size, const char *format, ...)
307 {
308 size_t ret;
309 va_list ap;
310
311 pa_assert(str);
312 pa_assert(size > 0);
313 pa_assert(format);
314
315 va_start(ap, format);
316 ret = pa_vsnprintf(str, size, format, ap);
317 va_end(ap);
318
319 return ret;
320 }
321
322 #define pa_xstrdup(s) ((s) != NULL ? strdup(s) : NULL)
323 #define pa_xstrndup(s,n) ((s) != NULL ? strndup(s,n) : NULL)
324 #define pa_xfree free
325 #define pa_xmalloc malloc
326 #define pa_xnew0(t,n) calloc(n, sizeof(t))
327 #define pa_xnew(t,n) pa_xnew0(t,n)
328 #define pa_xrealloc realloc
329 #define pa_xrenew(t,p,n) ((t*) realloc(p, (n)*sizeof(t)))
330
pa_xmemdup(const void * p,size_t l)331 static inline void* pa_xmemdup(const void *p, size_t l) {
332 return memcpy(malloc(l), p, l);
333
334 }
335 #define pa_xnewdup(t,p,n) ((t*) pa_xmemdup((p), (n)*sizeof(t)))
336
pa_xfreev(void ** a)337 static inline void pa_xfreev(void**a)
338 {
339 int i;
340 for (i = 0; a && a[i]; i++)
341 free(a[i]);
342 free(a);
343 }
pa_xstrfreev(char ** a)344 static inline void pa_xstrfreev(char **a) {
345 pa_xfreev((void**)a);
346 }
347
348
349 #define pa_cstrerror strerror
350
351 #define PA_PATH_SEP "/"
352 #define PA_PATH_SEP_CHAR '/'
353
354 #define PA_WHITESPACE "\n\r \t"
355
pa_sprintf_malloc(const char * fmt,...)356 static PA_PRINTF_FUNC(1,2) inline char *pa_sprintf_malloc(const char *fmt, ...)
357 {
358 char *res;
359 va_list args;
360 va_start(args, fmt);
361 if (vasprintf(&res, fmt, args) < 0)
362 res = NULL;
363 va_end(args);
364 return res;
365 }
366
367 #define pa_fopen_cloexec(f,m) fopen(f,m"e")
368
pa_path_get_filename(const char * p)369 static inline char *pa_path_get_filename(const char *p)
370 {
371 char *fn;
372 if (!p)
373 return NULL;
374 if ((fn = strrchr(p, PA_PATH_SEP_CHAR)))
375 return fn+1;
376 return (char*) p;
377 }
378
pa_is_path_absolute(const char * fn)379 static inline bool pa_is_path_absolute(const char *fn)
380 {
381 return *fn == PA_PATH_SEP_CHAR;
382 }
383
pa_maybe_prefix_path(const char * path,const char * prefix)384 static inline char* pa_maybe_prefix_path(const char *path, const char *prefix)
385 {
386 if (pa_is_path_absolute(path))
387 return pa_xstrdup(path);
388 return pa_sprintf_malloc("%s" PA_PATH_SEP "%s", prefix, path);
389 }
390
pa_endswith(const char * s,const char * sfx)391 static inline bool pa_endswith(const char *s, const char *sfx)
392 {
393 size_t l1, l2;
394 l1 = strlen(s);
395 l2 = strlen(sfx);
396 return l1 >= l2 && pa_streq(s + l1 - l2, sfx);
397 }
398
pa_replace(const char * s,const char * a,const char * b)399 static inline char *pa_replace(const char*s, const char*a, const char *b)
400 {
401 struct pa_array res;
402 size_t an, bn;
403
404 an = strlen(a);
405 bn = strlen(b);
406 pa_array_init(&res, an);
407
408 for (;;) {
409 const char *p;
410
411 if (!(p = strstr(s, a)))
412 break;
413
414 pa_array_add_data(&res, s, p-s);
415 pa_array_add_data(&res, b, bn);
416 s = p + an;
417 }
418 pa_array_add_data(&res, s, strlen(s) + 1);
419 return res.data;
420 }
421
pa_split(const char * c,const char * delimiter,const char ** state)422 static inline char *pa_split(const char *c, const char *delimiter, const char**state)
423 {
424 const char *current = *state ? *state : c;
425 size_t l;
426 if (!*current)
427 return NULL;
428 l = strcspn(current, delimiter);
429 *state = current+l;
430 if (**state)
431 (*state)++;
432 return pa_xstrndup(current, l);
433 }
434
pa_split_spaces(const char * c,const char ** state)435 static inline char *pa_split_spaces(const char *c, const char **state)
436 {
437 const char *current = *state ? *state : c;
438 size_t l;
439 if (!*current || *c == 0)
440 return NULL;
441 current += strspn(current, PA_WHITESPACE);
442 l = strcspn(current, PA_WHITESPACE);
443 *state = current+l;
444 return pa_xstrndup(current, l);
445 }
446
pa_split_spaces_strv(const char * s)447 static inline char **pa_split_spaces_strv(const char *s)
448 {
449 char **t, *e;
450 unsigned i = 0, n = 8;
451 const char *state = NULL;
452
453 t = pa_xnew(char*, n);
454 while ((e = pa_split_spaces(s, &state))) {
455 t[i++] = e;
456 if (i >= n) {
457 n *= 2;
458 t = pa_xrenew(char*, t, n);
459 }
460 }
461 if (i <= 0) {
462 pa_xfree(t);
463 return NULL;
464 }
465 t[i] = NULL;
466 return t;
467 }
468
pa_str_strip_suffix(const char * str,const char * suffix)469 static inline char* pa_str_strip_suffix(const char *str, const char *suffix)
470 {
471 size_t str_l, suf_l, prefix;
472 char *ret;
473
474 str_l = strlen(str);
475 suf_l = strlen(suffix);
476
477 if (str_l < suf_l)
478 return NULL;
479 prefix = str_l - suf_l;
480 if (!pa_streq(&str[prefix], suffix))
481 return NULL;
482 ret = pa_xmalloc(prefix + 1);
483 memcpy(ret, str, prefix);
484 ret[prefix] = '\0';
485 return ret;
486 }
487
pa_split_in_place(const char * c,const char * delimiter,size_t * n,const char ** state)488 static inline const char *pa_split_in_place(const char *c, const char *delimiter, size_t *n, const char**state)
489 {
490 const char *current = *state ? *state : c;
491 size_t l;
492 if (!*current)
493 return NULL;
494 l = strcspn(current, delimiter);
495 *state = current+l;
496 if (**state)
497 (*state)++;
498 *n = l;
499 return current;
500 }
501
pa_split_spaces_in_place(const char * c,size_t * n,const char ** state)502 static inline const char *pa_split_spaces_in_place(const char *c, size_t *n, const char **state)
503 {
504 const char *current = *state ? *state : c;
505 size_t l;
506 if (!*current || *c == 0)
507 return NULL;
508 current += strspn(current, PA_WHITESPACE);
509 l = strcspn(current, PA_WHITESPACE);
510 *state = current+l;
511 *n = l;
512 return current;
513 }
514
pa_str_in_list_spaces(const char * haystack,const char * needle)515 static inline bool pa_str_in_list_spaces(const char *haystack, const char *needle)
516 {
517 const char *s;
518 size_t n;
519 const char *state = NULL;
520
521 if (!haystack || !needle)
522 return false;
523
524 while ((s = pa_split_spaces_in_place(haystack, &n, &state))) {
525 if (pa_strneq(needle, s, n))
526 return true;
527 }
528
529 return false;
530 }
531
pa_strip(char * s)532 static inline char *pa_strip(char *s)
533 {
534 char *e, *l = NULL;
535 s += strspn(s, PA_WHITESPACE);
536 for (e = s; *e; e++)
537 if (!strchr(PA_WHITESPACE, *e))
538 l = e;
539 if (l)
540 *(l+1) = 0;
541 else
542 *s = 0;
543 return s;
544 }
545
pa_atod(const char * s,double * ret_d)546 static inline int pa_atod(const char *s, double *ret_d)
547 {
548 char *x;
549 *ret_d = strtod(s, &x);
550 return 0;
551 }
pa_atoi(const char * s,int32_t * ret_i)552 static inline int pa_atoi(const char *s, int32_t *ret_i)
553 {
554 *ret_i = (int32_t) atoi(s);
555 return 0;
556 }
pa_atou(const char * s,uint32_t * ret_u)557 static inline int pa_atou(const char *s, uint32_t *ret_u)
558 {
559 *ret_u = (uint32_t) atoi(s);
560 return 0;
561 }
pa_atol(const char * s,long * ret_l)562 static inline int pa_atol(const char *s, long *ret_l)
563 {
564 char *x;
565 *ret_l = strtol(s, &x, 0);
566 return 0;
567 }
568
pa_parse_boolean(const char * v)569 static inline int pa_parse_boolean(const char *v)
570 {
571 if (pa_streq(v, "1") || !strcasecmp(v, "y") || !strcasecmp(v, "t")
572 || !strcasecmp(v, "yes") || !strcasecmp(v, "true") || !strcasecmp(v, "on"))
573 return 1;
574 else if (pa_streq(v, "0") || !strcasecmp(v, "n") || !strcasecmp(v, "f")
575 || !strcasecmp(v, "no") || !strcasecmp(v, "false") || !strcasecmp(v, "off"))
576 return 0;
577 errno = EINVAL;
578 return -1;
579 }
580
pa_yes_no(bool b)581 static inline const char *pa_yes_no(bool b) {
582 return b ? "yes" : "no";
583 }
584
pa_strna(const char * x)585 static inline const char *pa_strna(const char *x) {
586 return x ? x : "n/a";
587 }
588
pa_sample_spec_init(pa_sample_spec * spec)589 static inline pa_sample_spec* pa_sample_spec_init(pa_sample_spec *spec)
590 {
591 spec->format = PA_SAMPLE_INVALID;
592 spec->rate = 0;
593 spec->channels = 0;
594 return spec;
595 }
596
pa_readlink(const char * p)597 static inline char *pa_readlink(const char *p) {
598 #ifdef HAVE_READLINK
599 size_t l = 100;
600
601 for (;;) {
602 char *c;
603 ssize_t n;
604
605 c = pa_xmalloc(l);
606
607 if ((n = readlink(p, c, l-1)) < 0) {
608 pa_xfree(c);
609 return NULL;
610 }
611
612 if ((size_t) n < l-1) {
613 c[n] = 0;
614 return c;
615 }
616
617 pa_xfree(c);
618 l *= 2;
619 }
620 #else
621 return NULL;
622 #endif
623 }
624
625 #include <spa/support/i18n.h>
626
627 extern struct spa_i18n *acp_i18n;
628
629 #define _(String) spa_i18n_text(acp_i18n, String)
630 #ifdef gettext_noop
631 #define N_(String) gettext_noop(String)
632 #else
633 #define N_(String) (String)
634 #endif
635
636 #include "channelmap.h"
637 #include "volume.h"
638
639 #ifdef __cplusplus
640 }
641 #endif
642
643 #endif /* PULSE_COMPAT_H */
644