blob: 01effca3dde211386910b804d53a96dc3a6b073e [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>
Alexandre Julliardc3e06df2002-05-14 23:18:23 +000043#ifdef HAVE_SYS_IOCTL_H
Alexandre Julliard8da12c41999-01-17 16:55:11 +000044#include <sys/ioctl.h>
Alexandre Julliardc3e06df2002-05-14 23:18:23 +000045#endif
Alexandre Julliard8da12c41999-01-17 16:55:11 +000046#include <errno.h>
47#include <fcntl.h>
Alexandre Julliardc3e06df2002-05-14 23:18:23 +000048#ifdef HAVE_TERMIOS_H
Alexandre Julliard8da12c41999-01-17 16:55:11 +000049#include <termios.h>
Alexandre Julliardc3e06df2002-05-14 23:18:23 +000050#endif
Alexandre Julliard85423c62000-11-08 04:28:54 +000051#ifdef HAVE_SYS_MMAN_H
52#include <sys/mman.h>
53#endif
Marcus Meissner592ba101999-01-20 14:18:55 +000054#ifdef HAVE_LIBIO_H
55# include <libio.h>
56#endif
Patrik Stridvallb9010211999-11-13 22:23:35 +000057#ifdef HAVE_SYSCALL_H
58# include <syscall.h>
59#endif
Bang Jun-Youngd0b304b2001-12-14 22:47:45 +000060#ifdef HAVE_STDINT_H
61# include <stdint.h>
62#endif
Patrik Stridvall9af5e691999-12-11 23:02:15 +000063
Patrik Stridvallb9010211999-11-13 22:23:35 +000064/***********************************************************************
65 * usleep
66 */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000067#ifndef HAVE_USLEEP
Alexandre Julliardc3e06df2002-05-14 23:18:23 +000068int usleep (unsigned int useconds)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000069{
Patrik Stridvallb9010211999-11-13 22:23:35 +000070#if defined(__EMX__)
71 DosSleep(useconds);
72 return 0;
73#elif defined(__BEOS__)
74 return snooze(useconds);
75#elif defined(HAVE_SELECT)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000076 struct timeval delay;
77
Alexandre Julliard2fa4f762000-10-31 00:20:51 +000078 delay.tv_sec = useconds / 1000000;
79 delay.tv_usec = useconds % 1000000;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000080
Alexandre Julliardca22b331996-07-12 19:02:39 +000081 select( 0, 0, 0, 0, &delay );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000082 return 0;
Patrik Stridvallb9010211999-11-13 22:23:35 +000083#else /* defined(__EMX__) || defined(__BEOS__) || defined(HAVE_SELECT) */
84 errno = ENOSYS;
85 return -1;
86#endif /* defined(__EMX__) || defined(__BEOS__) || defined(HAVE_SELECT) */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000087}
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000088#endif /* HAVE_USLEEP */
89
Patrik Stridvallb9010211999-11-13 22:23:35 +000090/***********************************************************************
91 * memmove
92 */
Alexandre Julliard18f92e71996-07-17 20:02:21 +000093#ifndef HAVE_MEMMOVE
Alexandre Julliardac9c9b01996-07-28 18:50:11 +000094void *memmove( void *dest, const void *src, unsigned int len )
Alexandre Julliard18f92e71996-07-17 20:02:21 +000095{
Alexandre Julliardac9c9b01996-07-28 18:50:11 +000096 register char *dst = dest;
97
Alexandre Julliard18f92e71996-07-17 20:02:21 +000098 /* Use memcpy if not overlapping */
Alexandre Julliardac9c9b01996-07-28 18:50:11 +000099 if ((dst + len <= (char *)src) || ((char *)src + len <= dst))
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000100 {
101 memcpy( dst, src, len );
102 }
103 /* Otherwise do it the hard way (FIXME: could do better than this) */
104 else if (dst < src)
105 {
Alexandre Julliardac9c9b01996-07-28 18:50:11 +0000106 while (len--) *dst++ = *((char *)src)++;
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000107 }
108 else
109 {
Alexandre Julliardac9c9b01996-07-28 18:50:11 +0000110 dst += len - 1;
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000111 src = (char *)src + len - 1;
Alexandre Julliardac9c9b01996-07-28 18:50:11 +0000112 while (len--) *dst-- = *((char *)src)--;
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000113 }
Alexandre Julliardac9c9b01996-07-28 18:50:11 +0000114 return dest;
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000115}
116#endif /* HAVE_MEMMOVE */
Alexandre Julliard44ed71f1997-12-21 19:17:50 +0000117
Patrik Stridvallb9010211999-11-13 22:23:35 +0000118/***********************************************************************
119 * strerror
120 */
Alexandre Julliard44ed71f1997-12-21 19:17:50 +0000121#ifndef HAVE_STRERROR
122const char *strerror( int err )
123{
124 /* Let's hope we have sys_errlist then */
125 return sys_errlist[err];
126}
127#endif /* HAVE_STRERROR */
Alexandre Julliard0623a6f1998-01-18 18:01:49 +0000128
Alexandre Julliard85423c62000-11-08 04:28:54 +0000129
130/***********************************************************************
131 * getpagesize
132 */
133#ifndef HAVE_GETPAGESIZE
134size_t getpagesize(void)
135{
136# ifdef __svr4__
137 return sysconf(_SC_PAGESIZE);
Alexandre Julliard60443072002-05-17 03:31:08 +0000138# elif defined(__i386__)
139 return 4096;
Alexandre Julliard85423c62000-11-08 04:28:54 +0000140# else
141# error Cannot get the page size on this platform
142# endif
143}
144#endif /* HAVE_GETPAGESIZE */
145
146
Patrik Stridvallb9010211999-11-13 22:23:35 +0000147/***********************************************************************
148 * clone
149 */
Alexandre Julliard0623a6f1998-01-18 18:01:49 +0000150#if !defined(HAVE_CLONE) && defined(__linux__)
Alexandre Julliard0623a6f1998-01-18 18:01:49 +0000151int clone( int (*fn)(void *), void *stack, int flags, void *arg )
152{
153#ifdef __i386__
154 int ret;
155 void **stack_ptr = (void **)stack;
156 *--stack_ptr = arg; /* Push argument on stack */
157 *--stack_ptr = fn; /* Push function pointer (popped into ebx) */
158 __asm__ __volatile__( "pushl %%ebx\n\t"
159 "movl %2,%%ebx\n\t"
160 "int $0x80\n\t"
161 "popl %%ebx\n\t" /* Contains fn in the child */
162 "testl %%eax,%%eax\n\t"
163 "jnz 0f\n\t"
Alexandre Julliard0f586c42001-02-20 01:59:27 +0000164 "xorl %ebp,%ebp\n\t" /* Terminate the stack frames */
Alexandre Julliard0623a6f1998-01-18 18:01:49 +0000165 "call *%%ebx\n\t" /* Should never return */
166 "xorl %%eax,%%eax\n\t" /* Just in case it does*/
167 "0:"
168 : "=a" (ret)
Marcus Meissner4ede2961999-02-21 18:18:42 +0000169 : "0" (SYS_clone), "r" (flags), "c" (stack_ptr) );
Alexandre Julliard0623a6f1998-01-18 18:01:49 +0000170 assert( ret ); /* If ret is 0, we returned from the child function */
171 if (ret > 0) return ret;
172 errno = -ret;
173 return -1;
174#else
175 errno = EINVAL;
176 return -1;
177#endif /* __i386__ */
178}
179#endif /* !HAVE_CLONE && __linux__ */
Alexandre Julliard8da12c41999-01-17 16:55:11 +0000180
Patrik Stridvallb9010211999-11-13 22:23:35 +0000181/***********************************************************************
182 * strcasecmp
183 */
Alexandre Julliard3b96efc1999-09-04 14:36:02 +0000184#ifndef HAVE_STRCASECMP
185int strcasecmp( const char *str1, const char *str2 )
186{
Morten Welindera2d11df2000-12-18 03:50:15 +0000187 const unsigned char *ustr1 = (const unsigned char *)str1;
188 const unsigned char *ustr2 = (const unsigned char *)str2;
189
190 while (*ustr1 && toupper(*ustr1) == toupper(*ustr2)) {
191 ustr1++;
192 ustr2++;
193 }
194 return toupper(*ustr1) - toupper(*ustr2);
Alexandre Julliard3b96efc1999-09-04 14:36:02 +0000195}
196#endif /* HAVE_STRCASECMP */
197
Patrik Stridvallb9010211999-11-13 22:23:35 +0000198/***********************************************************************
199 * strncasecmp
200 */
Alexandre Julliard3b96efc1999-09-04 14:36:02 +0000201#ifndef HAVE_STRNCASECMP
202int strncasecmp( const char *str1, const char *str2, size_t n )
203{
Morten Welindera2d11df2000-12-18 03:50:15 +0000204 const unsigned char *ustr1 = (const unsigned char *)str1;
205 const unsigned char *ustr2 = (const unsigned char *)str2;
Alexandre Julliard3b96efc1999-09-04 14:36:02 +0000206 int res;
Morten Welindera2d11df2000-12-18 03:50:15 +0000207
Alexandre Julliard3b96efc1999-09-04 14:36:02 +0000208 if (!n) return 0;
Morten Welindera2d11df2000-12-18 03:50:15 +0000209 while ((--n > 0) && *ustr1) {
210 if ((res = toupper(*ustr1) - toupper(*ustr2))) return res;
211 ustr1++;
212 ustr2++;
213 }
214 return toupper(*ustr1) - toupper(*ustr2);
Alexandre Julliard3b96efc1999-09-04 14:36:02 +0000215}
216#endif /* HAVE_STRNCASECMP */
217
Patrik Stridvallb9010211999-11-13 22:23:35 +0000218/***********************************************************************
Patrik Stridvallb9010211999-11-13 22:23:35 +0000219 * getsockopt
220 */
221#ifndef HAVE_GETSOCKOPT
222int getsockopt(int socket, int level, int option_name,
Alexandre Julliard2fa4f762000-10-31 00:20:51 +0000223 void *option_value, size_t *option_len)
Patrik Stridvallb9010211999-11-13 22:23:35 +0000224{
225 errno = ENOSYS;
226 return -1;
227}
228#endif /* !defined(HAVE_GETSOCKOPT) */
229
230/***********************************************************************
231 * inet_network
232 */
233#ifndef HAVE_INET_NETWORK
234unsigned long inet_network(const char *cp)
235{
236 errno = ENOSYS;
237 return 0;
238}
239#endif /* defined(HAVE_INET_NETWORK) */
240
241/***********************************************************************
Patrik Stridvallb9010211999-11-13 22:23:35 +0000242 * statfs
243 */
244#ifndef HAVE_STATFS
245int statfs(const char *name, struct statfs *info)
246{
247#ifdef __BEOS__
248 dev_t mydev;
249 fs_info fsinfo;
Alexandre Julliard2fa4f762000-10-31 00:20:51 +0000250
Patrik Stridvallb9010211999-11-13 22:23:35 +0000251 if(!info) {
252 errno = ENOSYS;
253 return -1;
254 }
255
256 if ((mydev = dev_for_path(name)) < 0) {
257 errno = ENOSYS;
Alexandre Julliard2fa4f762000-10-31 00:20:51 +0000258 return -1;
Patrik Stridvallb9010211999-11-13 22:23:35 +0000259 }
260
261 if (fs_stat_dev(mydev,&fsinfo) < 0) {
262 errno = ENOSYS;
Alexandre Julliard2fa4f762000-10-31 00:20:51 +0000263 return -1;
Patrik Stridvallb9010211999-11-13 22:23:35 +0000264 }
265
266 info->f_bsize = fsinfo.block_size;
267 info->f_blocks = fsinfo.total_blocks;
268 info->f_bfree = fsinfo.free_blocks;
Patrik Stridvallb9010211999-11-13 22:23:35 +0000269 return 0;
270#else /* defined(__BEOS__) */
271 errno = ENOSYS;
272 return -1;
273#endif /* defined(__BEOS__) */
274}
275#endif /* !defined(HAVE_STATFS) */
Alexandre Julliard85423c62000-11-08 04:28:54 +0000276
277
278/***********************************************************************
Alexandre Julliard27bb3112000-11-29 17:48:06 +0000279 * lstat
280 */
281#ifndef HAVE_LSTAT
282int lstat(const char *file_name, struct stat *buf)
283{
284 return stat( file_name, buf );
285}
286#endif /* HAVE_LSTAT */
287
Marcus Meissner786d2492002-07-29 23:55:39 +0000288/***********************************************************************
289 * mkstemp
290 */
291#ifndef HAVE_MKSTEMP
292int mkstemp(char *tmpfn)
293{
294 int tries;
295 char *xstart;
296
297 xstart = tmpfn+strlen(tmpfn)-1;
298 while ((xstart > tmpfn) && (*xstart == 'X'))
299 xstart--;
300 tries = 10;
301 while (tries--) {
302 char *newfn = mktemp(tmpfn);
303 int fd;
304 if (!newfn) /* something else broke horribly */
305 return -1;
306 fd = open(newfn,O_CREAT|O_RDWR|O_EXCL,0600);
307 if (fd!=-1)
308 return fd;
309 newfn = xstart;
310 /* fill up with X and try again ... */
311 while (*newfn) *newfn++ = 'X';
312 }
313 return -1;
314}
315#endif /* HAVE_MKSTEMP */
316
Alexandre Julliardf1a0de92002-01-07 21:00:27 +0000317
318/***********************************************************************
319 * pread
320 *
321 * FIXME: this is not thread-safe
322 */
323#ifndef HAVE_PREAD
324ssize_t pread( int fd, void *buf, size_t count, off_t offset )
325{
326 ssize_t ret;
327 off_t old_pos;
328
329 if ((old_pos = lseek( fd, 0, SEEK_CUR )) == -1) return -1;
330 if (lseek( fd, offset, SEEK_SET ) == -1) return -1;
331 if ((ret = read( fd, buf, count )) == -1)
332 {
333 int err = errno; /* save errno */
334 lseek( fd, old_pos, SEEK_SET );
335 errno = err;
336 return -1;
337 }
338 if (lseek( fd, old_pos, SEEK_SET ) == -1) return -1;
339 return ret;
340}
341#endif /* HAVE_PREAD */
342
343
344/***********************************************************************
345 * pwrite
346 *
347 * FIXME: this is not thread-safe
348 */
349#ifndef HAVE_PWRITE
350ssize_t pwrite( int fd, const void *buf, size_t count, off_t offset )
351{
352 ssize_t ret;
353 off_t old_pos;
354
355 if ((old_pos = lseek( fd, 0, SEEK_CUR )) == -1) return -1;
356 if (lseek( fd, offset, SEEK_SET ) == -1) return -1;
357 if ((ret = write( fd, buf, count )) == -1)
358 {
359 int err = errno; /* save errno */
360 lseek( fd, old_pos, SEEK_SET );
361 errno = err;
362 return -1;
363 }
364 if (lseek( fd, old_pos, SEEK_SET ) == -1) return -1;
365 return ret;
366}
367#endif /* HAVE_PWRITE */
368
369
Bang Jun-Youngd0b304b2001-12-14 22:47:45 +0000370#if defined(__svr4__) || defined(__NetBSD__)
Ulrich Weigandc52a11e2001-09-07 18:46:14 +0000371/***********************************************************************
Bang Jun-Youngd0b304b2001-12-14 22:47:45 +0000372 * try_mmap_fixed
Ulrich Weigandc52a11e2001-09-07 18:46:14 +0000373 *
374 * The purpose of this routine is to emulate the behaviour of
375 * the Linux mmap() routine if a non-NULL address is passed,
376 * but the MAP_FIXED flag is not set. Linux in this case tries
377 * to place the mapping at the specified address, *unless* the
378 * range is already in use. Solaris, however, completely ignores
379 * the address argument in this case.
380 *
381 * As Wine code occasionally relies on the Linux behaviour, e.g. to
382 * be able to map non-relocateable PE executables to their proper
383 * start addresses, or to map the DOS memory to 0, this routine
384 * emulates the Linux behaviour by checking whether the desired
385 * address range is still available, and placing the mapping there
386 * using MAP_FIXED if so.
387 */
Bang Jun-Youngd0b304b2001-12-14 22:47:45 +0000388static int try_mmap_fixed (void *addr, size_t len, int prot, int flags,
389 int fildes, off_t off)
Ulrich Weigandc52a11e2001-09-07 18:46:14 +0000390{
391 char * volatile result = NULL;
392 int pagesize = getpagesize();
393 pid_t pid;
394
395 /* We only try to map to a fixed address if
396 addr is non-NULL and properly aligned,
397 and MAP_FIXED isn't already specified. */
398
399 if ( !addr )
François Gouget15268722001-11-05 23:52:30 +0000400 return 0;
Ulrich Weigandc52a11e2001-09-07 18:46:14 +0000401 if ( (uintptr_t)addr & (pagesize-1) )
François Gouget15268722001-11-05 23:52:30 +0000402 return 0;
Ulrich Weigandc52a11e2001-09-07 18:46:14 +0000403 if ( flags & MAP_FIXED )
François Gouget15268722001-11-05 23:52:30 +0000404 return 0;
Ulrich Weigandc52a11e2001-09-07 18:46:14 +0000405
406 /* We use vfork() to freeze all threads of the
407 current process. This allows us to check without
408 race condition whether the desired memory range is
409 already in use. Note that because vfork() shares
410 the address spaces between parent and child, we
411 can actually perform the mapping in the child. */
412
413 if ( (pid = vfork()) == -1 )
414 {
Bang Jun-Youngd0b304b2001-12-14 22:47:45 +0000415 perror("try_mmap_fixed: vfork");
Ulrich Weigandc52a11e2001-09-07 18:46:14 +0000416 exit(1);
417 }
418 if ( pid == 0 )
419 {
420 int i;
421 char vec;
422
423 /* We call mincore() for every page in the desired range.
424 If any of these calls succeeds, the page is already
425 mapped and we must fail. */
426 for ( i = 0; i < len; i += pagesize )
427 if ( mincore( (caddr_t)addr + i, pagesize, &vec ) != -1 )
428 _exit(1);
429
430 /* Perform the mapping with MAP_FIXED set. This is safe
431 now, as none of the pages is currently in use. */
432 result = mmap( addr, len, prot, flags | MAP_FIXED, fildes, off );
433 if ( result == addr )
434 _exit(0);
435
436 if ( result != (void *) -1 ) /* This should never happen ... */
437 munmap( result, len );
438
439 _exit(1);
440 }
441
442 /* vfork() lets the parent continue only after the child
443 has exited. Furthermore, Wine sets SIGCHLD to SIG_IGN,
444 so we don't need to wait for the child. */
445
446 return result == addr;
447}
448#endif
449
Dimitrie O. Paun1ec253d2000-12-01 20:47:11 +0000450/***********************************************************************
Alexandre Julliard85423c62000-11-08 04:28:54 +0000451 * wine_anon_mmap
452 *
453 * Portable wrapper for anonymous mmaps
454 */
455void *wine_anon_mmap( void *start, size_t size, int prot, int flags )
456{
Alexandre Julliardc3e06df2002-05-14 23:18:23 +0000457#ifdef HAVE_MMAP
Alexandre Julliard85423c62000-11-08 04:28:54 +0000458 static int fdzero = -1;
459
460#ifdef MAP_ANON
461 flags |= MAP_ANON;
462#else
463 if (fdzero == -1)
464 {
465 if ((fdzero = open( "/dev/zero", O_RDONLY )) == -1)
466 {
467 perror( "/dev/zero: open" );
468 exit(1);
469 }
470 }
471#endif /* MAP_ANON */
Morten Welindera2d11df2000-12-18 03:50:15 +0000472
Alexandre Julliard85423c62000-11-08 04:28:54 +0000473#ifdef MAP_SHARED
474 flags &= ~MAP_SHARED;
475#endif
Morten Welindera2d11df2000-12-18 03:50:15 +0000476
477 /* Linux EINVAL's on us if we don't pass MAP_PRIVATE to an anon mmap */
Alexandre Julliard85423c62000-11-08 04:28:54 +0000478#ifdef MAP_PRIVATE
479 flags |= MAP_PRIVATE;
480#endif
Morten Welindera2d11df2000-12-18 03:50:15 +0000481
Bang Jun-Youngd0b304b2001-12-14 22:47:45 +0000482#if defined(__svr4__) || defined(__NetBSD__)
483 if ( try_mmap_fixed( start, size, prot, flags, fdzero, 0 ) )
Ulrich Weigandc52a11e2001-09-07 18:46:14 +0000484 return start;
485#endif
486
Alexandre Julliard85423c62000-11-08 04:28:54 +0000487 return mmap( start, size, prot, flags, fdzero, 0 );
Alexandre Julliardc3e06df2002-05-14 23:18:23 +0000488#else
489 return (void *)-1;
490#endif
Alexandre Julliard85423c62000-11-08 04:28:54 +0000491}
James Abbatielloe6758872000-12-13 21:32:55 +0000492
493
494/*
495 * These functions provide wrappers around dlopen() and associated
496 * functions. They work around a bug in glibc 2.1.x where calling
497 * a dl*() function after a previous dl*() function has failed
498 * without a dlerror() call between the two will cause a crash.
499 * They all take a pointer to a buffer that
500 * will receive the error description (from dlerror()). This
501 * parameter may be NULL if the error description is not required.
502 */
503
504/***********************************************************************
505 * wine_dlopen
506 */
507void *wine_dlopen( const char *filename, int flag, char *error, int errorsize )
508{
Alexandre Julliarded2f19a2001-06-27 21:42:00 +0000509#ifdef HAVE_DLOPEN
James Abbatielloe6758872000-12-13 21:32:55 +0000510 void *ret;
Francois Gouget0763abf2002-04-01 21:08:16 +0000511 const char *s;
James Abbatielloe6758872000-12-13 21:32:55 +0000512 dlerror(); dlerror();
513 ret = dlopen( filename, flag );
514 s = dlerror();
515 if (error)
516 {
517 strncpy( error, s ? s : "", errorsize );
518 error[errorsize - 1] = '\0';
519 }
520 dlerror();
521 return ret;
522#else
523 if (error)
524 {
525 strncpy( error, "dlopen interface not detected by configure", errorsize );
526 error[errorsize - 1] = '\0';
527 }
528 return NULL;
529#endif
530}
531
532/***********************************************************************
533 * wine_dlsym
534 */
535void *wine_dlsym( void *handle, const char *symbol, char *error, int errorsize )
536{
Alexandre Julliarded2f19a2001-06-27 21:42:00 +0000537#ifdef HAVE_DLOPEN
James Abbatielloe6758872000-12-13 21:32:55 +0000538 void *ret;
Francois Gouget0763abf2002-04-01 21:08:16 +0000539 const char *s;
James Abbatielloe6758872000-12-13 21:32:55 +0000540 dlerror(); dlerror();
541 ret = dlsym( handle, symbol );
542 s = dlerror();
543 if (error)
544 {
545 strncpy( error, s ? s : "", errorsize );
546 error[errorsize - 1] = '\0';
547 }
548 dlerror();
549 return ret;
550#else
551 if (error)
552 {
553 strncpy( error, "dlopen interface not detected by configure", errorsize );
554 error[errorsize - 1] = '\0';
555 }
556 return NULL;
557#endif
558}
559
560/***********************************************************************
561 * wine_dlclose
562 */
563int wine_dlclose( void *handle, char *error, int errorsize )
564{
Alexandre Julliarded2f19a2001-06-27 21:42:00 +0000565#ifdef HAVE_DLOPEN
James Abbatielloe6758872000-12-13 21:32:55 +0000566 int ret;
Francois Gouget0763abf2002-04-01 21:08:16 +0000567 const char *s;
James Abbatielloe6758872000-12-13 21:32:55 +0000568 dlerror(); dlerror();
569 ret = dlclose( handle );
570 s = dlerror();
571 if (error)
572 {
573 strncpy( error, s ? s : "", errorsize );
574 error[errorsize - 1] = '\0';
575 }
576 dlerror();
577 return ret;
578#else
579 if (error)
580 {
581 strncpy( error, "dlopen interface not detected by configure", errorsize );
582 error[errorsize - 1] = '\0';
583 }
584 return 1;
585#endif
586}
François Gouget50510202000-12-19 04:50:49 +0000587
588/***********************************************************************
589 * wine_rewrite_s4tos2
590 *
591 * Convert 4 byte Unicode strings to 2 byte Unicode strings in-place.
592 * This is only practical if literal strings are writable.
593 */
594unsigned short* wine_rewrite_s4tos2(const wchar_t* str4 )
595{
596 unsigned short *str2,*s2;
597
598 if (str4==NULL)
599 return NULL;
600
601 if ((*str4 & 0xffff0000) != 0) {
602 /* This string has already been converted. Return it as is */
603 return (unsigned short*)str4;
604 }
605
Vincent Béron9a624912002-05-31 23:06:46 +0000606 /* Note that we can also end up here if the string has a single
607 * character. In such a case we will convert the string over and
François Gouget50510202000-12-19 04:50:49 +0000608 * over again. But this is harmless.
609 */
610 str2=s2=(unsigned short*)str4;
611 do {
612 *s2=(unsigned short)*str4;
613 s2++;
614 } while (*str4++ != L'\0');
615
616 return str2;
617}
Andreas Mohra7ca2ba2001-01-12 23:07:11 +0000618
619#ifndef HAVE_ECVT
620/*
621 * NetBSD 1.5 doesn't have ecvt, fcvt, gcvt. We just check for ecvt, though.
622 * Fix/verify these implementations !
623 */
624
625/***********************************************************************
626 * ecvt
627 */
628char *ecvt (double number, int ndigits, int *decpt, int *sign)
629{
Gerald Pfeifer714066152001-10-02 17:18:09 +0000630 static char buf[40]; /* ought to be enough */
Andreas Mohra7ca2ba2001-01-12 23:07:11 +0000631 char *dec;
Vincent Béron9a624912002-05-31 23:06:46 +0000632 sprintf(buf, "%.*e", ndigits /* FIXME wrong */, number);
Andreas Mohra7ca2ba2001-01-12 23:07:11 +0000633 *sign = (number < 0);
634 dec = strchr(buf, '.');
635 *decpt = (dec) ? (int)dec - (int)buf : -1;
636 return buf;
637}
638
639/***********************************************************************
640 * fcvt
641 */
642char *fcvt (double number, int ndigits, int *decpt, int *sign)
643{
Gerald Pfeifer714066152001-10-02 17:18:09 +0000644 static char buf[40]; /* ought to be enough */
Andreas Mohra7ca2ba2001-01-12 23:07:11 +0000645 char *dec;
646 sprintf(buf, "%.*e", ndigits, number);
647 *sign = (number < 0);
648 dec = strchr(buf, '.');
649 *decpt = (dec) ? (int)dec - (int)buf : -1;
650 return buf;
651}
652
653/***********************************************************************
654 * gcvt
655 *
656 * FIXME: uses both E and F.
657 */
658char *gcvt (double number, size_t ndigit, char *buff)
659{
Gerald Pfeifer714066152001-10-02 17:18:09 +0000660 sprintf(buff, "%.*E", (int)ndigit, number);
Andreas Mohra7ca2ba2001-01-12 23:07:11 +0000661 return buff;
662}
663#endif /* HAVE_ECVT */
Alexandre Julliard894b1882002-04-25 21:40:56 +0000664
665
666/***********************************************************************
667 * interlocked functions
668 */
669#ifdef __i386__
670
671__ASM_GLOBAL_FUNC(interlocked_cmpxchg,
672 "movl 12(%esp),%eax\n\t"
673 "movl 8(%esp),%ecx\n\t"
674 "movl 4(%esp),%edx\n\t"
675 "lock; cmpxchgl %ecx,(%edx)\n\t"
676 "ret");
677__ASM_GLOBAL_FUNC(interlocked_cmpxchg_ptr,
678 "movl 12(%esp),%eax\n\t"
679 "movl 8(%esp),%ecx\n\t"
680 "movl 4(%esp),%edx\n\t"
681 "lock; cmpxchgl %ecx,(%edx)\n\t"
682 "ret");
683__ASM_GLOBAL_FUNC(interlocked_xchg,
684 "movl 8(%esp),%eax\n\t"
685 "movl 4(%esp),%edx\n\t"
686 "lock; xchgl %eax,(%edx)\n\t"
687 "ret");
688__ASM_GLOBAL_FUNC(interlocked_xchg_ptr,
689 "movl 8(%esp),%eax\n\t"
690 "movl 4(%esp),%edx\n\t"
691 "lock; xchgl %eax,(%edx)\n\t"
692 "ret");
693__ASM_GLOBAL_FUNC(interlocked_xchg_add,
694 "movl 8(%esp),%eax\n\t"
695 "movl 4(%esp),%edx\n\t"
696 "lock; xaddl %eax,(%edx)\n\t"
697 "ret");
698
Alexandre Julliardc1dec292002-08-06 23:51:25 +0000699#elif defined(__powerpc__)
700void* interlocked_cmpxchg_ptr( void **dest, void* xchg, void* compare)
701{
702 long ret;
703 long scratch;
704 __asm__ __volatile__(
705 "sync; "
706 "0: lwarx %0,0,%2 ;"
707 " xor. %1,%4,%0;"
708 " bne 1f;"
709 " stwcx. %3,0,%2;"
710 " bne- 0b;"
711 "1: "
712 "sync; "
713 : "=&r"(ret), "=&r"(scratch)
714 : "r"(dest), "r"(xchg), "r"(compare)
715 : "cr0", "memory");
716 return (void*)ret;
717}
718
719long interlocked_cmpxchg( long *dest, long xchg, long compare)
720{
721 long ret;
722 long scratch;
723 __asm__ __volatile__(
724 "sync; "
725 "0: lwarx %0,0,%2 ;"
726 " xor. %1,%4,%0;"
727 " bne 1f;"
728 " stwcx. %3,0,%2;"
729 " bne- 0b;"
730 "1: "
731 "sync; "
732 : "=&r"(ret), "=&r"(scratch)
733 : "r"(dest), "r"(xchg), "r"(compare)
734 : "cr0", "memory");
735 return ret;
736}
737
738long interlocked_xchg_add( long *dest, long incr )
739{
740 void *ret __attribute__ ((aligned (4))) = &ret;
741 long inc = incr;
742 long zero = 0;
743 __asm__ __volatile__(
744 "sync; "
745 "0: lwarx %0, %3, %1;"
746 " add %0, %2, %0;"
747 " stwcx. %0, %3, %1;"
748 " bne- 0b;"
749 "sync; "
750 : "=&r"(ret)
751 : "r"(dest), "r"(inc), "r"(zero)
752 : "cr0", "memory"
753 );
754 return (long)ret;
755}
756
757long interlocked_xchg( long* dest, long val )
758{
759 void *ret __attribute__ ((aligned (4))) = &ret;
760 __asm__ __volatile__(
761 "sync; "
762 "0: lwarx %0,0,%1 ;"
763 " stwcx. %2,0,%1;"
764 " bne- 0b;"
765 "sync; "
766 : "=&r"(ret)
767 : "r"(dest), "r"(val)
768 : "cr0", "memory");
769 return (long)ret;
770}
771
772void* interlocked_xchg_ptr( void** dest, void* val )
773{
774 void *ret __attribute__ ((aligned (4))) = &ret;
775 __asm__ __volatile__(
776 "sync; "
777 "0: lwarx %0,0,%1 ;"
778 " stwcx. %2,0,%1;"
779 " bne- 0b;"
780 "sync; "
781 : "=&r"(ret)
782 : "r"(dest), "r"(val)
783 : "cr0", "memory");
784 return (void*)ret;
785}
786
Alexandre Julliard894b1882002-04-25 21:40:56 +0000787#elif defined(__sparc__) && defined(__sun__)
788
789/*
790 * As the earlier Sparc processors lack necessary atomic instructions,
791 * I'm simply falling back to the library-provided _lwp_mutex routines
Vincent Béron9a624912002-05-31 23:06:46 +0000792 * to ensure mutual exclusion in a way appropriate for the current
793 * architecture.
Alexandre Julliard894b1882002-04-25 21:40:56 +0000794 *
795 * FIXME: If we have the compare-and-swap instruction (Sparc v9 and above)
796 * we could use this to speed up the Interlocked operations ...
797 */
798#include <synch.h>
799static lwp_mutex_t interlocked_mutex = DEFAULTMUTEX;
800
801long interlocked_cmpxchg( long *dest, long xchg, long compare )
802{
803 _lwp_mutex_lock( &interlocked_mutex );
804 if (*dest == compare) *dest = xchg;
805 else compare = *dest;
806 _lwp_mutex_unlock( &interlocked_mutex );
807 return compare;
808}
809
810void *interlocked_cmpxchg_ptr( void **dest, void *xchg, void *compare )
811{
812 _lwp_mutex_lock( &interlocked_mutex );
813 if (*dest == compare) *dest = xchg;
814 else compare = *dest;
815 _lwp_mutex_unlock( &interlocked_mutex );
816 return compare;
817}
818
819long interlocked_xchg( long *dest, long val )
820{
821 long retv;
822 _lwp_mutex_lock( &interlocked_mutex );
823 retv = *dest;
824 *dest = val;
825 _lwp_mutex_unlock( &interlocked_mutex );
826 return retv;
827}
828
829void *interlocked_xchg_ptr( void **dest, void *val )
830{
831 long retv;
832 _lwp_mutex_lock( &interlocked_mutex );
833 retv = *dest;
834 *dest = val;
835 _lwp_mutex_unlock( &interlocked_mutex );
836 return retv;
837}
838
839long interlocked_xchg_add( long *dest, long incr )
840{
841 long retv;
842 _lwp_mutex_lock( &interlocked_mutex );
843 retv = *dest;
844 *dest += incr;
845 _lwp_mutex_unlock( &interlocked_mutex );
846 return retv;
847}
Alexandre Julliard894b1882002-04-25 21:40:56 +0000848#else
849# error You must implement the interlocked* functions for your CPU
850#endif