m3core/src/unix/Common/UnixC.c


/* Copyright (C) 1993, Digital Equipment Corporation                  */
/* All rights reserved.                                               */
/* See the file COPYRIGHT for a full description.                     */

/*
On some platforms, such as 32bit Linux and 32bit Solaris,
various functions are defined to have 32bit limits by default.
unless #define _FILE_OFFSET_BITS 64, which only affects C source.

Usually they are also available with the name ending in "64" as well.
    open => open64
    stat => stat64
    etc.

It might take a #define to expose those names to C.
(Just to help motivate why there are so many #defines.)

Therefore, saying, e.g.
<*EXTERNAL*> PROCEDURE ftruncate (fd: int; length: off_t): int;

is wrong, unless you constrain off_t to 32 bits, which is not good.

It would be correct to say:
<*EXTERNAL ftruncate64*> PROCEDURE ftruncate (fd: int; length: off_t): int;

However that is not portable.
So use these wrappers instead.
*/

#ifdef _MSC_VER
#undef _DLL
#ifndef _MT
#define _MT
#endif
#endif

#include "m3unix.h"
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef _WIN32
#include <windows.h>
#endif

#ifdef __cplusplus
extern "C"
{
#endif

void Unix__Assertions(void)
{
    /* make sure things are normal */
    M3_STATIC_ASSERT(CHAR_BIT == 8);
    M3_STATIC_ASSERT(sizeof(short) == 2);
    M3_STATIC_ASSERT(sizeof(int) == 4);
    M3_STATIC_ASSERT((sizeof(long) == 4) || (sizeof(long) == 8));
    M3_STATIC_ASSERT((sizeof(void*) == 4) || (sizeof(void*) == 8));
    M3_STATIC_ASSERT((sizeof(size_t) == 4) || (sizeof(size_t) == 8));
    M3_STATIC_ASSERT(sizeof(ptrdiff_t) == sizeof(size_t));
    M3_STATIC_ASSERT(sizeof(void*) == sizeof(size_t));
#ifndef _WIN64
    M3_STATIC_ASSERT(sizeof(void*) == sizeof(long));
    M3_STATIC_ASSERT(sizeof(size_t) == sizeof(long));
#endif

#ifdef _MSC_VER
    M3_STATIC_ASSERT(sizeof(__int64) == 8);
#else
    M3_STATIC_ASSERT(sizeof(long long) == 8);
#endif

#ifndef _WIN32

/* make sure all the Modula-3 types are large enough */

#define CHECK_M3_TYPE_SIZE(x) M3_STATIC_ASSERT(sizeof(m3_##x) >= sizeof(x))
#define IS_TYPE_SIGNED(x)  (((x)-1) < (x)0)

    CHECK_M3_TYPE_SIZE(dev_t);
    CHECK_M3_TYPE_SIZE(gid_t);
    CHECK_M3_TYPE_SIZE(ino_t);
    CHECK_M3_TYPE_SIZE(mode_t);
    CHECK_M3_TYPE_SIZE(nlink_t);
    CHECK_M3_TYPE_SIZE(off_t);
    CHECK_M3_TYPE_SIZE(pid_t);
    CHECK_M3_TYPE_SIZE(pthread_t);
    CHECK_M3_TYPE_SIZE(uid_t);

    M3_STATIC_ASSERT(IS_TYPE_SIGNED(pid_t));
#endif
    Utime__Assertions();
    Usocket__Assertions();
}

/* open doesn't take any off_t parameter, but there is open64, that
#define _FILE_OFFSET_BITS 64 maps open to. */
int Unix__open(const char* path, int flags, m3_mode_t mode)
{
#ifdef _WIN32
    return _open(path, flags, mode);
#else
    return open(path, flags, mode);
#endif
}

/* wrapped in case passing mode_t vs. int varies */
int Unix__mkdir(const char* path, m3_mode_t mode)
{
#ifdef _WIN32
    return _mkdir(path);
#else
    return mkdir(path, mode);
#endif
}

#ifndef _WIN32

int Unix__truncate(const char* file, m3_off_t length)
{
    return truncate(file, length);
}

int Unix__ftruncate(int file, m3_off_t length)
{
    return ftruncate(file, length);
}

#endif

m3_off_t Unix__lseek(int fd, m3_off_t offset, int whence)
{
#ifdef _WIN32
    return _lseeki64(fd, offset, whence);
#else
    return lseek(fd, offset, whence);
#endif
}

#ifndef _WIN32

int Unix__fcntl(int fd, int request, int arg)
/* fcntl is actually fcntl(fd, request, ...).
Wrapper is needed on some systems to handle varargs.
See http://edoofus.blogspot.com/2008/08/interesting-bug-unbreaking-cvsupamd64.html.
*/
{
#ifdef __sun
/*
 * This is to work around a bug in the Solaris-2 'libsocket' library 
 * which redefines 'fcntl' in such a way as to zero out 'errno' if the
 * call is successful.
 * See m3-libs/m3core/src/unix/solaris-2-x/Unix.m3.
 */
    int e = errno;
    int r = fcntl(fd, request, arg);
    if (r == 0)
        errno = e;
    return r;
#else
    return fcntl(fd, request, arg);
#endif
}

int Unix__ioctl(int fd, int request, void* argp)
/* ioctl is varargs. See fcntl. */
{
#ifdef __sun
/*
 * This is to work around a bug in the Solaris-2 'libsocket' library 
 * which redefines 'ioctl' in such a way as to zero out 'errno' if the
 * call is successful.
 * See m3-libs/m3core/src/unix/solaris-2-x/Unix.m3.
 */
    int e = errno;
    int r = ioctl(fd, request, argp);
    if (r == 0)
        errno = e;
    return r;
#else
    return ioctl(fd, request, argp);
#endif
}

int Unix__mknod(const char* path, m3_mode_t mode, m3_dev_t dev)
/* no good reason to wrap this */
{
    return mknod(path, mode, dev);
}

#endif

m3_mode_t Unix__umask(m3_mode_t newmask)
{
#ifdef _WIN32
    return _umask(newmask);
#else
    return umask(newmask);
#endif
}

int Unix__chmod(const char* path, m3_mode_t mode)
{
#ifdef _WIN32
    return _chmod(path, mode);
#else
    return chmod(path, mode);
#endif
}

#ifndef _WIN32

int Unix__fchmod(int fd, m3_mode_t mode)
{
    return fchmod(fd, mode);
}

int Unix__chown(const char* path, m3_uid_t owner, m3_gid_t group)
{
    return chown(path, owner, group);
}

int Unix__fchown(int fd, m3_uid_t owner, m3_gid_t group)
{
    return fchown(fd, owner, group);
}

#endif

int Unix__creat(const char* path, m3_mode_t mode)
{
#ifdef _WIN32
    return _creat(path, mode);
#else
    return creat(path, mode);
#endif
}

int Unix__dup(int oldd)
{
#ifdef _WIN32
    return _dup(oldd);
#else
    return dup(oldd);
#endif
}

#ifndef _WIN32
m3_pid_t Unix__fork(void) { return fork(); }
#endif

int Unix__system(const char* s) { return system(s); }

int Unix__isatty(int file)
{
#ifdef _WIN32
    return _isatty(file);
#else
    return isatty(file);
#endif
}

int Unix__pipe(int files[2])
{
#ifdef _WIN32
    return _pipe(files, 0, _O_BINARY);
#else
    return pipe(files);
#endif
}

#ifndef _WIN32

INTEGER Unix__readlink(const char* path, char* buf, INTEGER bufsize) { return readlink(path, buf, bufsize); }

int Unix__symlink(const char* name1, const char* name2) { return symlink(name1, name2); }

#ifndef __INTERIX

int Unix__utimes(const char* file, const timeval_t* tvp) { return utimes(file, tvp); }

#endif

#endif

int Unix__rename(const char* from, const char* to) { return rename(from, to); }

int Unix__rmdir(const char* path)
{
#ifdef _WIN32
    return _rmdir(path);
#else
    return rmdir(path);
#endif
}

int Unix__unlink(const char* path)
{
#ifdef _WIN32
    return _unlink(path);
#else
    return unlink(path);
#endif
}

void Unix__underscore_exit(int exit_code)
{
    _exit(exit_code);
}

int Unix__select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, timeval_t* timeout)
{
    return select(nfds, readfds, writefds, exceptfds, timeout);
}

