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 #include <sys/ioctl.h>
47 #ifdef HAVE_SYS_MMAN_H
60 /***********************************************************************
64 unsigned int usleep (unsigned int useconds
)
69 #elif defined(__BEOS__)
70 return snooze(useconds
);
71 #elif defined(HAVE_SELECT)
74 delay
.tv_sec
= useconds
/ 1000000;
75 delay
.tv_usec
= useconds
% 1000000;
77 select( 0, 0, 0, 0, &delay
);
79 #else /* defined(__EMX__) || defined(__BEOS__) || defined(HAVE_SELECT) */
82 #endif /* defined(__EMX__) || defined(__BEOS__) || defined(HAVE_SELECT) */
84 #endif /* HAVE_USLEEP */
86 /***********************************************************************
90 void *memmove( void *dest
, const void *src
, unsigned int len
)
92 register char *dst
= dest
;
94 /* Use memcpy if not overlapping */
95 if ((dst
+ len
<= (char *)src
) || ((char *)src
+ len
<= dst
))
97 memcpy( dst
, src
, len
);
99 /* Otherwise do it the hard way (FIXME: could do better than this) */
102 while (len
--) *dst
++ = *((char *)src
)++;
107 src
= (char *)src
+ len
- 1;
108 while (len
--) *dst
-- = *((char *)src
)--;
112 #endif /* HAVE_MEMMOVE */
114 /***********************************************************************
117 #ifndef HAVE_STRERROR
118 const char *strerror( int err
)
120 /* Let's hope we have sys_errlist then */
121 return sys_errlist
[err
];
123 #endif /* HAVE_STRERROR */
126 /***********************************************************************
129 #ifndef HAVE_GETPAGESIZE
130 size_t getpagesize(void)
133 return sysconf(_SC_PAGESIZE
);
135 # error Cannot get the page size on this platform
138 #endif /* HAVE_GETPAGESIZE */
141 /***********************************************************************
144 #if !defined(HAVE_CLONE) && defined(__linux__)
145 int clone( int (*fn
)(void *), void *stack
, int flags
, void *arg
)
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"
155 "popl %%ebx\n\t" /* Contains fn in the child */
156 "testl %%eax,%%eax\n\t"
158 "xorl %ebp,%ebp\n\t" /* Terminate the stack frames */
159 "call *%%ebx\n\t" /* Should never return */
160 "xorl %%eax,%%eax\n\t" /* Just in case it does*/
163 : "0" (SYS_clone
), "r" (flags
), "c" (stack_ptr
) );
164 assert( ret
); /* If ret is 0, we returned from the child function */
165 if (ret
> 0) return ret
;
171 #endif /* __i386__ */
173 #endif /* !HAVE_CLONE && __linux__ */
175 /***********************************************************************
178 #ifndef HAVE_STRCASECMP
179 int strcasecmp( const char *str1
, const char *str2
)
181 const unsigned char *ustr1
= (const unsigned char *)str1
;
182 const unsigned char *ustr2
= (const unsigned char *)str2
;
184 while (*ustr1
&& toupper(*ustr1
) == toupper(*ustr2
)) {
188 return toupper(*ustr1
) - toupper(*ustr2
);
190 #endif /* HAVE_STRCASECMP */
192 /***********************************************************************
195 #ifndef HAVE_STRNCASECMP
196 int strncasecmp( const char *str1
, const char *str2
, size_t n
)
198 const unsigned char *ustr1
= (const unsigned char *)str1
;
199 const unsigned char *ustr2
= (const unsigned char *)str2
;
203 while ((--n
> 0) && *ustr1
) {
204 if ((res
= toupper(*ustr1
) - toupper(*ustr2
))) return res
;
208 return toupper(*ustr1
) - toupper(*ustr2
);
210 #endif /* HAVE_STRNCASECMP */
212 /***********************************************************************
215 #ifndef HAVE_GETNETBYADDR
216 struct netent
*getnetbyaddr(unsigned long net
, int type
)
221 #endif /* defined(HAVE_GETNETBYNAME) */
223 /***********************************************************************
226 #ifndef HAVE_GETNETBYNAME
227 struct netent
*getnetbyname(const char *name
)
232 #endif /* defined(HAVE_GETNETBYNAME) */
234 /***********************************************************************
237 #ifndef HAVE_GETPROTOBYNAME
238 struct protoent
*getprotobyname(const char *name
)
243 #endif /* !defined(HAVE_GETPROTOBYNAME) */
245 /***********************************************************************
248 #ifndef HAVE_GETPROTOBYNUMBER
249 struct protoent
*getprotobynumber(int proto
)
254 #endif /* !defined(HAVE_GETPROTOBYNUMBER) */
256 /***********************************************************************
259 #ifndef HAVE_GETSERVBYPORT
260 struct servent
*getservbyport(int port
, const char *proto
)
265 #endif /* !defined(HAVE_GETSERVBYPORT) */
267 /***********************************************************************
270 #ifndef HAVE_GETSOCKOPT
271 int getsockopt(int socket
, int level
, int option_name
,
272 void *option_value
, size_t *option_len
)
277 #endif /* !defined(HAVE_GETSOCKOPT) */
279 /***********************************************************************
282 #ifndef HAVE_INET_NETWORK
283 unsigned long inet_network(const char *cp
)
288 #endif /* defined(HAVE_INET_NETWORK) */
290 /***********************************************************************
294 int statfs(const char *name
, struct statfs
*info
)
305 if ((mydev
= dev_for_path(name
)) < 0) {
310 if (fs_stat_dev(mydev
,&fsinfo
) < 0) {
315 info
->f_bsize
= fsinfo
.block_size
;
316 info
->f_blocks
= fsinfo
.total_blocks
;
317 info
->f_bfree
= fsinfo
.free_blocks
;
319 #else /* defined(__BEOS__) */
322 #endif /* defined(__BEOS__) */
324 #endif /* !defined(HAVE_STATFS) */
327 /***********************************************************************
331 int lstat(const char *file_name
, struct stat
*buf
)
333 return stat( file_name
, buf
);
335 #endif /* HAVE_LSTAT */
338 /***********************************************************************
341 * FIXME: this is not thread-safe
344 ssize_t
pread( int fd
, void *buf
, size_t count
, off_t offset
)
349 if ((old_pos
= lseek( fd
, 0, SEEK_CUR
)) == -1) return -1;
350 if (lseek( fd
, offset
, SEEK_SET
) == -1) return -1;
351 if ((ret
= read( fd
, buf
, count
)) == -1)
353 int err
= errno
; /* save errno */
354 lseek( fd
, old_pos
, SEEK_SET
);
358 if (lseek( fd
, old_pos
, SEEK_SET
) == -1) return -1;
361 #endif /* HAVE_PREAD */
364 /***********************************************************************
367 * FIXME: this is not thread-safe
370 ssize_t
pwrite( int fd
, const void *buf
, size_t count
, off_t offset
)
375 if ((old_pos
= lseek( fd
, 0, SEEK_CUR
)) == -1) return -1;
376 if (lseek( fd
, offset
, SEEK_SET
) == -1) return -1;
377 if ((ret
= write( fd
, buf
, count
)) == -1)
379 int err
= errno
; /* save errno */
380 lseek( fd
, old_pos
, SEEK_SET
);
384 if (lseek( fd
, old_pos
, SEEK_SET
) == -1) return -1;
387 #endif /* HAVE_PWRITE */
390 #if defined(__svr4__) || defined(__NetBSD__)
391 /***********************************************************************
394 * The purpose of this routine is to emulate the behaviour of
395 * the Linux mmap() routine if a non-NULL address is passed,
396 * but the MAP_FIXED flag is not set. Linux in this case tries
397 * to place the mapping at the specified address, *unless* the
398 * range is already in use. Solaris, however, completely ignores
399 * the address argument in this case.
401 * As Wine code occasionally relies on the Linux behaviour, e.g. to
402 * be able to map non-relocateable PE executables to their proper
403 * start addresses, or to map the DOS memory to 0, this routine
404 * emulates the Linux behaviour by checking whether the desired
405 * address range is still available, and placing the mapping there
406 * using MAP_FIXED if so.
408 static int try_mmap_fixed (void *addr
, size_t len
, int prot
, int flags
,
409 int fildes
, off_t off
)
411 char * volatile result
= NULL
;
412 int pagesize
= getpagesize();
415 /* We only try to map to a fixed address if
416 addr is non-NULL and properly aligned,
417 and MAP_FIXED isn't already specified. */
421 if ( (uintptr_t)addr
& (pagesize
-1) )
423 if ( flags
& MAP_FIXED
)
426 /* We use vfork() to freeze all threads of the
427 current process. This allows us to check without
428 race condition whether the desired memory range is
429 already in use. Note that because vfork() shares
430 the address spaces between parent and child, we
431 can actually perform the mapping in the child. */
433 if ( (pid
= vfork()) == -1 )
435 perror("try_mmap_fixed: vfork");
443 /* We call mincore() for every page in the desired range.
444 If any of these calls succeeds, the page is already
445 mapped and we must fail. */
446 for ( i
= 0; i
< len
; i
+= pagesize
)
447 if ( mincore( (caddr_t
)addr
+ i
, pagesize
, &vec
) != -1 )
450 /* Perform the mapping with MAP_FIXED set. This is safe
451 now, as none of the pages is currently in use. */
452 result
= mmap( addr
, len
, prot
, flags
| MAP_FIXED
, fildes
, off
);
453 if ( result
== addr
)
456 if ( result
!= (void *) -1 ) /* This should never happen ... */
457 munmap( result
, len
);
462 /* vfork() lets the parent continue only after the child
463 has exited. Furthermore, Wine sets SIGCHLD to SIG_IGN,
464 so we don't need to wait for the child. */
466 return result
== addr
;
470 /***********************************************************************
473 * Portable wrapper for anonymous mmaps
475 void *wine_anon_mmap( void *start
, size_t size
, int prot
, int flags
)
477 static int fdzero
= -1;
484 if ((fdzero
= open( "/dev/zero", O_RDONLY
)) == -1)
486 perror( "/dev/zero: open" );
490 #endif /* MAP_ANON */
493 flags
&= ~MAP_SHARED
;
496 /* Linux EINVAL's on us if we don't pass MAP_PRIVATE to an anon mmap */
498 flags
|= MAP_PRIVATE
;
501 #if defined(__svr4__) || defined(__NetBSD__)
502 if ( try_mmap_fixed( start
, size
, prot
, flags
, fdzero
, 0 ) )
506 return mmap( start
, size
, prot
, flags
, fdzero
, 0 );
511 * These functions provide wrappers around dlopen() and associated
512 * functions. They work around a bug in glibc 2.1.x where calling
513 * a dl*() function after a previous dl*() function has failed
514 * without a dlerror() call between the two will cause a crash.
515 * They all take a pointer to a buffer that
516 * will receive the error description (from dlerror()). This
517 * parameter may be NULL if the error description is not required.
520 /***********************************************************************
523 void *wine_dlopen( const char *filename
, int flag
, char *error
, int errorsize
)
528 dlerror(); dlerror();
529 ret
= dlopen( filename
, flag
);
533 strncpy( error
, s
? s
: "", errorsize
);
534 error
[errorsize
- 1] = '\0';
541 strncpy( error
, "dlopen interface not detected by configure", errorsize
);
542 error
[errorsize
- 1] = '\0';
548 /***********************************************************************
551 void *wine_dlsym( void *handle
, const char *symbol
, char *error
, int errorsize
)
556 dlerror(); dlerror();
557 ret
= dlsym( handle
, symbol
);
561 strncpy( error
, s
? s
: "", errorsize
);
562 error
[errorsize
- 1] = '\0';
569 strncpy( error
, "dlopen interface not detected by configure", errorsize
);
570 error
[errorsize
- 1] = '\0';
576 /***********************************************************************
579 int wine_dlclose( void *handle
, char *error
, int errorsize
)
584 dlerror(); dlerror();
585 ret
= dlclose( handle
);
589 strncpy( error
, s
? s
: "", errorsize
);
590 error
[errorsize
- 1] = '\0';
597 strncpy( error
, "dlopen interface not detected by configure", errorsize
);
598 error
[errorsize
- 1] = '\0';
604 /***********************************************************************
605 * wine_rewrite_s4tos2
607 * Convert 4 byte Unicode strings to 2 byte Unicode strings in-place.
608 * This is only practical if literal strings are writable.
610 unsigned short* wine_rewrite_s4tos2(const wchar_t* str4
)
612 unsigned short *str2
,*s2
;
617 if ((*str4
& 0xffff0000) != 0) {
618 /* This string has already been converted. Return it as is */
619 return (unsigned short*)str4
;
622 /* Note that we can also end up here if the string has a single
623 * character. In such a case we will convert the string over and
624 * over again. But this is harmless.
626 str2
=s2
=(unsigned short*)str4
;
628 *s2
=(unsigned short)*str4
;
630 } while (*str4
++ != L
'\0');
637 * NetBSD 1.5 doesn't have ecvt, fcvt, gcvt. We just check for ecvt, though.
638 * Fix/verify these implementations !
641 /***********************************************************************
644 char *ecvt (double number
, int ndigits
, int *decpt
, int *sign
)
646 static char buf
[40]; /* ought to be enough */
648 sprintf(buf
, "%.*e", ndigits
/* FIXME wrong */, number
);
649 *sign
= (number
< 0);
650 dec
= strchr(buf
, '.');
651 *decpt
= (dec
) ? (int)dec
- (int)buf
: -1;
655 /***********************************************************************
658 char *fcvt (double number
, int ndigits
, int *decpt
, int *sign
)
660 static char buf
[40]; /* ought to be enough */
662 sprintf(buf
, "%.*e", ndigits
, number
);
663 *sign
= (number
< 0);
664 dec
= strchr(buf
, '.');
665 *decpt
= (dec
) ? (int)dec
- (int)buf
: -1;
669 /***********************************************************************
672 * FIXME: uses both E and F.
674 char *gcvt (double number
, size_t ndigit
, char *buff
)
676 sprintf(buff
, "%.*E", (int)ndigit
, number
);
679 #endif /* HAVE_ECVT */
682 /***********************************************************************
683 * interlocked functions
687 __ASM_GLOBAL_FUNC(interlocked_cmpxchg
,
688 "movl 12(%esp),%eax\n\t"
689 "movl 8(%esp),%ecx\n\t"
690 "movl 4(%esp),%edx\n\t"
691 "lock; cmpxchgl %ecx,(%edx)\n\t"
693 __ASM_GLOBAL_FUNC(interlocked_cmpxchg_ptr
,
694 "movl 12(%esp),%eax\n\t"
695 "movl 8(%esp),%ecx\n\t"
696 "movl 4(%esp),%edx\n\t"
697 "lock; cmpxchgl %ecx,(%edx)\n\t"
699 __ASM_GLOBAL_FUNC(interlocked_xchg
,
700 "movl 8(%esp),%eax\n\t"
701 "movl 4(%esp),%edx\n\t"
702 "lock; xchgl %eax,(%edx)\n\t"
704 __ASM_GLOBAL_FUNC(interlocked_xchg_ptr
,
705 "movl 8(%esp),%eax\n\t"
706 "movl 4(%esp),%edx\n\t"
707 "lock; xchgl %eax,(%edx)\n\t"
709 __ASM_GLOBAL_FUNC(interlocked_xchg_add
,
710 "movl 8(%esp),%eax\n\t"
711 "movl 4(%esp),%edx\n\t"
712 "lock; xaddl %eax,(%edx)\n\t"
715 #elif defined(__sparc__) && defined(__sun__)
718 * As the earlier Sparc processors lack necessary atomic instructions,
719 * I'm simply falling back to the library-provided _lwp_mutex routines
720 * to ensure mutual exclusion in a way appropriate for the current
723 * FIXME: If we have the compare-and-swap instruction (Sparc v9 and above)
724 * we could use this to speed up the Interlocked operations ...
727 static lwp_mutex_t interlocked_mutex
= DEFAULTMUTEX
;
729 long interlocked_cmpxchg( long *dest
, long xchg
, long compare
)
731 _lwp_mutex_lock( &interlocked_mutex
);
732 if (*dest
== compare
) *dest
= xchg
;
733 else compare
= *dest
;
734 _lwp_mutex_unlock( &interlocked_mutex
);
738 void *interlocked_cmpxchg_ptr( void **dest
, void *xchg
, void *compare
)
740 _lwp_mutex_lock( &interlocked_mutex
);
741 if (*dest
== compare
) *dest
= xchg
;
742 else compare
= *dest
;
743 _lwp_mutex_unlock( &interlocked_mutex
);
747 long interlocked_xchg( long *dest
, long val
)
750 _lwp_mutex_lock( &interlocked_mutex
);
753 _lwp_mutex_unlock( &interlocked_mutex
);
757 void *interlocked_xchg_ptr( void **dest
, void *val
)
760 _lwp_mutex_lock( &interlocked_mutex
);
763 _lwp_mutex_unlock( &interlocked_mutex
);
767 long interlocked_xchg_add( long *dest
, long incr
)
770 _lwp_mutex_lock( &interlocked_mutex
);
773 _lwp_mutex_unlock( &interlocked_mutex
);
778 # error You must implement the interlocked* functions for your CPU