blob: 64f8149b603fff68ec6f2ad02af35df379e4d178 [file] [log] [blame]
Alexandre Julliard18f92e71996-07-17 20:02:21 +00001/*
2 * Misc. functions for systems that don't have them
3 *
4 * Copyright 1996 Alexandre Julliard
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00005 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but 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 this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Alexandre Julliard18f92e71996-07-17 20:02:21 +000019 */
20
François Gouget14259412001-11-06 20:57:11 +000021#include "config.h"
Marcus Meissner3f1ed522001-05-14 20:09:37 +000022#include "wine/port.h"
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +000023
Patrik Stridvallb9010211999-11-13 22:23:35 +000024#ifdef __BEOS__
25#include <be/kernel/fs_info.h>
26#include <be/kernel/OS.h>
27#endif
28
29#include <assert.h>
Alexandre Julliard3b96efc1999-09-04 14:36:02 +000030#include <ctype.h>
Marcus Meissner3b092841999-02-20 16:46:39 +000031#include <stdio.h>
Alexandre Julliard335b9e32000-12-19 19:38:48 +000032#include <stdlib.h>
David Luyeree517e81999-02-28 12:27:56 +000033#include <string.h>
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +000034#include <unistd.h>
Alexandre Julliardca22b331996-07-12 19:02:39 +000035#include <sys/types.h>
Michal Pasternak60983992002-03-29 18:04:43 +000036#ifdef HAVE_SYS_INTTYPES_H
37# include <sys/inttypes.h>
38#endif
Patrik Stridvall136fae52002-03-11 05:08:38 +000039#ifdef HAVE_SYS_TIME_h
40# include <sys/time.h>
41#endif
Alexandre Julliard8da12c41999-01-17 16:55:11 +000042#include <sys/stat.h>
43#include <sys/ioctl.h>
44#include <errno.h>
45#include <fcntl.h>
46#include <termios.h>
Alexandre Julliard85423c62000-11-08 04:28:54 +000047#ifdef HAVE_SYS_MMAN_H
48#include <sys/mman.h>
49#endif
Marcus Meissner592ba101999-01-20 14:18:55 +000050#ifdef HAVE_LIBIO_H
51# include <libio.h>
52#endif
Patrik Stridvallb9010211999-11-13 22:23:35 +000053#ifdef HAVE_SYSCALL_H
54# include <syscall.h>
55#endif
Bang Jun-Youngd0b304b2001-12-14 22:47:45 +000056#ifdef HAVE_STDINT_H
57# include <stdint.h>
58#endif
Patrik Stridvall9af5e691999-12-11 23:02:15 +000059
Patrik Stridvallb9010211999-11-13 22:23:35 +000060/***********************************************************************
61 * usleep
62 */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000063#ifndef HAVE_USLEEP
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000064unsigned int usleep (unsigned int useconds)
65{
Patrik Stridvallb9010211999-11-13 22:23:35 +000066#if defined(__EMX__)
67 DosSleep(useconds);
68 return 0;
69#elif defined(__BEOS__)
70 return snooze(useconds);
71#elif defined(HAVE_SELECT)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000072 struct timeval delay;
73
Alexandre Julliard2fa4f762000-10-31 00:20:51 +000074 delay.tv_sec = useconds / 1000000;
75 delay.tv_usec = useconds % 1000000;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000076
Alexandre Julliardca22b331996-07-12 19:02:39 +000077 select( 0, 0, 0, 0, &delay );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000078 return 0;
Patrik Stridvallb9010211999-11-13 22:23:35 +000079#else /* defined(__EMX__) || defined(__BEOS__) || defined(HAVE_SELECT) */
80 errno = ENOSYS;
81 return -1;
82#endif /* defined(__EMX__) || defined(__BEOS__) || defined(HAVE_SELECT) */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000083}
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000084#endif /* HAVE_USLEEP */
85
Patrik Stridvallb9010211999-11-13 22:23:35 +000086/***********************************************************************
87 * memmove
88 */
Alexandre Julliard18f92e71996-07-17 20:02:21 +000089#ifndef HAVE_MEMMOVE
Alexandre Julliardac9c9b01996-07-28 18:50:11 +000090void *memmove( void *dest, const void *src, unsigned int len )
Alexandre Julliard18f92e71996-07-17 20:02:21 +000091{
Alexandre Julliardac9c9b01996-07-28 18:50:11 +000092 register char *dst = dest;
93
Alexandre Julliard18f92e71996-07-17 20:02:21 +000094 /* Use memcpy if not overlapping */
Alexandre Julliardac9c9b01996-07-28 18:50:11 +000095 if ((dst + len <= (char *)src) || ((char *)src + len <= dst))
Alexandre Julliard18f92e71996-07-17 20:02:21 +000096 {
97 memcpy( dst, src, len );
98 }
99 /* Otherwise do it the hard way (FIXME: could do better than this) */
100 else if (dst < src)
101 {
Alexandre Julliardac9c9b01996-07-28 18:50:11 +0000102 while (len--) *dst++ = *((char *)src)++;
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000103 }
104 else
105 {
Alexandre Julliardac9c9b01996-07-28 18:50:11 +0000106 dst += len - 1;
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000107 src = (char *)src + len - 1;
Alexandre Julliardac9c9b01996-07-28 18:50:11 +0000108 while (len--) *dst-- = *((char *)src)--;
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000109 }
Alexandre Julliardac9c9b01996-07-28 18:50:11 +0000110 return dest;
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000111}
112#endif /* HAVE_MEMMOVE */
Alexandre Julliard44ed71f1997-12-21 19:17:50 +0000113
Patrik Stridvallb9010211999-11-13 22:23:35 +0000114/***********************************************************************
115 * strerror
116 */
Alexandre Julliard44ed71f1997-12-21 19:17:50 +0000117#ifndef HAVE_STRERROR
118const char *strerror( int err )
119{
120 /* Let's hope we have sys_errlist then */
121 return sys_errlist[err];
122}
123#endif /* HAVE_STRERROR */
Alexandre Julliard0623a6f1998-01-18 18:01:49 +0000124
Alexandre Julliard85423c62000-11-08 04:28:54 +0000125
126/***********************************************************************
127 * getpagesize
128 */
129#ifndef HAVE_GETPAGESIZE
130size_t getpagesize(void)
131{
132# ifdef __svr4__
133 return sysconf(_SC_PAGESIZE);
134# else
135# error Cannot get the page size on this platform
136# endif
137}
138#endif /* HAVE_GETPAGESIZE */
139
140
Patrik Stridvallb9010211999-11-13 22:23:35 +0000141/***********************************************************************
142 * clone
143 */
Alexandre Julliard0623a6f1998-01-18 18:01:49 +0000144#if !defined(HAVE_CLONE) && defined(__linux__)
Alexandre Julliard0623a6f1998-01-18 18:01:49 +0000145int clone( int (*fn)(void *), void *stack, int flags, void *arg )
146{
147#ifdef __i386__
148 int ret;
149 void **stack_ptr = (void **)stack;
150 *--stack_ptr = arg; /* Push argument on stack */
151 *--stack_ptr = fn; /* Push function pointer (popped into ebx) */
152 __asm__ __volatile__( "pushl %%ebx\n\t"
153 "movl %2,%%ebx\n\t"
154 "int $0x80\n\t"
155 "popl %%ebx\n\t" /* Contains fn in the child */
156 "testl %%eax,%%eax\n\t"
157 "jnz 0f\n\t"
Alexandre Julliard0f586c42001-02-20 01:59:27 +0000158 "xorl %ebp,%ebp\n\t" /* Terminate the stack frames */
Alexandre Julliard0623a6f1998-01-18 18:01:49 +0000159 "call *%%ebx\n\t" /* Should never return */
160 "xorl %%eax,%%eax\n\t" /* Just in case it does*/
161 "0:"
162 : "=a" (ret)
Marcus Meissner4ede2961999-02-21 18:18:42 +0000163 : "0" (SYS_clone), "r" (flags), "c" (stack_ptr) );
Alexandre Julliard0623a6f1998-01-18 18:01:49 +0000164 assert( ret ); /* If ret is 0, we returned from the child function */
165 if (ret > 0) return ret;
166 errno = -ret;
167 return -1;
168#else
169 errno = EINVAL;
170 return -1;
171#endif /* __i386__ */
172}
173#endif /* !HAVE_CLONE && __linux__ */
Alexandre Julliard8da12c41999-01-17 16:55:11 +0000174
Patrik Stridvallb9010211999-11-13 22:23:35 +0000175/***********************************************************************
176 * strcasecmp
177 */
Alexandre Julliard3b96efc1999-09-04 14:36:02 +0000178#ifndef HAVE_STRCASECMP
179int strcasecmp( const char *str1, const char *str2 )
180{
Morten Welindera2d11df2000-12-18 03:50:15 +0000181 const unsigned char *ustr1 = (const unsigned char *)str1;
182 const unsigned char *ustr2 = (const unsigned char *)str2;
183
184 while (*ustr1 && toupper(*ustr1) == toupper(*ustr2)) {
185 ustr1++;
186 ustr2++;
187 }
188 return toupper(*ustr1) - toupper(*ustr2);
Alexandre Julliard3b96efc1999-09-04 14:36:02 +0000189}
190#endif /* HAVE_STRCASECMP */
191
Patrik Stridvallb9010211999-11-13 22:23:35 +0000192/***********************************************************************
193 * strncasecmp
194 */
Alexandre Julliard3b96efc1999-09-04 14:36:02 +0000195#ifndef HAVE_STRNCASECMP
196int strncasecmp( const char *str1, const char *str2, size_t n )
197{
Morten Welindera2d11df2000-12-18 03:50:15 +0000198 const unsigned char *ustr1 = (const unsigned char *)str1;
199 const unsigned char *ustr2 = (const unsigned char *)str2;
Alexandre Julliard3b96efc1999-09-04 14:36:02 +0000200 int res;
Morten Welindera2d11df2000-12-18 03:50:15 +0000201
Alexandre Julliard3b96efc1999-09-04 14:36:02 +0000202 if (!n) return 0;
Morten Welindera2d11df2000-12-18 03:50:15 +0000203 while ((--n > 0) && *ustr1) {
204 if ((res = toupper(*ustr1) - toupper(*ustr2))) return res;
205 ustr1++;
206 ustr2++;
207 }
208 return toupper(*ustr1) - toupper(*ustr2);
Alexandre Julliard3b96efc1999-09-04 14:36:02 +0000209}
210#endif /* HAVE_STRNCASECMP */
211
Patrik Stridvallb9010211999-11-13 22:23:35 +0000212/***********************************************************************
Alexandre Julliard3f510ad2002-01-01 01:13:03 +0000213 * openpty
Patrik Stridvallb9010211999-11-13 22:23:35 +0000214 * NOTE
215 * It looks like the openpty that comes with glibc in RedHat 5.0
216 * is buggy (second call returns what looks like a dup of 0 and 1
217 * instead of a new pty), this is a generic replacement.
218 *
219 * FIXME
220 * We should have a autoconf check for this.
Alexandre Julliard8da12c41999-01-17 16:55:11 +0000221 */
Alexandre Julliard3f510ad2002-01-01 01:13:03 +0000222#ifndef HAVE_OPENPTY
223int openpty(int *master, int *slave, char *name, struct termios *term, struct winsize *winsize)
Alexandre Julliard8da12c41999-01-17 16:55:11 +0000224{
Morten Welindera2d11df2000-12-18 03:50:15 +0000225 const char *ptr1, *ptr2;
Alexandre Julliard8da12c41999-01-17 16:55:11 +0000226 char pts_name[512];
227
228 strcpy (pts_name, "/dev/ptyXY");
229
230 for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1 != 0; ptr1++) {
231 pts_name[8] = *ptr1;
232 for (ptr2 = "0123456789abcdef"; *ptr2 != 0; ptr2++) {
233 pts_name[9] = *ptr2;
234
235 if ((*master = open(pts_name, O_RDWR)) < 0) {
236 if (errno == ENOENT)
237 return -1;
238 else
239 continue;
240 }
241 pts_name[5] = 't';
242 if ((*slave = open(pts_name, O_RDWR)) < 0) {
243 pts_name[5] = 'p';
Morten Welindera2d11df2000-12-18 03:50:15 +0000244 close (*master);
Alexandre Julliard8da12c41999-01-17 16:55:11 +0000245 continue;
246 }
247
248 if (term != NULL)
Alexandre Julliard2fa4f762000-10-31 00:20:51 +0000249 tcsetattr(*slave, TCSANOW, term);
250 if (winsize != NULL)
251 ioctl(*slave, TIOCSWINSZ, winsize);
252 if (name != NULL)
253 strcpy(name, pts_name);
Alexandre Julliard8da12c41999-01-17 16:55:11 +0000254 return *slave;
255 }
256 }
Morten Welindera2d11df2000-12-18 03:50:15 +0000257 errno = EMFILE;
Alexandre Julliard8da12c41999-01-17 16:55:11 +0000258 return -1;
259}
Alexandre Julliard3f510ad2002-01-01 01:13:03 +0000260#endif /* HAVE_OPENPTY */
Alexandre Julliard8da12c41999-01-17 16:55:11 +0000261
Patrik Stridvallb9010211999-11-13 22:23:35 +0000262/***********************************************************************
263 * getnetbyaddr
264 */
265#ifndef HAVE_GETNETBYADDR
266struct netent *getnetbyaddr(unsigned long net, int type)
267{
268 errno = ENOSYS;
269 return NULL;
270}
271#endif /* defined(HAVE_GETNETBYNAME) */
272
273/***********************************************************************
274 * getnetbyname
275 */
276#ifndef HAVE_GETNETBYNAME
277struct netent *getnetbyname(const char *name)
278{
279 errno = ENOSYS;
280 return NULL;
281}
282#endif /* defined(HAVE_GETNETBYNAME) */
283
284/***********************************************************************
285 * getprotobyname
286 */
287#ifndef HAVE_GETPROTOBYNAME
288struct protoent *getprotobyname(const char *name)
289{
290 errno = ENOSYS;
291 return NULL;
292}
293#endif /* !defined(HAVE_GETPROTOBYNAME) */
294
295/***********************************************************************
296 * getprotobynumber
297 */
298#ifndef HAVE_GETPROTOBYNUMBER
299struct protoent *getprotobynumber(int proto)
300{
301 errno = ENOSYS;
302 return NULL;
303}
304#endif /* !defined(HAVE_GETPROTOBYNUMBER) */
305
306/***********************************************************************
307 * getservbyport
308 */
309#ifndef HAVE_GETSERVBYPORT
310struct servent *getservbyport(int port, const char *proto)
311{
312 errno = ENOSYS;
313 return NULL;
314}
315#endif /* !defined(HAVE_GETSERVBYPORT) */
316
317/***********************************************************************
318 * getsockopt
319 */
320#ifndef HAVE_GETSOCKOPT
321int getsockopt(int socket, int level, int option_name,
Alexandre Julliard2fa4f762000-10-31 00:20:51 +0000322 void *option_value, size_t *option_len)
Patrik Stridvallb9010211999-11-13 22:23:35 +0000323{
324 errno = ENOSYS;
325 return -1;
326}
327#endif /* !defined(HAVE_GETSOCKOPT) */
328
329/***********************************************************************
330 * inet_network
331 */
332#ifndef HAVE_INET_NETWORK
333unsigned long inet_network(const char *cp)
334{
335 errno = ENOSYS;
336 return 0;
337}
338#endif /* defined(HAVE_INET_NETWORK) */
339
340/***********************************************************************
Patrik Stridvallb9010211999-11-13 22:23:35 +0000341 * statfs
342 */
343#ifndef HAVE_STATFS
344int statfs(const char *name, struct statfs *info)
345{
346#ifdef __BEOS__
347 dev_t mydev;
348 fs_info fsinfo;
Alexandre Julliard2fa4f762000-10-31 00:20:51 +0000349
Patrik Stridvallb9010211999-11-13 22:23:35 +0000350 if(!info) {
351 errno = ENOSYS;
352 return -1;
353 }
354
355 if ((mydev = dev_for_path(name)) < 0) {
356 errno = ENOSYS;
Alexandre Julliard2fa4f762000-10-31 00:20:51 +0000357 return -1;
Patrik Stridvallb9010211999-11-13 22:23:35 +0000358 }
359
360 if (fs_stat_dev(mydev,&fsinfo) < 0) {
361 errno = ENOSYS;
Alexandre Julliard2fa4f762000-10-31 00:20:51 +0000362 return -1;
Patrik Stridvallb9010211999-11-13 22:23:35 +0000363 }
364
365 info->f_bsize = fsinfo.block_size;
366 info->f_blocks = fsinfo.total_blocks;
367 info->f_bfree = fsinfo.free_blocks;
Patrik Stridvallb9010211999-11-13 22:23:35 +0000368 return 0;
369#else /* defined(__BEOS__) */
370 errno = ENOSYS;
371 return -1;
372#endif /* defined(__BEOS__) */
373}
374#endif /* !defined(HAVE_STATFS) */
Alexandre Julliard85423c62000-11-08 04:28:54 +0000375
376
377/***********************************************************************
Alexandre Julliard27bb3112000-11-29 17:48:06 +0000378 * lstat
379 */
380#ifndef HAVE_LSTAT
381int lstat(const char *file_name, struct stat *buf)
382{
383 return stat( file_name, buf );
384}
385#endif /* HAVE_LSTAT */
386
Alexandre Julliardf1a0de92002-01-07 21:00:27 +0000387
388/***********************************************************************
389 * pread
390 *
391 * FIXME: this is not thread-safe
392 */
393#ifndef HAVE_PREAD
394ssize_t pread( int fd, void *buf, size_t count, off_t offset )
395{
396 ssize_t ret;
397 off_t old_pos;
398
399 if ((old_pos = lseek( fd, 0, SEEK_CUR )) == -1) return -1;
400 if (lseek( fd, offset, SEEK_SET ) == -1) return -1;
401 if ((ret = read( fd, buf, count )) == -1)
402 {
403 int err = errno; /* save errno */
404 lseek( fd, old_pos, SEEK_SET );
405 errno = err;
406 return -1;
407 }
408 if (lseek( fd, old_pos, SEEK_SET ) == -1) return -1;
409 return ret;
410}
411#endif /* HAVE_PREAD */
412
413
414/***********************************************************************
415 * pwrite
416 *
417 * FIXME: this is not thread-safe
418 */
419#ifndef HAVE_PWRITE
420ssize_t pwrite( int fd, const void *buf, size_t count, off_t offset )
421{
422 ssize_t ret;
423 off_t old_pos;
424
425 if ((old_pos = lseek( fd, 0, SEEK_CUR )) == -1) return -1;
426 if (lseek( fd, offset, SEEK_SET ) == -1) return -1;
427 if ((ret = write( fd, buf, count )) == -1)
428 {
429 int err = errno; /* save errno */
430 lseek( fd, old_pos, SEEK_SET );
431 errno = err;
432 return -1;
433 }
434 if (lseek( fd, old_pos, SEEK_SET ) == -1) return -1;
435 return ret;
436}
437#endif /* HAVE_PWRITE */
438
439
Marcus Meissner3f1ed522001-05-14 20:09:37 +0000440/***********************************************************************
Dimitrie O. Paun1ec253d2000-12-01 20:47:11 +0000441 * getrlimit
442 */
443#ifndef HAVE_GETRLIMIT
444int getrlimit (int resource, struct rlimit *rlim)
445{
446 return -1; /* FAIL */
447}
448#endif /* HAVE_GETRLIMIT */
449
Ulrich Weigandc52a11e2001-09-07 18:46:14 +0000450
Bang Jun-Youngd0b304b2001-12-14 22:47:45 +0000451#if defined(__svr4__) || defined(__NetBSD__)
Ulrich Weigandc52a11e2001-09-07 18:46:14 +0000452/***********************************************************************
Bang Jun-Youngd0b304b2001-12-14 22:47:45 +0000453 * try_mmap_fixed
Ulrich Weigandc52a11e2001-09-07 18:46:14 +0000454 *
455 * The purpose of this routine is to emulate the behaviour of
456 * the Linux mmap() routine if a non-NULL address is passed,
457 * but the MAP_FIXED flag is not set. Linux in this case tries
458 * to place the mapping at the specified address, *unless* the
459 * range is already in use. Solaris, however, completely ignores
460 * the address argument in this case.
461 *
462 * As Wine code occasionally relies on the Linux behaviour, e.g. to
463 * be able to map non-relocateable PE executables to their proper
464 * start addresses, or to map the DOS memory to 0, this routine
465 * emulates the Linux behaviour by checking whether the desired
466 * address range is still available, and placing the mapping there
467 * using MAP_FIXED if so.
468 */
Bang Jun-Youngd0b304b2001-12-14 22:47:45 +0000469static int try_mmap_fixed (void *addr, size_t len, int prot, int flags,
470 int fildes, off_t off)
Ulrich Weigandc52a11e2001-09-07 18:46:14 +0000471{
472 char * volatile result = NULL;
473 int pagesize = getpagesize();
474 pid_t pid;
475
476 /* We only try to map to a fixed address if
477 addr is non-NULL and properly aligned,
478 and MAP_FIXED isn't already specified. */
479
480 if ( !addr )
François Gouget15268722001-11-05 23:52:30 +0000481 return 0;
Ulrich Weigandc52a11e2001-09-07 18:46:14 +0000482 if ( (uintptr_t)addr & (pagesize-1) )
François Gouget15268722001-11-05 23:52:30 +0000483 return 0;
Ulrich Weigandc52a11e2001-09-07 18:46:14 +0000484 if ( flags & MAP_FIXED )
François Gouget15268722001-11-05 23:52:30 +0000485 return 0;
Ulrich Weigandc52a11e2001-09-07 18:46:14 +0000486
487 /* We use vfork() to freeze all threads of the
488 current process. This allows us to check without
489 race condition whether the desired memory range is
490 already in use. Note that because vfork() shares
491 the address spaces between parent and child, we
492 can actually perform the mapping in the child. */
493
494 if ( (pid = vfork()) == -1 )
495 {
Bang Jun-Youngd0b304b2001-12-14 22:47:45 +0000496 perror("try_mmap_fixed: vfork");
Ulrich Weigandc52a11e2001-09-07 18:46:14 +0000497 exit(1);
498 }
499 if ( pid == 0 )
500 {
501 int i;
502 char vec;
503
504 /* We call mincore() for every page in the desired range.
505 If any of these calls succeeds, the page is already
506 mapped and we must fail. */
507 for ( i = 0; i < len; i += pagesize )
508 if ( mincore( (caddr_t)addr + i, pagesize, &vec ) != -1 )
509 _exit(1);
510
511 /* Perform the mapping with MAP_FIXED set. This is safe
512 now, as none of the pages is currently in use. */
513 result = mmap( addr, len, prot, flags | MAP_FIXED, fildes, off );
514 if ( result == addr )
515 _exit(0);
516
517 if ( result != (void *) -1 ) /* This should never happen ... */
518 munmap( result, len );
519
520 _exit(1);
521 }
522
523 /* vfork() lets the parent continue only after the child
524 has exited. Furthermore, Wine sets SIGCHLD to SIG_IGN,
525 so we don't need to wait for the child. */
526
527 return result == addr;
528}
529#endif
530
Dimitrie O. Paun1ec253d2000-12-01 20:47:11 +0000531/***********************************************************************
Alexandre Julliard85423c62000-11-08 04:28:54 +0000532 * wine_anon_mmap
533 *
534 * Portable wrapper for anonymous mmaps
535 */
536void *wine_anon_mmap( void *start, size_t size, int prot, int flags )
537{
538 static int fdzero = -1;
539
540#ifdef MAP_ANON
541 flags |= MAP_ANON;
542#else
543 if (fdzero == -1)
544 {
545 if ((fdzero = open( "/dev/zero", O_RDONLY )) == -1)
546 {
547 perror( "/dev/zero: open" );
548 exit(1);
549 }
550 }
551#endif /* MAP_ANON */
Morten Welindera2d11df2000-12-18 03:50:15 +0000552
Alexandre Julliard85423c62000-11-08 04:28:54 +0000553#ifdef MAP_SHARED
554 flags &= ~MAP_SHARED;
555#endif
Morten Welindera2d11df2000-12-18 03:50:15 +0000556
557 /* Linux EINVAL's on us if we don't pass MAP_PRIVATE to an anon mmap */
Alexandre Julliard85423c62000-11-08 04:28:54 +0000558#ifdef MAP_PRIVATE
559 flags |= MAP_PRIVATE;
560#endif
Morten Welindera2d11df2000-12-18 03:50:15 +0000561
Bang Jun-Youngd0b304b2001-12-14 22:47:45 +0000562#if defined(__svr4__) || defined(__NetBSD__)
563 if ( try_mmap_fixed( start, size, prot, flags, fdzero, 0 ) )
Ulrich Weigandc52a11e2001-09-07 18:46:14 +0000564 return start;
565#endif
566
Alexandre Julliard85423c62000-11-08 04:28:54 +0000567 return mmap( start, size, prot, flags, fdzero, 0 );
568}
James Abbatielloe6758872000-12-13 21:32:55 +0000569
570
571/*
572 * These functions provide wrappers around dlopen() and associated
573 * functions. They work around a bug in glibc 2.1.x where calling
574 * a dl*() function after a previous dl*() function has failed
575 * without a dlerror() call between the two will cause a crash.
576 * They all take a pointer to a buffer that
577 * will receive the error description (from dlerror()). This
578 * parameter may be NULL if the error description is not required.
579 */
580
581/***********************************************************************
582 * wine_dlopen
583 */
584void *wine_dlopen( const char *filename, int flag, char *error, int errorsize )
585{
Alexandre Julliarded2f19a2001-06-27 21:42:00 +0000586#ifdef HAVE_DLOPEN
James Abbatielloe6758872000-12-13 21:32:55 +0000587 void *ret;
Francois Gouget0763abf2002-04-01 21:08:16 +0000588 const char *s;
James Abbatielloe6758872000-12-13 21:32:55 +0000589 dlerror(); dlerror();
590 ret = dlopen( filename, flag );
591 s = dlerror();
592 if (error)
593 {
594 strncpy( error, s ? s : "", errorsize );
595 error[errorsize - 1] = '\0';
596 }
597 dlerror();
598 return ret;
599#else
600 if (error)
601 {
602 strncpy( error, "dlopen interface not detected by configure", errorsize );
603 error[errorsize - 1] = '\0';
604 }
605 return NULL;
606#endif
607}
608
609/***********************************************************************
610 * wine_dlsym
611 */
612void *wine_dlsym( void *handle, const char *symbol, char *error, int errorsize )
613{
Alexandre Julliarded2f19a2001-06-27 21:42:00 +0000614#ifdef HAVE_DLOPEN
James Abbatielloe6758872000-12-13 21:32:55 +0000615 void *ret;
Francois Gouget0763abf2002-04-01 21:08:16 +0000616 const char *s;
James Abbatielloe6758872000-12-13 21:32:55 +0000617 dlerror(); dlerror();
618 ret = dlsym( handle, symbol );
619 s = dlerror();
620 if (error)
621 {
622 strncpy( error, s ? s : "", errorsize );
623 error[errorsize - 1] = '\0';
624 }
625 dlerror();
626 return ret;
627#else
628 if (error)
629 {
630 strncpy( error, "dlopen interface not detected by configure", errorsize );
631 error[errorsize - 1] = '\0';
632 }
633 return NULL;
634#endif
635}
636
637/***********************************************************************
638 * wine_dlclose
639 */
640int wine_dlclose( void *handle, char *error, int errorsize )
641{
Alexandre Julliarded2f19a2001-06-27 21:42:00 +0000642#ifdef HAVE_DLOPEN
James Abbatielloe6758872000-12-13 21:32:55 +0000643 int ret;
Francois Gouget0763abf2002-04-01 21:08:16 +0000644 const char *s;
James Abbatielloe6758872000-12-13 21:32:55 +0000645 dlerror(); dlerror();
646 ret = dlclose( handle );
647 s = dlerror();
648 if (error)
649 {
650 strncpy( error, s ? s : "", errorsize );
651 error[errorsize - 1] = '\0';
652 }
653 dlerror();
654 return ret;
655#else
656 if (error)
657 {
658 strncpy( error, "dlopen interface not detected by configure", errorsize );
659 error[errorsize - 1] = '\0';
660 }
661 return 1;
662#endif
663}
François Gouget50510202000-12-19 04:50:49 +0000664
665/***********************************************************************
666 * wine_rewrite_s4tos2
667 *
668 * Convert 4 byte Unicode strings to 2 byte Unicode strings in-place.
669 * This is only practical if literal strings are writable.
670 */
671unsigned short* wine_rewrite_s4tos2(const wchar_t* str4 )
672{
673 unsigned short *str2,*s2;
674
675 if (str4==NULL)
676 return NULL;
677
678 if ((*str4 & 0xffff0000) != 0) {
679 /* This string has already been converted. Return it as is */
680 return (unsigned short*)str4;
681 }
682
683 /* Note that we can also end up here if the string has a single
684 * character. In such a case we will convert the string over and
685 * over again. But this is harmless.
686 */
687 str2=s2=(unsigned short*)str4;
688 do {
689 *s2=(unsigned short)*str4;
690 s2++;
691 } while (*str4++ != L'\0');
692
693 return str2;
694}
Andreas Mohra7ca2ba2001-01-12 23:07:11 +0000695
696#ifndef HAVE_ECVT
697/*
698 * NetBSD 1.5 doesn't have ecvt, fcvt, gcvt. We just check for ecvt, though.
699 * Fix/verify these implementations !
700 */
701
702/***********************************************************************
703 * ecvt
704 */
705char *ecvt (double number, int ndigits, int *decpt, int *sign)
706{
Gerald Pfeifer714066152001-10-02 17:18:09 +0000707 static char buf[40]; /* ought to be enough */
Andreas Mohra7ca2ba2001-01-12 23:07:11 +0000708 char *dec;
709 sprintf(buf, "%.*e", ndigits /* FIXME wrong */, number);
710 *sign = (number < 0);
711 dec = strchr(buf, '.');
712 *decpt = (dec) ? (int)dec - (int)buf : -1;
713 return buf;
714}
715
716/***********************************************************************
717 * fcvt
718 */
719char *fcvt (double number, int ndigits, int *decpt, int *sign)
720{
Gerald Pfeifer714066152001-10-02 17:18:09 +0000721 static char buf[40]; /* ought to be enough */
Andreas Mohra7ca2ba2001-01-12 23:07:11 +0000722 char *dec;
723 sprintf(buf, "%.*e", ndigits, number);
724 *sign = (number < 0);
725 dec = strchr(buf, '.');
726 *decpt = (dec) ? (int)dec - (int)buf : -1;
727 return buf;
728}
729
730/***********************************************************************
731 * gcvt
732 *
733 * FIXME: uses both E and F.
734 */
735char *gcvt (double number, size_t ndigit, char *buff)
736{
Gerald Pfeifer714066152001-10-02 17:18:09 +0000737 sprintf(buff, "%.*E", (int)ndigit, number);
Andreas Mohra7ca2ba2001-01-12 23:07:11 +0000738 return buff;
739}
740#endif /* HAVE_ECVT */
Alexandre Julliard894b1882002-04-25 21:40:56 +0000741
742
743/***********************************************************************
744 * interlocked functions
745 */
746#ifdef __i386__
747
748__ASM_GLOBAL_FUNC(interlocked_cmpxchg,
749 "movl 12(%esp),%eax\n\t"
750 "movl 8(%esp),%ecx\n\t"
751 "movl 4(%esp),%edx\n\t"
752 "lock; cmpxchgl %ecx,(%edx)\n\t"
753 "ret");
754__ASM_GLOBAL_FUNC(interlocked_cmpxchg_ptr,
755 "movl 12(%esp),%eax\n\t"
756 "movl 8(%esp),%ecx\n\t"
757 "movl 4(%esp),%edx\n\t"
758 "lock; cmpxchgl %ecx,(%edx)\n\t"
759 "ret");
760__ASM_GLOBAL_FUNC(interlocked_xchg,
761 "movl 8(%esp),%eax\n\t"
762 "movl 4(%esp),%edx\n\t"
763 "lock; xchgl %eax,(%edx)\n\t"
764 "ret");
765__ASM_GLOBAL_FUNC(interlocked_xchg_ptr,
766 "movl 8(%esp),%eax\n\t"
767 "movl 4(%esp),%edx\n\t"
768 "lock; xchgl %eax,(%edx)\n\t"
769 "ret");
770__ASM_GLOBAL_FUNC(interlocked_xchg_add,
771 "movl 8(%esp),%eax\n\t"
772 "movl 4(%esp),%edx\n\t"
773 "lock; xaddl %eax,(%edx)\n\t"
774 "ret");
775
776#elif defined(__sparc__) && defined(__sun__)
777
778/*
779 * As the earlier Sparc processors lack necessary atomic instructions,
780 * I'm simply falling back to the library-provided _lwp_mutex routines
781 * to ensure mutual exclusion in a way appropriate for the current
782 * architecture.
783 *
784 * FIXME: If we have the compare-and-swap instruction (Sparc v9 and above)
785 * we could use this to speed up the Interlocked operations ...
786 */
787#include <synch.h>
788static lwp_mutex_t interlocked_mutex = DEFAULTMUTEX;
789
790long interlocked_cmpxchg( long *dest, long xchg, long compare )
791{
792 _lwp_mutex_lock( &interlocked_mutex );
793 if (*dest == compare) *dest = xchg;
794 else compare = *dest;
795 _lwp_mutex_unlock( &interlocked_mutex );
796 return compare;
797}
798
799void *interlocked_cmpxchg_ptr( void **dest, void *xchg, void *compare )
800{
801 _lwp_mutex_lock( &interlocked_mutex );
802 if (*dest == compare) *dest = xchg;
803 else compare = *dest;
804 _lwp_mutex_unlock( &interlocked_mutex );
805 return compare;
806}
807
808long interlocked_xchg( long *dest, long val )
809{
810 long retv;
811 _lwp_mutex_lock( &interlocked_mutex );
812 retv = *dest;
813 *dest = val;
814 _lwp_mutex_unlock( &interlocked_mutex );
815 return retv;
816}
817
818void *interlocked_xchg_ptr( void **dest, void *val )
819{
820 long retv;
821 _lwp_mutex_lock( &interlocked_mutex );
822 retv = *dest;
823 *dest = val;
824 _lwp_mutex_unlock( &interlocked_mutex );
825 return retv;
826}
827
828long interlocked_xchg_add( long *dest, long incr )
829{
830 long retv;
831 _lwp_mutex_lock( &interlocked_mutex );
832 retv = *dest;
833 *dest += incr;
834 _lwp_mutex_unlock( &interlocked_mutex );
835 return retv;
836}
837
838#else
839# error You must implement the interlocked* functions for your CPU
840#endif