#ifndef _WIN32

int Unix__fsync(int file)
{
    return fsync(file);
}

int Unix__getdtablesize()
{
    return getdtablesize();
}

#endif

int Unix__gethostname(char* name, size_t namelen)
{
    return gethostname(name, namelen);
}

#ifndef _WIN32

int Unix__getpagesize(void)
{
    return getpagesize();
}

#endif

char* Unix__getcwd(char* pathname, size_t size)
{
#ifdef _WIN32
    return _getcwd(pathname, size);
#else
    return getcwd(pathname, size);
#endif
}

int Unix__access(const char* path, int mode)
{
#ifdef _WIN32
    return _access(path, mode);
#else
    return access(path, mode);
#endif
}

#ifndef _WIN32

void* Unix__sbrk(INTEGER inc)
{
    return sbrk(inc);
}

#endif

int Unix__chdir(const char* path)
{
#ifdef _WIN32
    return _chdir(path);
#else
    return chdir(path);
#endif
}

int Unix__close(int d)
{
#ifdef _WIN32
    return _close(d);
#else
    return close(d);
#endif
}

int Unix__dup2(int oldd, int newd)
{
#ifdef _WIN32
    return _dup2(oldd, newd);
#else
    return dup2(oldd, newd);
#endif
}

#ifndef _WIN32

int Unix__execve(const char* name, char** argv, char** envp)
{
    return execve(name, argv, envp);
}

M3WRAP1(unsigned, sleep, unsigned)

#endif

void Unix__exit(int i)
{
    exit(i);
}

#ifdef __cplusplus
} /* extern C */
#endif