2 * Misc. functions for systems that don't have them
4 * Copyright 1996 Alexandre Julliard
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.
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.
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
22 #include "wine/port.h"
25 #include <be/kernel/fs_info.h>
26 #include <be/kernel/OS.h>
35 #include <sys/types.h>
36 #ifdef HAVE_SYS_INTTYPES_H
37 # include <sys/inttypes.h>
39 #ifdef HAVE_SYS_TIME_h
40 # include <sys/time.h>
43 #ifdef HAVE_SYS_IOCTL_H
44 #include <sys/ioctl.h>
51 #ifdef HAVE_SYS_MMAN_H
64 /***********************************************************************
68 int usleep (unsigned int useconds
)
73 #elif defined(__BEOS__)
74 return snooze(useconds
);
75 #elif defined(HAVE_SELECT)
78 delay
.tv_sec
= useconds
/ 1000000;
79 delay
.tv_usec
= useconds
% 1000000;
81 select( 0, 0, 0, 0, &delay
);
83 #else /* defined(__EMX__) || defined(__BEOS__) || defined(HAVE_SELECT) */
86 #endif /* defined(__EMX__) || defined(__BEOS__) || defined(HAVE_SELECT) */
88 #endif /* HAVE_USLEEP */
90 /***********************************************************************
94 void *memmove( void *dest
, const void *src
, unsigned int len
)
96 register char *dst
= dest
;
98 /* Use memcpy if not overlapping */
99 if ((dst
+ len
<= (char *)src
) || ((char *)src
+ len
<= dst
))
101 memcpy( dst
, src
, len
);
103 /* Otherwise do it the hard way (FIXME: could do better than this) */
106 while (len
--) *dst
++ = *((char *)src
)++;
111 src
= (char *)src
+ len
- 1;
112 while (len
--) *dst
-- = *((char *)src
)--;
116 #endif /* HAVE_MEMMOVE */
118 /***********************************************************************
121 #ifndef HAVE_STRERROR
122 const char *strerror( int err
)
124 /* Let's hope we have sys_errlist then */
125 return sys_errlist
[err
];
127 #endif /* HAVE_STRERROR */
130 /***********************************************************************
133 #ifndef HAVE_GETPAGESIZE
134 size_t getpagesize(void)
137 return sysconf(_SC_PAGESIZE
);
138 # elif defined(__i386__)
141 # error Cannot get the page size on this platform
144 #endif /* HAVE_GETPAGESIZE */
147 /***********************************************************************
150 #if !defined(HAVE_CLONE) && defined(__linux__)
151 int clone( int (*fn
)(void *), void *stack
, int flags
, void *arg
)
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"
161 "popl %%ebx\n\t" /* Contains fn in the child */
162 "testl %%eax,%%eax\n\t"
164 "xorl %ebp,%ebp\n\t" /* Terminate the stack frames */
165 "call *%%ebx\n\t" /* Should never return */
166 "xorl %%eax,%%eax\n\t" /* Just in case it does*/
169 : "0" (SYS_clone
), "r" (flags
), "c" (stack_ptr
) );
170 assert( ret
); /* If ret is 0, we returned from the child function */
171 if (ret
> 0) return ret
;
177 #endif /* __i386__ */
179 #endif /* !HAVE_CLONE && __linux__ */
181 /***********************************************************************
184 #ifndef HAVE_STRCASECMP
185 int strcasecmp( const char *str1
, const char *str2
)
187 const unsigned char *ustr1
= (const unsigned char *)str1
;
188 const unsigned char *ustr2
= (const unsigned char *)str2
;
190 while (*ustr1
&& toupper(*ustr1
) == toupper(*ustr2
)) {
194 return toupper(*ustr1
) - toupper(*ustr2
);
196 #endif /* HAVE_STRCASECMP */
198 /***********************************************************************
201 #ifndef HAVE_STRNCASECMP
202 int strncasecmp( const char *str1
, const char *str2
, size_t n
)
204 const unsigned char *ustr1
= (const unsigned char *)str1
;
205 const unsigned char *ustr2
= (const unsigned char *)str2
;
209 while ((--n
> 0) && *ustr1
) {
210 if ((res
= toupper(*ustr1
) - toupper(*ustr2
))) return res
;
214 return toupper(*ustr1
) - toupper(*ustr2
);
216 #endif /* HAVE_STRNCASECMP */
218 /***********************************************************************
221 #ifndef HAVE_GETNETBYADDR
222 struct netent
*getnetbyaddr(unsigned long net
, int type
)
227 #endif /* defined(HAVE_GETNETBYNAME) */
229 /***********************************************************************
232 #ifndef HAVE_GETNETBYNAME
233 struct netent
*getnetbyname(const char *name
)
238 #endif /* defined(HAVE_GETNETBYNAME) */
240 /***********************************************************************
243 #ifndef HAVE_GETPROTOBYNAME
244 struct protoent
*getprotobyname(const char *name
)
249 #endif /* !defined(HAVE_GETPROTOBYNAME) */
251 /***********************************************************************
254 #ifndef HAVE_GETPROTOBYNUMBER
255 struct protoent
*getprotobynumber(int proto
)
260 #endif /* !defined(HAVE_GETPROTOBYNUMBER) */
262 /***********************************************************************
265 #ifndef HAVE_GETSERVBYPORT
266 struct servent
*getservbyport(int port
, const char *proto
)
271 #endif /* !defined(HAVE_GETSERVBYPORT) */
273 /***********************************************************************
276 #ifndef HAVE_GETSOCKOPT
277 int getsockopt(int socket
, int level
, int option_name
,
278 void *option_value
, size_t *option_len
)
283 #endif /* !defined(HAVE_GETSOCKOPT) */
285 /***********************************************************************
288 #ifndef HAVE_INET_NETWORK
289 unsigned long inet_network(const char *cp
)
294 #endif /* defined(HAVE_INET_NETWORK) */
296 /***********************************************************************
300 int statfs(const char *name
, struct statfs
*info
)
311 if ((mydev
= dev_for_path(name
)) < 0) {
316 if (fs_stat_dev(mydev
,&fsinfo
) < 0) {
321 info
->f_bsize
= fsinfo
.block_size
;
322 info
->f_blocks
= fsinfo
.total_blocks
;
323 info
->f_bfree
= fsinfo
.free_blocks
;
325 #else /* defined(__BEOS__) */
328 #endif /* defined(__BEOS__) */
330 #endif /* !defined(HAVE_STATFS) */
333 /***********************************************************************
337 int lstat(const char *file_name
, struct stat
*buf
)
339 return stat( file_name
, buf
);
341 #endif /* HAVE_LSTAT */
344 /***********************************************************************
347 * FIXME: this is not thread-safe
350 ssize_t
pread( int fd
, void *buf
, size_t count
, off_t offset
)
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
= read( fd
, buf
, count
)) == -1)
359 int err
= errno
; /* save errno */
360 lseek( fd
, old_pos
, SEEK_SET
);
364 if (lseek( fd
, old_pos
, SEEK_SET
) == -1) return -1;
367 #endif /* HAVE_PREAD */
370 /***********************************************************************
373 * FIXME: this is not thread-safe
376 ssize_t
pwrite( int fd
, const void *buf
, size_t count
, off_t offset
)
381 if ((old_pos
= lseek( fd
, 0, SEEK_CUR
)) == -1) return -1;
382 if (lseek( fd
, offset
, SEEK_SET
) == -1) return -1;
383 if ((ret
= write( fd
, buf
, count
)) == -1)
385 int err
= errno
; /* save errno */
386 lseek( fd
, old_pos
, SEEK_SET
);
390 if (lseek( fd
, old_pos
, SEEK_SET
) == -1) return -1;
393 #endif /* HAVE_PWRITE */
396 #if defined(__svr4__) || defined(__NetBSD__)
397 /***********************************************************************
400 * The purpose of this routine is to emulate the behaviour of
401 * the Linux mmap() routine if a non-NULL address is passed,
402 * but the MAP_FIXED flag is not set. Linux in this case tries
403 * to place the mapping at the specified address, *unless* the
404 * range is already in use. Solaris, however, completely ignores
405 * the address argument in this case.
407 * As Wine code occasionally relies on the Linux behaviour, e.g. to
408 * be able to map non-relocateable PE executables to their proper
409 * start addresses, or to map the DOS memory to 0, this routine
410 * emulates the Linux behaviour by checking whether the desired
411 * address range is still available, and placing the mapping there
412 * using MAP_FIXED if so.
414 static int try_mmap_fixed (void *addr
, size_t len
, int prot
, int flags
,
415 int fildes
, off_t off
)
417 char * volatile result
= NULL
;
418 int pagesize
= getpagesize();
421 /* We only try to map to a fixed address if
422 addr is non-NULL and properly aligned,
423 and MAP_FIXED isn't already specified. */
427 if ( (uintptr_t)addr
& (pagesize
-1) )
429 if ( flags
& MAP_FIXED
)
432 /* We use vfork() to freeze all threads of the
433 current process. This allows us to check without
434 race condition whether the desired memory range is
435 already in use. Note that because vfork() shares
436 the address spaces between parent and child, we
437 can actually perform the mapping in the child. */
439 if ( (pid
= vfork()) == -1 )
441 perror("try_mmap_fixed: vfork");
449 /* We call mincore() for every page in the desired range.
450 If any of these calls succeeds, the page is already
451 mapped and we must fail. */
452 for ( i
= 0; i
< len
; i
+= pagesize
)
453 if ( mincore( (caddr_t
)addr
+ i
, pagesize
, &vec
) != -1 )
456 /* Perform the mapping with MAP_FIXED set. This is safe
457 now, as none of the pages is currently in use. */
458 result
= mmap( addr
, len
, prot
, flags
| MAP_FIXED
, fildes
, off
);
459 if ( result
== addr
)
462 if ( result
!= (void *) -1 ) /* This should never happen ... */
463 munmap( result
, len
);
468 /* vfork() lets the parent continue only after the child
469 has exited. Furthermore, Wine sets SIGCHLD to SIG_IGN,
470 so we don't need to wait for the child. */
472 return result
== addr
;
476 /***********************************************************************
479 * Portable wrapper for anonymous mmaps
481 void *wine_anon_mmap( void *start
, size_t size
, int prot
, int flags
)
484 static int fdzero
= -1;
491 if ((fdzero
= open( "/dev/zero", O_RDONLY
)) == -1)
493 perror( "/dev/zero: open" );
497 #endif /* MAP_ANON */
500 flags
&= ~MAP_SHARED
;
503 /* Linux EINVAL's on us if we don't pass MAP_PRIVATE to an anon mmap */
505 flags
|= MAP_PRIVATE
;
508 #if defined(__svr4__) || defined(__NetBSD__)
509 if ( try_mmap_fixed( start
, size
, prot
, flags
, fdzero
, 0 ) )
513 return mmap( start
, size
, prot
, flags
, fdzero
, 0 );
521 * These functions provide wrappers around dlopen() and associated
522 * functions. They work around a bug in glibc 2.1.x where calling
523 * a dl*() function after a previous dl*() function has failed
524 * without a dlerror() call between the two will cause a crash.
525 * They all take a pointer to a buffer that
526 * will receive the error description (from dlerror()). This
527 * parameter may be NULL if the error description is not required.
530 /***********************************************************************
533 void *wine_dlopen( const char *filename
, int flag
, char *error
, int errorsize
)
538 dlerror(); dlerror();
539 ret
= dlopen( filename
, flag
);
543 strncpy( error
, s
? s
: "", errorsize
);
544 error
[errorsize
- 1] = '\0';
551 strncpy( error
, "dlopen interface not detected by configure", errorsize
);
552 error
[errorsize
- 1] = '\0';
558 /***********************************************************************
561 void *wine_dlsym( void *handle
, const char *symbol
, char *error
, int errorsize
)
566 dlerror(); dlerror();
567 ret
= dlsym( handle
, symbol
);
571 strncpy( error
, s
? s
: "", errorsize
);
572 error
[errorsize
- 1] = '\0';
579 strncpy( error
, "dlopen interface not detected by configure", errorsize
);
580 error
[errorsize
- 1] = '\0';
586 /***********************************************************************
589 int wine_dlclose( void *handle
, char *error
, int errorsize
)
594 dlerror(); dlerror();
595 ret
= dlclose( handle
);
599 strncpy( error
, s
? s
: "", errorsize
);
600 error
[errorsize
- 1] = '\0';
607 strncpy( error
, "dlopen interface not detected by configure", errorsize
);
608 error
[errorsize
- 1] = '\0';
614 /***********************************************************************
615 * wine_rewrite_s4tos2
617 * Convert 4 byte Unicode strings to 2 byte Unicode strings in-place.
618 * This is only practical if literal strings are writable.
620 unsigned short* wine_rewrite_s4tos2(const wchar_t* str4
)
622 unsigned short *str2
,*s2
;
627 if ((*str4
& 0xffff0000) != 0) {
628 /* This string has already been converted. Return it as is */
629 return (unsigned short*)str4
;
632 /* Note that we can also end up here if the string has a single
633 * character. In such a case we will convert the string over and
634 * over again. But this is harmless.
636 str2
=s2
=(unsigned short*)str4
;
638 *s2
=(unsigned short)*str4
;
640 } while (*str4
++ != L
'\0');
647 * NetBSD 1.5 doesn't have ecvt, fcvt, gcvt. We just check for ecvt, though.
648 * Fix/verify these implementations !
651 /***********************************************************************
654 char *ecvt (double number
, int ndigits
, int *decpt
, int *sign
)
656 static char buf
[40]; /* ought to be enough */
658 sprintf(buf
, "%.*e", ndigits
/* FIXME wrong */, number
);
659 *sign
= (number
< 0);
660 dec
= strchr(buf
, '.');
661 *decpt
= (dec
) ? (int)dec
- (int)buf
: -1;
665 /***********************************************************************
668 char *fcvt (double number
, int ndigits
, int *decpt
, int *sign
)
670 static char buf
[40]; /* ought to be enough */
672 sprintf(buf
, "%.*e", ndigits
, number
);
673 *sign
= (number
< 0);
674 dec
= strchr(buf
, '.');
675 *decpt
= (dec
) ? (int)dec
- (int)buf
: -1;
679 /***********************************************************************
682 * FIXME: uses both E and F.
684 char *gcvt (double number
, size_t ndigit
, char *buff
)
686 sprintf(buff
, "%.*E", (int)ndigit
, number
);
689 #endif /* HAVE_ECVT */
692 /***********************************************************************
693 * interlocked functions
697 __ASM_GLOBAL_FUNC(interlocked_cmpxchg
,
698 "movl 12(%esp),%eax\n\t"
699 "movl 8(%esp),%ecx\n\t"
700 "movl 4(%esp),%edx\n\t"
701 "lock; cmpxchgl %ecx,(%edx)\n\t"
703 __ASM_GLOBAL_FUNC(interlocked_cmpxchg_ptr
,
704 "movl 12(%esp),%eax\n\t"
705 "movl 8(%esp),%ecx\n\t"
706 "movl 4(%esp),%edx\n\t"
707 "lock; cmpxchgl %ecx,(%edx)\n\t"
709 __ASM_GLOBAL_FUNC(interlocked_xchg
,
710 "movl 8(%esp),%eax\n\t"
711 "movl 4(%esp),%edx\n\t"
712 "lock; xchgl %eax,(%edx)\n\t"
714 __ASM_GLOBAL_FUNC(interlocked_xchg_ptr
,
715 "movl 8(%esp),%eax\n\t"
716 "movl 4(%esp),%edx\n\t"
717 "lock; xchgl %eax,(%edx)\n\t"
719 __ASM_GLOBAL_FUNC(interlocked_xchg_add
,
720 "movl 8(%esp),%eax\n\t"
721 "movl 4(%esp),%edx\n\t"
722 "lock; xaddl %eax,(%edx)\n\t"
725 #elif defined(__sparc__) && defined(__sun__)
728 * As the earlier Sparc processors lack necessary atomic instructions,
729 * I'm simply falling back to the library-provided _lwp_mutex routines
730 * to ensure mutual exclusion in a way appropriate for the current
733 * FIXME: If we have the compare-and-swap instruction (Sparc v9 and above)
734 * we could use this to speed up the Interlocked operations ...
737 static lwp_mutex_t interlocked_mutex
= DEFAULTMUTEX
;
739 long interlocked_cmpxchg( long *dest
, long xchg
, long compare
)
741 _lwp_mutex_lock( &interlocked_mutex
);
742 if (*dest
== compare
) *dest
= xchg
;
743 else compare
= *dest
;
744 _lwp_mutex_unlock( &interlocked_mutex
);
748 void *interlocked_cmpxchg_ptr( void **dest
, void *xchg
, void *compare
)
750 _lwp_mutex_lock( &interlocked_mutex
);
751 if (*dest
== compare
) *dest
= xchg
;
752 else compare
= *dest
;
753 _lwp_mutex_unlock( &interlocked_mutex
);
757 long interlocked_xchg( long *dest
, long val
)
760 _lwp_mutex_lock( &interlocked_mutex
);
763 _lwp_mutex_unlock( &interlocked_mutex
);
767 void *interlocked_xchg_ptr( void **dest
, void *val
)
770 _lwp_mutex_lock( &interlocked_mutex
);
773 _lwp_mutex_unlock( &interlocked_mutex
);
777 long interlocked_xchg_add( long *dest
, long incr
)
780 _lwp_mutex_lock( &interlocked_mutex
);
783 _lwp_mutex_unlock( &interlocked_mutex
);
788 # error You must implement the interlocked* functions for your CPU