blob: d2c2c1bbe6554522f6c7cfd839937d356b2b3204 [file] [log] [blame]
Alexandre Julliard18f92e71996-07-17 20:02:21 +00001/*
2 * Misc. functions for systems that don't have them
3 *
4 * Copyright 1996 Alexandre Julliard
5 */
6
Patrik Stridvall9af5e691999-12-11 23:02:15 +00007#include "config.h"
Marcus Meissner3f1ed522001-05-14 20:09:37 +00008#include "wine/port.h"
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +00009
Patrik Stridvallb9010211999-11-13 22:23:35 +000010#ifdef __BEOS__
11#include <be/kernel/fs_info.h>
12#include <be/kernel/OS.h>
13#endif
14
15#include <assert.h>
Alexandre Julliard3b96efc1999-09-04 14:36:02 +000016#include <ctype.h>
Marcus Meissner3b092841999-02-20 16:46:39 +000017#include <stdio.h>
Alexandre Julliard335b9e32000-12-19 19:38:48 +000018#include <stdlib.h>
David Luyeree517e81999-02-28 12:27:56 +000019#include <string.h>
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +000020#include <unistd.h>
Alexandre Julliardca22b331996-07-12 19:02:39 +000021#include <sys/types.h>
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000022#include <sys/time.h>
Alexandre Julliard8da12c41999-01-17 16:55:11 +000023#include <sys/stat.h>
24#include <sys/ioctl.h>
25#include <errno.h>
26#include <fcntl.h>
27#include <termios.h>
Alexandre Julliard85423c62000-11-08 04:28:54 +000028#ifdef HAVE_SYS_MMAN_H
29#include <sys/mman.h>
30#endif
Marcus Meissner592ba101999-01-20 14:18:55 +000031#ifdef HAVE_LIBIO_H
32# include <libio.h>
33#endif
Patrik Stridvallb9010211999-11-13 22:23:35 +000034#ifdef HAVE_SYSCALL_H
35# include <syscall.h>
36#endif
Marcus Meissner2d7be871999-12-05 23:06:40 +000037#ifdef HAVE_PTY_H
38# include <pty.h>
39#endif
Hidenori Takeshima01f78aa2000-07-09 12:19:09 +000040#ifdef HAVE_LIBUTIL_H
41# include <libutil.h>
42#endif
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000043
Patrik Stridvall9af5e691999-12-11 23:02:15 +000044
Patrik Stridvallb9010211999-11-13 22:23:35 +000045/***********************************************************************
46 * usleep
47 */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000048#ifndef HAVE_USLEEP
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000049unsigned int usleep (unsigned int useconds)
50{
Patrik Stridvallb9010211999-11-13 22:23:35 +000051#if defined(__EMX__)
52 DosSleep(useconds);
53 return 0;
54#elif defined(__BEOS__)
55 return snooze(useconds);
56#elif defined(HAVE_SELECT)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000057 struct timeval delay;
58
Alexandre Julliard2fa4f762000-10-31 00:20:51 +000059 delay.tv_sec = useconds / 1000000;
60 delay.tv_usec = useconds % 1000000;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000061
Alexandre Julliardca22b331996-07-12 19:02:39 +000062 select( 0, 0, 0, 0, &delay );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000063 return 0;
Patrik Stridvallb9010211999-11-13 22:23:35 +000064#else /* defined(__EMX__) || defined(__BEOS__) || defined(HAVE_SELECT) */
65 errno = ENOSYS;
66 return -1;
67#endif /* defined(__EMX__) || defined(__BEOS__) || defined(HAVE_SELECT) */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000068}
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000069#endif /* HAVE_USLEEP */
70
Patrik Stridvallb9010211999-11-13 22:23:35 +000071/***********************************************************************
72 * memmove
73 */
Alexandre Julliard18f92e71996-07-17 20:02:21 +000074#ifndef HAVE_MEMMOVE
Alexandre Julliardac9c9b01996-07-28 18:50:11 +000075void *memmove( void *dest, const void *src, unsigned int len )
Alexandre Julliard18f92e71996-07-17 20:02:21 +000076{
Alexandre Julliardac9c9b01996-07-28 18:50:11 +000077 register char *dst = dest;
78
Alexandre Julliard18f92e71996-07-17 20:02:21 +000079 /* Use memcpy if not overlapping */
Alexandre Julliardac9c9b01996-07-28 18:50:11 +000080 if ((dst + len <= (char *)src) || ((char *)src + len <= dst))
Alexandre Julliard18f92e71996-07-17 20:02:21 +000081 {
82 memcpy( dst, src, len );
83 }
84 /* Otherwise do it the hard way (FIXME: could do better than this) */
85 else if (dst < src)
86 {
Alexandre Julliardac9c9b01996-07-28 18:50:11 +000087 while (len--) *dst++ = *((char *)src)++;
Alexandre Julliard18f92e71996-07-17 20:02:21 +000088 }
89 else
90 {
Alexandre Julliardac9c9b01996-07-28 18:50:11 +000091 dst += len - 1;
Alexandre Julliard18f92e71996-07-17 20:02:21 +000092 src = (char *)src + len - 1;
Alexandre Julliardac9c9b01996-07-28 18:50:11 +000093 while (len--) *dst-- = *((char *)src)--;
Alexandre Julliard18f92e71996-07-17 20:02:21 +000094 }
Alexandre Julliardac9c9b01996-07-28 18:50:11 +000095 return dest;
Alexandre Julliard18f92e71996-07-17 20:02:21 +000096}
97#endif /* HAVE_MEMMOVE */
Alexandre Julliard44ed71f1997-12-21 19:17:50 +000098
Patrik Stridvallb9010211999-11-13 22:23:35 +000099/***********************************************************************
100 * strerror
101 */
Alexandre Julliard44ed71f1997-12-21 19:17:50 +0000102#ifndef HAVE_STRERROR
103const char *strerror( int err )
104{
105 /* Let's hope we have sys_errlist then */
106 return sys_errlist[err];
107}
108#endif /* HAVE_STRERROR */
Alexandre Julliard0623a6f1998-01-18 18:01:49 +0000109
Alexandre Julliard85423c62000-11-08 04:28:54 +0000110
111/***********************************************************************
112 * getpagesize
113 */
114#ifndef HAVE_GETPAGESIZE
115size_t getpagesize(void)
116{
117# ifdef __svr4__
118 return sysconf(_SC_PAGESIZE);
119# else
120# error Cannot get the page size on this platform
121# endif
122}
123#endif /* HAVE_GETPAGESIZE */
124
125
Patrik Stridvallb9010211999-11-13 22:23:35 +0000126/***********************************************************************
127 * clone
128 */
Alexandre Julliard0623a6f1998-01-18 18:01:49 +0000129#if !defined(HAVE_CLONE) && defined(__linux__)
Alexandre Julliard0623a6f1998-01-18 18:01:49 +0000130int clone( int (*fn)(void *), void *stack, int flags, void *arg )
131{
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"
Alexandre Julliard0f586c42001-02-20 01:59:27 +0000143 "xorl %ebp,%ebp\n\t" /* Terminate the stack frames */
Alexandre Julliard0623a6f1998-01-18 18:01:49 +0000144 "call *%%ebx\n\t" /* Should never return */
145 "xorl %%eax,%%eax\n\t" /* Just in case it does*/
146 "0:"
147 : "=a" (ret)
Marcus Meissner4ede2961999-02-21 18:18:42 +0000148 : "0" (SYS_clone), "r" (flags), "c" (stack_ptr) );
Alexandre Julliard0623a6f1998-01-18 18:01:49 +0000149 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__ */
157}
158#endif /* !HAVE_CLONE && __linux__ */
Alexandre Julliard8da12c41999-01-17 16:55:11 +0000159
Patrik Stridvallb9010211999-11-13 22:23:35 +0000160/***********************************************************************
161 * strcasecmp
162 */
Alexandre Julliard3b96efc1999-09-04 14:36:02 +0000163#ifndef HAVE_STRCASECMP
164int strcasecmp( const char *str1, const char *str2 )
165{
Morten Welindera2d11df2000-12-18 03:50:15 +0000166 const unsigned char *ustr1 = (const unsigned char *)str1;
167 const unsigned char *ustr2 = (const unsigned char *)str2;
168
169 while (*ustr1 && toupper(*ustr1) == toupper(*ustr2)) {
170 ustr1++;
171 ustr2++;
172 }
173 return toupper(*ustr1) - toupper(*ustr2);
Alexandre Julliard3b96efc1999-09-04 14:36:02 +0000174}
175#endif /* HAVE_STRCASECMP */
176
Patrik Stridvallb9010211999-11-13 22:23:35 +0000177/***********************************************************************
178 * strncasecmp
179 */
Alexandre Julliard3b96efc1999-09-04 14:36:02 +0000180#ifndef HAVE_STRNCASECMP
181int strncasecmp( const char *str1, const char *str2, size_t n )
182{
Morten Welindera2d11df2000-12-18 03:50:15 +0000183 const unsigned char *ustr1 = (const unsigned char *)str1;
184 const unsigned char *ustr2 = (const unsigned char *)str2;
Alexandre Julliard3b96efc1999-09-04 14:36:02 +0000185 int res;
Morten Welindera2d11df2000-12-18 03:50:15 +0000186
Alexandre Julliard3b96efc1999-09-04 14:36:02 +0000187 if (!n) return 0;
Morten Welindera2d11df2000-12-18 03:50:15 +0000188 while ((--n > 0) && *ustr1) {
189 if ((res = toupper(*ustr1) - toupper(*ustr2))) return res;
190 ustr1++;
191 ustr2++;
192 }
193 return toupper(*ustr1) - toupper(*ustr2);
Alexandre Julliard3b96efc1999-09-04 14:36:02 +0000194}
195#endif /* HAVE_STRNCASECMP */
196
Patrik Stridvallb9010211999-11-13 22:23:35 +0000197/***********************************************************************
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.
203 *
204 * FIXME
205 * We should have a autoconf check for this.
Alexandre Julliard8da12c41999-01-17 16:55:11 +0000206 */
Alexandre Julliard2fa4f762000-10-31 00:20:51 +0000207int wine_openpty(int *master, int *slave, char *name,
208 struct termios *term, struct winsize *winsize)
Alexandre Julliard8da12c41999-01-17 16:55:11 +0000209{
Marcus Meissner2d7be871999-12-05 23:06:40 +0000210#ifdef HAVE_OPENPTY
Morten Welindera2d11df2000-12-18 03:50:15 +0000211 return openpty(master, slave, name, term, winsize);
Marcus Meissner2d7be871999-12-05 23:06:40 +0000212#else
Morten Welindera2d11df2000-12-18 03:50:15 +0000213 const char *ptr1, *ptr2;
Alexandre Julliard8da12c41999-01-17 16:55:11 +0000214 char pts_name[512];
215
216 strcpy (pts_name, "/dev/ptyXY");
217
218 for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1 != 0; ptr1++) {
219 pts_name[8] = *ptr1;
220 for (ptr2 = "0123456789abcdef"; *ptr2 != 0; ptr2++) {
221 pts_name[9] = *ptr2;
222
223 if ((*master = open(pts_name, O_RDWR)) < 0) {
224 if (errno == ENOENT)
225 return -1;
226 else
227 continue;
228 }
229 pts_name[5] = 't';
230 if ((*slave = open(pts_name, O_RDWR)) < 0) {
231 pts_name[5] = 'p';
Morten Welindera2d11df2000-12-18 03:50:15 +0000232 close (*master);
Alexandre Julliard8da12c41999-01-17 16:55:11 +0000233 continue;
234 }
235
236 if (term != NULL)
Alexandre Julliard2fa4f762000-10-31 00:20:51 +0000237 tcsetattr(*slave, TCSANOW, term);
238 if (winsize != NULL)
239 ioctl(*slave, TIOCSWINSZ, winsize);
240 if (name != NULL)
241 strcpy(name, pts_name);
Alexandre Julliard8da12c41999-01-17 16:55:11 +0000242 return *slave;
243 }
244 }
Morten Welindera2d11df2000-12-18 03:50:15 +0000245 errno = EMFILE;
Alexandre Julliard8da12c41999-01-17 16:55:11 +0000246 return -1;
Marcus Meissner2d7be871999-12-05 23:06:40 +0000247#endif
Alexandre Julliard8da12c41999-01-17 16:55:11 +0000248}
249
Patrik Stridvallb9010211999-11-13 22:23:35 +0000250/***********************************************************************
251 * getnetbyaddr
252 */
253#ifndef HAVE_GETNETBYADDR
254struct netent *getnetbyaddr(unsigned long net, int type)
255{
256 errno = ENOSYS;
257 return NULL;
258}
259#endif /* defined(HAVE_GETNETBYNAME) */
260
261/***********************************************************************
262 * getnetbyname
263 */
264#ifndef HAVE_GETNETBYNAME
265struct netent *getnetbyname(const char *name)
266{
267 errno = ENOSYS;
268 return NULL;
269}
270#endif /* defined(HAVE_GETNETBYNAME) */
271
272/***********************************************************************
273 * getprotobyname
274 */
275#ifndef HAVE_GETPROTOBYNAME
276struct protoent *getprotobyname(const char *name)
277{
278 errno = ENOSYS;
279 return NULL;
280}
281#endif /* !defined(HAVE_GETPROTOBYNAME) */
282
283/***********************************************************************
284 * getprotobynumber
285 */
286#ifndef HAVE_GETPROTOBYNUMBER
287struct protoent *getprotobynumber(int proto)
288{
289 errno = ENOSYS;
290 return NULL;
291}
292#endif /* !defined(HAVE_GETPROTOBYNUMBER) */
293
294/***********************************************************************
295 * getservbyport
296 */
297#ifndef HAVE_GETSERVBYPORT
298struct servent *getservbyport(int port, const char *proto)
299{
300 errno = ENOSYS;
301 return NULL;
302}
303#endif /* !defined(HAVE_GETSERVBYPORT) */
304
305/***********************************************************************
306 * getsockopt
307 */
308#ifndef HAVE_GETSOCKOPT
309int getsockopt(int socket, int level, int option_name,
Alexandre Julliard2fa4f762000-10-31 00:20:51 +0000310 void *option_value, size_t *option_len)
Patrik Stridvallb9010211999-11-13 22:23:35 +0000311{
312 errno = ENOSYS;
313 return -1;
314}
315#endif /* !defined(HAVE_GETSOCKOPT) */
316
317/***********************************************************************
318 * inet_network
319 */
320#ifndef HAVE_INET_NETWORK
321unsigned long inet_network(const char *cp)
322{
323 errno = ENOSYS;
324 return 0;
325}
326#endif /* defined(HAVE_INET_NETWORK) */
327
328/***********************************************************************
329 * settimeofday
330 */
331#ifndef HAVE_SETTIMEOFDAY
332int settimeofday(struct timeval *tp, void *reserved)
333{
334 tp->tv_sec = 0;
335 tp->tv_usec = 0;
336
337 errno = ENOSYS;
338 return -1;
339}
340#endif /* HAVE_SETTIMEOFDAY */
341
342/***********************************************************************
343 * statfs
344 */
345#ifndef HAVE_STATFS
346int statfs(const char *name, struct statfs *info)
347{
348#ifdef __BEOS__
349 dev_t mydev;
350 fs_info fsinfo;
Alexandre Julliard2fa4f762000-10-31 00:20:51 +0000351
Patrik Stridvallb9010211999-11-13 22:23:35 +0000352 if(!info) {
353 errno = ENOSYS;
354 return -1;
355 }
356
357 if ((mydev = dev_for_path(name)) < 0) {
358 errno = ENOSYS;
Alexandre Julliard2fa4f762000-10-31 00:20:51 +0000359 return -1;
Patrik Stridvallb9010211999-11-13 22:23:35 +0000360 }
361
362 if (fs_stat_dev(mydev,&fsinfo) < 0) {
363 errno = ENOSYS;
Alexandre Julliard2fa4f762000-10-31 00:20:51 +0000364 return -1;
Patrik Stridvallb9010211999-11-13 22:23:35 +0000365 }
366
367 info->f_bsize = fsinfo.block_size;
368 info->f_blocks = fsinfo.total_blocks;
369 info->f_bfree = fsinfo.free_blocks;
Patrik Stridvallb9010211999-11-13 22:23:35 +0000370 return 0;
371#else /* defined(__BEOS__) */
372 errno = ENOSYS;
373 return -1;
374#endif /* defined(__BEOS__) */
375}
376#endif /* !defined(HAVE_STATFS) */
Alexandre Julliard85423c62000-11-08 04:28:54 +0000377
378
379/***********************************************************************
Alexandre Julliard27bb3112000-11-29 17:48:06 +0000380 * lstat
381 */
382#ifndef HAVE_LSTAT
383int lstat(const char *file_name, struct stat *buf)
384{
385 return stat( file_name, buf );
386}
387#endif /* HAVE_LSTAT */
388
Marcus Meissner3f1ed522001-05-14 20:09:37 +0000389/***********************************************************************
Dimitrie O. Paun1ec253d2000-12-01 20:47:11 +0000390 * getrlimit
391 */
392#ifndef HAVE_GETRLIMIT
393int getrlimit (int resource, struct rlimit *rlim)
394{
395 return -1; /* FAIL */
396}
397#endif /* HAVE_GETRLIMIT */
398
Ulrich Weigandc52a11e2001-09-07 18:46:14 +0000399
400#ifdef __svr4__
401/***********************************************************************
402 * solaris_try_mmap
403 *
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.
410 *
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.
417 */
418static int solaris_try_mmap (void *addr, size_t len, int prot, int flags,
419 int fildes, off_t off)
420{
421 char * volatile result = NULL;
422 int pagesize = getpagesize();
423 pid_t pid;
424
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. */
428
429 if ( !addr )
430 return FALSE;
431 if ( (uintptr_t)addr & (pagesize-1) )
432 return FALSE;
433 if ( flags & MAP_FIXED )
434 return FALSE;
435
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. */
442
443 if ( (pid = vfork()) == -1 )
444 {
445 perror("solaris_try_mmap: vfork");
446 exit(1);
447 }
448 if ( pid == 0 )
449 {
450 int i;
451 char vec;
452
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);
459
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);
465
466 if ( result != (void *) -1 ) /* This should never happen ... */
467 munmap( result, len );
468
469 _exit(1);
470 }
471
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. */
475
476 return result == addr;
477}
478#endif
479
Dimitrie O. Paun1ec253d2000-12-01 20:47:11 +0000480/***********************************************************************
Alexandre Julliard85423c62000-11-08 04:28:54 +0000481 * wine_anon_mmap
482 *
483 * Portable wrapper for anonymous mmaps
484 */
485void *wine_anon_mmap( void *start, size_t size, int prot, int flags )
486{
487 static int fdzero = -1;
488
489#ifdef MAP_ANON
490 flags |= MAP_ANON;
491#else
492 if (fdzero == -1)
493 {
494 if ((fdzero = open( "/dev/zero", O_RDONLY )) == -1)
495 {
496 perror( "/dev/zero: open" );
497 exit(1);
498 }
499 }
500#endif /* MAP_ANON */
Morten Welindera2d11df2000-12-18 03:50:15 +0000501
Alexandre Julliard85423c62000-11-08 04:28:54 +0000502#ifdef MAP_SHARED
503 flags &= ~MAP_SHARED;
504#endif
Morten Welindera2d11df2000-12-18 03:50:15 +0000505
506 /* Linux EINVAL's on us if we don't pass MAP_PRIVATE to an anon mmap */
Alexandre Julliard85423c62000-11-08 04:28:54 +0000507#ifdef MAP_PRIVATE
508 flags |= MAP_PRIVATE;
509#endif
Morten Welindera2d11df2000-12-18 03:50:15 +0000510
Ulrich Weigandc52a11e2001-09-07 18:46:14 +0000511#ifdef __svr4__
512 if ( solaris_try_mmap( start, size, prot, flags, fdzero, 0 ) )
513 return start;
514#endif
515
Alexandre Julliard85423c62000-11-08 04:28:54 +0000516 return mmap( start, size, prot, flags, fdzero, 0 );
517}
James Abbatielloe6758872000-12-13 21:32:55 +0000518
519
520/*
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.
528 */
529
530/***********************************************************************
531 * wine_dlopen
532 */
533void *wine_dlopen( const char *filename, int flag, char *error, int errorsize )
534{
Alexandre Julliarded2f19a2001-06-27 21:42:00 +0000535#ifdef HAVE_DLOPEN
James Abbatielloe6758872000-12-13 21:32:55 +0000536 void *ret;
537 char *s;
538 dlerror(); dlerror();
539 ret = dlopen( filename, flag );
540 s = dlerror();
541 if (error)
542 {
543 strncpy( error, s ? s : "", errorsize );
544 error[errorsize - 1] = '\0';
545 }
546 dlerror();
547 return ret;
548#else
549 if (error)
550 {
551 strncpy( error, "dlopen interface not detected by configure", errorsize );
552 error[errorsize - 1] = '\0';
553 }
554 return NULL;
555#endif
556}
557
558/***********************************************************************
559 * wine_dlsym
560 */
561void *wine_dlsym( void *handle, const char *symbol, char *error, int errorsize )
562{
Alexandre Julliarded2f19a2001-06-27 21:42:00 +0000563#ifdef HAVE_DLOPEN
James Abbatielloe6758872000-12-13 21:32:55 +0000564 void *ret;
565 char *s;
566 dlerror(); dlerror();
567 ret = dlsym( handle, symbol );
568 s = dlerror();
569 if (error)
570 {
571 strncpy( error, s ? s : "", errorsize );
572 error[errorsize - 1] = '\0';
573 }
574 dlerror();
575 return ret;
576#else
577 if (error)
578 {
579 strncpy( error, "dlopen interface not detected by configure", errorsize );
580 error[errorsize - 1] = '\0';
581 }
582 return NULL;
583#endif
584}
585
586/***********************************************************************
587 * wine_dlclose
588 */
589int wine_dlclose( void *handle, char *error, int errorsize )
590{
Alexandre Julliarded2f19a2001-06-27 21:42:00 +0000591#ifdef HAVE_DLOPEN
James Abbatielloe6758872000-12-13 21:32:55 +0000592 int ret;
593 char *s;
594 dlerror(); dlerror();
595 ret = dlclose( handle );
596 s = dlerror();
597 if (error)
598 {
599 strncpy( error, s ? s : "", errorsize );
600 error[errorsize - 1] = '\0';
601 }
602 dlerror();
603 return ret;
604#else
605 if (error)
606 {
607 strncpy( error, "dlopen interface not detected by configure", errorsize );
608 error[errorsize - 1] = '\0';
609 }
610 return 1;
611#endif
612}
François Gouget50510202000-12-19 04:50:49 +0000613
614/***********************************************************************
615 * wine_rewrite_s4tos2
616 *
617 * Convert 4 byte Unicode strings to 2 byte Unicode strings in-place.
618 * This is only practical if literal strings are writable.
619 */
620unsigned short* wine_rewrite_s4tos2(const wchar_t* str4 )
621{
622 unsigned short *str2,*s2;
623
624 if (str4==NULL)
625 return NULL;
626
627 if ((*str4 & 0xffff0000) != 0) {
628 /* This string has already been converted. Return it as is */
629 return (unsigned short*)str4;
630 }
631
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.
635 */
636 str2=s2=(unsigned short*)str4;
637 do {
638 *s2=(unsigned short)*str4;
639 s2++;
640 } while (*str4++ != L'\0');
641
642 return str2;
643}
Andreas Mohra7ca2ba2001-01-12 23:07:11 +0000644
645#ifndef HAVE_ECVT
646/*
647 * NetBSD 1.5 doesn't have ecvt, fcvt, gcvt. We just check for ecvt, though.
648 * Fix/verify these implementations !
649 */
650
651/***********************************************************************
652 * ecvt
653 */
654char *ecvt (double number, int ndigits, int *decpt, int *sign)
655{
Gerald Pfeifer714066152001-10-02 17:18:09 +0000656 static char buf[40]; /* ought to be enough */
Andreas Mohra7ca2ba2001-01-12 23:07:11 +0000657 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;
663}
664
665/***********************************************************************
666 * fcvt
667 */
668char *fcvt (double number, int ndigits, int *decpt, int *sign)
669{
Gerald Pfeifer714066152001-10-02 17:18:09 +0000670 static char buf[40]; /* ought to be enough */
Andreas Mohra7ca2ba2001-01-12 23:07:11 +0000671 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;
677}
678
679/***********************************************************************
680 * gcvt
681 *
682 * FIXME: uses both E and F.
683 */
684char *gcvt (double number, size_t ndigit, char *buff)
685{
Gerald Pfeifer714066152001-10-02 17:18:09 +0000686 sprintf(buff, "%.*E", (int)ndigit, number);
Andreas Mohra7ca2ba2001-01-12 23:07:11 +0000687 return buff;
688}
689#endif /* HAVE_ECVT */