replace memory allocation function calls with pa_xXXXX()
[profile/ivi/pulseaudio.git] / src / polypcore / core-util.c
1 /* $Id$ */
2
3 /***
4   This file is part of polypaudio.
5  
6   polypaudio is free software; you can redistribute it and/or modify
7   it under the terms of the GNU Lesser General Public License as
8   published by the Free Software Foundation; either version 2.1 of the
9   License, or (at your option) any later version.
10  
11   polypaudio is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15  
16   You should have received a copy of the GNU Lesser General Public
17   License along with polypaudio; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #include <signal.h>
29 #include <errno.h>
30 #include <assert.h>
31 #include <string.h>
32 #include <stdio.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35 #include <limits.h>
36 #include <time.h>
37 #include <ctype.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <sys/time.h>
41
42 #ifdef HAVE_SCHED_H
43 #include <sched.h>
44 #endif
45
46 #ifdef HAVE_SYS_RESOURCE_H
47 #include <sys/resource.h>
48 #endif
49
50 #ifdef HAVE_PTHREAD
51 #include <pthread.h>
52 #endif
53
54 #ifdef HAVE_NETDB_H
55 #include <netdb.h>
56 #endif
57
58 #ifdef HAVE_WINDOWS_H
59 #include <windows.h>
60 #endif
61
62 #ifdef HAVE_PWD_H
63 #include <pwd.h>
64 #endif
65
66 #ifdef HAVE_GRP_H
67 #include <grp.h>
68 #endif
69
70 #include <samplerate.h>
71
72 #include <polyp/xmalloc.h>
73 #include <polyp/util.h>
74
75 #include <polypcore/winsock.h>
76 #include <polypcore/log.h>
77
78 #include "core-util.h"
79
80 #ifndef OS_IS_WIN32
81 #define PA_RUNTIME_PATH_PREFIX "/tmp/polypaudio-"
82 #define PATH_SEP '/'
83 #else
84 #define PA_RUNTIME_PATH_PREFIX "%TEMP%\\polypaudio-"
85 #define PATH_SEP '\\'
86 #endif
87
88 #ifdef OS_IS_WIN32
89
90 #define POLYP_ROOTENV "POLYP_ROOT"
91
92 int pa_set_root(HANDLE handle) {
93     char library_path[MAX_PATH + sizeof(POLYP_ROOTENV) + 1], *sep;
94
95     strcpy(library_path, POLYP_ROOTENV "=");
96
97     if (!GetModuleFileName(handle, library_path + sizeof(POLYP_ROOTENV), MAX_PATH))
98         return 0;
99
100     sep = strrchr(library_path, '\\');
101     if (sep)
102         *sep = '\0';
103
104     if (_putenv(library_path) < 0)
105         return 0;
106
107     return 1;
108 }
109
110 #endif
111
112 /** Make a file descriptor nonblock. Doesn't do any error checking */
113 void pa_make_nonblock_fd(int fd) {
114 #ifdef O_NONBLOCK
115     int v;
116     assert(fd >= 0);
117
118     if ((v = fcntl(fd, F_GETFL)) >= 0)
119         if (!(v & O_NONBLOCK))
120             fcntl(fd, F_SETFL, v|O_NONBLOCK);
121 #elif defined(OS_IS_WIN32)
122     u_long arg = 1;
123     if (ioctlsocket(fd, FIONBIO, &arg) < 0) {
124         if (WSAGetLastError() == WSAENOTSOCK)
125             pa_log_warn(__FILE__": WARNING: Only sockets can be made non-blocking!");
126     }
127 #else
128     pa_log_warn(__FILE__": WARNING: Non-blocking I/O not supported.!");
129 #endif
130 }
131
132 /** Creates a directory securely */
133 int pa_make_secure_dir(const char* dir) {
134     struct stat st;
135     assert(dir);
136
137 #ifdef OS_IS_WIN32
138     if (mkdir(dir) < 0)
139 #else
140     if (mkdir(dir, 0700) < 0)
141 #endif
142         if (errno != EEXIST)
143             return -1;
144
145 #ifdef HAVE_CHOWN
146     chown(dir, getuid(), getgid());
147 #endif
148 #ifdef HAVE_CHMOD
149     chmod(dir, 0700);
150 #endif
151     
152 #ifdef HAVE_LSTAT
153     if (lstat(dir, &st) < 0)
154 #else
155     if (stat(dir, &st) < 0)
156 #endif
157         goto fail;
158     
159 #ifndef OS_IS_WIN32
160     if (!S_ISDIR(st.st_mode) || (st.st_uid != getuid()) || ((st.st_mode & 0777) != 0700))
161         goto fail;
162 #else
163     fprintf(stderr, "FIXME: pa_make_secure_dir()\n");
164 #endif
165     
166     return 0;
167     
168 fail:
169     rmdir(dir);
170     return -1;
171 }
172
173 /* Return a newly allocated sting containing the parent directory of the specified file */
174 char *pa_parent_dir(const char *fn) {
175     char *slash, *dir = pa_xstrdup(fn);
176
177     slash = (char*) pa_path_get_filename(dir);
178     if (slash == fn)
179         return NULL;
180
181     *(slash-1) = 0;
182     return dir;
183 }
184
185 /* Creates a the parent directory of the specified path securely */
186 int pa_make_secure_parent_dir(const char *fn) {
187     int ret = -1;
188     char *dir;
189
190     if (!(dir = pa_parent_dir(fn)))
191         goto finish;
192     
193     if (pa_make_secure_dir(dir) < 0)
194         goto finish;
195
196     ret = 0;
197     
198 finish:
199     pa_xfree(dir);
200     return ret;
201 }
202
203 /** Platform independent read function. Necessary since not all systems
204  * treat all file descriptors equal. */
205 ssize_t pa_read(int fd, void *buf, size_t count) {
206     ssize_t r;
207
208 #ifdef OS_IS_WIN32
209     r = recv(fd, buf, count, 0);
210     if (r < 0) {
211         if (WSAGetLastError() != WSAENOTSOCK) {
212             errno = WSAGetLastError();
213             return r;
214         }
215     }
216
217     if (r < 0)
218 #endif
219         r = read(fd, buf, count);
220
221     return r;
222 }
223
224 /** Similar to pa_read(), but handles writes */
225 ssize_t pa_write(int fd, const void *buf, size_t count) {
226     ssize_t r;
227
228 #ifdef OS_IS_WIN32
229     r = send(fd, buf, count, 0);
230     if (r < 0) {
231         if (WSAGetLastError() != WSAENOTSOCK) {
232             errno = WSAGetLastError();
233             return r;
234         }
235     }
236
237     if (r < 0)
238 #endif
239         r = write(fd, buf, count);
240
241     return r;
242 }
243
244 /** Calls read() in a loop. Makes sure that as much as 'size' bytes,
245  * unless EOF is reached or an error occured */
246 ssize_t pa_loop_read(int fd, void*data, size_t size) {
247     ssize_t ret = 0;
248     assert(fd >= 0 && data && size);
249
250     while (size > 0) {
251         ssize_t r;
252
253         if ((r = pa_read(fd, data, size)) < 0)
254             return r;
255
256         if (r == 0)
257             break;
258         
259         ret += r;
260         data = (uint8_t*) data + r;
261         size -= r;
262     }
263
264     return ret;
265 }
266
267 /** Similar to pa_loop_read(), but wraps write() */
268 ssize_t pa_loop_write(int fd, const void*data, size_t size) {
269     ssize_t ret = 0;
270     assert(fd >= 0 && data && size);
271
272     while (size > 0) {
273         ssize_t r;
274
275         if ((r = pa_write(fd, data, size)) < 0)
276             return r;
277
278         if (r == 0)
279             break;
280         
281         ret += r;
282         data = (const uint8_t*) data + r;
283         size -= r;
284     }
285
286     return ret;
287 }
288
289 /* Print a warning messages in case that the given signal is not
290  * blocked or trapped */
291 void pa_check_signal_is_blocked(int sig) {
292 #ifdef HAVE_SIGACTION
293     struct sigaction sa;
294     sigset_t set;
295
296     /* If POSIX threads are supported use thread-aware
297      * pthread_sigmask() function, to check if the signal is
298      * blocked. Otherwise fall back to sigprocmask() */
299     
300 #ifdef HAVE_PTHREAD    
301     if (pthread_sigmask(SIG_SETMASK, NULL, &set) < 0) {
302 #endif
303         if (sigprocmask(SIG_SETMASK, NULL, &set) < 0) {
304             pa_log(__FILE__": sigprocmask() failed: %s", strerror(errno));
305             return;
306         }
307 #ifdef HAVE_PTHREAD
308     }
309 #endif
310
311     if (sigismember(&set, sig))
312         return;
313
314     /* Check whether the signal is trapped */
315     
316     if (sigaction(sig, NULL, &sa) < 0) {
317         pa_log(__FILE__": sigaction() failed: %s", strerror(errno));
318         return;
319     }
320         
321     if (sa.sa_handler != SIG_DFL)
322         return;
323     
324     pa_log(__FILE__": WARNING: %s is not trapped. This might cause malfunction!", pa_strsignal(sig));
325 #else /* HAVE_SIGACTION */
326     pa_log(__FILE__": WARNING: %s might not be trapped. This might cause malfunction!", pa_strsignal(sig));
327 #endif
328 }
329
330 /* The following function is based on an example from the GNU libc
331  * documentation. This function is similar to GNU's asprintf(). */
332 char *pa_sprintf_malloc(const char *format, ...) {
333     int  size = 100;
334     char *c = NULL;
335     
336     assert(format);
337     
338     for(;;) {
339         int r;
340         va_list ap;
341
342         c = pa_xrealloc(c, size);
343
344         va_start(ap, format);
345         r = vsnprintf(c, size, format, ap);
346         va_end(ap);
347         
348         if (r > -1 && r < size)
349             return c;
350
351         if (r > -1)    /* glibc 2.1 */
352             size = r+1; 
353         else           /* glibc 2.0 */
354             size *= 2;
355     }
356 }
357
358 /* Same as the previous function, but use a va_list instead of an
359  * ellipsis */
360 char *pa_vsprintf_malloc(const char *format, va_list ap) {
361     int  size = 100;
362     char *c = NULL;
363     
364     assert(format);
365     
366     for(;;) {
367         int r;
368         c = pa_xrealloc(c, size);
369         r = vsnprintf(c, size, format, ap);
370         
371         if (r > -1 && r < size)
372             return c;
373
374         if (r > -1)    /* glibc 2.1 */
375             size = r+1; 
376         else           /* glibc 2.0 */
377             size *= 2;
378     }
379 }
380
381 /* Similar to OpenBSD's strlcpy() function */
382 char *pa_strlcpy(char *b, const char *s, size_t l) {
383     assert(b && s && l > 0);
384
385     strncpy(b, s, l);
386     b[l-1] = 0;
387     return b;
388 }
389
390 #define NICE_LEVEL (-15)
391
392 /* Raise the priority of the current process as much as possible and
393 sensible: set the nice level to -15 and enable realtime scheduling if
394 supported.*/
395 void pa_raise_priority(void) {
396
397 #ifdef HAVE_SYS_RESOURCE_H
398     if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0)
399         pa_log_warn(__FILE__": setpriority() failed: %s", strerror(errno));
400     else 
401         pa_log_info(__FILE__": Successfully gained nice level %i.", NICE_LEVEL); 
402 #endif
403     
404 #ifdef _POSIX_PRIORITY_SCHEDULING
405     {
406         struct sched_param sp;
407
408         if (sched_getparam(0, &sp) < 0) {
409             pa_log(__FILE__": sched_getparam() failed: %s", strerror(errno));
410             return;
411         }
412         
413         sp.sched_priority = 1;
414         if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0) {
415             pa_log_warn(__FILE__": sched_setscheduler() failed: %s", strerror(errno));
416             return;
417         }
418
419         pa_log_info(__FILE__": Successfully enabled SCHED_FIFO scheduling."); 
420     }
421 #endif
422
423 #ifdef OS_IS_WIN32
424     if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS))
425         pa_log_warn(__FILE__": SetPriorityClass() failed: 0x%08X", GetLastError());
426     else
427         pa_log_info(__FILE__": Successfully gained high priority class."); 
428 #endif
429 }
430
431 /* Reset the priority to normal, inverting the changes made by pa_raise_priority() */
432 void pa_reset_priority(void) {
433 #ifdef OS_IS_WIN32
434     SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
435 #endif
436
437 #ifdef _POSIX_PRIORITY_SCHEDULING
438     {
439         struct sched_param sp;
440         sched_getparam(0, &sp);
441         sp.sched_priority = 0;
442         sched_setscheduler(0, SCHED_OTHER, &sp);
443     }
444 #endif
445
446 #ifdef HAVE_SYS_RESOURCE_H
447     setpriority(PRIO_PROCESS, 0, 0);
448 #endif
449 }
450
451 /* Set the FD_CLOEXEC flag for a fd */
452 int pa_fd_set_cloexec(int fd, int b) {
453
454 #ifdef FD_CLOEXEC
455     int v;
456     assert(fd >= 0);
457
458     if ((v = fcntl(fd, F_GETFD, 0)) < 0)
459         return -1;
460     
461     v = (v & ~FD_CLOEXEC) | (b ? FD_CLOEXEC : 0);
462     
463     if (fcntl(fd, F_SETFD, v) < 0)
464         return -1;
465 #endif    
466
467     return 0;
468 }
469
470 /* Try to parse a boolean string value.*/
471 int pa_parse_boolean(const char *v) {
472     
473     if (!strcmp(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on"))
474         return 1;
475     else if (!strcmp(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off"))
476         return 0;
477
478     return -1;
479 }
480
481 /* Split the specified string wherever one of the strings in delimiter
482  * occurs. Each time it is called returns a newly allocated string
483  * with pa_xmalloc(). The variable state points to, should be
484  * initiallized to NULL before the first call. */
485 char *pa_split(const char *c, const char *delimiter, const char**state) {
486     const char *current = *state ? *state : c;
487     size_t l;
488
489     if (!*current)
490         return NULL;
491     
492     l = strcspn(current, delimiter);
493     *state = current+l;
494
495     if (**state)
496         (*state)++;
497
498     return pa_xstrndup(current, l);
499 }
500
501 /* What is interpreted as whitespace? */
502 #define WHITESPACE " \t\n"
503
504 /* Split a string into words. Otherwise similar to pa_split(). */
505 char *pa_split_spaces(const char *c, const char **state) {
506     const char *current = *state ? *state : c;
507     size_t l;
508
509     if (!*current || *c == 0)
510         return NULL;
511
512     current += strspn(current, WHITESPACE);
513     l = strcspn(current, WHITESPACE);
514
515     *state = current+l;
516
517     return pa_xstrndup(current, l);
518 }
519
520 /* Return the name of an UNIX signal. Similar to GNU's strsignal() */
521 const char *pa_strsignal(int sig) {
522     switch(sig) {
523         case SIGINT: return "SIGINT";
524         case SIGTERM: return "SIGTERM";
525 #ifdef SIGUSR1
526         case SIGUSR1: return "SIGUSR1";
527 #endif
528 #ifdef SIGUSR2
529         case SIGUSR2: return "SIGUSR2";
530 #endif
531 #ifdef SIGXCPU
532         case SIGXCPU: return "SIGXCPU";
533 #endif
534 #ifdef SIGPIPE
535         case SIGPIPE: return "SIGPIPE";
536 #endif
537 #ifdef SIGCHLD
538         case SIGCHLD: return "SIGCHLD";
539 #endif
540 #ifdef SIGHUP
541         case SIGHUP: return "SIGHUP";
542 #endif
543         default: return "UNKNOWN SIGNAL";
544     }
545 }
546
547 #ifdef HAVE_GRP_H
548
549 /* Check whether the specified GID and the group name match */
550 static int is_group(gid_t gid, const char *name) {
551     struct group group, *result = NULL;
552     long n;
553     void *data;
554     int r = -1;
555
556 #ifdef HAVE_GETGRGID_R
557 #ifdef _SC_GETGR_R_SIZE_MAX
558     n = sysconf(_SC_GETGR_R_SIZE_MAX);
559 #else
560     n = -1;
561 #endif
562     if (n < 0) n = 512;
563     data = pa_xmalloc(n);
564
565     if (getgrgid_r(gid, &group, data, n, &result) < 0 || !result) {
566         pa_log(__FILE__ ": getgrgid_r(%u) failed: %s", gid, strerror(errno));
567         goto finish;
568     }
569
570     r = strcmp(name, result->gr_name) == 0;
571     
572 finish:
573     pa_xfree(data);
574 #else
575     /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) that do not
576      * support getgrgid_r. */
577     if ((result = getgrgid(gid)) == NULL) {
578         pa_log(__FILE__ ": getgrgid(%u) failed: %s", gid, strerror(errno));
579         goto finish;
580     }
581
582     r = strcmp(name, result->gr_name) == 0;
583
584 finish:
585 #endif
586     
587     return r;
588 }
589
590 /* Check the current user is member of the specified group */
591 int pa_own_uid_in_group(const char *name, gid_t *gid) {
592     GETGROUPS_T *gids, tgid;
593     int n = sysconf(_SC_NGROUPS_MAX);
594     int r = -1, i;
595
596     assert(n > 0);
597     
598     gids = pa_xmalloc(sizeof(GETGROUPS_T)*n);
599     
600     if ((n = getgroups(n, gids)) < 0) {
601         pa_log(__FILE__": getgroups() failed: %s", strerror(errno));
602         goto finish;
603     }
604
605     for (i = 0; i < n; i++) {
606         if (is_group(gids[i], name) > 0) {
607             *gid = gids[i];
608             r = 1;
609             goto finish;
610         }
611     }
612
613     if (is_group(tgid = getgid(), name) > 0) {
614         *gid = tgid;
615         r = 1;
616         goto finish;
617     }
618
619     r = 0;
620     
621 finish:
622
623     pa_xfree(gids);
624     return r;
625 }
626
627 int pa_uid_in_group(uid_t uid, const char *name) {
628     char *g_buf, *p_buf;
629     long g_n, p_n;
630     struct group grbuf, *gr;
631     char **i;
632     int r = -1;
633     
634     g_n = sysconf(_SC_GETGR_R_SIZE_MAX);
635     g_buf = pa_xmalloc(g_n);
636
637     p_n = sysconf(_SC_GETPW_R_SIZE_MAX);
638     p_buf = pa_xmalloc(p_n);
639     
640     if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr)
641         goto finish;
642
643     r = 0;
644     for (i = gr->gr_mem; *i; i++) {
645         struct passwd pwbuf, *pw;
646         
647         if (getpwnam_r(*i, &pwbuf, p_buf, (size_t) p_n, &pw) != 0 || !pw)
648             continue;
649
650         if (pw->pw_uid == uid) {
651             r = 1;
652             break;
653         }
654     }
655
656 finish:
657     pa_xfree(g_buf);
658     pa_xfree(p_buf);
659
660     return r;
661 }
662
663 #else /* HAVE_GRP_H */
664
665 int pa_own_uid_in_group(const char *name, gid_t *gid) {
666     return -1;
667     
668 }
669
670 int pa_uid_in_group(uid_t uid, const char *name) {
671     return -1;
672 }
673
674 #endif
675
676 /* Lock or unlock a file entirely.
677   (advisory on UNIX, mandatory on Windows) */
678 int pa_lock_fd(int fd, int b) {
679 #ifdef F_SETLKW
680     struct flock flock;
681
682     /* Try a R/W lock first */
683     
684     flock.l_type = b ? F_WRLCK : F_UNLCK;
685     flock.l_whence = SEEK_SET;
686     flock.l_start = 0;
687     flock.l_len = 0;
688
689     if (fcntl(fd, F_SETLKW, &flock) >= 0)
690         return 0;
691
692     /* Perhaps the file descriptor qas opened for read only, than try again with a read lock. */
693     if (b && errno == EBADF) {
694         flock.l_type = F_RDLCK;
695         if (fcntl(fd, F_SETLKW, &flock) >= 0)
696             return 0;
697     }
698         
699     pa_log(__FILE__": %slock failed: %s", !b ? "un" : "", strerror(errno));
700 #endif
701
702 #ifdef OS_IS_WIN32
703     HANDLE h = (HANDLE)_get_osfhandle(fd);
704
705     if (b && LockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
706         return 0;
707     if (!b && UnlockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
708         return 0;
709
710     pa_log(__FILE__": %slock failed: 0x%08X", !b ? "un" : "", GetLastError());
711 #endif
712
713     return -1;
714 }
715
716 /* Remove trailing newlines from a string */
717 char* pa_strip_nl(char *s) {
718     assert(s);
719
720     s[strcspn(s, "\r\n")] = 0;
721     return s;
722 }
723
724 /* Create a temporary lock file and lock it. */
725 int pa_lock_lockfile(const char *fn) {
726     int fd = -1;
727     assert(fn);
728
729     for (;;) {
730         struct stat st;
731         
732         if ((fd = open(fn, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0) {
733             pa_log(__FILE__": failed to create lock file '%s': %s", fn, strerror(errno));
734             goto fail;
735         }
736         
737         if (pa_lock_fd(fd, 1) < 0) {
738             pa_log(__FILE__": failed to lock file '%s'.", fn);
739             goto fail;
740         }
741         
742         if (fstat(fd, &st) < 0) {
743             pa_log(__FILE__": failed to fstat() file '%s'.", fn);
744             goto fail;
745         }
746
747         /* Check wheter the file has been removed meanwhile. When yes, restart this loop, otherwise, we're done */
748         if (st.st_nlink >= 1)
749             break;
750             
751         if (pa_lock_fd(fd, 0) < 0) {
752             pa_log(__FILE__": failed to unlock file '%s'.", fn);
753             goto fail;
754         }
755         
756         if (close(fd) < 0) {
757             pa_log(__FILE__": failed to close file '%s'.", fn);
758             goto fail;
759         }
760
761         fd = -1;
762     }
763         
764     return fd;
765
766 fail:
767
768     if (fd >= 0)
769         close(fd);
770
771     return -1;
772 }
773
774 /* Unlock a temporary lcok file */
775 int pa_unlock_lockfile(const char *fn, int fd) {
776     int r = 0;
777     assert(fn && fd >= 0);
778
779     if (unlink(fn) < 0) {
780         pa_log_warn(__FILE__": WARNING: unable to remove lock file '%s': %s", fn, strerror(errno));
781         r = -1;
782     }
783     
784     if (pa_lock_fd(fd, 0) < 0) {
785         pa_log_warn(__FILE__": WARNING: failed to unlock file '%s'.", fn);
786         r = -1;
787     }
788
789     if (close(fd) < 0) {
790         pa_log_warn(__FILE__": WARNING: failed to close lock file '%s': %s", fn, strerror(errno));
791         r = -1;
792     }
793
794     return r;
795 }
796
797 /* Try to open a configuration file. If "env" is specified, open the
798  * value of the specified environment variable. Otherwise look for a
799  * file "local" in the home directory or a file "global" in global
800  * file system. If "result" is non-NULL, a pointer to a newly
801  * allocated buffer containing the used configuration file is
802  * stored there.*/
803 FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result, const char *mode) {
804     const char *fn;
805     char h[PATH_MAX];
806
807 #ifdef OS_IS_WIN32
808     char buf[PATH_MAX];
809
810     if (!getenv(POLYP_ROOTENV))
811         pa_set_root(NULL);
812 #endif
813
814     if (env && (fn = getenv(env))) {
815 #ifdef OS_IS_WIN32
816         if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX))
817             return NULL;
818         fn = buf;
819 #endif
820
821         if (result)
822             *result = pa_xstrdup(fn);
823
824         return fopen(fn, mode);
825     }
826
827     if (local && pa_get_home_dir(h, sizeof(h))) {
828         FILE *f;
829         char *lfn;
830         
831         fn = lfn = pa_sprintf_malloc("%s/%s", h, local);
832
833 #ifdef OS_IS_WIN32
834         if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX))
835             return NULL;
836         fn = buf;
837 #endif
838
839         f = fopen(fn, mode);
840
841         if (f || errno != ENOENT) {
842             if (result)
843                 *result = pa_xstrdup(fn);
844             pa_xfree(lfn);
845             return f;
846         }
847         
848         pa_xfree(lfn);
849     }
850
851     if (!global) {
852         if (result)
853             *result = NULL;
854         errno = ENOENT;
855         return NULL;
856     }
857
858 #ifdef OS_IS_WIN32
859     if (!ExpandEnvironmentStrings(global, buf, PATH_MAX))
860         return NULL;
861     global = buf;
862 #endif
863
864     if (result)
865         *result = pa_xstrdup(global);
866     
867     return fopen(global, mode);
868 }
869                  
870 /* Format the specified data as a hexademical string */
871 char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength) {
872     size_t i = 0, j = 0;
873     const char hex[] = "0123456789abcdef";
874     assert(d && s && slength > 0);
875
876     while (i < dlength && j+3 <= slength) {
877         s[j++] = hex[*d >> 4];
878         s[j++] = hex[*d & 0xF];
879
880         d++;
881         i++;
882     }
883
884     s[j < slength ? j : slength] = 0;
885     return s;
886 }
887
888 /* Convert a hexadecimal digit to a number or -1 if invalid */
889 static int hexc(char c) {
890     if (c >= '0' && c <= '9')
891         return c - '0';
892
893     if (c >= 'A' && c <= 'F')
894         return c - 'A' + 10;
895
896     if (c >= 'a' && c <= 'f')
897         return c - 'a' + 10;
898
899     return -1;
900 }
901
902 /* Parse a hexadecimal string as created by pa_hexstr() to a BLOB */
903 size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) {
904     size_t j = 0;
905     assert(p && d);
906
907     while (j < dlength && *p) {
908         int b;
909
910         if ((b = hexc(*(p++))) < 0)
911             return (size_t) -1;
912         
913         d[j] = (uint8_t) (b << 4);
914
915         if (!*p)
916             return (size_t) -1;
917
918         if ((b = hexc(*(p++))) < 0)
919             return (size_t) -1;
920
921         d[j] |= (uint8_t) b;
922         j++;
923     }
924
925     return j;
926 }
927
928 /* Returns nonzero when *s starts with *pfx */
929 int pa_startswith(const char *s, const char *pfx) {
930     size_t l;
931     
932     assert(s);
933     assert(pfx);
934     
935     l = strlen(pfx);
936
937     return strlen(s) >= l && strncmp(s, pfx, l) == 0;
938 }
939
940 /* Returns nonzero when *s ends with *sfx */
941 int pa_endswith(const char *s, const char *sfx) {
942     size_t l1, l2;
943     
944     assert(s);
945     assert(sfx);
946     
947     l1 = strlen(s);
948     l2 = strlen(sfx);
949
950     return l1 >= l2 && strcmp(s+l1-l2, sfx) == 0;
951 }
952
953 /* if fn is null return the polypaudio run time path in s (/tmp/polypaudio)
954  * if fn is non-null and starts with / return fn in s
955  * otherwise append fn to the run time path and return it in s */
956 char *pa_runtime_path(const char *fn, char *s, size_t l) {
957     char u[256];
958
959 #ifndef OS_IS_WIN32
960     if (fn && *fn == '/')
961 #else
962     if (fn && strlen(fn) >= 3 && isalpha(fn[0]) && fn[1] == ':' && fn[2] == '\\')
963 #endif
964         return pa_strlcpy(s, fn, l);
965
966     if (fn)    
967         snprintf(s, l, "%s%s%c%s", PA_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)), PATH_SEP, fn);
968     else
969         snprintf(s, l, "%s%s", PA_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)));
970
971 #ifdef OS_IS_WIN32
972     {
973         char buf[l];
974         strcpy(buf, s);
975         ExpandEnvironmentStrings(buf, s, l);
976     }
977 #endif
978
979     return s;
980 }
981
982 /* Convert the string s to a signed integer in *ret_i */
983 int pa_atoi(const char *s, int32_t *ret_i) {
984     char *x = NULL;
985     long l;
986     assert(s && ret_i);
987
988     l = strtol(s, &x, 0);
989
990     if (!x || *x)
991         return -1;
992
993     *ret_i = (int32_t) l;
994     
995     return 0;
996 }
997
998 /* Convert the string s to an unsigned integer in *ret_u */
999 int pa_atou(const char *s, uint32_t *ret_u) {
1000     char *x = NULL;
1001     unsigned long l;
1002     assert(s && ret_u);
1003
1004     l = strtoul(s, &x, 0);
1005
1006     if (!x || *x)
1007         return -1;
1008
1009     *ret_u = (uint32_t) l;
1010     
1011     return 0;
1012 }