
/**
 * C's &lt;fenv.h&gt;
 * Authors: Walter Bright, Digital Mars, http://www.digitalmars.com
 * License: Public Domain
 * Macros:
 *      WIKI=Phobos/StdCFenv
 */

module std.c.fenv;

extern (C):

version (Windows)
{
    /// Entire floating point environment

    struct fenv_t
    {
        ushort status;
        ushort control;
        ushort round;
        ushort reserved[2];
    }

    extern fenv_t _FE_DFL_ENV;

    /// Default floating point environment
    fenv_t* FE_DFL_ENV = &_FE_DFL_ENV;

    alias int fexcept_t;        /// Floating point status flags

    int fetestexcept(int excepts);              ///
    int feraiseexcept(int excepts);             ///
    int feclearexcept(int excepts);             ///
    //int fegetexcept(fexcept_t *flagp,int excepts);    ///
    //int fesetexcept(fexcept_t *flagp,int excepts);    ///
    int fegetround();                   ///
    int fesetround(int round);          ///
    int fegetprec();                    ///
    int fesetprec(int prec);            ///
    int fegetenv(fenv_t *envp);         ///
    int fesetenv(fenv_t *envp);         ///
    //void feprocentry(fenv_t *envp);   ///
    //void feprocexit(const fenv_t *envp);      ///

    int fegetexceptflag(fexcept_t *flagp,int excepts);  ///
    int fesetexceptflag(fexcept_t *flagp,int excepts);  ///
    int feholdexcept(fenv_t *envp);             ///
    int feupdateenv(fenv_t *envp);              ///

}
else version (linux)
{
    /// Entire floating point environment

    struct fenv_t
    {
        ushort __control_word;
        ushort __unused1;
        ushort __status_word;
        ushort __unused2;
        ushort __tags;
        ushort __unused3;
        uint __eip;
        ushort __cs_selector;
        ushort __opcode;
        uint __data_offset;
        ushort __data_selector;
        ushort __unused5;
    }

    /// Default floating point environment
    fenv_t* FE_DFL_ENV = cast(fenv_t*)(-1);

    alias int fexcept_t;        /// Floating point status flags

    int fetestexcept(int excepts);              ///
    int feraiseexcept(int excepts);             ///
    int feclearexcept(int excepts);             ///
    //int fegetexcept(fexcept_t *flagp,int excepts);    ///
    //int fesetexcept(fexcept_t *flagp,int excepts);    ///
    int fegetround();                   ///
    int fesetround(int round);          ///
    int fegetprec();                    ///
    int fesetprec(int prec);            ///
    int fegetenv(fenv_t *envp);         ///
    int fesetenv(fenv_t *envp);         ///
    //void feprocentry(fenv_t *envp);   ///
    //void feprocexit(const fenv_t *envp);      ///

    int fegetexceptflag(fexcept_t *flagp,int excepts);  ///
    int fesetexceptflag(fexcept_t *flagp,int excepts);  ///
    int feholdexcept(fenv_t *envp);             ///
    int feupdateenv(fenv_t *envp);              ///
}
else version (OSX)
{
    /// Entire floating point environment

    struct fenv_t
    {
        ushort __control;
        ushort __status;
        uint __mxcsr;
        char[8] __reserved;
    }

    extern fenv_t _FE_DFL_ENV;

    /// Default floating point environment
    fenv_t* FE_DFL_ENV = &_FE_DFL_ENV;

    alias int fexcept_t;        /// Floating point status flags

    int fetestexcept(int excepts);              ///
    int feraiseexcept(int excepts);             ///
    int feclearexcept(int excepts);             ///
    //int fegetexcept(fexcept_t *flagp,int excepts);    ///
    //int fesetexcept(fexcept_t *flagp,int excepts);    ///
    int fegetround();                   ///
    int fesetround(int round);          ///
    int fegetprec();                    ///
    int fesetprec(int prec);            ///
    int fegetenv(fenv_t *envp);         ///
    int fesetenv(fenv_t *envp);         ///
    //void feprocentry(fenv_t *envp);   ///
    //void feprocexit(const fenv_t *envp);      ///

    int fegetexceptflag(fexcept_t *flagp,int excepts);  ///
    int fesetexceptflag(fexcept_t *flagp,int excepts);  ///
    int feholdexcept(fenv_t *envp);             ///
    int feupdateenv(fenv_t *envp);              ///
}
else version (FreeBSD)
{
    /// Entire floating point environment

    struct fenv_t
    {
        struct X87
        {
            uint __control;
            uint __status;
            uint __tag;
            char[16] other;
        }

        X87 __x87;
        uint __mxcsr;
    }

    extern fenv_t __fe_defl_env;

    /// Default floating point environment
    fenv_t* FE_DFL_ENV = &__fe_defl_env;

    alias ushort fexcept_t;     /// Floating point status flags
}
else version (Solaris)
{
    /// Entire floating point environment

    struct fenv_t
    {
       struct __fex_handler_t
       {
           int __mode;
           void (*__handler)();
       }

       __fex_handler_t[12] __handlers;
       uint __fsr;
    }

    /// Default floating point environment
    extern fenv_t __fenv_dfl_env;

    fenv_t* FE_DFL_ENV = &__fenv_dfl_env;

    alias int fexcept_t;       /// Floating point status flags

    int fetestexcept(int excepts);             ///
    int feraiseexcept(int excepts);            ///
    int feclearexcept(int excepts);            ///
    //int fegetexcept(fexcept_t *flagp,int excepts);   ///
    //int fesetexcept(fexcept_t *flagp,int excepts);   ///
    int fegetround();                  ///
    int fesetround(int round);         ///
    int fegetprec();                   ///
    int fesetprec(int prec);           ///
    int fegetenv(fenv_t *envp);                ///
    int fesetenv(fenv_t *envp);                ///
    //void feprocentry(fenv_t *envp);  ///
    //void feprocexit(const fenv_t *envp);     ///

    int fegetexceptflag(fexcept_t *flagp,int excepts); ///
    int fesetexceptflag(fexcept_t *flagp,int excepts); ///
    int feholdexcept(fenv_t *envp);            ///
    int feupdateenv(fenv_t *envp);             ///
}
else
{
    static assert(0);
}



/// The various floating point exceptions
enum
{
    FE_INVALID          = 1,            ///
    FE_DENORMAL         = 2,            ///
    FE_DIVBYZERO        = 4,            ///
    FE_OVERFLOW         = 8,            ///
    FE_UNDERFLOW        = 0x10,         ///
    FE_INEXACT          = 0x20,         ///
    FE_ALL_EXCEPT       = 0x3F,         /// Mask of all the exceptions
}

/// Rounding modes
enum
{
    FE_TONEAREST        = 0,            ///
    FE_UPWARD           = 0x800,        ///
    FE_DOWNWARD         = 0x400,        ///
    FE_TOWARDZERO       = 0xC00,        ///
}

/// Floating point precision
enum
{
    FE_FLTPREC  = 0,                    ///
    FE_DBLPREC  = 0x200,                ///
    FE_LDBLPREC = 0x300,                ///
}

