split polypcore/util.[ch] into polypcore/core-util.[ch] and polyp/util.[ch]
[profile/ivi/pulseaudio.git] / src / polyp / 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_NETDB_H
43 #include <netdb.h>
44 #endif
45
46 #ifdef HAVE_PWD_H
47 #include <pwd.h>
48 #endif
49
50 #ifdef HAVE_GRP_H
51 #include <grp.h>
52 #endif
53
54 #ifdef HAVE_WINDOWS_H
55 #include <windows.h>
56 #endif
57
58 #include <polyp/xmalloc.h>
59 #include <polypcore/log.h>
60 #include <polypcore/util.h>
61
62 #include "util.h"
63
64 #ifndef OS_IS_WIN32
65 #define PATH_SEP '/'
66 #else
67 #define PATH_SEP '\\'
68 #endif
69
70 /* Return the current username in the specified string buffer. */
71 char *pa_get_user_name(char *s, size_t l) {
72     char *p;
73     char buf[1024];
74
75 #ifdef HAVE_PWD_H
76     struct passwd pw, *r;
77 #endif
78
79     assert(s && l > 0);
80
81     if (!(p = getenv("USER")) && !(p = getenv("LOGNAME")) && !(p = getenv("USERNAME"))) {
82 #ifdef HAVE_PWD_H
83         
84 #ifdef HAVE_GETPWUID_R
85         if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) {
86 #else
87         /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X)
88             * that do not support getpwuid_r. */
89         if ((r = getpwuid(getuid())) == NULL) {
90 #endif
91             snprintf(s, l, "%lu", (unsigned long) getuid());
92             return s;
93         }
94         
95         p = r->pw_name;
96
97 #elif defined(OS_IS_WIN32) /* HAVE_PWD_H */
98         DWORD size = sizeof(buf);
99
100         if (!GetUserName(buf, &size))
101             return NULL;
102
103         p = buf;
104
105 #else /* HAVE_PWD_H */
106         return NULL;
107 #endif /* HAVE_PWD_H */
108     }
109
110     return pa_strlcpy(s, p, l);
111 }
112
113 /* Return the current hostname in the specified buffer. */
114 char *pa_get_host_name(char *s, size_t l) {
115     assert(s && l > 0);
116     if (gethostname(s, l) < 0) {
117         pa_log(__FILE__": gethostname(): %s", strerror(errno));
118         return NULL;
119     }
120     s[l-1] = 0;
121     return s;
122 }
123
124 /* Return the home directory of the current user */
125 char *pa_get_home_dir(char *s, size_t l) {
126     char *e;
127
128 #ifdef HAVE_PWD_H
129     char buf[1024];
130     struct passwd pw, *r;
131 #endif
132
133     assert(s && l);
134
135     if ((e = getenv("HOME")))
136         return pa_strlcpy(s, e, l);
137
138     if ((e = getenv("USERPROFILE")))
139         return pa_strlcpy(s, e, l);
140
141 #ifdef HAVE_PWD_H
142 #ifdef HAVE_GETPWUID_R
143     if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) {
144         pa_log(__FILE__": getpwuid_r() failed");
145 #else
146     /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X)
147         * that do not support getpwuid_r. */
148     if ((r = getpwuid(getuid())) == NULL) {
149         pa_log(__FILE__": getpwuid_r() failed");
150 #endif
151         return NULL;
152     }
153
154     return pa_strlcpy(s, r->pw_dir, l);
155 #else /* HAVE_PWD_H */
156     return NULL;
157 #endif
158 }
159
160 struct timeval *pa_gettimeofday(struct timeval *tv) {
161 #ifdef HAVE_GETTIMEOFDAY
162     assert(tv);
163     
164     return gettimeofday(tv, NULL) < 0 ? NULL : tv;
165 #elif defined(OS_IS_WIN32)
166     /*
167      * Copied from implementation by Steven Edwards (LGPL).
168      * Found on wine mailing list.
169      */
170
171 #if defined(_MSC_VER) || defined(__BORLANDC__)
172 #define EPOCHFILETIME (116444736000000000i64)
173 #else
174 #define EPOCHFILETIME (116444736000000000LL)
175 #endif
176
177     FILETIME        ft;
178     LARGE_INTEGER   li;
179     __int64         t;
180
181     assert(tv);
182
183     GetSystemTimeAsFileTime(&ft);
184     li.LowPart  = ft.dwLowDateTime;
185     li.HighPart = ft.dwHighDateTime;
186     t  = li.QuadPart;       /* In 100-nanosecond intervals */
187     t -= EPOCHFILETIME;     /* Offset to the Epoch time */
188     t /= 10;                /* In microseconds */
189     tv->tv_sec  = (long)(t / 1000000);
190     tv->tv_usec = (long)(t % 1000000);
191
192     return tv;
193 #else
194 #error "Platform lacks gettimeofday() or equivalent function."
195 #endif
196 }
197
198 /* Calculate the difference between the two specfified timeval
199  * timestamsps. */
200 pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) {
201     pa_usec_t r;
202     assert(a && b);
203
204     /* Check which whan is the earlier time and swap the two arguments if reuqired. */
205     if (pa_timeval_cmp(a, b) < 0) {
206         const struct timeval *c;
207         c = a;
208         a = b;
209         b = c;
210     }
211
212     /* Calculate the second difference*/
213     r = ((pa_usec_t) a->tv_sec - b->tv_sec)* 1000000;
214
215     /* Calculate the microsecond difference */
216     if (a->tv_usec > b->tv_usec)
217         r += ((pa_usec_t) a->tv_usec - b->tv_usec);
218     else if (a->tv_usec < b->tv_usec)
219         r -= ((pa_usec_t) b->tv_usec - a->tv_usec);
220
221     return r;
222 }
223
224 /* Compare the two timeval structs and return 0 when equal, negative when a < b, positive otherwse */
225 int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) {
226     assert(a && b);
227
228     if (a->tv_sec < b->tv_sec)
229         return -1;
230
231     if (a->tv_sec > b->tv_sec)
232         return 1;
233
234     if (a->tv_usec < b->tv_usec)
235         return -1;
236
237     if (a->tv_usec > b->tv_usec)
238         return 1;
239
240     return 0;
241 }
242
243 /* Return the time difference between now and the specified timestamp */
244 pa_usec_t pa_timeval_age(const struct timeval *tv) {
245     struct timeval now;
246     assert(tv);
247     
248     return pa_timeval_diff(pa_gettimeofday(&now), tv);
249 }
250
251 /* Add the specified time inmicroseconds to the specified timeval structure */
252 void pa_timeval_add(struct timeval *tv, pa_usec_t v) {
253     unsigned long secs;
254     assert(tv);
255     
256     secs = (v/1000000);
257     tv->tv_sec += (unsigned long) secs;
258     v -= secs*1000000;
259
260     tv->tv_usec += v;
261
262     /* Normalize */
263     while (tv->tv_usec >= 1000000) {
264         tv->tv_sec++;
265         tv->tv_usec -= 1000000;
266     }
267 }
268
269 /* Return the binary file name of the current process. Works on Linux
270  * only. This shoul be used for eyecandy only, don't rely on return
271  * non-NULL! */
272 char *pa_get_binary_name(char *s, size_t l) {
273
274 #ifdef HAVE_READLINK
275     char path[PATH_MAX];
276     int i;
277     assert(s && l);
278
279     /* This works on Linux only */
280     
281     snprintf(path, sizeof(path), "/proc/%u/exe", (unsigned) getpid());
282     if ((i = readlink(path, s, l-1)) < 0)
283         return NULL;
284
285     s[i] = 0;
286     return s;
287 #elif defined(OS_IS_WIN32)
288     char path[PATH_MAX];
289     if (!GetModuleFileName(NULL, path, PATH_MAX))
290         return NULL;
291     pa_strlcpy(s, pa_path_get_filename(path), l);
292     return s;
293 #else
294     return NULL;
295 #endif
296 }
297
298 /* Return a pointer to the filename inside a path (which is the last
299  * component). */
300 const char *pa_path_get_filename(const char *p) {
301     char *fn;
302
303     if ((fn = strrchr(p, PATH_SEP)))
304         return fn+1;
305
306     return (const char*) p;
307 }
308
309 /* Return the fully qualified domain name in *s */
310 char *pa_get_fqdn(char *s, size_t l) {
311     char hn[256];
312 #ifdef HAVE_GETADDRINFO    
313     struct addrinfo *a, hints;
314 #endif
315
316     if (!pa_get_host_name(hn, sizeof(hn)))
317         return NULL;
318
319 #ifdef HAVE_GETADDRINFO
320     memset(&hints, 0, sizeof(hints));
321     hints.ai_family = AF_UNSPEC;
322     hints.ai_flags = AI_CANONNAME;
323     
324     if (getaddrinfo(hn, NULL, &hints, &a) < 0 || !a || !a->ai_canonname || !*a->ai_canonname)
325         return pa_strlcpy(s, hn, l);
326
327     pa_strlcpy(s, a->ai_canonname, l);
328     freeaddrinfo(a);
329     return s;
330 #else
331     return pa_strlcpy(s, hn, l);
332 #endif
333 }
334
335 /* Wait t milliseconds */
336 int pa_msleep(unsigned long t) {
337 #ifdef OS_IS_WIN32
338     Sleep(t);
339     return 0;
340 #elif defined(HAVE_NANOSLEEP)
341     struct timespec ts;
342
343     ts.tv_sec = t/1000;
344     ts.tv_nsec = (t % 1000) * 1000000;
345
346     return nanosleep(&ts, NULL);
347 #else
348 #error "Platform lacks a sleep function."
349 #endif
350 }