diff options
author | Pierre Ossman <ossman@cendio.se> | 2006-01-05 22:51:37 +0000 |
---|---|---|
committer | Pierre Ossman <ossman@cendio.se> | 2006-01-05 22:51:37 +0000 |
commit | 19d9fcbda8637099854f2d8147b402b4420d19f5 (patch) | |
tree | 993f0ebc9045bd893cd3039d0ae6277ee5806c05 | |
parent | 2f74bb9d437fc165695e1d4bb7516ca979962a49 (diff) |
Port to Windows. This is mostly glue layers for the poor POSIX support
on Windows. A few notes
* Only sockets behave somewhat like file descriptors in UNIX.
* There are no fixed paths. Closes thing is environment variables that point
to system directories. We also figure out where the binary/dll is
located and use that as configuration directory.
git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@418 fefdeb5f-60dc-0310-8127-8f9354f1896f
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | polyp/Makefile.am | 24 | ||||
-rw-r--r-- | polyp/client-conf.c | 20 | ||||
-rw-r--r-- | polyp/daemon-conf.c | 20 | ||||
-rw-r--r-- | polyp/default.pa.win32 | 43 | ||||
-rw-r--r-- | polyp/dllmain.c | 46 | ||||
-rw-r--r-- | polyp/iochannel.c | 32 | ||||
-rw-r--r-- | polyp/main.c | 75 | ||||
-rw-r--r-- | polyp/mainloop-signal.c | 92 | ||||
-rw-r--r-- | polyp/mainloop.c | 24 | ||||
-rw-r--r-- | polyp/module-protocol-stub.c | 7 | ||||
-rw-r--r-- | polyp/pid.c | 31 | ||||
-rw-r--r-- | polyp/poll.c | 24 | ||||
-rw-r--r-- | polyp/polyplib-context.c | 14 | ||||
-rw-r--r-- | polyp/pstream.c | 4 | ||||
-rw-r--r-- | polyp/random.c | 18 | ||||
-rw-r--r-- | polyp/scache.c | 21 | ||||
-rw-r--r-- | polyp/socket-client.c | 9 | ||||
-rw-r--r-- | polyp/socket-server.c | 7 | ||||
-rw-r--r-- | polyp/socket-util.c | 7 | ||||
-rw-r--r-- | polyp/tagstruct.c | 4 | ||||
-rw-r--r-- | polyp/util.c | 246 |
22 files changed, 712 insertions, 58 deletions
diff --git a/configure.ac b/configure.ac index 1899e92c..5ff28a56 100644 --- a/configure.ac +++ b/configure.ac @@ -138,7 +138,7 @@ AC_CHECK_HEADERS([linux/input.h], [HAVE_EVDEV=1], [HAVE_EVDEV=0]) AM_CONDITIONAL([HAVE_EVDEV], [test "x$HAVE_EVDEV" = "x1"]) # Windows -AC_CHECK_HEADERS([winsock2.h ws2tcpip.h]) +AC_CHECK_HEADERS([windows.h winsock2.h ws2tcpip.h]) # Other AC_CHECK_HEADERS([sys/ioctl.h]) diff --git a/polyp/Makefile.am b/polyp/Makefile.am index beac830c..dcd3fc17 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -298,6 +298,7 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES = \ cdecl.h \ client-conf.c client-conf.h \ conf-parser.c conf-parser.h \ + dllmain.c \ dynarray.c dynarray.h \ gcc-printf.h \ idxset.c idxset.h \ @@ -432,6 +433,7 @@ libpolypcore_la_SOURCES = \ cli-text.c cli-text.h \ client.c client.h \ core.c core.h \ + dllmain.c \ dynarray.c dynarray.h \ endianmacros.h \ g711.c g711.h \ @@ -562,7 +564,7 @@ libpdispatch_la_LIBADD = $(AM_LIBADD) libtagstruct.la libpolypcore.la libiochannel_la_SOURCES = iochannel.c iochannel.h libiochannel_la_LDFLAGS = -avoid-version -libiochannel_la_LIBADD = $(AM_LIBADD) libsocket-util.la libpolypcore.la +libiochannel_la_LIBADD = $(AM_LIBADD) libsocket-util.la libpolypcore.la $(WINSOCK_LIBS) libpacket_la_SOURCES = packet.c packet.h libpacket_la_LDFLAGS = -avoid-version @@ -727,6 +729,11 @@ modlib_LTLIBRARIES += \ module-mmkbd-evdev.la endif +if OS_IS_WIN32 +modlib_LTLIBRARIES += \ + module-waveout.la +endif + # These are generated by a M4 script SYMDEF_FILES = \ @@ -766,7 +773,8 @@ SYMDEF_FILES = \ module-oss-symdef.h \ module-oss-mmap-symdef.h \ module-alsa-sink-symdef.h \ - module-alsa-source-symdef.h + module-alsa-source-symdef.h \ + module-waveout-symdef.h EXTRA_DIST += $(SYMDEF_FILES) BUILT_SOURCES += $(SYMDEF_FILES) @@ -974,6 +982,13 @@ module_mmkbd_evdev_la_LDFLAGS = -module -avoid-version module_mmkbd_evdev_la_LIBADD = $(AM_LIBADD) module_mmkbd_evdev_la_CFLAGS = $(AM_CFLAGS) +# Windows waveout + +module_waveout_la_SOURCES = module-waveout.c +module_waveout_la_LDFLAGS = -module -avoid-version +module_waveout_la_LIBADD = $(AM_LIBADD) libpolypcore.la -lwinmm +module_waveout_la_CFLAGS = $(AM_CFLAGS) + ################################### # Some minor stuff # ################################### @@ -990,8 +1005,13 @@ esdcompat.sh: esdcompat.sh.in Makefile client.conf: client.conf.in Makefile sed -e 's,@POLYPAUDIO_BINARY\@,$(POLYPAUDIO_BINARY),g' < $< > $@ +if OS_IS_WIN32 +default.pa: default.pa.win32 + cp $< $@ +else default.pa: default.pa.in Makefile sed -e 's,@POLYPAUDIO_BINARY\@,$(POLYPAUDIO_BINARY),g' < $< > $@ +endif daemon.conf: daemon.conf.in Makefile sed -e 's,@DLSEARCHPATH\@,$(modlibdir),g' \ diff --git a/polyp/client-conf.c b/polyp/client-conf.c index 4906383d..04c3d2ef 100644 --- a/polyp/client-conf.c +++ b/polyp/client-conf.c @@ -19,6 +19,10 @@ USA. ***/ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + #include <stdlib.h> #include <assert.h> #include <unistd.h> @@ -33,11 +37,21 @@ #include "authkey.h" #ifndef DEFAULT_CONFIG_DIR -#define DEFAULT_CONFIG_DIR "/etc/polypaudio" +# ifndef OS_IS_WIN32 +# define DEFAULT_CONFIG_DIR "/etc/polypaudio" +# else +# define DEFAULT_CONFIG_DIR "%POLYP_ROOT%" +# endif +#endif + +#ifndef OS_IS_WIN32 +# define PATH_SEP "/" +#else +# define PATH_SEP "\\" #endif -#define DEFAULT_CLIENT_CONFIG_FILE DEFAULT_CONFIG_DIR"/client.conf" -#define DEFAULT_CLIENT_CONFIG_FILE_USER ".polypaudio/client.conf" +#define DEFAULT_CLIENT_CONFIG_FILE DEFAULT_CONFIG_DIR PATH_SEP "client.conf" +#define DEFAULT_CLIENT_CONFIG_FILE_USER ".polypaudio" PATH_SEP "client.conf" #define ENV_CLIENT_CONFIG_FILE "POLYP_CLIENTCONFIG" #define ENV_DEFAULT_SINK "POLYP_SINK" diff --git a/polyp/daemon-conf.c b/polyp/daemon-conf.c index a6afd05a..780581b2 100644 --- a/polyp/daemon-conf.c +++ b/polyp/daemon-conf.c @@ -37,13 +37,23 @@ #include "resampler.h" #ifndef DEFAULT_CONFIG_DIR -#define DEFAULT_CONFIG_DIR "/etc/polypaudio" +# ifndef OS_IS_WIN32 +# define DEFAULT_CONFIG_DIR "/etc/polypaudio" +# else +# define DEFAULT_CONFIG_DIR "%POLYP_ROOT%" +# endif #endif -#define DEFAULT_SCRIPT_FILE DEFAULT_CONFIG_DIR"/default.pa" -#define DEFAULT_SCRIPT_FILE_USER ".polypaudio/default.pa" -#define DEFAULT_CONFIG_FILE DEFAULT_CONFIG_DIR"/daemon.conf" -#define DEFAULT_CONFIG_FILE_USER ".polypaudio/daemon.conf" +#ifndef OS_IS_WIN32 +# define PATH_SEP "/" +#else +# define PATH_SEP "\\" +#endif + +#define DEFAULT_SCRIPT_FILE DEFAULT_CONFIG_DIR PATH_SEP "default.pa" +#define DEFAULT_SCRIPT_FILE_USER ".polypaudio" PATH_SEP "default.pa" +#define DEFAULT_CONFIG_FILE DEFAULT_CONFIG_DIR PATH_SEP "daemon.conf" +#define DEFAULT_CONFIG_FILE_USER ".polypaudio" PATH_SEP "daemon.conf" #define ENV_SCRIPT_FILE "POLYP_SCRIPT" #define ENV_CONFIG_FILE "POLYP_CONFIG" diff --git a/polyp/default.pa.win32 b/polyp/default.pa.win32 new file mode 100644 index 00000000..3478adab --- /dev/null +++ b/polyp/default.pa.win32 @@ -0,0 +1,43 @@ +#
+# This file is part of polypaudio.
+#
+# polypaudio is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# polypaudio 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
+# General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with polypaudio; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+
+
+# Load audio drivers statically
+
+load-module module-waveout sink_name=output source_name=input
+load-module module-null-sink
+
+# Load audio drivers automatically on access
+
+#add-autoload-sink output module-waveout sink_name=output source_name=input
+#add-autoload-source input module-waveout sink_name=output source_name=input
+
+# Load several protocols
+#load-module module-esound-protocol-tcp
+#load-module module-native-protocol-tcp
+#load-module module-simple-protocol-tcp
+#load-module module-cli-protocol-tcp
+
+# Make some devices default
+set-default-sink output
+set-default-source input
+
+.nofail
+
+# Load something to the sample cache
+load-sample x11-bell %WINDIR%\Media\ding.wav
+load-sample-dir-lazy %WINDIR%\Media\*.wav
diff --git a/polyp/dllmain.c b/polyp/dllmain.c new file mode 100644 index 00000000..34d0eed1 --- /dev/null +++ b/polyp/dllmain.c @@ -0,0 +1,46 @@ +/* $Id: dllmain.c 317 2004-12-11 00:10:41Z lennart $ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio 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 + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef OS_IS_WIN32 + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <windows.h> + +extern pa_set_root(HANDLE handle); + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { + if (fdwReason != DLL_PROCESS_ATTACH) + return TRUE; + + if (!pa_set_root(hinstDLL)) + return FALSE; + + return TRUE; +} + +#endif /* OS_IS_WIN32 */ diff --git a/polyp/iochannel.c b/polyp/iochannel.c index 0e7e8db8..08a4e362 100644 --- a/polyp/iochannel.c +++ b/polyp/iochannel.c @@ -28,6 +28,10 @@ #include <fcntl.h> #include <unistd.h> +#ifdef HAVE_WINSOCK2_H +#include <winsock2.h> +#endif + #include "iochannel.h" #include "util.h" #include "socket-util.h" @@ -189,7 +193,19 @@ ssize_t pa_iochannel_write(struct pa_iochannel*io, const void*data, size_t l) { ssize_t r; assert(io && data && l && io->ofd >= 0); - if ((r = write(io->ofd, data, l)) >= 0) { +#ifdef OS_IS_WIN32 + r = send(io->ofd, data, l, 0); + if (r < 0) { + if (WSAGetLastError() != WSAENOTSOCK) { + errno = WSAGetLastError(); + return r; + } + } + + if (r < 0) +#endif + r = write(io->ofd, data, l); + if (r >= 0) { io->writable = 0; enable_mainloop_sources(io); } @@ -201,7 +217,19 @@ ssize_t pa_iochannel_read(struct pa_iochannel*io, void*data, size_t l) { ssize_t r; assert(io && data && io->ifd >= 0); - if ((r = read(io->ifd, data, l)) >= 0) { +#ifdef OS_IS_WIN32 + r = recv(io->ifd, data, l, 0); + if (r < 0) { + if (WSAGetLastError() != WSAENOTSOCK) { + errno = WSAGetLastError(); + return r; + } + } + + if (r < 0) +#endif + r = read(io->ifd, data, l); + if (r >= 0) { io->readable = 0; enable_mainloop_sources(io); } diff --git a/polyp/main.c b/polyp/main.c index 3f9f359e..437f0a41 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -35,7 +35,16 @@ #include <memblock.h> #include <limits.h> #include <fcntl.h> +#include <unistd.h> +#include <sys/types.h> + +#ifdef HAVE_SYS_IOCTL_H #include <sys/ioctl.h> +#endif + +#ifdef HAVE_WINSOCK2_H +#include <winsock2.h> +#endif #ifdef HAVE_LIBWRAP #include <syslog.h> @@ -66,6 +75,23 @@ int allow_severity = LOG_INFO; int deny_severity = LOG_WARNING; #endif +#ifdef OS_IS_WIN32 + +static void message_cb(struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata) { + MSG msg; + + while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + if (msg.message == WM_QUIT) + raise(SIGTERM); + else { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } +} + +#endif + static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { pa_log_info(__FILE__": Got signal %s.\n", pa_strsignal(sig)); @@ -124,6 +150,10 @@ int main(int argc, char *argv[]) { gid_t gid = (gid_t) -1; #endif +#ifdef OS_IS_WIN32 + struct pa_defer_event *defer; +#endif + pa_limit_caps(); #ifdef HAVE_GETUID @@ -142,6 +172,13 @@ int main(int argc, char *argv[]) { r = lt_dlinit(); assert(r == 0); +#ifdef OS_IS_WIN32 + { + WSADATA data; + WSAStartup(MAKEWORD(2, 0), &data); + } +#endif + pa_log_set_ident("polypaudio"); conf = pa_daemon_conf_new(); @@ -230,6 +267,7 @@ int main(int argc, char *argv[]) { goto finish; } +#ifdef HAVE_FORK if (pipe(daemon_pipe) < 0) { pa_log(__FILE__": failed to create pipe.\n"); goto finish; @@ -261,6 +299,7 @@ int main(int argc, char *argv[]) { close(daemon_pipe[0]); daemon_pipe[0] = -1; +#endif if (conf->auto_log_target) pa_log_set_target(PA_LOG_SYSLOG, NULL); @@ -271,7 +310,8 @@ int main(int argc, char *argv[]) { #ifdef HAVE_SETPGID setpgid(0,0); #endif - + +#ifndef OS_IS_WIN32 close(0); close(1); close(2); @@ -279,7 +319,10 @@ int main(int argc, char *argv[]) { open("/dev/null", O_RDONLY); open("/dev/null", O_WRONLY); open("/dev/null", O_WRONLY); - +#else + FreeConsole(); +#endif + #ifdef SIGTTOU signal(SIGTTOU, SIG_IGN); #endif @@ -290,18 +333,23 @@ int main(int argc, char *argv[]) { signal(SIGTSTP, SIG_IGN); #endif +#ifdef TIOCNOTTY if ((tty_fd = open("/dev/tty", O_RDWR)) >= 0) { ioctl(tty_fd, TIOCNOTTY, (char*) 0); close(tty_fd); } +#endif } chdir("/"); if (conf->use_pid_file) { if (pa_pid_file_create() < 0) { + pa_log(__FILE__": pa_pid_file_create() failed.\n"); +#ifdef HAVE_FORK if (conf->daemonize) pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); +#endif goto finish; } @@ -322,9 +370,14 @@ int main(int argc, char *argv[]) { signal(SIGPIPE, SIG_IGN); #endif +#ifdef OS_IS_WIN32 + defer = pa_mainloop_get_api(mainloop)->defer_new(pa_mainloop_get_api(mainloop), message_cb, NULL); + assert(defer); +#endif + if (conf->daemonize) c->running_as_daemon = 1; - + #ifdef SIGUSR1 pa_signal_new(SIGUSR1, signal_callback, c); #endif @@ -350,17 +403,23 @@ int main(int argc, char *argv[]) { if (r < 0 && conf->fail) { pa_log(__FILE__": failed to initialize daemon.\n"); +#ifdef HAVE_FORK if (conf->daemonize) pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); +#endif } else if (!c->modules || pa_idxset_ncontents(c->modules) == 0) { pa_log(__FILE__": daemon startup without any loaded modules, refusing to work.\n"); +#ifdef HAVE_FORK if (conf->daemonize) pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); +#endif } else { retval = 0; +#ifdef HAVE_FORK if (conf->daemonize) pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); +#endif c->disallow_module_loading = conf->disallow_module_loading; c->exit_idle_time = conf->exit_idle_time; @@ -378,7 +437,11 @@ int main(int argc, char *argv[]) { pa_log_info(__FILE__": Daemon shutdown initiated.\n"); } } - + +#ifdef OS_IS_WIN32 + pa_mainloop_get_api(mainloop)->defer_free(defer); +#endif + pa_core_free(c); pa_cpu_limit_done(); @@ -397,6 +460,10 @@ finish: close_pipe(daemon_pipe); +#ifdef OS_IS_WIN32 + WSACleanup(); +#endif + lt_dlexit(); return retval; diff --git a/polyp/mainloop-signal.c b/polyp/mainloop-signal.c index eb3f5ddc..432498a8 100644 --- a/polyp/mainloop-signal.c +++ b/polyp/mainloop-signal.c @@ -32,6 +32,10 @@ #include <unistd.h> #include <fcntl.h> +#ifdef HAVE_WINDOWS_H +#include <windows.h> +#endif + #include "mainloop-signal.h" #include "util.h" #include "xmalloc.h" @@ -53,19 +57,70 @@ struct pa_signal_event { static struct pa_mainloop_api *api = NULL; static int signal_pipe[2] = { -1, -1 }; static struct pa_io_event* io_event = NULL; +static struct pa_defer_event *defer_event = NULL; static struct pa_signal_event *signals = NULL; +#ifdef OS_IS_WIN32 +static unsigned int waiting_signals = 0; +static CRITICAL_SECTION crit; +#endif + static void signal_handler(int sig) { #ifndef HAVE_SIGACTION signal(sig, signal_handler); #endif write(signal_pipe[1], &sig, sizeof(sig)); + +#ifdef OS_IS_WIN32 + EnterCriticalSection(&crit); + waiting_signals++; + LeaveCriticalSection(&crit); +#endif +} + +static void dispatch(struct pa_mainloop_api*a, int sig) { + struct pa_signal_event*s; + + for (s = signals; s; s = s->next) + if (s->sig == sig) { + assert(s->callback); + s->callback(a, s, sig, s->userdata); + break; + } +} + +static void defer(struct pa_mainloop_api*a, struct pa_defer_event*e, void *userdata) { + ssize_t r; + int sig; + unsigned int sigs; + +#ifdef OS_IS_WIN32 + EnterCriticalSection(&crit); + sigs = waiting_signals; + waiting_signals = 0; + LeaveCriticalSection(&crit); +#endif + + while (sigs) { + if ((r = read(signal_pipe[0], &sig, sizeof(sig))) < 0) { + pa_log(__FILE__": read(): %s\n", strerror(errno)); + return; + } + + if (r != sizeof(sig)) { + pa_log(__FILE__": short read()\n"); + return; + } + + dispatch(a, sig); + + sigs--; + } } static void callback(struct pa_mainloop_api*a, struct pa_io_event*e, int fd, enum pa_io_event_flags f, void *userdata) { ssize_t r; int sig; - struct pa_signal_event*s; assert(a && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == signal_pipe[0]); @@ -81,19 +136,18 @@ static void callback(struct pa_mainloop_api*a, struct pa_io_event*e, int fd, enu pa_log(__FILE__": short read()\n"); return; } - - for (s = signals; s; s = s->next) - if (s->sig == sig) { - assert(s->callback); - s->callback(a, s, sig, s->userdata); - break; - } + + dispatch(a, sig); } int pa_signal_init(struct pa_mainloop_api *a) { - assert(!api && a && signal_pipe[0] == -1 && signal_pipe[1] == -1 && !io_event); - + assert(!api && a && signal_pipe[0] == -1 && signal_pipe[1] == -1 && !io_event && !defer_event); + +#ifdef OS_IS_WIN32 + if (_pipe(signal_pipe, 200, _O_BINARY) < 0) { +#else if (pipe(signal_pipe) < 0) { +#endif pa_log(__FILE__": pipe() failed: %s\n", strerror(errno)); return -1; } @@ -104,20 +158,36 @@ int pa_signal_init(struct pa_mainloop_api *a) { pa_fd_set_cloexec(signal_pipe[1], 1); api = a; + +#ifndef OS_IS_WIN32 io_event = api->io_new(api, signal_pipe[0], PA_IO_EVENT_INPUT, callback, NULL); assert(io_event); +#else + defer_event = api->defer_new(api, defer, NULL); + assert(defer_event); + + InitializeCriticalSection(&crit); +#endif + return 0; } void pa_signal_done(void) { - assert(api && signal_pipe[0] >= 0 && signal_pipe[1] >= 0 && io_event); + assert(api && signal_pipe[0] >= 0 && signal_pipe[1] >= 0 && (io_event || defer_event)); while (signals) pa_signal_free(signals); +#ifndef OS_IS_WIN32 api->io_free(io_event); io_event = NULL; +#else + api->defer_free(defer_event); + defer_event = NULL; + + DeleteCriticalSection(&crit); +#endif close(signal_pipe[0]); close(signal_pipe[1]); diff --git a/polyp/mainloop.c b/polyp/mainloop.c index 90243bdf..9cfd5397 100644 --- a/polyp/mainloop.c +++ b/polyp/mainloop.c @@ -38,6 +38,10 @@ #include "poll.h" #endif +#ifdef HAVE_WINSOCK2_H +#include <winsock2.h> +#endif + #include "mainloop.h" #include "util.h" #include "idxset.h" @@ -108,6 +112,26 @@ static struct pa_io_event* mainloop_io_new(struct pa_mainloop_api*a, int fd, enu e->destroy_callback = NULL; e->pollfd = NULL; +#ifdef OS_IS_WIN32 + { + fd_set xset; + struct timeval tv; + + tv.tv_sec = 0; + tv.tv_usec = 0; + + FD_ZERO (&xset); + FD_SET (fd, &xset); + + if ((select((SELECT_TYPE_ARG1) fd, NULL, NULL, SELECT_TYPE_ARG234 &xset, + SELECT_TYPE_ARG5 &tv) == -1) && + (WSAGetLastError() == WSAENOTSOCK)) { + pa_log_warn(__FILE__": WARNING: cannot monitor non-socket file descriptors.\n"); + e->dead = 1; + } + } +#endif + pa_idxset_put(m->io_events, e, NULL); m->rebuild_pollfds = 1; return e; diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c index 7cd5ed3f..8c06a610 100644 --- a/polyp/module-protocol-stub.c +++ b/polyp/module-protocol-stub.c @@ -40,6 +40,13 @@ #include <netinet/in.h> #endif +#ifdef HAVE_WINSOCK2_H +#include <winsock2.h> +#endif +#ifdef HAVE_WS2TCPIP_H +#include <ws2tcpip.h> +#endif + #include "module.h" #include "socket-server.h" #include "socket-util.h" diff --git a/polyp/pid.c b/polyp/pid.c index 2fac687e..ae3dc7f5 100644 --- a/polyp/pid.c +++ b/polyp/pid.c @@ -35,6 +35,10 @@ #include <limits.h> #include <signal.h> +#ifdef HAVE_WINDOWS_H +#include <windows.h> +#endif + #include "pid.h" #include "util.h" #include "log.h" @@ -130,6 +134,10 @@ int pa_pid_file_create(void) { pid_t pid; size_t l; +#ifdef OS_IS_WIN32 + HANDLE process; +#endif + pa_runtime_path("pid", fn, sizeof(fn)); if ((fd = open_pid_file(fn, O_CREAT|O_RDWR)) < 0) @@ -138,7 +146,12 @@ int pa_pid_file_create(void) { if ((pid = read_pid(fn, fd)) == (pid_t) -1) pa_log(__FILE__": corrupt PID file, overwriting.\n"); else if (pid > 0) { +#ifdef OS_IS_WIN32 + if ((process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid)) != NULL) { + CloseHandle(process); +#else if (kill(pid, 0) >= 0 || errno != ESRCH) { +#endif pa_log(__FILE__": daemon already running.\n"); goto fail; } @@ -198,6 +211,12 @@ int pa_pid_file_remove(void) { goto fail; } +#ifdef OS_IS_WIN32 + pa_lock_fd(fd, 0); + close(fd); + fd = -1; +#endif + if (unlink(fn) < 0) { pa_log(__FILE__": failed to remove PID file '%s': %s\n", fn, strerror(errno)); goto fail; @@ -223,6 +242,8 @@ int pa_pid_file_check_running(pid_t *pid) { return pa_pid_file_kill(0, pid); } +#ifndef OS_IS_WIN32 + /* Kill a current running daemon. Return non-zero on success, -1 * otherwise. If successful *pid contains the PID of the daemon * process. */ @@ -242,7 +263,7 @@ int pa_pid_file_kill(int sig, pid_t *pid) { if ((*pid = read_pid(fn, fd)) == (pid_t) -1) goto fail; - + ret = kill(*pid, sig); fail: @@ -255,3 +276,11 @@ fail: return ret; } + +#else /* OS_IS_WIN32 */ + +int pa_pid_file_kill(int sig, pid_t *pid) { + return -1; +} + +#endif diff --git a/polyp/poll.c b/polyp/poll.c index 82ea3d88..7c25f348 100644 --- a/polyp/poll.c +++ b/polyp/poll.c @@ -36,6 +36,17 @@ #include <sys/select.h> #endif +#ifdef HAVE_WINSOCK2_H +#include <winsock2.h> + +#define EBADF WSAEBADF +#define ESHUTDOWN WSAESHUTDOWN +#define ECONNRESET WSAECONNRESET +#define ECONNABORTED WSAECONNABORTED +#define ENETRESET WSAENETRESET + +#endif /* HAVE_WINSOCK2_H */ + #ifndef HAVE_SYS_POLL_H #include "util.h" @@ -59,7 +70,16 @@ int poll (struct pollfd *fds, unsigned long int nfds, int timeout) { return 0; } +#ifdef OS_IS_WIN32 + /* + * Windows does not support signals properly so waiting for them would + * mean a deadlock. + */ + pa_msleep(100); + return 0; +#else return select(0, NULL, NULL, NULL, NULL); +#endif } for (f = fds; f < &fds[nfds]; ++f) { @@ -138,6 +158,10 @@ int poll (struct pollfd *fds, unsigned long int nfds, int timeout) { } } +#ifdef OS_IS_WIN32 + errno = WSAGetLastError(); +#endif + if (ready > 0) { ready = 0; for (f = fds; f < &fds[nfds]; ++f) { diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index 1b9d7de6..da91995b 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -32,6 +32,7 @@ #include <sys/stat.h> #include <errno.h> #include <signal.h> +#include <limits.h> #ifdef HAVE_SYS_WAIT_H #include <sys/wait.h> @@ -44,6 +45,13 @@ #include <netdb.h> #endif +#ifdef HAVE_WINSOCK2_H +#include <winsock2.h> +#define ETIMEDOUT WSAETIMEDOUT +#define ECONNREFUSED WSAECONNREFUSED +#define EHOSTUNREACH WSAEHOSTUNREACH +#endif + #include "polyplib-internal.h" #include "polyplib-context.h" #include "native-common.h" @@ -382,6 +390,8 @@ finish: static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata); +#ifndef OS_IS_WIN32 + static int context_connect_spawn(struct pa_context *c) { pid_t pid; int status, r; @@ -495,6 +505,8 @@ fail: return -1; } +#endif /* OS_IS_WIN32 */ + static int try_next_connection(struct pa_context *c) { char *u = NULL; int r = -1; @@ -509,10 +521,12 @@ static int try_next_connection(struct pa_context *c) { if (!u) { +#ifndef OS_IS_WIN32 if (c->do_autospawn) { r = context_connect_spawn(c); goto finish; } +#endif pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); goto finish; diff --git a/polyp/pstream.c b/polyp/pstream.c index a64856d7..607b0c1a 100644 --- a/polyp/pstream.c +++ b/polyp/pstream.c @@ -32,6 +32,10 @@ #include <netinet/in.h> #endif +#ifdef HAVE_WINSOCK2_H +#include <winsock2.h> +#endif + #include "pstream.h" #include "queue.h" #include "xmalloc.h" diff --git a/polyp/random.c b/polyp/random.c index 456954a2..12f27bfd 100644 --- a/polyp/random.c +++ b/polyp/random.c @@ -19,6 +19,10 @@ USA. ***/ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + #include <fcntl.h> #include <unistd.h> #include <errno.h> @@ -31,13 +35,16 @@ #include "util.h" #include "log.h" +#ifndef OS_IS_WIN32 #define RANDOM_DEVICE "/dev/urandom" +#endif void pa_random(void *ret_data, size_t length) { int fd; ssize_t r = 0; assert(ret_data && length); - + +#ifdef RANDOM_DEVICE if ((fd = open(RANDOM_DEVICE, O_RDONLY)) >= 0) { if ((r = pa_loop_read(fd, ret_data, length)) < 0 || (size_t) r != length) @@ -45,17 +52,20 @@ void pa_random(void *ret_data, size_t length) { close(fd); } +#endif if ((size_t) r != length) { uint8_t *p; size_t l; - + +#ifdef RANDOM_DEVICE pa_log_warn(__FILE__": WARNING: Failed to open entropy device '"RANDOM_DEVICE"': %s" ", falling back to unsecure pseudo RNG.\n", strerror(errno)); +#endif - srandom(time(NULL)); + srand(time(NULL)); for (p = ret_data, l = length; l > 0; p++, l--) - *p = (uint8_t) random(); + *p = (uint8_t) rand(); } } diff --git a/polyp/scache.c b/polyp/scache.c index 0dec33ce..2953145d 100644 --- a/polyp/scache.c +++ b/polyp/scache.c @@ -37,6 +37,10 @@ #include <glob.h> #endif +#ifdef HAVE_WINDOWS_H +#include <windows.h> +#endif + #include "scache.h" #include "sink-input.h" #include "mainloop.h" @@ -147,6 +151,13 @@ int pa_scache_add_file(struct pa_core *c, const char *name, const char *filename struct pa_memchunk chunk; int r; +#ifdef OS_IS_WIN32 + char buf[MAX_PATH]; + + if (ExpandEnvironmentStrings(filename, buf, MAX_PATH)) + filename = buf; +#endif + if (pa_sound_file_load(filename, &ss, &chunk, c->memblock_stat) < 0) return -1; @@ -158,6 +169,14 @@ int pa_scache_add_file(struct pa_core *c, const char *name, const char *filename int pa_scache_add_file_lazy(struct pa_core *c, const char *name, const char *filename, uint32_t *index) { struct pa_scache_entry *e; + +#ifdef OS_IS_WIN32 + char buf[MAX_PATH]; + + if (ExpandEnvironmentStrings(filename, buf, MAX_PATH)) + filename = buf; +#endif + assert(c && name); if (!(e = scache_add_item(c, name))) @@ -313,7 +332,9 @@ static void add_file(struct pa_core *c, const char *pathname) { return; } +#if defined(S_ISREG) && defined(S_ISLNK) if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) +#endif pa_scache_add_file_lazy(c, e, pathname, NULL); } diff --git a/polyp/socket-client.c b/polyp/socket-client.c index 0d712fa3..6d8cb2ab 100644 --- a/polyp/socket-client.c +++ b/polyp/socket-client.c @@ -48,6 +48,15 @@ #include <netdb.h> #endif +#ifdef HAVE_WINSOCK2_H +#include <winsock2.h> +#define EINPROGRESS WSAEINPROGRESS +#define ETIMEDOUT WSAETIMEDOUT +#endif +#ifdef HAVE_WS2TCPIP_H +#include <ws2tcpip.h> +#endif + #ifdef HAVE_LIBASYNCNS #include <asyncns.h> #endif diff --git a/polyp/socket-server.c b/polyp/socket-server.c index 0cca4ae8..b7e4feda 100644 --- a/polyp/socket-server.c +++ b/polyp/socket-server.c @@ -44,6 +44,13 @@ #include <netinet/in.h> #endif +#ifdef HAVE_WINSOCK2_H +#include <winsock2.h> +#endif +#ifdef HAVE_WS2TCPIP_H +#include <ws2tcpip.h> +#endif + #ifdef HAVE_LIBWRAP #include <tcpd.h> #endif diff --git a/polyp/socket-util.c b/polyp/socket-util.c index 60f8d167..699b28c2 100644 --- a/polyp/socket-util.c +++ b/polyp/socket-util.c @@ -57,6 +57,11 @@ #include <netdb.h> #endif +#ifdef HAVE_WINSOCK2_H +#include <winsock2.h> +#define ETIMEDOUT WSAETIMEDOUT +#endif + #include "socket-util.h" #include "util.h" #include "xmalloc.h" @@ -72,6 +77,7 @@ void pa_socket_peer_to_string(int fd, char *c, size_t l) { return; } +#ifndef OS_IS_WIN32 if (S_ISSOCK(st.st_mode)) { union { struct sockaddr sa; @@ -104,6 +110,7 @@ void pa_socket_peer_to_string(int fd, char *c, size_t l) { snprintf(c, l, "STDIN/STDOUT client"); return; } +#endif /* OS_IS_WIN32 */ snprintf(c, l, "Unknown client"); } diff --git a/polyp/tagstruct.c b/polyp/tagstruct.c index a3bd7d99..59178bf0 100644 --- a/polyp/tagstruct.c +++ b/polyp/tagstruct.c @@ -33,6 +33,10 @@ #include <netinet/in.h> #endif +#ifdef HAVE_WINSOCK2_H +#include <winsock2.h> +#endif + #include "tagstruct.h" #include "xmalloc.h" diff --git a/polyp/util.c b/polyp/util.c index acfa0314..0495896f 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -32,12 +32,12 @@ #include <stdio.h> #include <fcntl.h> #include <unistd.h> +#include <limits.h> +#include <time.h> +#include <ctype.h> #include <sys/types.h> #include <sys/stat.h> -#include <signal.h> #include <sys/time.h> -#include <limits.h> -#include <unistd.h> #ifdef HAVE_SCHED_H #include <sched.h> @@ -55,6 +55,17 @@ #include <netdb.h> #endif +#ifdef HAVE_WINDOWS_H +#include <windows.h> +#endif + +#ifdef HAVE_WINSOCK2_H +#include <winsock2.h> +#endif +#ifdef HAVE_WS2TCPIP_H +#include <ws2tcpip.h> +#endif + #include <samplerate.h> #ifdef HAVE_PWD_H @@ -68,16 +79,56 @@ #include "xmalloc.h" #include "log.h" +#ifndef OS_IS_WIN32 #define PA_RUNTIME_PATH_PREFIX "/tmp/polypaudio-" +#define PATH_SEP '/' +#else +#define PA_RUNTIME_PATH_PREFIX "%TEMP%\\polypaudio-" +#define PATH_SEP '\\' +#endif + +#ifdef OS_IS_WIN32 + +#define POLYP_ROOTENV "POLYP_ROOT" + +int pa_set_root(HANDLE handle) { + char library_path[MAX_PATH + sizeof(POLYP_ROOTENV) + 1], *sep; + + strcpy(library_path, POLYP_ROOTENV "="); + + if (!GetModuleFileName(handle, library_path + sizeof(POLYP_ROOTENV), MAX_PATH)) + return 0; + + sep = strrchr(library_path, '\\'); + if (sep) + *sep = '\0'; + + if (_putenv(library_path) < 0) + return 0; + + return 1; +} + +#endif /** Make a file descriptor nonblock. Doesn't do any error checking */ void pa_make_nonblock_fd(int fd) { +#ifdef O_NONBLOCK int v; assert(fd >= 0); if ((v = fcntl(fd, F_GETFL)) >= 0) if (!(v & O_NONBLOCK)) fcntl(fd, F_SETFL, v|O_NONBLOCK); +#elif defined(OS_IS_WIN32) + u_long arg = 1; + if (ioctlsocket(fd, FIONBIO, &arg) < 0) { + if (WSAGetLastError() == WSAENOTSOCK) + pa_log_warn(__FILE__": WARNING: Only sockets can be made non-blocking!\n"); + } +#else + pa_log_warn(__FILE__": WARNING: Non-blocking I/O not supported.!\n"); +#endif } /** Creates a directory securely */ @@ -85,15 +136,27 @@ int pa_make_secure_dir(const char* dir) { struct stat st; assert(dir); - if (mkdir(dir, 0700) < 0) +#ifdef OS_IS_WIN32 + if (mkdir(dir) < 0) +#else + if (mkdir(dir, 0700) < 0) +#endif if (errno != EEXIST) return -1; - - if (lstat(dir, &st) < 0) + +#ifdef OS_IS_WIN32 + if (stat(dir, &st) < 0) +#else + if (lstat(dir, &st) < 0) +#endif goto fail; - + +#ifndef OS_IS_WIN32 if (!S_ISDIR(st.st_mode) || (st.st_uid != getuid()) || ((st.st_mode & 0777) != 0700)) goto fail; +#else + fprintf(stderr, "FIXME: pa_make_secure_dir()\n"); +#endif return 0; @@ -106,10 +169,11 @@ fail: int pa_make_secure_parent_dir(const char *fn) { int ret = -1; char *slash, *dir = pa_xstrdup(fn); - - if (!(slash = strrchr(dir, '/'))) + + slash = pa_path_get_filename(dir); + if (slash == fn) goto finish; - *slash = 0; + *(slash-1) = 0; if (pa_make_secure_dir(dir) < 0) goto finish; @@ -285,6 +349,15 @@ char *pa_get_user_name(char *s, size_t l) { } p = r->pw_name; + +#elif defined(OS_IS_WIN32) /* HAVE_PWD_H */ + DWORD size = sizeof(buf); + + if (!GetUserName(buf, &size)) + return NULL; + + p = buf; + #else /* HAVE_PWD_H */ return NULL; #endif /* HAVE_PWD_H */ @@ -318,6 +391,9 @@ char *pa_get_home_dir(char *s, size_t l) { if ((e = getenv("HOME"))) return pa_strlcpy(s, e, l); + if ((e = getenv("USERPROFILE"))) + return pa_strlcpy(s, e, l); + #ifdef HAVE_PWD_H #ifdef HAVE_GETPWUID_R if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) { @@ -349,6 +425,34 @@ char *pa_strlcpy(char *b, const char *s, size_t l) { int pa_gettimeofday(struct timeval *tv) { #ifdef HAVE_GETTIMEOFDAY return gettimeofday(tv, NULL); +#elif defined(OS_IS_WIN32) + /* + * Copied from implementation by Steven Edwards (LGPL). + * Found on wine mailing list. + */ + +#if defined(_MSC_VER) || defined(__BORLANDC__) +#define EPOCHFILETIME (116444736000000000i64) +#else +#define EPOCHFILETIME (116444736000000000LL) +#endif + + FILETIME ft; + LARGE_INTEGER li; + __int64 t; + + if (tv) { + GetSystemTimeAsFileTime(&ft); + li.LowPart = ft.dwLowDateTime; + li.HighPart = ft.dwHighDateTime; + t = li.QuadPart; /* In 100-nanosecond intervals */ + t -= EPOCHFILETIME; /* Offset to the Epoch time */ + t /= 10; /* In microseconds */ + tv->tv_sec = (long)(t / 1000000); + tv->tv_usec = (long)(t % 1000000); + } + + return 0; #else #error "Platform lacks gettimeofday() or equivalent function." #endif @@ -432,10 +536,12 @@ sensible: set the nice level to -15 and enable realtime scheduling if supported.*/ void pa_raise_priority(void) { +#ifdef HAVE_SYS_RESOURCE_H if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0) pa_log_warn(__FILE__": setpriority() failed: %s\n", strerror(errno)); else pa_log_info(__FILE__": Successfully gained nice level %i.\n", NICE_LEVEL); +#endif #ifdef _POSIX_PRIORITY_SCHEDULING { @@ -455,10 +561,21 @@ void pa_raise_priority(void) { pa_log_info(__FILE__": Successfully enabled SCHED_FIFO scheduling.\n"); } #endif + +#ifdef OS_IS_WIN32 + if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) + pa_log_warn(__FILE__": SetPriorityClass() failed: 0x%08X\n", GetLastError()); + else + pa_log_info(__FILE__": Successfully gained high priority class.\n"); +#endif } /* Reset the priority to normal, inverting the changes made by pa_raise_priority() */ void pa_reset_priority(void) { +#ifdef OS_IS_WIN32 + SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); +#endif + #ifdef _POSIX_PRIORITY_SCHEDULING { struct sched_param sp; @@ -468,11 +585,15 @@ void pa_reset_priority(void) { } #endif +#ifdef HAVE_SYS_RESOURCE_H setpriority(PRIO_PROCESS, 0, 0); +#endif } /* Set the FD_CLOEXEC flag for a fd */ int pa_fd_set_cloexec(int fd, int b) { + +#ifdef FD_CLOEXEC int v; assert(fd >= 0); @@ -483,7 +604,8 @@ int pa_fd_set_cloexec(int fd, int b) { if (fcntl(fd, F_SETFD, v) < 0) return -1; - +#endif + return 0; } @@ -491,6 +613,8 @@ int pa_fd_set_cloexec(int fd, int b) { * only. This shoul be used for eyecandy only, don't rely on return * non-NULL! */ char *pa_get_binary_name(char *s, size_t l) { + +#ifdef HAVE_READLINK char path[PATH_MAX]; int i; assert(s && l); @@ -503,6 +627,15 @@ char *pa_get_binary_name(char *s, size_t l) { s[i] = 0; return s; +#elif defined(OS_IS_WIN32) + char path[PATH_MAX]; + if (!GetModuleFileName(NULL, path, PATH_MAX)) + return NULL; + pa_strlcpy(s, pa_path_get_filename(path), l); + return s; +#else + return NULL; +#endif } /* Return a pointer to the filename inside a path (which is the last @@ -510,7 +643,7 @@ char *pa_get_binary_name(char *s, size_t l) { char *pa_path_get_filename(const char *p) { char *fn; - if ((fn = strrchr(p, '/'))) + if ((fn = strrchr(p, PATH_SEP))) return fn+1; return (char*) p; @@ -684,6 +817,7 @@ int pa_uid_in_group(const char *name, gid_t *gid) { /* Lock or unlock a file entirely. (advisory) */ int pa_lock_fd(int fd, int b) { +#ifdef F_SETLKW struct flock flock; /* Try a R/W lock first */ @@ -704,6 +838,19 @@ int pa_lock_fd(int fd, int b) { } pa_log(__FILE__": %slock failed: %s\n", !b ? "un" : "", strerror(errno)); +#endif + +#ifdef OS_IS_WIN32 + HANDLE h = (HANDLE)_get_osfhandle(fd); + + if (b && LockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF)) + return 0; + if (!b && UnlockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF)) + return 0; + + pa_log(__FILE__": %slock failed: 0x%08X\n", !b ? "un" : "", GetLastError()); +#endif + return -1; } @@ -795,31 +942,51 @@ int pa_unlock_lockfile(const char *fn, int fd) { * allocated buffer containing the used configuration file is * stored there.*/ FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result) { - const char *e; + const char *fn; char h[PATH_MAX]; - if (env && (e = getenv(env))) { +#ifdef OS_IS_WIN32 + char buf[PATH_MAX]; + + if (!getenv(POLYP_ROOTENV)) + pa_set_root(NULL); +#endif + + if (env && (fn = getenv(env))) { +#ifdef OS_IS_WIN32 + if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX)) + return NULL; + fn = buf; +#endif + if (result) - *result = pa_xstrdup(e); - return fopen(e, "r"); + *result = pa_xstrdup(fn); + + return fopen(fn, "r"); } if (local && pa_get_home_dir(h, sizeof(h))) { FILE *f; - char *l; + char *lfn; - l = pa_sprintf_malloc("%s/%s", h, local); - f = fopen(l, "r"); + lfn = pa_sprintf_malloc("%s/%s", h, local); + +#ifdef OS_IS_WIN32 + if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) + return NULL; + lfn = buf; +#endif + + f = fopen(lfn, "r"); if (f || errno != ENOENT) { if (result) - *result = l; - else - pa_xfree(l); + *result = pa_xstrdup(lfn); + pa_xfree(lfn); return f; } - pa_xfree(l); + pa_xfree(lfn); } if (!global) { @@ -829,6 +996,12 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env return NULL; } +#ifdef OS_IS_WIN32 + if (!ExpandEnvironmentStrings(global, buf, PATH_MAX)) + return NULL; + global = buf; +#endif + if (result) *result = pa_xstrdup(global); @@ -934,21 +1107,44 @@ int pa_startswith(const char *s, const char *pfx) { char *pa_runtime_path(const char *fn, char *s, size_t l) { char u[256]; +#ifndef OS_IS_WIN32 if (fn && *fn == '/') +#else + if (fn && strlen(fn) >= 3 && isalpha(fn[0]) && fn[1] == ':' && fn[2] == '\\') +#endif return pa_strlcpy(s, fn, l); - - snprintf(s, l, PA_RUNTIME_PATH_PREFIX"%s%s%s", pa_get_user_name(u, sizeof(u)), fn ? "/" : "", fn ? fn : ""); + + if (fn) + snprintf(s, l, "%s%s%c%s", PA_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)), PATH_SEP, fn); + else + snprintf(s, l, "%s%s", PA_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u))); + +#ifdef OS_IS_WIN32 + { + char buf[l]; + strcpy(buf, s); + ExpandEnvironmentStrings(buf, s, l); + } +#endif + return s; } /* Wait t milliseconds */ int pa_msleep(unsigned long t) { +#ifdef OS_IS_WIN32 + Sleep(t); + return 0; +#elif defined(HAVE_NANOSLEEP) struct timespec ts; ts.tv_sec = t/1000; ts.tv_nsec = (t % 1000) * 1000000; return nanosleep(&ts, NULL); +#else +#error "Platform lacks a sleep function." +#endif } /* Convert the string s to a signed integer in *ret_i */ |