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.
*/

#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 all the Modula-3 types are large enough */

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

#ifndef _WIN32

    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);

    assert(IS_TYPE_SIGNED(pid_t) == 1);

#endif

    assert(CHAR_BIT == 8);
    assert(sizeof(short) == 2);
    assert(sizeof(int) == 4);
    assert((sizeof(long) == 4) || (sizeof(long) == 8));
    assert((sizeof(void*) == 4) || (sizeof(void*) == 8));
    assert((sizeof(size_t) == 4) || (sizeof(size_t) == 8));
    assert(sizeof(void*) == sizeof(size_t));
#ifndef _WIN64
    assert(sizeof(void*) == sizeof(long));
    assert(sizeof(size_t) == sizeof(long));
#endif
#ifdef _MSC_VER
    assert(sizeof(__int64) == 8);
#else
    assert(sizeof(long long) == 8);
#endif
}

/* 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
}

#ifndef _WIN32

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

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

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

int Unix__pipe(int files[2]) { return pipe(files); }

#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
}

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

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