Added version info to 16-bit shell.dll.
[wine/multimedia.git] / library / port.c
blobdef94694d34f660c58088383110df16e918b24d4
1 /*
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
21 #include "config.h"
22 #include "wine/port.h"
24 #ifdef __BEOS__
25 #include <be/kernel/fs_info.h>
26 #include <be/kernel/OS.h>
27 #endif
29 #include <assert.h>
30 #include <ctype.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35 #include <sys/types.h>
36 #ifdef HAVE_SYS_INTTYPES_H
37 # include <sys/inttypes.h>
38 #endif
39 #ifdef HAVE_SYS_TIME_h
40 # include <sys/time.h>
41 #endif
42 #include <sys/stat.h>
43 #ifdef HAVE_SYS_IOCTL_H
44 #include <sys/ioctl.h>
45 #endif
46 #include <errno.h>
47 #include <fcntl.h>
48 #ifdef HAVE_TERMIOS_H
49 #include <termios.h>
50 #endif
51 #ifdef HAVE_SYS_MMAN_H
52 #include <sys/mman.h>
53 #endif
54 #ifdef HAVE_LIBIO_H
55 # include <libio.h>
56 #endif
57 #ifdef HAVE_SYSCALL_H
58 # include <syscall.h>
59 #endif
60 #ifdef HAVE_STDINT_H
61 # include <stdint.h>
62 #endif
64 /***********************************************************************
65 * usleep
67 #ifndef HAVE_USLEEP
68 int usleep (unsigned int useconds)
70 #if defined(__EMX__)
71 DosSleep(useconds);
72 return 0;
73 #elif defined(__BEOS__)
74 return snooze(useconds);
75 #elif defined(HAVE_SELECT)
76 struct timeval delay;
78 delay.tv_sec = useconds / 1000000;
79 delay.tv_usec = useconds % 1000000;
81 select( 0, 0, 0, 0, &delay );
82 return 0;
83 #else /* defined(__EMX__) || defined(__BEOS__) || defined(HAVE_SELECT) */
84 errno = ENOSYS;
85 return -1;
86 #endif /* defined(__EMX__) || defined(__BEOS__) || defined(HAVE_SELECT) */
88 #endif /* HAVE_USLEEP */
90 /***********************************************************************
91 * memmove
93 #ifndef HAVE_MEMMOVE
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) */
104 else if (dst < src)
106 while (len--) *dst++ = *((char *)src)++;
108 else
110 dst += len - 1;
111 src = (char *)src + len - 1;
112 while (len--) *dst-- = *((char *)src)--;
114 return dest;
116 #endif /* HAVE_MEMMOVE */
118 /***********************************************************************
119 * strerror
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 /***********************************************************************
131 * getpagesize
133 #ifndef HAVE_GETPAGESIZE
134 size_t getpagesize(void)
136 # ifdef __svr4__
137 return sysconf(_SC_PAGESIZE);
138 # elif defined(__i386__)
139 return 4096;
140 # else
141 # error Cannot get the page size on this platform
142 # endif
144 #endif /* HAVE_GETPAGESIZE */
147 /***********************************************************************
148 * clone
150 #if !defined(HAVE_CLONE) && defined(__linux__)
151 int clone( int (*fn)(void *), void *stack, int flags, void *arg )
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"
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*/
167 "0:"
168 : "=a" (ret)
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;
172 errno = -ret;
173 return -1;
174 #else
175 errno = EINVAL;
176 return -1;
177 #endif /* __i386__ */
179 #endif /* !HAVE_CLONE && __linux__ */
181 /***********************************************************************
182 * strcasecmp
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)) {
191 ustr1++;
192 ustr2++;
194 return toupper(*ustr1) - toupper(*ustr2);
196 #endif /* HAVE_STRCASECMP */
198 /***********************************************************************
199 * strncasecmp
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;
206 int res;
208 if (!n) return 0;
209 while ((--n > 0) && *ustr1) {
210 if ((res = toupper(*ustr1) - toupper(*ustr2))) return res;
211 ustr1++;
212 ustr2++;
214 return toupper(*ustr1) - toupper(*ustr2);
216 #endif /* HAVE_STRNCASECMP */
218 /***********************************************************************
219 * getnetbyaddr
221 #ifndef HAVE_GETNETBYADDR
222 struct netent *getnetbyaddr(unsigned long net, int type)
224 errno = ENOSYS;
225 return NULL;
227 #endif /* defined(HAVE_GETNETBYNAME) */
229 /***********************************************************************
230 * getnetbyname
232 #ifndef HAVE_GETNETBYNAME
233 struct netent *getnetbyname(const char *name)
235 errno = ENOSYS;
236 return NULL;
238 #endif /* defined(HAVE_GETNETBYNAME) */
240 /***********************************************************************
241 * getprotobyname
243 #ifndef HAVE_GETPROTOBYNAME
244 struct protoent *getprotobyname(const char *name)
246 errno = ENOSYS;
247 return NULL;
249 #endif /* !defined(HAVE_GETPROTOBYNAME) */
251 /***********************************************************************
252 * getprotobynumber
254 #ifndef HAVE_GETPROTOBYNUMBER
255 struct protoent *getprotobynumber(int proto)
257 errno = ENOSYS;
258 return NULL;
260 #endif /* !defined(HAVE_GETPROTOBYNUMBER) */
262 /***********************************************************************
263 * getservbyport
265 #ifndef HAVE_GETSERVBYPORT
266 struct servent *getservbyport(int port, const char *proto)
268 errno = ENOSYS;
269 return NULL;
271 #endif /* !defined(HAVE_GETSERVBYPORT) */
273 /***********************************************************************
274 * getsockopt
276 #ifndef HAVE_GETSOCKOPT
277 int getsockopt(int socket, int level, int option_name,
278 void *option_value, size_t *option_len)
280 errno = ENOSYS;
281 return -1;
283 #endif /* !defined(HAVE_GETSOCKOPT) */
285 /***********************************************************************
286 * inet_network
288 #ifndef HAVE_INET_NETWORK
289 unsigned long inet_network(const char *cp)
291 errno = ENOSYS;
292 return 0;
294 #endif /* defined(HAVE_INET_NETWORK) */
296 /***********************************************************************
297 * statfs
299 #ifndef HAVE_STATFS
300 int statfs(const char *name, struct statfs *info)
302 #ifdef __BEOS__
303 dev_t mydev;
304 fs_info fsinfo;
306 if(!info) {
307 errno = ENOSYS;
308 return -1;
311 if ((mydev = dev_for_path(name)) < 0) {
312 errno = ENOSYS;
313 return -1;
316 if (fs_stat_dev(mydev,&fsinfo) < 0) {
317 errno = ENOSYS;
318 return -1;
321 info->f_bsize = fsinfo.block_size;
322 info->f_blocks = fsinfo.total_blocks;
323 info->f_bfree = fsinfo.free_blocks;
324 return 0;
325 #else /* defined(__BEOS__) */
326 errno = ENOSYS;
327 return -1;
328 #endif /* defined(__BEOS__) */
330 #endif /* !defined(HAVE_STATFS) */
333 /***********************************************************************
334 * lstat
336 #ifndef HAVE_LSTAT
337 int lstat(const char *file_name, struct stat *buf)
339 return stat( file_name, buf );
341 #endif /* HAVE_LSTAT */
344 /***********************************************************************
345 * pread
347 * FIXME: this is not thread-safe
349 #ifndef HAVE_PREAD
350 ssize_t pread( int fd, void *buf, size_t count, off_t offset )
352 ssize_t ret;
353 off_t old_pos;
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 );
361 errno = err;
362 return -1;
364 if (lseek( fd, old_pos, SEEK_SET ) == -1) return -1;
365 return ret;
367 #endif /* HAVE_PREAD */
370 /***********************************************************************
371 * pwrite
373 * FIXME: this is not thread-safe
375 #ifndef HAVE_PWRITE
376 ssize_t pwrite( int fd, const void *buf, size_t count, off_t offset )
378 ssize_t ret;
379 off_t old_pos;
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 );
387 errno = err;
388 return -1;
390 if (lseek( fd, old_pos, SEEK_SET ) == -1) return -1;
391 return ret;
393 #endif /* HAVE_PWRITE */
396 #if defined(__svr4__) || defined(__NetBSD__)
397 /***********************************************************************
398 * try_mmap_fixed
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();
419 pid_t pid;
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. */
425 if ( !addr )
426 return 0;
427 if ( (uintptr_t)addr & (pagesize-1) )
428 return 0;
429 if ( flags & MAP_FIXED )
430 return 0;
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");
442 exit(1);
444 if ( pid == 0 )
446 int i;
447 char vec;
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 )
454 _exit(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 )
460 _exit(0);
462 if ( result != (void *) -1 ) /* This should never happen ... */
463 munmap( result, len );
465 _exit(1);
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;
474 #endif
476 /***********************************************************************
477 * wine_anon_mmap
479 * Portable wrapper for anonymous mmaps
481 void *wine_anon_mmap( void *start, size_t size, int prot, int flags )
483 #ifdef HAVE_MMAP
484 static int fdzero = -1;
486 #ifdef MAP_ANON
487 flags |= MAP_ANON;
488 #else
489 if (fdzero == -1)
491 if ((fdzero = open( "/dev/zero", O_RDONLY )) == -1)
493 perror( "/dev/zero: open" );
494 exit(1);
497 #endif /* MAP_ANON */
499 #ifdef MAP_SHARED
500 flags &= ~MAP_SHARED;
501 #endif
503 /* Linux EINVAL's on us if we don't pass MAP_PRIVATE to an anon mmap */
504 #ifdef MAP_PRIVATE
505 flags |= MAP_PRIVATE;
506 #endif
508 #if defined(__svr4__) || defined(__NetBSD__)
509 if ( try_mmap_fixed( start, size, prot, flags, fdzero, 0 ) )
510 return start;
511 #endif
513 return mmap( start, size, prot, flags, fdzero, 0 );
514 #else
515 return (void *)-1;
516 #endif
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 /***********************************************************************
531 * wine_dlopen
533 void *wine_dlopen( const char *filename, int flag, char *error, int errorsize )
535 #ifdef HAVE_DLOPEN
536 void *ret;
537 const char *s;
538 dlerror(); dlerror();
539 ret = dlopen( filename, flag );
540 s = dlerror();
541 if (error)
543 strncpy( error, s ? s : "", errorsize );
544 error[errorsize - 1] = '\0';
546 dlerror();
547 return ret;
548 #else
549 if (error)
551 strncpy( error, "dlopen interface not detected by configure", errorsize );
552 error[errorsize - 1] = '\0';
554 return NULL;
555 #endif
558 /***********************************************************************
559 * wine_dlsym
561 void *wine_dlsym( void *handle, const char *symbol, char *error, int errorsize )
563 #ifdef HAVE_DLOPEN
564 void *ret;
565 const char *s;
566 dlerror(); dlerror();
567 ret = dlsym( handle, symbol );
568 s = dlerror();
569 if (error)
571 strncpy( error, s ? s : "", errorsize );
572 error[errorsize - 1] = '\0';
574 dlerror();
575 return ret;
576 #else
577 if (error)
579 strncpy( error, "dlopen interface not detected by configure", errorsize );
580 error[errorsize - 1] = '\0';
582 return NULL;
583 #endif
586 /***********************************************************************
587 * wine_dlclose
589 int wine_dlclose( void *handle, char *error, int errorsize )
591 #ifdef HAVE_DLOPEN
592 int ret;
593 const char *s;
594 dlerror(); dlerror();
595 ret = dlclose( handle );
596 s = dlerror();
597 if (error)
599 strncpy( error, s ? s : "", errorsize );
600 error[errorsize - 1] = '\0';
602 dlerror();
603 return ret;
604 #else
605 if (error)
607 strncpy( error, "dlopen interface not detected by configure", errorsize );
608 error[errorsize - 1] = '\0';
610 return 1;
611 #endif
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;
624 if (str4==NULL)
625 return NULL;
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;
637 do {
638 *s2=(unsigned short)*str4;
639 s2++;
640 } while (*str4++ != L'\0');
642 return str2;
645 #ifndef HAVE_ECVT
647 * NetBSD 1.5 doesn't have ecvt, fcvt, gcvt. We just check for ecvt, though.
648 * Fix/verify these implementations !
651 /***********************************************************************
652 * ecvt
654 char *ecvt (double number, int ndigits, int *decpt, int *sign)
656 static char buf[40]; /* ought to be enough */
657 char *dec;
658 sprintf(buf, "%.*e", ndigits /* FIXME wrong */, number);
659 *sign = (number < 0);
660 dec = strchr(buf, '.');
661 *decpt = (dec) ? (int)dec - (int)buf : -1;
662 return buf;
665 /***********************************************************************
666 * fcvt
668 char *fcvt (double number, int ndigits, int *decpt, int *sign)
670 static char buf[40]; /* ought to be enough */
671 char *dec;
672 sprintf(buf, "%.*e", ndigits, number);
673 *sign = (number < 0);
674 dec = strchr(buf, '.');
675 *decpt = (dec) ? (int)dec - (int)buf : -1;
676 return buf;
679 /***********************************************************************
680 * gcvt
682 * FIXME: uses both E and F.
684 char *gcvt (double number, size_t ndigit, char *buff)
686 sprintf(buff, "%.*E", (int)ndigit, number);
687 return buff;
689 #endif /* HAVE_ECVT */
692 /***********************************************************************
693 * interlocked functions
695 #ifdef __i386__
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"
702 "ret");
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"
708 "ret");
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"
713 "ret");
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"
718 "ret");
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"
723 "ret");
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
731 * architecture.
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 ...
736 #include <synch.h>
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 );
745 return compare;
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 );
754 return compare;
757 long interlocked_xchg( long *dest, long val )
759 long retv;
760 _lwp_mutex_lock( &interlocked_mutex );
761 retv = *dest;
762 *dest = val;
763 _lwp_mutex_unlock( &interlocked_mutex );
764 return retv;
767 void *interlocked_xchg_ptr( void **dest, void *val )
769 long retv;
770 _lwp_mutex_lock( &interlocked_mutex );
771 retv = *dest;
772 *dest = val;
773 _lwp_mutex_unlock( &interlocked_mutex );
774 return retv;
777 long interlocked_xchg_add( long *dest, long incr )
779 long retv;
780 _lwp_mutex_lock( &interlocked_mutex );
781 retv = *dest;
782 *dest += incr;
783 _lwp_mutex_unlock( &interlocked_mutex );
784 return retv;
787 #else
788 # error You must implement the interlocked* functions for your CPU
789 #endif