Now C tests are able to access argc/argv as passed to the program.
[wine.git] / library / port.c
blob9d46554b3f8a1a377b9abff48c7ab27b717f82e0
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 #include <sys/ioctl.h>
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <termios.h>
47 #ifdef HAVE_SYS_MMAN_H
48 #include <sys/mman.h>
49 #endif
50 #ifdef HAVE_LIBIO_H
51 # include <libio.h>
52 #endif
53 #ifdef HAVE_SYSCALL_H
54 # include <syscall.h>
55 #endif
56 #ifdef HAVE_STDINT_H
57 # include <stdint.h>
58 #endif
60 /***********************************************************************
61 * usleep
63 #ifndef HAVE_USLEEP
64 unsigned int usleep (unsigned int useconds)
66 #if defined(__EMX__)
67 DosSleep(useconds);
68 return 0;
69 #elif defined(__BEOS__)
70 return snooze(useconds);
71 #elif defined(HAVE_SELECT)
72 struct timeval delay;
74 delay.tv_sec = useconds / 1000000;
75 delay.tv_usec = useconds % 1000000;
77 select( 0, 0, 0, 0, &delay );
78 return 0;
79 #else /* defined(__EMX__) || defined(__BEOS__) || defined(HAVE_SELECT) */
80 errno = ENOSYS;
81 return -1;
82 #endif /* defined(__EMX__) || defined(__BEOS__) || defined(HAVE_SELECT) */
84 #endif /* HAVE_USLEEP */
86 /***********************************************************************
87 * memmove
89 #ifndef HAVE_MEMMOVE
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) */
100 else if (dst < src)
102 while (len--) *dst++ = *((char *)src)++;
104 else
106 dst += len - 1;
107 src = (char *)src + len - 1;
108 while (len--) *dst-- = *((char *)src)--;
110 return dest;
112 #endif /* HAVE_MEMMOVE */
114 /***********************************************************************
115 * strerror
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 /***********************************************************************
127 * getpagesize
129 #ifndef HAVE_GETPAGESIZE
130 size_t getpagesize(void)
132 # ifdef __svr4__
133 return sysconf(_SC_PAGESIZE);
134 # else
135 # error Cannot get the page size on this platform
136 # endif
138 #endif /* HAVE_GETPAGESIZE */
141 /***********************************************************************
142 * clone
144 #if !defined(HAVE_CLONE) && defined(__linux__)
145 int clone( int (*fn)(void *), void *stack, int flags, void *arg )
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"
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*/
161 "0:"
162 : "=a" (ret)
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;
166 errno = -ret;
167 return -1;
168 #else
169 errno = EINVAL;
170 return -1;
171 #endif /* __i386__ */
173 #endif /* !HAVE_CLONE && __linux__ */
175 /***********************************************************************
176 * strcasecmp
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)) {
185 ustr1++;
186 ustr2++;
188 return toupper(*ustr1) - toupper(*ustr2);
190 #endif /* HAVE_STRCASECMP */
192 /***********************************************************************
193 * strncasecmp
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;
200 int res;
202 if (!n) return 0;
203 while ((--n > 0) && *ustr1) {
204 if ((res = toupper(*ustr1) - toupper(*ustr2))) return res;
205 ustr1++;
206 ustr2++;
208 return toupper(*ustr1) - toupper(*ustr2);
210 #endif /* HAVE_STRNCASECMP */
212 /***********************************************************************
213 * openpty
214 * 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.
219 * FIXME
220 * We should have a autoconf check for this.
222 #ifndef HAVE_OPENPTY
223 int openpty(int *master, int *slave, char *name, struct termios *term, struct winsize *winsize)
225 const char *ptr1, *ptr2;
226 char pts_name[512];
228 strcpy (pts_name, "/dev/ptyXY");
230 for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1 != 0; ptr1++) {
231 pts_name[8] = *ptr1;
232 for (ptr2 = "0123456789abcdef"; *ptr2 != 0; ptr2++) {
233 pts_name[9] = *ptr2;
235 if ((*master = open(pts_name, O_RDWR)) < 0) {
236 if (errno == ENOENT)
237 return -1;
238 else
239 continue;
241 pts_name[5] = 't';
242 if ((*slave = open(pts_name, O_RDWR)) < 0) {
243 pts_name[5] = 'p';
244 close (*master);
245 continue;
248 if (term != NULL)
249 tcsetattr(*slave, TCSANOW, term);
250 if (winsize != NULL)
251 ioctl(*slave, TIOCSWINSZ, winsize);
252 if (name != NULL)
253 strcpy(name, pts_name);
254 return *slave;
257 errno = EMFILE;
258 return -1;
260 #endif /* HAVE_OPENPTY */
262 /***********************************************************************
263 * getnetbyaddr
265 #ifndef HAVE_GETNETBYADDR
266 struct netent *getnetbyaddr(unsigned long net, int type)
268 errno = ENOSYS;
269 return NULL;
271 #endif /* defined(HAVE_GETNETBYNAME) */
273 /***********************************************************************
274 * getnetbyname
276 #ifndef HAVE_GETNETBYNAME
277 struct netent *getnetbyname(const char *name)
279 errno = ENOSYS;
280 return NULL;
282 #endif /* defined(HAVE_GETNETBYNAME) */
284 /***********************************************************************
285 * getprotobyname
287 #ifndef HAVE_GETPROTOBYNAME
288 struct protoent *getprotobyname(const char *name)
290 errno = ENOSYS;
291 return NULL;
293 #endif /* !defined(HAVE_GETPROTOBYNAME) */
295 /***********************************************************************
296 * getprotobynumber
298 #ifndef HAVE_GETPROTOBYNUMBER
299 struct protoent *getprotobynumber(int proto)
301 errno = ENOSYS;
302 return NULL;
304 #endif /* !defined(HAVE_GETPROTOBYNUMBER) */
306 /***********************************************************************
307 * getservbyport
309 #ifndef HAVE_GETSERVBYPORT
310 struct servent *getservbyport(int port, const char *proto)
312 errno = ENOSYS;
313 return NULL;
315 #endif /* !defined(HAVE_GETSERVBYPORT) */
317 /***********************************************************************
318 * getsockopt
320 #ifndef HAVE_GETSOCKOPT
321 int getsockopt(int socket, int level, int option_name,
322 void *option_value, size_t *option_len)
324 errno = ENOSYS;
325 return -1;
327 #endif /* !defined(HAVE_GETSOCKOPT) */
329 /***********************************************************************
330 * inet_network
332 #ifndef HAVE_INET_NETWORK
333 unsigned long inet_network(const char *cp)
335 errno = ENOSYS;
336 return 0;
338 #endif /* defined(HAVE_INET_NETWORK) */
340 /***********************************************************************
341 * statfs
343 #ifndef HAVE_STATFS
344 int statfs(const char *name, struct statfs *info)
346 #ifdef __BEOS__
347 dev_t mydev;
348 fs_info fsinfo;
350 if(!info) {
351 errno = ENOSYS;
352 return -1;
355 if ((mydev = dev_for_path(name)) < 0) {
356 errno = ENOSYS;
357 return -1;
360 if (fs_stat_dev(mydev,&fsinfo) < 0) {
361 errno = ENOSYS;
362 return -1;
365 info->f_bsize = fsinfo.block_size;
366 info->f_blocks = fsinfo.total_blocks;
367 info->f_bfree = fsinfo.free_blocks;
368 return 0;
369 #else /* defined(__BEOS__) */
370 errno = ENOSYS;
371 return -1;
372 #endif /* defined(__BEOS__) */
374 #endif /* !defined(HAVE_STATFS) */
377 /***********************************************************************
378 * lstat
380 #ifndef HAVE_LSTAT
381 int lstat(const char *file_name, struct stat *buf)
383 return stat( file_name, buf );
385 #endif /* HAVE_LSTAT */
388 /***********************************************************************
389 * pread
391 * FIXME: this is not thread-safe
393 #ifndef HAVE_PREAD
394 ssize_t pread( int fd, void *buf, size_t count, off_t offset )
396 ssize_t ret;
397 off_t old_pos;
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)
403 int err = errno; /* save errno */
404 lseek( fd, old_pos, SEEK_SET );
405 errno = err;
406 return -1;
408 if (lseek( fd, old_pos, SEEK_SET ) == -1) return -1;
409 return ret;
411 #endif /* HAVE_PREAD */
414 /***********************************************************************
415 * pwrite
417 * FIXME: this is not thread-safe
419 #ifndef HAVE_PWRITE
420 ssize_t pwrite( int fd, const void *buf, size_t count, off_t offset )
422 ssize_t ret;
423 off_t old_pos;
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)
429 int err = errno; /* save errno */
430 lseek( fd, old_pos, SEEK_SET );
431 errno = err;
432 return -1;
434 if (lseek( fd, old_pos, SEEK_SET ) == -1) return -1;
435 return ret;
437 #endif /* HAVE_PWRITE */
440 /***********************************************************************
441 * getrlimit
443 #ifndef HAVE_GETRLIMIT
444 int getrlimit (int resource, struct rlimit *rlim)
446 return -1; /* FAIL */
448 #endif /* HAVE_GETRLIMIT */
451 #if defined(__svr4__) || defined(__NetBSD__)
452 /***********************************************************************
453 * try_mmap_fixed
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.
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.
469 static int try_mmap_fixed (void *addr, size_t len, int prot, int flags,
470 int fildes, off_t off)
472 char * volatile result = NULL;
473 int pagesize = getpagesize();
474 pid_t pid;
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. */
480 if ( !addr )
481 return 0;
482 if ( (uintptr_t)addr & (pagesize-1) )
483 return 0;
484 if ( flags & MAP_FIXED )
485 return 0;
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. */
494 if ( (pid = vfork()) == -1 )
496 perror("try_mmap_fixed: vfork");
497 exit(1);
499 if ( pid == 0 )
501 int i;
502 char vec;
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);
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);
517 if ( result != (void *) -1 ) /* This should never happen ... */
518 munmap( result, len );
520 _exit(1);
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. */
527 return result == addr;
529 #endif
531 /***********************************************************************
532 * wine_anon_mmap
534 * Portable wrapper for anonymous mmaps
536 void *wine_anon_mmap( void *start, size_t size, int prot, int flags )
538 static int fdzero = -1;
540 #ifdef MAP_ANON
541 flags |= MAP_ANON;
542 #else
543 if (fdzero == -1)
545 if ((fdzero = open( "/dev/zero", O_RDONLY )) == -1)
547 perror( "/dev/zero: open" );
548 exit(1);
551 #endif /* MAP_ANON */
553 #ifdef MAP_SHARED
554 flags &= ~MAP_SHARED;
555 #endif
557 /* Linux EINVAL's on us if we don't pass MAP_PRIVATE to an anon mmap */
558 #ifdef MAP_PRIVATE
559 flags |= MAP_PRIVATE;
560 #endif
562 #if defined(__svr4__) || defined(__NetBSD__)
563 if ( try_mmap_fixed( start, size, prot, flags, fdzero, 0 ) )
564 return start;
565 #endif
567 return mmap( start, size, prot, flags, fdzero, 0 );
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.
581 /***********************************************************************
582 * wine_dlopen
584 void *wine_dlopen( const char *filename, int flag, char *error, int errorsize )
586 #ifdef HAVE_DLOPEN
587 void *ret;
588 const char *s;
589 dlerror(); dlerror();
590 ret = dlopen( filename, flag );
591 s = dlerror();
592 if (error)
594 strncpy( error, s ? s : "", errorsize );
595 error[errorsize - 1] = '\0';
597 dlerror();
598 return ret;
599 #else
600 if (error)
602 strncpy( error, "dlopen interface not detected by configure", errorsize );
603 error[errorsize - 1] = '\0';
605 return NULL;
606 #endif
609 /***********************************************************************
610 * wine_dlsym
612 void *wine_dlsym( void *handle, const char *symbol, char *error, int errorsize )
614 #ifdef HAVE_DLOPEN
615 void *ret;
616 const char *s;
617 dlerror(); dlerror();
618 ret = dlsym( handle, symbol );
619 s = dlerror();
620 if (error)
622 strncpy( error, s ? s : "", errorsize );
623 error[errorsize - 1] = '\0';
625 dlerror();
626 return ret;
627 #else
628 if (error)
630 strncpy( error, "dlopen interface not detected by configure", errorsize );
631 error[errorsize - 1] = '\0';
633 return NULL;
634 #endif
637 /***********************************************************************
638 * wine_dlclose
640 int wine_dlclose( void *handle, char *error, int errorsize )
642 #ifdef HAVE_DLOPEN
643 int ret;
644 const char *s;
645 dlerror(); dlerror();
646 ret = dlclose( handle );
647 s = dlerror();
648 if (error)
650 strncpy( error, s ? s : "", errorsize );
651 error[errorsize - 1] = '\0';
653 dlerror();
654 return ret;
655 #else
656 if (error)
658 strncpy( error, "dlopen interface not detected by configure", errorsize );
659 error[errorsize - 1] = '\0';
661 return 1;
662 #endif
665 /***********************************************************************
666 * wine_rewrite_s4tos2
668 * Convert 4 byte Unicode strings to 2 byte Unicode strings in-place.
669 * This is only practical if literal strings are writable.
671 unsigned short* wine_rewrite_s4tos2(const wchar_t* str4 )
673 unsigned short *str2,*s2;
675 if (str4==NULL)
676 return NULL;
678 if ((*str4 & 0xffff0000) != 0) {
679 /* This string has already been converted. Return it as is */
680 return (unsigned short*)str4;
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.
687 str2=s2=(unsigned short*)str4;
688 do {
689 *s2=(unsigned short)*str4;
690 s2++;
691 } while (*str4++ != L'\0');
693 return str2;
696 #ifndef HAVE_ECVT
698 * NetBSD 1.5 doesn't have ecvt, fcvt, gcvt. We just check for ecvt, though.
699 * Fix/verify these implementations !
702 /***********************************************************************
703 * ecvt
705 char *ecvt (double number, int ndigits, int *decpt, int *sign)
707 static char buf[40]; /* ought to be enough */
708 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;
716 /***********************************************************************
717 * fcvt
719 char *fcvt (double number, int ndigits, int *decpt, int *sign)
721 static char buf[40]; /* ought to be enough */
722 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;
730 /***********************************************************************
731 * gcvt
733 * FIXME: uses both E and F.
735 char *gcvt (double number, size_t ndigit, char *buff)
737 sprintf(buff, "%.*E", (int)ndigit, number);
738 return buff;
740 #endif /* HAVE_ECVT */