Fixed bugs in safe arrays.
[wine/gsoc_dplay.git] / library / port.c
blobd2c2c1bbe6554522f6c7cfd839937d356b2b3204
1 /*
2 * Misc. functions for systems that don't have them
4 * Copyright 1996 Alexandre Julliard
5 */
7 #include "config.h"
8 #include "wine/port.h"
10 #ifdef __BEOS__
11 #include <be/kernel/fs_info.h>
12 #include <be/kernel/OS.h>
13 #endif
15 #include <assert.h>
16 #include <ctype.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <sys/types.h>
22 #include <sys/time.h>
23 #include <sys/stat.h>
24 #include <sys/ioctl.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <termios.h>
28 #ifdef HAVE_SYS_MMAN_H
29 #include <sys/mman.h>
30 #endif
31 #ifdef HAVE_LIBIO_H
32 # include <libio.h>
33 #endif
34 #ifdef HAVE_SYSCALL_H
35 # include <syscall.h>
36 #endif
37 #ifdef HAVE_PTY_H
38 # include <pty.h>
39 #endif
40 #ifdef HAVE_LIBUTIL_H
41 # include <libutil.h>
42 #endif
45 /***********************************************************************
46 * usleep
48 #ifndef HAVE_USLEEP
49 unsigned int usleep (unsigned int useconds)
51 #if defined(__EMX__)
52 DosSleep(useconds);
53 return 0;
54 #elif defined(__BEOS__)
55 return snooze(useconds);
56 #elif defined(HAVE_SELECT)
57 struct timeval delay;
59 delay.tv_sec = useconds / 1000000;
60 delay.tv_usec = useconds % 1000000;
62 select( 0, 0, 0, 0, &delay );
63 return 0;
64 #else /* defined(__EMX__) || defined(__BEOS__) || defined(HAVE_SELECT) */
65 errno = ENOSYS;
66 return -1;
67 #endif /* defined(__EMX__) || defined(__BEOS__) || defined(HAVE_SELECT) */
69 #endif /* HAVE_USLEEP */
71 /***********************************************************************
72 * memmove
74 #ifndef HAVE_MEMMOVE
75 void *memmove( void *dest, const void *src, unsigned int len )
77 register char *dst = dest;
79 /* Use memcpy if not overlapping */
80 if ((dst + len <= (char *)src) || ((char *)src + len <= dst))
82 memcpy( dst, src, len );
84 /* Otherwise do it the hard way (FIXME: could do better than this) */
85 else if (dst < src)
87 while (len--) *dst++ = *((char *)src)++;
89 else
91 dst += len - 1;
92 src = (char *)src + len - 1;
93 while (len--) *dst-- = *((char *)src)--;
95 return dest;
97 #endif /* HAVE_MEMMOVE */
99 /***********************************************************************
100 * strerror
102 #ifndef HAVE_STRERROR
103 const char *strerror( int err )
105 /* Let's hope we have sys_errlist then */
106 return sys_errlist[err];
108 #endif /* HAVE_STRERROR */
111 /***********************************************************************
112 * getpagesize
114 #ifndef HAVE_GETPAGESIZE
115 size_t getpagesize(void)
117 # ifdef __svr4__
118 return sysconf(_SC_PAGESIZE);
119 # else
120 # error Cannot get the page size on this platform
121 # endif
123 #endif /* HAVE_GETPAGESIZE */
126 /***********************************************************************
127 * clone
129 #if !defined(HAVE_CLONE) && defined(__linux__)
130 int clone( int (*fn)(void *), void *stack, int flags, void *arg )
132 #ifdef __i386__
133 int ret;
134 void **stack_ptr = (void **)stack;
135 *--stack_ptr = arg; /* Push argument on stack */
136 *--stack_ptr = fn; /* Push function pointer (popped into ebx) */
137 __asm__ __volatile__( "pushl %%ebx\n\t"
138 "movl %2,%%ebx\n\t"
139 "int $0x80\n\t"
140 "popl %%ebx\n\t" /* Contains fn in the child */
141 "testl %%eax,%%eax\n\t"
142 "jnz 0f\n\t"
143 "xorl %ebp,%ebp\n\t" /* Terminate the stack frames */
144 "call *%%ebx\n\t" /* Should never return */
145 "xorl %%eax,%%eax\n\t" /* Just in case it does*/
146 "0:"
147 : "=a" (ret)
148 : "0" (SYS_clone), "r" (flags), "c" (stack_ptr) );
149 assert( ret ); /* If ret is 0, we returned from the child function */
150 if (ret > 0) return ret;
151 errno = -ret;
152 return -1;
153 #else
154 errno = EINVAL;
155 return -1;
156 #endif /* __i386__ */
158 #endif /* !HAVE_CLONE && __linux__ */
160 /***********************************************************************
161 * strcasecmp
163 #ifndef HAVE_STRCASECMP
164 int strcasecmp( const char *str1, const char *str2 )
166 const unsigned char *ustr1 = (const unsigned char *)str1;
167 const unsigned char *ustr2 = (const unsigned char *)str2;
169 while (*ustr1 && toupper(*ustr1) == toupper(*ustr2)) {
170 ustr1++;
171 ustr2++;
173 return toupper(*ustr1) - toupper(*ustr2);
175 #endif /* HAVE_STRCASECMP */
177 /***********************************************************************
178 * strncasecmp
180 #ifndef HAVE_STRNCASECMP
181 int strncasecmp( const char *str1, const char *str2, size_t n )
183 const unsigned char *ustr1 = (const unsigned char *)str1;
184 const unsigned char *ustr2 = (const unsigned char *)str2;
185 int res;
187 if (!n) return 0;
188 while ((--n > 0) && *ustr1) {
189 if ((res = toupper(*ustr1) - toupper(*ustr2))) return res;
190 ustr1++;
191 ustr2++;
193 return toupper(*ustr1) - toupper(*ustr2);
195 #endif /* HAVE_STRNCASECMP */
197 /***********************************************************************
198 * wine_openpty
199 * NOTE
200 * It looks like the openpty that comes with glibc in RedHat 5.0
201 * is buggy (second call returns what looks like a dup of 0 and 1
202 * instead of a new pty), this is a generic replacement.
204 * FIXME
205 * We should have a autoconf check for this.
207 int wine_openpty(int *master, int *slave, char *name,
208 struct termios *term, struct winsize *winsize)
210 #ifdef HAVE_OPENPTY
211 return openpty(master, slave, name, term, winsize);
212 #else
213 const char *ptr1, *ptr2;
214 char pts_name[512];
216 strcpy (pts_name, "/dev/ptyXY");
218 for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1 != 0; ptr1++) {
219 pts_name[8] = *ptr1;
220 for (ptr2 = "0123456789abcdef"; *ptr2 != 0; ptr2++) {
221 pts_name[9] = *ptr2;
223 if ((*master = open(pts_name, O_RDWR)) < 0) {
224 if (errno == ENOENT)
225 return -1;
226 else
227 continue;
229 pts_name[5] = 't';
230 if ((*slave = open(pts_name, O_RDWR)) < 0) {
231 pts_name[5] = 'p';
232 close (*master);
233 continue;
236 if (term != NULL)
237 tcsetattr(*slave, TCSANOW, term);
238 if (winsize != NULL)
239 ioctl(*slave, TIOCSWINSZ, winsize);
240 if (name != NULL)
241 strcpy(name, pts_name);
242 return *slave;
245 errno = EMFILE;
246 return -1;
247 #endif
250 /***********************************************************************
251 * getnetbyaddr
253 #ifndef HAVE_GETNETBYADDR
254 struct netent *getnetbyaddr(unsigned long net, int type)
256 errno = ENOSYS;
257 return NULL;
259 #endif /* defined(HAVE_GETNETBYNAME) */
261 /***********************************************************************
262 * getnetbyname
264 #ifndef HAVE_GETNETBYNAME
265 struct netent *getnetbyname(const char *name)
267 errno = ENOSYS;
268 return NULL;
270 #endif /* defined(HAVE_GETNETBYNAME) */
272 /***********************************************************************
273 * getprotobyname
275 #ifndef HAVE_GETPROTOBYNAME
276 struct protoent *getprotobyname(const char *name)
278 errno = ENOSYS;
279 return NULL;
281 #endif /* !defined(HAVE_GETPROTOBYNAME) */
283 /***********************************************************************
284 * getprotobynumber
286 #ifndef HAVE_GETPROTOBYNUMBER
287 struct protoent *getprotobynumber(int proto)
289 errno = ENOSYS;
290 return NULL;
292 #endif /* !defined(HAVE_GETPROTOBYNUMBER) */
294 /***********************************************************************
295 * getservbyport
297 #ifndef HAVE_GETSERVBYPORT
298 struct servent *getservbyport(int port, const char *proto)
300 errno = ENOSYS;
301 return NULL;
303 #endif /* !defined(HAVE_GETSERVBYPORT) */
305 /***********************************************************************
306 * getsockopt
308 #ifndef HAVE_GETSOCKOPT
309 int getsockopt(int socket, int level, int option_name,
310 void *option_value, size_t *option_len)
312 errno = ENOSYS;
313 return -1;
315 #endif /* !defined(HAVE_GETSOCKOPT) */
317 /***********************************************************************
318 * inet_network
320 #ifndef HAVE_INET_NETWORK
321 unsigned long inet_network(const char *cp)
323 errno = ENOSYS;
324 return 0;
326 #endif /* defined(HAVE_INET_NETWORK) */
328 /***********************************************************************
329 * settimeofday
331 #ifndef HAVE_SETTIMEOFDAY
332 int settimeofday(struct timeval *tp, void *reserved)
334 tp->tv_sec = 0;
335 tp->tv_usec = 0;
337 errno = ENOSYS;
338 return -1;
340 #endif /* HAVE_SETTIMEOFDAY */
342 /***********************************************************************
343 * statfs
345 #ifndef HAVE_STATFS
346 int statfs(const char *name, struct statfs *info)
348 #ifdef __BEOS__
349 dev_t mydev;
350 fs_info fsinfo;
352 if(!info) {
353 errno = ENOSYS;
354 return -1;
357 if ((mydev = dev_for_path(name)) < 0) {
358 errno = ENOSYS;
359 return -1;
362 if (fs_stat_dev(mydev,&fsinfo) < 0) {
363 errno = ENOSYS;
364 return -1;
367 info->f_bsize = fsinfo.block_size;
368 info->f_blocks = fsinfo.total_blocks;
369 info->f_bfree = fsinfo.free_blocks;
370 return 0;
371 #else /* defined(__BEOS__) */
372 errno = ENOSYS;
373 return -1;
374 #endif /* defined(__BEOS__) */
376 #endif /* !defined(HAVE_STATFS) */
379 /***********************************************************************
380 * lstat
382 #ifndef HAVE_LSTAT
383 int lstat(const char *file_name, struct stat *buf)
385 return stat( file_name, buf );
387 #endif /* HAVE_LSTAT */
389 /***********************************************************************
390 * getrlimit
392 #ifndef HAVE_GETRLIMIT
393 int getrlimit (int resource, struct rlimit *rlim)
395 return -1; /* FAIL */
397 #endif /* HAVE_GETRLIMIT */
400 #ifdef __svr4__
401 /***********************************************************************
402 * solaris_try_mmap
404 * The purpose of this routine is to emulate the behaviour of
405 * the Linux mmap() routine if a non-NULL address is passed,
406 * but the MAP_FIXED flag is not set. Linux in this case tries
407 * to place the mapping at the specified address, *unless* the
408 * range is already in use. Solaris, however, completely ignores
409 * the address argument in this case.
411 * As Wine code occasionally relies on the Linux behaviour, e.g. to
412 * be able to map non-relocateable PE executables to their proper
413 * start addresses, or to map the DOS memory to 0, this routine
414 * emulates the Linux behaviour by checking whether the desired
415 * address range is still available, and placing the mapping there
416 * using MAP_FIXED if so.
418 static int solaris_try_mmap (void *addr, size_t len, int prot, int flags,
419 int fildes, off_t off)
421 char * volatile result = NULL;
422 int pagesize = getpagesize();
423 pid_t pid;
425 /* We only try to map to a fixed address if
426 addr is non-NULL and properly aligned,
427 and MAP_FIXED isn't already specified. */
429 if ( !addr )
430 return FALSE;
431 if ( (uintptr_t)addr & (pagesize-1) )
432 return FALSE;
433 if ( flags & MAP_FIXED )
434 return FALSE;
436 /* We use vfork() to freeze all threads of the
437 current process. This allows us to check without
438 race condition whether the desired memory range is
439 already in use. Note that because vfork() shares
440 the address spaces between parent and child, we
441 can actually perform the mapping in the child. */
443 if ( (pid = vfork()) == -1 )
445 perror("solaris_try_mmap: vfork");
446 exit(1);
448 if ( pid == 0 )
450 int i;
451 char vec;
453 /* We call mincore() for every page in the desired range.
454 If any of these calls succeeds, the page is already
455 mapped and we must fail. */
456 for ( i = 0; i < len; i += pagesize )
457 if ( mincore( (caddr_t)addr + i, pagesize, &vec ) != -1 )
458 _exit(1);
460 /* Perform the mapping with MAP_FIXED set. This is safe
461 now, as none of the pages is currently in use. */
462 result = mmap( addr, len, prot, flags | MAP_FIXED, fildes, off );
463 if ( result == addr )
464 _exit(0);
466 if ( result != (void *) -1 ) /* This should never happen ... */
467 munmap( result, len );
469 _exit(1);
472 /* vfork() lets the parent continue only after the child
473 has exited. Furthermore, Wine sets SIGCHLD to SIG_IGN,
474 so we don't need to wait for the child. */
476 return result == addr;
478 #endif
480 /***********************************************************************
481 * wine_anon_mmap
483 * Portable wrapper for anonymous mmaps
485 void *wine_anon_mmap( void *start, size_t size, int prot, int flags )
487 static int fdzero = -1;
489 #ifdef MAP_ANON
490 flags |= MAP_ANON;
491 #else
492 if (fdzero == -1)
494 if ((fdzero = open( "/dev/zero", O_RDONLY )) == -1)
496 perror( "/dev/zero: open" );
497 exit(1);
500 #endif /* MAP_ANON */
502 #ifdef MAP_SHARED
503 flags &= ~MAP_SHARED;
504 #endif
506 /* Linux EINVAL's on us if we don't pass MAP_PRIVATE to an anon mmap */
507 #ifdef MAP_PRIVATE
508 flags |= MAP_PRIVATE;
509 #endif
511 #ifdef __svr4__
512 if ( solaris_try_mmap( start, size, prot, flags, fdzero, 0 ) )
513 return start;
514 #endif
516 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 /***********************************************************************
531 * wine_dlopen
533 void *wine_dlopen( const char *filename, int flag, char *error, int errorsize )
535 #ifdef HAVE_DLOPEN
536 void *ret;
537 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 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 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 */