
#def GET_TYPE_FROM_C

if test -x /usr/bin/cat
then
    CAT=/usr/bin/cat
elif test -x /bin/cat
then
    CAT=/bin/cat
else
    CAT=cat
fi

if test -x /usr/bin/cc
then
    CC=/usr/bin/cc
elif test -x /bin/cc
then
    CC=/bin/cc
else
    CC=cc
fi

if test -x /usr/bin/rm
then
    RM=/usr/bin/rm
elif test -x /bin/rm
then
    RM=/bin/rm
else
    RM=rm
fi

$CAT <<EOS > ~/.clover/tmpfiles/a.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
$PARAM0

int main()
{
    size_t size = sizeof($PARAM1);

    if(size == 1) {
        printf("byte");
    }
    else if(size == 2) {
        printf("short");
    }
    else if(size == 4) {
        printf("uint");
    }
    else if(size == 8) {
        printf("long");
    }
    else {
        exit(2);
    }

    exit(0);
}
EOS

$CC -o ~/.clover/tmpfiles/a.out ~/.clover/tmpfiles/a.c
~/.clover/tmpfiles/a.out
$RM -f ~/.clover/tmpfiles/a.c ~/.clover/tmpfiles/a.out
#enddef

#def DEFINE_CONSTRUCTOR_WITH_LONG

if test -x /usr/bin/cat
then
    CAT=/usr/bin/cat
elif test -x /bin/cat
then
    CAT=/bin/cat
else
    CAT=cat
fi

if test -x /usr/bin/cc
then
    CC=/usr/bin/cc
elif test -x /bin/cc
then
    CC=/bin/cc
else
    CC=cc
fi

if test -x /usr/bin/rm
then
    RM=/usr/bin/rm
elif test -x /bin/rm
then
    RM=/bin/rm
else
    RM=rm
fi

$CAT <<EOS > ~/.clover/tmpfiles/a.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
$PARAM0

int main()
{
    size_t size = sizeof($PARAM1);

    if(size == 1) {
        printf("$PARAM2(long value) { self.setValue(value.toByte()); }");
    }
    else if(size == 2) {
        printf("$PARAM2(long value) { self.setValue(value.toShort()); }");
    }
    else if(size == 4) {
        printf("$PARAM2(long value) { self.setValue(value.toUInt()); }");
    }
    else if(size == 8) {
        /// pass ///
    }
    else {
        exit(2);
    }

    exit(0);
}
EOS

$CC -o ~/.clover/tmpfiles/a.out ~/.clover/tmpfiles/a.c
~/.clover/tmpfiles/a.out
$RM -f ~/.clover/tmpfiles/a.c ~/.clover/tmpfiles/a.out
#enddef

#def CALL_C_BLOCK

if test -x /usr/bin/cat
then
    CAT=/usr/bin/cat
elif test -x /bin/cat
then
    CAT=/bin/cat
else
    CAT=cat
fi

if test -x /usr/bin/cc
then
    CC=/usr/bin/cc
elif test -x /bin/cc
then
    CC=/bin/cc
else
    CC=cc
fi

if test -x /usr/bin/rm
then
    RM=/usr/bin/rm
elif test -x /bin/rm
then
    RM=/bin/rm
else
    RM=rm
fi

if test -x /usr/bin/mv
then
    MV=/usr/bin/mv
elif test -x /bin/mv
then
    MV=/bin/mv
else
    MV=mv
fi

$MV $BLOCK_FILE ~/.clover/tmpfiles/a.c
$CC -o ~/.clover/tmpfiles/a.out ~/.clover/tmpfiles/a.c
~/.clover/tmpfiles/a.out
$RM -f  ~/.clover/tmpfiles/a.out ~/.clover/tmpfiles/a.c
#enddef

class dev_t extends
#call GET_TYPE_FROM_C #include\ <fcntl.h> dev_t
#endcall
{
    dev_t(
#call GET_TYPE_FROM_C #include\ <fcntl.h> dev_t
#endcall
                          value)
    {
        self.setValue(value);
    }

#call DEFINE_CONSTRUCTOR_WITH_LONG #include\ <fcntl.h> dev_t dev_t
#endcall
}

class mode_t extends
#call GET_TYPE_FROM_C #include\ <fcntl.h> mode_t
#endcall
{
    mode_t (
#call GET_TYPE_FROM_C #include\ <fcntl.h> mode_t
#endcall
                          value)
    {
        self.setValue(value);
    }

#call DEFINE_CONSTRUCTOR_WITH_LONG #include\ <fcntl.h> mode_t mode_t
#endcall

    permission to_permission() {
        return new permission(self & (FileAccess.S_ISUID|FileAccess.S_ISGID|FileAccess.S_ISVTX|FileAccess.S_IRWXU|FileAccess.S_IRWXG|FileAccess.S_IRWXO));
    }
}

class permission extends mode_t
{
    permission (
#call GET_TYPE_FROM_C #include\ <fcntl.h> mode_t
#endcall
                            value)
    {
        self.setValue(value);
    }

    virtual String toString() {
        StringBuffer result = new StringBuffer("");

        if((self & FileAccess.S_ISUID) == FileAccess.S_ISUID) {
            result += "s";
        }
        else {
            result += "-";
        }
        if((self & FileAccess.S_ISGID) == FileAccess.S_ISGID) {
            result += "s";
        }
        else {
            result += "-";
        }
        if((self & FileAccess.S_ISVTX) == FileAccess.S_ISVTX) {
            result += "t";
        }
        else {
            result += "-";
        }
        if((self & FileAccess.S_IRUSR) == FileAccess.S_IRUSR) {
            result += "r";
        }
        else {
            result += "-";
        }
        if((self & FileAccess.S_IWUSR) == FileAccess.S_IWUSR) {
            result += "w";
        }
        else {
            result += "-";
        }
        if((self & FileAccess.S_IXUSR) == FileAccess.S_IXUSR) {
            result += "x";
        }
        else {
            result += "-";
        }
        if((self & FileAccess.S_IRGRP) == FileAccess.S_IRGRP) {
            result += "r";
        }
        else {
            result += "-";
        }
        if((self & FileAccess.S_IWGRP) == FileAccess.S_IWGRP) {
            result += "w";
        }
        else {
            result += "-";
        }
        if((self & FileAccess.S_IXGRP) == FileAccess.S_IXGRP) {
            result += "x";
        }
        else {
            result += "-";
        }
        if((self & FileAccess.S_IROTH) == FileAccess.S_IROTH) {
            result += "r";
        }
        else {
            result += "-";
        }
        if((self & FileAccess.S_IWOTH) == FileAccess.S_IWOTH) {
            result += "w";
        }
        else {
            result += "-";
        }
        if((self & FileAccess.S_IXOTH) == FileAccess.S_IXOTH) {
            result += "x";
        }
        else {
            result += "-";
        }

        return result.toString();
    }
}

class uid_t extends
#call GET_TYPE_FROM_C #include\ <fcntl.h> uid_t
#endcall
{
    uid_t (
#call GET_TYPE_FROM_C #include\ <fcntl.h> uid_t
#endcall
                          value)
    {
        self.setValue(value);
    }

#call DEFINE_CONSTRUCTOR_WITH_LONG #include\ <fcntl.h> uid_t uid_t
#endcall

    virtual String toString() {
        String result = super();

        p"/etc/passwd".readOut().toString().lines().each() {|String line|
            Array<String> fields = line.chomp().split(/:/);
            
            if(fields[2].toInt().toLong().to_uid_t() == self) {
                result = fields[0] + ":" + fields[2];
            }
        }

        return result;
    }
}

class gid_t extends
#call GET_TYPE_FROM_C #include\ <fcntl.h> gid_t
#endcall
{
    gid_t (
#call GET_TYPE_FROM_C #include\ <fcntl.h> gid_t
#endcall
                          value)
    {
        self.setValue(value);
    }

#call DEFINE_CONSTRUCTOR_WITH_LONG #include\ <fcntl.h> gid_t gid_t
#endcall

    virtual String toString() {
        String result = super();

        p"/etc/group".readOut().toString().lines().each() {|String line|
            Array<String> fields = line.chomp().split(/:/);
            
            if(fields[2].toInt().toLong().to_gid_t() == self) {
                result = fields[0] + ":" + fields[2];
            }
        }

        return result;
    }
}

class off_t extends
#call GET_TYPE_FROM_C #include\ <fcntl.h> off_t
#endcall
{
    off_t (
#call GET_TYPE_FROM_C #include\ <fcntl.h> off_t
#endcall
                          value)
    {
        self.setValue(value);
    }

#call DEFINE_CONSTRUCTOR_WITH_LONG #include\ <fcntl.h> off_t off_t
#endcall
}

class time_t extends
#call GET_TYPE_FROM_C #include\ <fcntl.h> time_t
#endcall
{
    time_t (
#call GET_TYPE_FROM_C #include\ <fcntl.h> time_t
#endcall
                          value)
    {
        self.setValue(value);
    }

#call DEFINE_CONSTRUCTOR_WITH_LONG #include\ <fcntl.h> time_t time_t
#endcall
    tm to_tm() {
        return new tm(self);
    }
}

class pid_t extends
#call GET_TYPE_FROM_C #include\ <unistd.h> pid_t
#endcall
{
    pid_t (
#call GET_TYPE_FROM_C #include\ <unistd.h> pid_t
#endcall
                          value)
    {
        self.setValue(value);
    }

#call DEFINE_CONSTRUCTOR_WITH_LONG #include\ <unistd.h> pid_t pid_t
#endcall
}

class WaitStatus extends int
{
    WaitStatus(int status) {
        self.setValue(status);
    }

    native bool WIFEXITED();
    native int WEXITSTATUS();
    native bool WIFSIGNALED();
    native int WTERMSIG();

    native int WCOREDUMP();
    native bool WIFSTOPPED();
    native int WSTOPSIG();
    native bool WIFCONTINUED();
}

enum WaitOption extends int
{
    WNOHANG, WUNTRACED, WCONTINUED
}

class WaitOption
{
    WaitOption(int value) {
        self.setValue(value);
    }
    static bool preinitialize() {
        WaitOption.WNOHANG, WaitOption.WUNTRACED, WaitOption.WCONTINUED =
#call CALL_C_BLOCK
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(int argc, char* argv[]) {
    printf("%d.toWaitOption(), %d.toWaitOption(), %d.toWaitOption();", WNOHANG, WUNTRACED, WCONTINUED);

    exit(0);
}
#endcall

        return true;
    }
}

mixin struct uint version 2
{
}

mixin struct long version 2
{
    FileKind toFileKind() {
        return new FileKind(self);
    }

    FileAccess toFileAccess() {
        return new FileAccess(self);
    }

    dev_t to_dev_t() {
        return new dev_t(self);
    }

/*
    ino_t to_ino_t() {
        return new ino_t(self);
    }
*/

    mode_t to_mode_t() {
        return new mode_t(self);
    }

/*
    nlink_t to_nlink_t() {
        return new nlink_t(self);
    }
*/

    uid_t to_uid_t() {
        return new uid_t(self);
    }

    gid_t to_gid_t() {
        return new gid_t(self);
    }

    off_t to_off_t() {
        return new off_t(self);
    }

/*
    blksize_t to_blksize_t() {
        return new blksize_t(self);
    }

    blkcnt_t to_blkcnt_t() {
        return new blkcnt_t(self);
    }
*/

    time_t to_time_t() {
        return new time_t(self);
    }

    tcflag_t to_tcflag_t() {
        return new tcflag_t(self);
    }

    cc_t to_cc_t() {
        return new cc_t(self);
    }

    TCSetAttrAction toTCSetAttrAction() {
        return new TCSetAttrAction(self);
    }
}

enum AccessMode extends int
{
    F_OK, R_OK, W_OK, X_OK
}

class AccessMode
{
    AccessMode(int value) {
        self.setValue(value);
    }
    static bool preinitialize() {
        AccessMode.F_OK, AccessMode.R_OK, AccessMode.W_OK, AccessMode.X_OK = 
#call CALL_C_BLOCK
#include <stdlib.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

int main(int argc, char* argv[]) {
    printf("%d.toAccessMode(), %d.toAccessMode(), %d.toAccessMode(), %d.toAccessMode();", F_OK, R_OK, W_OK, X_OK);

    exit(0);
}
#endcall

        return true;
    }
}

class utimbuf 
{
    time_t actime;
    time_t modtime;

    utimbuf(time_t actime, time_t modtime) {
        self.actime = actime;
        self.modtime = modtime;
    }
}

enum FileLockOperation extends int
{
    LOCK_SH, LOCK_EX, LOCK_UN, LOCK_NB
}

class FileLockOperation
{
    FileLockOperation(int value) {
        self.setValue(value);
    }

    static bool preinitialize() {
        FileLockOperation.LOCK_SH, FileLockOperation.LOCK_EX, FileLockOperation.LOCK_UN, FileLockOperation.LOCK_NB = 
#call CALL_C_BLOCK
#include <stdlib.h>
#include <stdio.h>
#include <sys/file.h>

int main(int argc, char* argv[]) {
    printf("%d.toFileLockOperation(), %d.toFileLockOperation(), %d.toFileLockOperation(), %d.toFileLockOperation();", LOCK_SH, LOCK_EX, LOCK_UN, LOCK_NB);

    exit(0);
}
#endcall
        return true;
    }
}

enum FnmatchFlags extends int
{
    FNM_NOESCAPE, FNM_PATHNAME, FNM_PERIOD, FNM_LEADING_DIR, FNM_CASEFOLD
}

class FnmatchFlags
{
    FnmatchFlags(int value) {
        self.setValue(value);
    }

    static bool preinitialize() {
        FnmatchFlags.FNM_NOESCAPE, FnmatchFlags.FNM_PATHNAME, FnmatchFlags.FNM_PERIOD, FnmatchFlags.FNM_LEADING_DIR, FnmatchFlags.FNM_CASEFOLD = 
#call CALL_C_BLOCK
#include <stdlib.h>
#include <stdio.h>
#define _GNU_SOURCE
#include <fnmatch.h>

int main(int argc, char* argv[]) {
    printf("%d.toFnmatchFlags(), %d.toFnmatchFlags(), %d.toFnmatchFlags(), %d.toFnmatchFlags(), %d.toFnmatchFlags();", FNM_NOESCAPE, FNM_PATHNAME, FNM_PERIOD, FNM_LEADING_DIR, FNM_CASEFOLD);

    exit(0);
}
#endcall
        return true;
    }
}

class DIR extends pointer
{
    DIR(pointer value) {
        self.setValue(value);
    }
}

class dirent
{
    pointer c_dirent_value;
    Bytes d_name;

    virtual bool operator==(dirent@Nullable value) {
        if(self.type() == Null || value.type() == Null) {
            return self.type() == Null && value.type() == Null;
        }

        return self.c_dirent_value == value.c_dirent_value && self.d_name == value.d_name;
    }

    virtual bool operator!=(dirent@Nullable value) {
        return !(self == value);
    }
}

class tcflag_t extends
#call GET_TYPE_FROM_C #include\ <termios.h> tcflag_t
#endcall
{
    tcflag_t (
#call GET_TYPE_FROM_C #include\ <termios.h> tcflag_t
#endcall
                          value)
    {
        self.setValue(value);
    }

#call DEFINE_CONSTRUCTOR_WITH_LONG #include\ <termios.h> tcflag_t tcflag_t
#endcall
}

enum tcflag_t 
{
    IGNBRK, BRKINT, IGNPAR, PARMRK, INPCK, ISTRIP, INLCR, IGNCR, ICRNL, IUCLC, IXON, IXANY, IXOFF, IMAXBEL, IUTF8, OPOST, OLCUC, ONLCR, OCRNL, ONOCR, ONLRET, OFILL, OFDEL, NLDLY, CRDLY, TABDLY, BSDLY, VTDLY, FFDLY, CBAUD, CBAUDEX, CSIZE, CSTOPB, CREAD, PARENB, PARODD, HUPCL, CLOCAL, CIBAUD, CMSPAR, CRTSCTS, ISIG, ICANON, XCASE, ECHO, ECHOE, ECHOK, ECHONL, ECHOCTL, ECHOPRT, ECHOKE, FLUSHO, NOFLSH, TOSTOP, PENDIN, IEXTEN
}

class tcflag_t 
{
    static bool preinitialize() {
        tcflag_t.IGNBRK, tcflag_t.BRKINT, tcflag_t.IGNPAR, tcflag_t.PARMRK, tcflag_t.INPCK = 
#call CALL_C_BLOCK
#include <unistd.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("%dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t();", IGNBRK, BRKINT, IGNPAR, PARMRK, INPCK);

    exit(0);
}
#endcall

        tcflag_t.ISTRIP, tcflag_t.INLCR, tcflag_t.IGNCR, tcflag_t.ICRNL, tcflag_t.IUCLC = 
#call CALL_C_BLOCK
#include <unistd.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("%dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t();", ISTRIP, INLCR, IGNCR, ICRNL, IUCLC);

    exit(0);
}
#endcall

        tcflag_t.IXON, tcflag_t.IXANY, tcflag_t.IXOFF, tcflag_t.IMAXBEL, tcflag_t.IUTF8 = 
#call CALL_C_BLOCK
#include <unistd.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("%dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t();", IXON, IXANY, IXOFF, IMAXBEL, IUTF8);

    exit(0);
}
#endcall

        tcflag_t.OPOST, tcflag_t.OLCUC, tcflag_t.ONLCR, tcflag_t.OCRNL, tcflag_t.ONOCR = 
#call CALL_C_BLOCK
#include <unistd.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("%dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t();", OPOST, OLCUC, ONLCR, OCRNL, ONOCR);

    exit(0);
}
#endcall

        tcflag_t.ONLRET, tcflag_t.OFILL, tcflag_t.OFDEL, tcflag_t.NLDLY, tcflag_t.CRDLY = 
#call CALL_C_BLOCK
#include <unistd.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("%dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t();", ONLRET, OFILL, OFDEL, NLDLY, CRDLY);

    exit(0);
}
#endcall

        tcflag_t.TABDLY, tcflag_t.BSDLY, tcflag_t.VTDLY, tcflag_t.FFDLY, tcflag_t.CBAUD = 
#call CALL_C_BLOCK
#include <unistd.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("%dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t();", TABDLY, BSDLY, VTDLY, FFDLY, CBAUD);

    exit(0);
}
#endcall

        tcflag_t.CBAUDEX, tcflag_t.CSIZE, tcflag_t.CSTOPB, tcflag_t.CREAD, tcflag_t.PARENB = 
#call CALL_C_BLOCK
#include <unistd.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("%dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t();", CBAUDEX, CSIZE, CSTOPB, CREAD, PARENB);

    exit(0);
}
#endcall

        tcflag_t.PARODD, tcflag_t.HUPCL, tcflag_t.CLOCAL, tcflag_t.CIBAUD = 
#call CALL_C_BLOCK
#include <unistd.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("%dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t();", PARODD, HUPCL, CLOCAL, CIBAUD);

    exit(0);
}
#endcall

        tcflag_t.CMSPAR, tcflag_t.CRTSCTS, tcflag_t.ISIG, tcflag_t.ICANON, tcflag_t.XCASE = 
#call CALL_C_BLOCK
#include <unistd.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("%dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t();", CMSPAR, CRTSCTS, ISIG, ICANON, XCASE);

    exit(0);
}
#endcall

        tcflag_t.ECHO, tcflag_t.ECHOE, tcflag_t.ECHOK, tcflag_t.ECHONL, tcflag_t.ECHOCTL = 
#call CALL_C_BLOCK
#include <unistd.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("%dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t();", ECHO, ECHOE, ECHOK, ECHONL, ECHOCTL);

    exit(0);
}
#endcall

        tcflag_t.ECHOPRT, tcflag_t.ECHOKE, tcflag_t.FLUSHO, tcflag_t.NOFLSH = 
#call CALL_C_BLOCK
#include <unistd.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("%dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t();", ECHOPRT, ECHOKE, FLUSHO, NOFLSH);

    exit(0);
}
#endcall

        tcflag_t.TOSTOP, tcflag_t.PENDIN, tcflag_t.IEXTEN = 
#call CALL_C_BLOCK
#include <unistd.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("%dl.to_tcflag_t(), %dl.to_tcflag_t(), %dl.to_tcflag_t();", TOSTOP, PENDIN, IEXTEN);

    exit(0);
}
#endcall

        return true;
    }
}

class cc_t extends
#call GET_TYPE_FROM_C #include\ <termios.h> cc_t
#endcall
{
    cc_t (
#call GET_TYPE_FROM_C #include\ <termios.h> cc_t
#endcall
                          value)
    {
        self.setValue(value);
    }

#call DEFINE_CONSTRUCTOR_WITH_LONG #include\ <termios.h> cc_t cc_t
#endcall
}

enum cc_t 
{
    VEOF, VEOL, VEOL2, VERASE, VINTR, VKILL, VLNEXT, VMIN, VQUIT, VREPRINT, VSTART, VSTOP, VSUSP, VTIME, VWERASE
}

class cc_t 
{
    static bool preinitialize() {
        cc_t.VEOF, cc_t.VEOL, cc_t.VEOL2, cc_t.VERASE, cc_t.VINTR = 
#call CALL_C_BLOCK
#include <unistd.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("%dl.to_cc_t(), %dl.to_cc_t(), %dl.to_cc_t(), %dl.to_cc_t(), %dl.to_cc_t();", VEOF, VEOL, VEOL2, VERASE, VINTR);

    exit(0);
}
#endcall

        cc_t.VKILL, cc_t.VLNEXT, cc_t.VMIN, cc_t.VQUIT, cc_t.VREPRINT = 
#call CALL_C_BLOCK
#include <unistd.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("%dl.to_cc_t(), %dl.to_cc_t(), %dl.to_cc_t(), %dl.to_cc_t(), %dl.to_cc_t();", VKILL, VLNEXT, VMIN, VQUIT, VREPRINT);

    exit(0);
}
#endcall

        cc_t.VSTART, cc_t.VSTOP, cc_t.VSUSP = 
#call CALL_C_BLOCK
#include <unistd.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("%dl.to_cc_t(), %dl.to_cc_t(), %dl.to_cc_t();", VSTART, VSTOP, VSUSP);

    exit(0);
}
#endcall

        cc_t.VTIME, cc_t.VWERASE = 
#call CALL_C_BLOCK
#include <unistd.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("%dl.to_cc_t(), %dl.to_cc_t();", VTIME, VWERASE);

    exit(0);
}
#endcall

        return true;

    }
}

class termios 
{
    tcflag_t c_iflag;
    tcflag_t c_oflag;
    tcflag_t c_cflag;
    tcflag_t c_lflag;
    Array<cc_t> c_cc;

    virtual String toString() {
        StringBuffer result = new StringBuffer("");

        result += "[c_iflags]\n";
        if((self.c_iflag & tcflag_t.IGNBRK) == tcflag_t.IGNBRK) {
            result += "IGNBRK ";
        }
        if((self.c_iflag & tcflag_t.BRKINT) == tcflag_t.BRKINT) {
            result += "BRKINT ";
        }
        if((self.c_iflag & tcflag_t.IGNPAR) == tcflag_t.IGNPAR) {
            result += "IGNPAR ";
        }
        if((self.c_iflag & tcflag_t.PARMRK) == tcflag_t.PARMRK) {
            result += "PARMRK ";
        }
        if((self.c_iflag & tcflag_t.INPCK) == tcflag_t.INPCK) {
            result += "INPCK ";
        }
        if((self.c_iflag & tcflag_t.ISTRIP) == tcflag_t.ISTRIP) {
            result += "ISTRIP ";
        }
        if((self.c_iflag & tcflag_t.INLCR) == tcflag_t.INLCR) {
            result += "INLCR ";
        }
        if((self.c_iflag & tcflag_t.IGNCR) == tcflag_t.IGNCR) {
            result += "IGNCR ";
        }
        if((self.c_iflag & tcflag_t.ICRNL) == tcflag_t.ICRNL) {
            result += "ICRNL ";
        }
        if((self.c_iflag & tcflag_t.IUCLC) == tcflag_t.IUCLC) {
            result += "IUCLC ";
        }
        if((self.c_iflag & tcflag_t.IXON) == tcflag_t.IXON) {
            result += "IXON ";
        }
        if((self.c_iflag & tcflag_t.IXANY) == tcflag_t.IXANY) {
            result += "IXANY ";
        }
        if((self.c_iflag & tcflag_t.IXOFF) == tcflag_t.IXOFF) {
            result += "IXOFF ";
        }
        if((self.c_iflag & tcflag_t.IMAXBEL) == tcflag_t.IMAXBEL) {
            result += "IMAXBEL ";
        }
        if((self.c_iflag & tcflag_t.IUTF8) == tcflag_t.IUTF8) {
            result += "IUTF8 ";
        }

        result += "\n[c_oflag]\n";
        if((self.c_oflag & tcflag_t.OPOST) == tcflag_t.OPOST) {
            result += "OPOST ";
        }
        if((self.c_oflag & tcflag_t.OLCUC) == tcflag_t.OLCUC) {
            result += "OLCUC ";
        }
        if((self.c_oflag & tcflag_t.ONLCR) == tcflag_t.ONLCR) {
            result += "ONLCR ";
        }
        if((self.c_oflag & tcflag_t.OCRNL) == tcflag_t.OCRNL) {
            result += "OCRNL ";
        }
        if((self.c_oflag & tcflag_t.ONOCR) == tcflag_t.ONOCR) {
            result += "ONOCR ";
        }
        if((self.c_oflag & tcflag_t.ONLRET) == tcflag_t.ONLRET) {
            result += "ONLRET ";
        }
        if((self.c_oflag & tcflag_t.OFILL) == tcflag_t.OFILL) {
            result += "OFILL ";
        }
        if((self.c_oflag & tcflag_t.OFDEL) == tcflag_t.OFDEL) {
            result += "OFDEL ";
        }
        if((self.c_oflag & tcflag_t.NLDLY) == tcflag_t.NLDLY) {
            result += "NDLY ";
        }
        if((self.c_oflag & tcflag_t.CRDLY) == tcflag_t.CRDLY) {
            result += "CRDLY ";
        }
        if((self.c_oflag & tcflag_t.TABDLY) == tcflag_t.TABDLY) {
            result += "TABDLY ";
        }
        if((self.c_oflag & tcflag_t.BSDLY) == tcflag_t.BSDLY) {
            result += "BSDLY ";
        }
        if((self.c_oflag & tcflag_t.VTDLY) == tcflag_t.VTDLY) {
            result += "VTDLY ";
        }
        if((self.c_oflag & tcflag_t.FFDLY) == tcflag_t.FFDLY) {
            result += "FFDLY ";
        }

        result += "\n[c_cflag]\n";
        if((self.c_cflag & tcflag_t.CBAUD) == tcflag_t.CBAUD) {
            result += "CBAUD ";
        }
        if((self.c_cflag & tcflag_t.CBAUDEX) == tcflag_t.CBAUDEX) {
            result += "CBAUDEX ";
        }
        if((self.c_cflag & tcflag_t.CSIZE) == tcflag_t.CSIZE) {
            result += "CSIZE ";
        }
        if((self.c_cflag & tcflag_t.CSTOPB) == tcflag_t.CSTOPB) {
            result += "CSTOPB ";
        }
        if((self.c_cflag & tcflag_t.CREAD) == tcflag_t.CREAD) {
            result += "CREAD ";
        }
        if((self.c_cflag & tcflag_t.PARENB) == tcflag_t.PARENB) {
            result += "PARENB ";
        }
        if((self.c_cflag & tcflag_t.PARODD) == tcflag_t.PARODD) {
            result += "PARODD ";
        }
        if((self.c_cflag & tcflag_t.HUPCL) == tcflag_t.HUPCL) {
            result += "HUPCL ";
        }
        if((self.c_cflag & tcflag_t.CLOCAL) == tcflag_t.CLOCAL) {
            result += "CLOCAL ";
        }
        if((self.c_cflag & tcflag_t.CIBAUD) == tcflag_t.CIBAUD) {
            result += "CIBAUD ";
        }
        if((self.c_cflag & tcflag_t.CMSPAR) == tcflag_t.CMSPAR) {
            result += "CMSPAR ";
        }
        if((self.c_cflag & tcflag_t.CRTSCTS) == tcflag_t.CRTSCTS) {
            result += "CRTSCTS ";
        }

        result += "\n[c_lflag]\n";
        if((self.c_lflag & tcflag_t.ISIG) == tcflag_t.ISIG) {
            result += "ISIG ";
        }
        if((self.c_lflag & tcflag_t.ICANON) == tcflag_t.ICANON) {
            result += "ICANON ";
        }
        if((self.c_lflag & tcflag_t.XCASE) == tcflag_t.XCASE) {
            result += "XCASE ";
        }
        if((self.c_lflag & tcflag_t.ECHO) == tcflag_t.ECHO) {
            result += "ECHO ";
        }
        if((self.c_lflag & tcflag_t.ECHOE) == tcflag_t.ECHOE) {
            result += "ECHOE ";
        }
        if((self.c_lflag & tcflag_t.ECHOK) == tcflag_t.ECHOK) {
            result += "ECHOK ";
        }
        if((self.c_lflag & tcflag_t.ECHONL) == tcflag_t.ECHONL) {
            result += "ECHONL ";
        }
        if((self.c_lflag & tcflag_t.ECHOCTL) == tcflag_t.ECHOCTL) {
            result += "ECHOCTL ";
        }
        if((self.c_lflag & tcflag_t.ECHOPRT) == tcflag_t.ECHOPRT) {
            result += "ECHOPRT ";
        }
        if((self.c_lflag & tcflag_t.ECHOKE) == tcflag_t.ECHOKE) {
            result += "ECHOKE ";
        }
        if((self.c_lflag & tcflag_t.FLUSHO) == tcflag_t.FLUSHO) {
            result += "FLUSHO ";
        }
        if((self.c_lflag & tcflag_t.NOFLSH) == tcflag_t.NOFLSH) {
            result += "NOFLSH ";
        }
        if((self.c_lflag & tcflag_t.TOSTOP) == tcflag_t.TOSTOP) {
            result += "TOSTOP ";
        }
        if((self.c_lflag & tcflag_t.PENDIN) == tcflag_t.PENDIN) {
            result += "PENDIN ";
        }
        if((self.c_lflag & tcflag_t.IEXTEN) == tcflag_t.IEXTEN) {
            result += "IEXTEN ";
        }

        result += "\n[c_cc]\n";

        result += sprintf("VEOF %d\n", self.c_cc[cc_t.VEOF.toInt()]);
        result += sprintf("VEOL %d\n", self.c_cc[cc_t.VEOL.toInt()]);
        result += sprintf("VEOL2 %d\n", self.c_cc[cc_t.VEOL2.toInt()]);
        result += sprintf("VERASE %d\n", self.c_cc[cc_t.VERASE.toInt()]);
        result += sprintf("VINTR %d\n", self.c_cc[cc_t.VINTR.toInt()]);
        result += sprintf("VKILL %d\n", self.c_cc[cc_t.VKILL.toInt()]);
        result += sprintf("VLNEXT %d\n", self.c_cc[cc_t.VLNEXT.toInt()]);
        result += sprintf("VMIN %d\n", self.c_cc[cc_t.VMIN.toInt()]);
        result += sprintf("VQUIT %d\n", self.c_cc[cc_t.VQUIT.toInt()]);
        result += sprintf("VREPRINT %d\n", self.c_cc[cc_t.VREPRINT.toInt()]);
        result += sprintf("VSTART %d\n", self.c_cc[cc_t.VSTART.toInt()]);
        result += sprintf("VSTOP %d\n", self.c_cc[cc_t.VSTOP.toInt()]);
        result += sprintf("VSUSP %d\n", self.c_cc[cc_t.VSUSP.toInt()]);
        result += sprintf("VTIME %d\n", self.c_cc[cc_t.VTIME.toInt()]);
        result += sprintf("VWERASE %d\n", self.c_cc[cc_t.VWERASE.toInt()]);

        return result.toString();
    }
}

enum TCSetAttrAction extends int
{
    TCSANOW, TCSADRAIN, TCSAFLUSH
}

class TCSetAttrAction
{
    TCSetAttrAction(long value) {
        self.setValue(value.toInt());
    }

    TCSetAttrAction(int value) {
        self.setValue(value);
    }

    static bool preinitialize() {
        TCSetAttrAction.TCSANOW, TCSetAttrAction.TCSADRAIN, TCSetAttrAction.TCSAFLUSH = 
#call CALL_C_BLOCK
#include <unistd.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("%dl.toTCSetAttrAction(), %dl.toTCSetAttrAction(), %dl.toTCSetAttrAction();", TCSANOW, TCSADRAIN, TCSAFLUSH);

    exit(0);
}
#endcall

        return true;
    }
}

mixin class System version 2
{
    native static Path getcwd();
    native static void execv(String command, Array<String> params) throws ConvertingStringCodeException, SystemException;
    native static void execvp(String command, Array<String> params) throws ConvertingStringCodeException, SystemException;
    native static pid_t fork() with void block() throws Exception, SystemException;
    native static int dup2(int fd1, int fd2) throws SystemException;
    native static int pipe(int* read_fd, int* write_fd) throws SystemException;
    native static pid_t getpid();
    native static pid_t getppid();
    native static pid_t getpgid(pid_t pid) throws SystemException;
    native static void setpgid(pid_t pid, pid_t pgid) throws SystemException;
    native static void tcsetpgrp(int fd, pid_t pgid) throws SystemException;
    native static int close(int fd) throws SystemException;
    native static Tuple<pid_t,WaitStatus> wait() throws SystemException;
    native static Tuple<pid_t,WaitStatus> waitpid(pid_t pid, WaitOption option) throws SystemException;
    native static int open(Path file_name, FileMode mode, int permission=0644) throws SystemException;
    native static int write(int fd, Bytes data) throws SystemException;
    native static int read(int fd, Bytes data, int size) throws SystemException;

    native static void stat(Path path, stat buf) throws SystemException;
    native static void lstat(Path path, stat buf) throws SystemException;
    native static time_t time();
    native static Path basename(Path path);
    native static Path dirname(Path path);
    native static void chmod(Path path, mode_t mode) throws SystemException;
    native static void lchmod(Path path, mode_t mode) throws SystemException;
    native static void chown(Path path, uid_t owner, gid_t group) throws SystemException;
    native static void lchown(Path path, uid_t owner, gid_t group) throws SystemException;
    native static uid_t getuid();
    native static gid_t getgid();
    native static void unlink(Path path) throws SystemException;

    /// the result is return value and err message //
    native static Tuple<int,String> access(Path path, AccessMode mode);

    native static void utime(Path path, utimbuf@Nullable times) throws SystemException;
    native static time_t mktime(tm time) throws SystemException;
    native static bool fnmatch(String pattern, Path path, FnmatchFlags flags) throws SystemException;
    native static void link(Path oldpath, Path newpath) throws SystemException;
    native static void symlink(Path oldpath, Path newpath) throws SystemException;
    native static Path readlink(Path path) throws SystemException;
    native static void rename(Path oldname, Path newname) throws SystemException;
    native static void truncate(Path path, off_t length) throws SystemException;
    native static mode_t umask(mode_t mask);
    native static void flock(int fd, FileLockOperation operation) throws SystemException;
    native static DIR opendir(Path path) throws SystemException;
    native static dirent@Nullable readdir(DIR dir) throws SystemException;
    native static void closedir(DIR dir) throws SystemException;
    native static void chdir(Path path) throws SystemException;
    native static void chroot(Path path) throws SystemException;
    native static void rmdir(Path path) throws SystemException;
    native static void mkdir(Path path,mode_t mode) throws SystemException;
    native static bool isatty(int fd);
    native static void tcgetattr(int fd, termios termios);
    native static void tcsetattr(int fd, TCSetAttrAction actions, termios termios);
    native static void kill(pid_t pid, Signal sig) throws SystemException;
    native static Path realpath(Path path) throws SystemException;
}

mixin class String version 2
{
    Command toCommand() {
        return new Command(self, 0);
    }

    Path toPath() {
        return new Path(self);
    }
}

class tm
{
    protected int tm_sec;
    protected int tm_min;
    protected int tm_hour;
    protected int tm_mday;
    protected int tm_mon;
    protected int tm_year;
    protected int tm_wday;
    protected int tm_yday;
    protected bool tm_isdst;

    native tm(time_t time);

    tm(int year, int month, int day_of_month, int hour=0, int minuts=0, int sec=0, int day_of_week=0, int day_of_year=0, bool isdst=false)
    {
        self.setYear(year);
        self.setMonth(month);
        self.setDayOfMonth(day_of_month);
        self.setHour(hour);
        self.setMinuts(minuts);
        self.setSecond(sec);
        self.setDayOfWeek(day_of_week);
        self.setDayOfYear(day_of_year);
        self.setDaylightSavingTime(isdst);
    }

    int second() {
        return self.tm_sec;
    }
    void setSecond(int value) {
        self.tm_sec = value;
    }
    int minuts() {
        return self.tm_min;
    }
    void setMinuts(int value) {
        self.tm_min = value;
    }
    int hour() {
        return self.tm_hour;
    }
    void setHour(int value) {
        self.tm_hour = value;
    }
    int dayOfMonth() {
        return self.tm_mday;
    }
    void setDayOfMonth(int value) {
        self.tm_mday = value;
    }
    int month() {
        return self.tm_mon + 1;
    }
    void setMonth(int value) {
        self.tm_mon = value -1;
    }
    int year() {
        return self.tm_year + 1900;
    }
    void setYear(int value) {
        self.tm_year = value - 1900;
    }
    int dayOfWeek() {
        return self.tm_wday;
    }
    void setDayOfWeek(int value) {
        self.tm_wday = value;
    }
    int dayOfYear() {
        return self.tm_yday;
    }
    void setDayOfYear(int value) {
        self.tm_yday = value;
    }
    bool isDaylightSavingTime() {
        return self.tm_isdst;
    }
    void setDaylightSavingTime(bool value) {
        self.tm_isdst = value;
    }

    virtual String toString() {
        return sprintf("%d-%02d-%02d %02d:%02d", self.year(), self.month(), self.dayOfMonth(), self.hour(), self.minuts());
    }

    time_t to_time_t() throws SystemException{
        return System.mktime(self);
    }
}

mixin class Clover version 2
{
    alias printf;
    alias sprintf;

    static Jobs jobs = new Jobs();

    /// called at the first part of runtime ///
    mixin static bool initialize() {
        bool result = mixin();
        if(result == false) {
            return false;
        }

        System.srand(System.time().toInt());

        if(System.getenv("CLOVER_NO_DELETE_TMP_FILES") == null) {
            String clover_home = System.getenv("HOME") + "/.clover/";

            Command.rm("-Rf", clover_home + "tmpfiles/*");
        }

        return true;
    }
    native static String sprintf(String format, Array<anonymous> params, ...);
    native static void printf(String format, Array<anonymous> params, ...);
}

enum FileMode extends int
{
    O_APPEND, O_ASYNC, O_CLOEXEC, O_CREAT, O_DIRECTORY, O_DSYNC, O_EXCL, O_NOCTTY, O_NOFOLLOW, O_NONBLOCK, O_RDONLY, O_RDWR, O_SYNC, O_TRUNC, O_WRONLY
}

class FileMode 
{
    FileMode(int value) {
        self.setValue(value);
    }

    static bool preinitialize() {
        FileMode.O_APPEND, FileMode.O_ASYNC, FileMode.O_CLOEXEC, FileMode.O_CREAT, FileMode.O_DIRECTORY, FileMode.O_DSYNC, FileMode.O_EXCL = 
#call CALL_C_BLOCK
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[]) {
    printf("%d.toFileMode(), %d.toFileMode(), %d.toFileMode(), %d.toFileMode(), %d.toFileMode(), %d.toFileMode(), %d.toFileMode();", O_APPEND, O_ASYNC, O_CLOEXEC, O_CREAT, O_DIRECTORY, O_DSYNC, O_EXCL);
    exit(0);
}
#endcall
        FileMode.O_NOCTTY, FileMode.O_NOFOLLOW, FileMode.O_NONBLOCK, FileMode.O_RDONLY, FileMode.O_RDWR, FileMode.O_SYNC, FileMode.O_TRUNC, FileMode.O_WRONLY = 
#call CALL_C_BLOCK
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[]) {
    printf("%d.toFileMode(), %d.toFileMode(), %d.toFileMode(), %d.toFileMode(), %d.toFileMode(), %d.toFileMode(), %d.toFileMode(), %d.toFileMode();",  O_NOCTTY, O_NOFOLLOW, O_NONBLOCK, O_RDONLY, O_RDWR, O_SYNC, O_TRUNC, O_WRONLY);
    exit(0);
}
#endcall

        return true;
    }
}

enum FileKind extends mode_t 
{
    S_IFMT, S_IFDIR, S_IFCHR, S_IFBLK, S_IFREG, S_IFIFO, S_IFLNK, S_IFSOCK
}

class FileKind
{
    FileKind (
#call GET_TYPE_FROM_C #include\ <fcntl.h> mode_t
#endcall
                          value)
    {
        self.setValue(value);
    }

#call DEFINE_CONSTRUCTOR_WITH_LONG #include\ <fcntl.h> mode_t FileKind
#endcall

    static bool preinitialize() {
        FileKind.S_IFMT, FileKind.S_IFDIR, FileKind.S_IFCHR, FileKind.S_IFBLK, FileKind.S_IFREG, FileKind.S_IFIFO, FileKind.S_IFLNK, FileKind.S_IFSOCK = 
#call CALL_C_BLOCK
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>

int main() {
    printf("%dl.toFileKind(), %dl.toFileKind(), %dl.toFileKind(), %dl.toFileKind(), %dl.toFileKind(), %dl.toFileKind(), %dl.toFileKind(), %dl.toFileKind();", S_IFMT, S_IFDIR, S_IFCHR, S_IFBLK, S_IFREG, S_IFIFO, S_IFLNK, S_IFSOCK);

    exit(0);
}

#endcall

        return true;
    }
}

enum Signal extends int
{
    SIGABRT, SIGALRM, SIGBUS, SIGCHLD, SIGCONT, SIGHUP, SIGFPE, SIGILL, SIGINT, SIGIO, SIGKILL, SIGQUIT, SIGPIPE, SIGPROF, SIGPWR, SIGSEGV, SIGSTOP, SIGTERM, SIGTRAP, SIGTSTP, SIGTTIN, SIGTTOU, SIGWINCH, SIGURG, SIGUSR1, SIGUSR2, SIGXCPU, SIGXFSZ, SIGVTALRM
}

class Signal
{
    Signal(int value) 
    {
        self.setValue(value);
    }

    static bool preinitialize() {
        Signal.SIGABRT, Signal.SIGALRM, Signal.SIGBUS, Signal.SIGCHLD, Signal.SIGCONT =
#call CALL_C_BLOCK
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("%d.toSignal(), %d.toSignal(), %d.toSignal(), %d.toSignal(), %d.toSignal();", SIGABRT, SIGALRM, SIGBUS, SIGCHLD, SIGCONT);

    exit(0);
}
#endcall
        Signal.SIGHUP, Signal.SIGFPE, Signal.SIGILL, Signal.SIGINT, Signal.SIGIO = 
#call CALL_C_BLOCK
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("%d.toSignal(), %d.toSignal(), %d.toSignal(), %d.toSignal(), %d.toSignal();", SIGHUP, SIGFPE, SIGILL, SIGINT, SIGIO);

    exit(0);
}
#endcall
         Signal.SIGKILL, Signal.SIGQUIT, Signal.SIGPIPE, Signal.SIGPROF, Signal.SIGPWR =
#call CALL_C_BLOCK
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("%d.toSignal(), %d.toSignal(), %d.toSignal(), %d.toSignal(), %d.toSignal();", SIGKILL, SIGQUIT, SIGPIPE, SIGPROF, SIGPWR);

    exit(0);
}
#endcall
         Signal.SIGSEGV, Signal.SIGSTOP, Signal.SIGTERM, Signal.SIGTRAP, Signal.SIGTSTP = 
#call CALL_C_BLOCK
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("%d.toSignal(), %d.toSignal(), %d.toSignal(), %d.toSignal(), %d.toSignal();", SIGSEGV, SIGSTOP, SIGTERM, SIGTRAP, SIGTSTP);

    exit(0);
}
#endcall
        Signal.SIGTTIN, Signal.SIGTTOU, Signal.SIGWINCH, Signal.SIGURG, Signal.SIGUSR1 =
#call CALL_C_BLOCK
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("%d.toSignal(), %d.toSignal(), %d.toSignal(), %d.toSignal(), %d.toSignal();", SIGTTIN, SIGTTOU, SIGWINCH, SIGURG, SIGUSR1);

    exit(0);
}
#endcall
        Signal.SIGUSR2, Signal.SIGXCPU, Signal.SIGXFSZ, Signal.SIGVTALRM =
#call CALL_C_BLOCK
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("%d.toSignal(), %d.toSignal(), %d.toSignal(), %d.toSignal();", SIGUSR2, SIGXCPU, SIGXFSZ, SIGVTALRM);

    exit(0);
}
#endcall

        return true;
    }
}

enum FileAccess extends mode_t 
{
    S_ISUID, S_ISGID, S_ISVTX, S_IRWXU, S_IRUSR, S_IWUSR, S_IXUSR, S_IRWXG, S_IRGRP, S_IWGRP, S_IXGRP, S_IRWXO, S_IROTH, S_IWOTH, S_IXOTH
}

class FileAccess
{
    FileAccess (
#call GET_TYPE_FROM_C #include\ <fcntl.h> mode_t
#endcall
                          value)
    {
        self.setValue(value);
    }

#call DEFINE_CONSTRUCTOR_WITH_LONG #include\ <fcntl.h> mode_t FileAccess
#endcall

    static bool preinitialize() {
        FileAccess.S_ISUID, FileAccess.S_ISGID, FileAccess.S_ISVTX, FileAccess.S_IRWXU, FileAccess.S_IRUSR, FileAccess.S_IWUSR, FileAccess.S_IXUSR, FileAccess.S_IRWXG = 
#call CALL_C_BLOCK
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>

int main() {
    printf("%dl.toFileAccess(), %dl.toFileAccess(), %dl.toFileAccess(), %dl.toFileAccess(), %dl.toFileAccess(), %dl.toFileAccess(), %dl.toFileAccess(), %dl.toFileAccess();", S_ISUID, S_ISGID, S_ISVTX, S_IRWXU, S_IRUSR, S_IWUSR, S_IXUSR, S_IRWXG);

    exit(0);
}
#endcall

        FileAccess.S_IRGRP, FileAccess.S_IWGRP, FileAccess.S_IXGRP, FileAccess.S_IRWXO, FileAccess.S_IROTH, FileAccess.S_IWOTH, FileAccess.S_IXOTH = 
#call CALL_C_BLOCK
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>

int main() {
    printf("%dl.toFileAccess(), %dl.toFileAccess(), %dl.toFileAccess(), %dl.toFileAccess(), %dl.toFileAccess(), %dl.toFileAccess(), %dl.toFileAccess();", S_IRGRP, S_IWGRP, S_IXGRP, S_IRWXO, S_IROTH, S_IWOTH, S_IXOTH);

    exit(0);
}
#endcall

        return true;
    }
}

class stat
{
    dev_t st_dev;
    //ino_t st_ino;
    mode_t st_mode;
    //nlink_t st_nlink;
    uid_t st_uid;
    gid_t st_gid;
    dev_t st_rdev;
    off_t st_size;
    //blksize_t st_blksize;
    //blkcnt_t st_blocks;
    time_t st_atime;
    time_t st_mtime;
    time_t st_ctime;

    stat(Path path, bool lstat=false) throws SystemException {
        if(lstat) {
            System.lstat(path, self);
        }
        else {
            System.stat(path, self);
        }
    }
    bool S_ISDIR() {
        return (self.st_mode & FileKind.S_IFMT) == FileKind.S_IFDIR;
    }
    bool S_ISCHR() {
        return (self.st_mode & FileKind.S_IFMT) == FileKind.S_IFCHR;
    }
    bool S_ISBLK() {
        return (self.st_mode & FileKind.S_IFMT) == FileKind.S_IFBLK;
    }
    bool S_ISREG() {
        return (self.st_mode & FileKind.S_IFMT) == FileKind.S_IFREG;
    }
    bool S_ISFIFO() {
        return (self.st_mode & FileKind.S_IFMT) == FileKind.S_IFIFO;
    }
    bool S_ISLNK() {
        return (self.st_mode & FileKind.S_IFMT) == FileKind.S_IFLNK;
    }
    bool S_ISSOCK() {
        return (self.st_mode & FileKind.S_IFMT) == FileKind.S_IFSOCK;
    }
    uid_t to_uid_t() {
        return self.st_uid;
    }
    gid_t to_gid_t() {
        return self.st_gid;
    }
    permission to_permission() {
        return self.st_mode.to_permission();
    }
    bool S_IXUGO() {
        return ((self.st_mode & FileAccess.S_IXUSR) == FileAccess.S_IXUSR) && ((self.st_mode & FileAccess.S_IXGRP) == FileAccess.S_IXGRP) && ((self.st_mode & FileAccess.S_IXOTH) == FileAccess.S_IXOTH);
    }
    tm atime() {
        return new tm(self.st_atime);
    }
    tm ctime() {
        return new tm(self.st_ctime);
    }
    tm mtime() {
        return new tm(self.st_mtime);
    }
    off_t size() {
        return self.st_size;
    }
}

class Path extends String
{
    Path(String value) {
        String new_value = "";
        if(value[0] == '~') {
            String home = System.getenv("HOME");

            if(home != null) {
                if(home[-1] == '/') {
                    new_value = home + value[1..null];
                }
                else {
                    new_value = home + "/" + value[1..null];
                }
            }
            else {
                new_value = value;
            }
        }
        else {
            new_value = value;
        }

        self.setValue(new_value);
    }

    virtual String toString() {
        String result = new String("");
        result.setValue(self);
        return result;
    }

    void toFile(String mode="r", int permission=0666) with void block(File file) throws Exception, SystemException
    {
        File file = File.open(self, mode, permission);
        block(file);
        file.close();
    }

    void write(Bytes data, int permission=0666) throws SystemException, Exception {
        File f = File.open(self, "w", permission);
        f.write(data);
        f.close();
    }

    Bytes readOut(int permission=0666) throws SystemException, Exception 
    {
        File f = File.open(self, "r", permission);
        Bytes result = f.readOut();
        f.close();

        return result;
    }

    stat to_stat() {
        return new stat(self, false);
    }
    stat to_lstat() {
        return new stat(self, true);
    }
    Path basename(String suffix=null) {
        Path result = System.basename(self);

        if(suffix == ".*") {
            int index = result.rindex(/\./);

            if(index != -1) {
                result = result[0..index].toPath();
            }
        }
        else if(suffix != null) {
            int index = result.rindex(suffix);

            if(index != -1 && index == result.length() - suffix.length()) {
                result = result[0..index].toPath();
            }
        }

        return result;
    }

    Path dirname() {
        return System.dirname(self);
    }

    Path extname() {
        int index = self.rindex(".");
        Path dirname = self.dirname();

        if(index == -1 || index == 0 || self[index-1] == '/' 
            || index < dirname.length()) 
        {
            return p"";
        }
        else {
            return self[index..null].toPath();
        }
    }

    void chmod(mode_t mode) throws SystemException {
        System.chmod(self, mode);
    }
    void lchmod(mode_t mode) throws SystemException {
        System.lchmod(self, mode);
    }
    void chown(uid_t owner=-1l.to_uid_t(), gid_t group=-1l.to_gid_t()) throws SystemException 
    {
        System.chown(self, owner, group);
    }
    void lchown(uid_t owner=-1l.to_uid_t(), gid_t group=-1l.to_gid_t()) throws SystemException 
    {
        System.lchown(self, owner, group);
    }
    void unlink() throws SystemException {
        System.unlink(self);
    }
    int access(AccessMode mode=AccessMode.F_OK) {
        return System.access(self, mode).get1();
    }
    bool existance() {
        return self.access(AccessMode.F_OK) == 0;
    }
    void utime(time_t actime, time_t modtime) {
        System.utime(self, new utimbuf(actime, modtime));
    }

    bool fnmatch(String pattern, FnmatchFlags flags=0.toFnmatchFlags()) {
        return System.fnmatch(pattern, self, flags);
    }

    bool isIdentical(Path path2) {
        return self.absolutePath() == path2.absolutePath();
    }

    Path absolutePath() {
        String result = self.clone();

        /// add current path to head ///
        if(result[0] != '/') {
            result = System.getcwd() + "/" + result;
        }

        /// delete ./ ///
        result = result.sub(/(\/\.)($|\/)/g) {
            |Array<String> group_strings, String prematch, String match, String postmatch|
            if(group_strings.length() == 2) {
                if(group_strings[1] == "/") {
                    return "/";
                }
            }

            return "";
        };

        /// delete .. ///
        result = result.sub(/^(\/\.\.)+($|\/)/) {
            |Array<String> group_strings, String prematch, String match, String postmatch|
            if(group_strings.length() == 2) {
                if(group_strings[1] == "/") {
                    return "/";
                }
            }

            return "";
        }

        result = result.sub(/(\/[^\/]+)(\/\.\.)($|\/)/g) {
            |Array<String> group_strings, String prematch, String match, String postmatch|

            if(group_strings.length() == 3) {
                if(group_strings[2] == "/") {
                    return "/";
                }
            }
            
            return "";
        }

        /// Is this path directory? If that is true, append / to the tail. If that is false, remove '/' at the tail  ///
        bool is_directory = false;
        try {
            is_directory = result.toPath().to_stat().S_ISDIR();
        }
        catch(SystemException e) {
            if(result[-1] == '/') {
                try {
                    is_directory = result[0..-1].toPath().to_stat().S_ISDIR();
                }
                catch(SystemException e) {
                    is_directory = false;
                }
            }
        }

        if(is_directory) {
            if(result[-1] != '/') {
                result += "/";
            }
        }
        else {
            if(result[-1] == '/') {
                result = result[0..-1];
            }
        }

        if(result == "") {
            result = "/";
        }
        
        return result.toPath();
    }

    Path realpath() throws SystemException {
        return System.realpath(self);
    }

    void link(Path newpath) throws SystemException {
        System.link(self, newpath);
    }

    void symlink(Path newpath) throws SystemException {
        System.symlink(self, newpath);
    }

    Path readlink() throws SystemException {
        return System.readlink(self);
    }

    void rename(Path path) throws SystemException {
        System.rename(self, path);
    }

    void truncate(off_t length) throws SystemException {
        System.truncate(self, length);
    }

    Array<Path> entries() throws SystemException {
        return Directory.entries(self);
    }

    Array<Path> glob(String pattern, FnmatchFlags flags=0.toFnmatchFlags()) throws SystemException
    {
        return Directory.glob(self, pattern, flags);
    }

    void chdir() throws SystemException {
        System.chdir(self);
    }

    void rmdir() throws SystemException {
        System.rmdir(self);
    }

    void mkdir(mode_t mode=0777l.to_mode_t()) {
        System.mkdir(self, mode);
    }
}

mixin struct int version 2
{
    Signal toSignal() {
        return new Signal(self);
    }
    WaitOption toWaitOption() {
        return new WaitOption(self);
    }
    AccessMode toAccessMode() {
        return new AccessMode(self);
    }
    FnmatchFlags toFnmatchFlags() {
        return new FnmatchFlags(self);
    }
    FileLockOperation toFileLockOperation() {
        return new FileLockOperation(self);
    }
    FileMode toFileMode() {
        return new FileMode(self);
    }
    pid_t to_pid_t() {
        return new pid_t(self);
    }
}

abstract class FileBase 
{
    int descriptor;

    abstract int write(Bytes data) throws IOException, Exception;
    abstract int read(Bytes data, int size) throws IOException;
}

class File extends FileBase
{
    Path path;

    File(Path path, String mode="r", int permission=0666) throws Exception, SystemException {
        if(mode == "w") {
            self.descriptor = System.open(path, (FileMode.O_CREAT|FileMode.O_WRONLY|FileMode.O_TRUNC).toFileMode(), permission);
        }
        else if(mode == "w+") {
            self.descriptor = System.open(path, (FileMode.O_RDWR|FileMode.O_CREAT|FileMode.O_TRUNC).toFileMode(), permission);
        }
        else if(mode == "r") {
            self.descriptor = System.open(path, FileMode.O_RDONLY, permission);
        }
        else if(mode == "r+") {
            self.descriptor = System.open(path, FileMode.O_RDWR, permission);
        }
        else if(mode == "a") {
            self.descriptor = System.open(path, (FileMode.O_WRONLY|FileMode.O_CREAT|FileMode.O_APPEND).toFileMode(), permission);
        }
        else if(mode == "a+") {
            self.descriptor = System.open(path, (FileMode.O_RDWR|FileMode.O_CREAT|FileMode.O_APPEND).toFileMode(), permission);
        }
        else {
            throw new Exception("invalid mode");
        }

        self.path = path;
    }

    static File open(Path path, String mode="r", int permission=0666) {
        return new File(path, mode, permission);
    }

    static void open(Path path, String mode="r", int permission=0666) with void block(File file) throws Exception, SystemException
    {
        File file = new File(path, mode, permission);
        block(file);
        file.close();
    }

    virtual int write(Bytes data) throws SystemException, Exception {
        if(self.descriptor == null) {
            throw new Exception("This file is not opened");
        }

        return System.write(self.descriptor, data);
    }
    virtual int read(Bytes data, int size) throws SystemException, Exception {
        if(self.descriptor == null) {
            throw new Exception("This file is not opened");
        }

        return System.read(self.descriptor, data, size);
    }

    int close() throws SystemException, Exception {
        if(self.descriptor == null) {
            throw new Exception("This file is not opened");
        }

        return System.close(self.descriptor);
    }

    static mode_t umask() {
        mode_t mask = System.umask(0l.to_mode_t());
        System.umask(mask);
        return mask;
    }

    static void umask(mode_t mask) {
        System.umask(mask);
    }

    void flock(FileLockOperation operation) throws SystemException,Exception {
        if(self.descriptor == null) {
            throw new Exception("This file is not opened");
        }

        System.flock(self.descriptor, operation);
    }

    Path toPath() throws Exception {
        if(self.path == null) {
            throw new Exception("This file is not opened");
        }

        return self.path;
    }

    stat to_stat() throws Exception {
        if(self.path == null) {
            throw new Exception("This file is not opened");
        }

        return self.path.to_stat();
    }

    Bytes readOut() throws SystemException, Exception {
        if(self.descriptor == null) {
            throw new Exception("This file is not opened");
        }

        Bytes result = B"";

        while(true) {
            Bytes buf = B"";

            System.read(self.descriptor, buf, 1024@size);

            result += buf;

            if(buf.length() < 1024) {
                break;
            }
        }

        return result;
    }
}

class Directory
{
    Path path;
    DIR dir;

    Directory(Path path) throws SystemException {
        self.path = path;
        self.dir = System.opendir(path);
    }

    Path@Nullable readdir() throws SystemException, Exception {
        if(self.dir == null) {
            throw new Exception("This directory is not opened");
        }

        dirent entry = System.readdir(self.dir);

        if(entry == null) {
            return null;
        }
        else {
            return entry.d_name.toString().toPath();
        }
    }

    void close() throws Exception {
        if(self.dir == null) {
            throw new Exception("This directory is not opened");
        }

        System.closedir(self.dir);
    }

    static Array<Path> entries(Path path) throws SystemException {
        Directory dir = new Directory(path);
        Array<Path> result = new Array<Path>();

        while(true) {
            Path entry = dir.readdir();

            if(entry == null) {
                break;
            }

            if(entry != p"." && entry != p"..") {
                result.add(entry);
            }
        }
        dir.close();

        return result;
    }

    static Array<Path> glob(Path path, String pattern, FnmatchFlags flags=0.toFnmatchFlags()) throws SystemException
    {
        Directory dir = new Directory(path);
        Array<Path> result = new Array<Path>();

        while(true) {
            Path entry = dir.readdir();

            if(entry == null) {
                break;
            }

            if(System.fnmatch(pattern, entry, flags)) {
                result.add(entry);
            }
        }
        dir.close();

        return result;
    }

    static Array<Path> glob(String pattern, FnmatchFlags flags=0.toFnmatchFlags()) throws SystemException
    {
        return Directory.glob(p".", pattern, flags);
    }
}

class Job 
{
    String title;
    pid_t pgrp;
    termios terminfo;

    Job(String title, pid_t pgrp, termios terminfo) {
        self.title = title;
        self.pgrp = pgrp;
        self.terminfo = terminfo;
    }

    virtual String toString() {
        return self.title;
    }
}

class Jobs 
{
    Array<Job> jobs;

    Jobs() {
        self.jobs = new Array<Job>();
    }
    void add(Job job) {
        self.jobs.add(job);
    }
    void forground(int job_num) {
        if(job_num >= 0 && job_num < self.jobs.length()) {
            Job job = self.jobs[job_num];

            termios terminfo = new termios();
            System.tcgetattr(0, terminfo);

            System.tcsetattr(0, TCSetAttrAction.TCSANOW, job.terminfo);
            System.tcsetpgrp(0, job.pgrp);

            System.kill(job.pgrp, Signal.SIGCONT);

            pid_t pid2, WaitStatus status = System.waitpid(job.pgrp, WaitOption.WUNTRACED);

            if(status.WIFSTOPPED()) {
                int rcode = status.WSTOPSIG() +128;

                termios terminfo2 = new termios();
                System.tcgetattr(0, terminfo2);

                job.terminfo = terminfo2;

                System.tcsetattr(0, TCSetAttrAction.TCSANOW, terminfo);
                System.tcsetpgrp(0, System.getpid());
            }
            else if(status.WIFSIGNALED()) {
                printf("Job<%s> is done.\n", job.title);

                self.jobs.deleteIf() { |Job job2| return job2.ID() == job.ID() };

                System.tcsetattr(0, TCSetAttrAction.TCSANOW, terminfo);
                System.tcsetpgrp(0, System.getpid());
            }
            else {
                self.jobs.deleteIf() { |Job job2| return job2.ID() == job.ID(); };

                System.tcsetattr(0, TCSetAttrAction.TCSANOW, terminfo);
                System.tcsetpgrp(0, System.getpid());
            }
        }
    }

    virtual String toString() {
        StringBuffer result = new StringBuffer("");

        for(int i=0; i<self.jobs.length(); i++) {
            result += "<" + i.toString() + ">";
            result += self.jobs[i].toString();
            result += "\n";
        }

        return result.toString();
    }
}

dynamic_typing final class Command implements IInspectable 
{
    protected String data;
    protected int resultCode;

    static Array<String> controllingTerminalPrograms = { "vim", "less", "top", "lv", "htop", "emacs", "nano", "vi", "fd", "mc" };

    Command() {
        self.data = "";
        self.resultCode = 0;
    }

    Command(Command value) {
        self.setValue(value);
    }

    Command(String data, int result_code) {
        self.data = data;
        self.resultCode = result_code;
    }

    int resultCode() {
        return self.resultCode;
    }

    virtual String toString() {
        return self.data;
    }

    Command write(Path path, int permission=0666) throws SystemException, Exception {
        File f = new File(path, "w", permission);
        f.write(self.data.toBytes());
        f.close();

        return self;
    }

    static Command excuteCommandWithControllingTerminalByPipe(String method_name, Array<anonymous> params, Block method_block, String pipe_data)
    {
        int parent2child_write_fd = 0;
        int parent2child_read_fd = 0;

        System.pipe(parent2child_read_fd, parent2child_write_fd);

        pid_t pid = System.fork() {
            System.close(parent2child_write_fd);

            pid_t pid = System.getpid();

            System.setpgid(0.to_pid_t(), 0.to_pid_t());
            System.tcsetpgrp(0, pid);

            System.dup2(parent2child_read_fd, 0);
            System.close(parent2child_read_fd);

            try {
                System.execvp(method_name, params.select() {|anonymous param| return String->substitutionPosibility(param.type()); } );
            } catch(SystemException e) {
                System.write(2, (e.getMessage() + "\n").toBytes());
                System.exit(2);
            }
        }

        System.setpgid(pid, pid);
        System.tcsetpgrp(0, pid);

        System.close(parent2child_read_fd);

        if(pipe_data != null) {
            System.write(parent2child_write_fd, pipe_data.toBytes());
        }
        System.close(parent2child_write_fd);

        pid_t pid2, WaitStatus status = System.waitpid(pid, WaitOption.WUNTRACED);

        if(status.WIFSTOPPED()) {
            int rcode = status.WSTOPSIG() +128;
            String title = method_name;

            termios terminfo = new termios();
            System.tcgetattr(0, terminfo);

            Job job = new Job(title, pid, terminfo);

            Clover.jobs.add(job);

            System.tcsetpgrp(0, System.getpid());

            return new Command("", rcode);
        }
        else {
            System.tcsetpgrp(0, System.getpid());

            return new Command("", status.WEXITSTATUS());
        }
    }

    static Command excuteCommandWithControllingTerminal(String method_name, Array<anonymous> params, Block method_block)
    {
        pid_t pid = System.fork() {
            pid_t pid = System.getpid();

            System.setpgid(0.to_pid_t(), 0.to_pid_t());
            System.tcsetpgrp(0, pid);

            try {
                System.execvp(method_name, params.select() {|anonymous param| return String->substitutionPosibility(param.type()); } );
            } catch(SystemException e) {
                System.write(2, (e.getMessage() + "\n").toBytes());
                System.exit(2);
            }
        }

        System.setpgid(pid, pid);
        System.tcsetpgrp(0, pid);

        pid_t pid2, WaitStatus status = System.waitpid(pid, WaitOption.WUNTRACED);

        System.tcsetpgrp(0, System.getpid());

        if(status.WIFSTOPPED()) {
            int rcode = status.WSTOPSIG() +128;
            String title = method_name;

            termios terminfo = new termios();
            System.tcgetattr(0, terminfo);

            Job job = new Job(title, pid, terminfo);

            Clover.jobs.add(job);

            System.tcsetpgrp(0, System.getpid());

            return new Command("", rcode);
        }
        else {
            System.tcsetpgrp(0, System.getpid());

            return new Command("", status.WEXITSTATUS());
        }

        return new Command("", status.WEXITSTATUS());
    }

    static Command executeCommand(String method_name, Array<anonymous> params, Block method_block, String pipe_data) 
    {
        int child2parent_write_fd = 0;
        int child2parent_read_fd = 0;
        int parent2child_write_fd = 0;
        int parent2child_read_fd = 0;

        System.pipe(child2parent_read_fd, child2parent_write_fd);
        System.pipe(parent2child_read_fd, parent2child_write_fd);

        pid_t pid = System.fork() {
            System.close(parent2child_write_fd);
            System.close(child2parent_read_fd);

            System.dup2(parent2child_read_fd, 0);
            System.dup2(child2parent_write_fd, 1);

            System.close(parent2child_read_fd);
            System.close(child2parent_write_fd);

            try {
                System.execvp(method_name, params.select() {|anonymous param| return String->substitutionPosibility(param.type()); } );
            } catch(SystemException e) {
                System.write(2, (e.getMessage() + "\n").toBytes());
                System.exit(2);
            }
        }

        System.close(parent2child_read_fd);
        System.close(child2parent_write_fd);

        if(pipe_data != null) {
            System.write(parent2child_write_fd, pipe_data.toBytes());
        }
        System.close(parent2child_write_fd);

        Bytes child_output = B"";
        
        while(true) {
            Bytes pipe_data = B"";

            int readed_byte = System.read(child2parent_read_fd, pipe_data, 10);

            if(readed_byte == 0) {
                break;
            }

            child_output += pipe_data;
        }

        System.close(child2parent_read_fd);

        pid_t pid2, WaitStatus status = System.waitpid(pid, WaitOption.WUNTRACED);

        return new Command(child_output.toString(), status.WEXITSTATUS());
    }

    static Command methodMissing(String method_name, Array<anonymous> params, Block method_block) 
    {
        if(Command.controllingTerminalPrograms.include(method_name)) {
            return Command.excuteCommandWithControllingTerminal(method_name, params, method_block);
        }
        else {
            return Command.executeCommand(method_name, params, method_block, null);
        }
    }

    Command methodMissing(String method_name, Array<anonymous> params, Block method_block)
    {
        if(Command.controllingTerminalPrograms.include(method_name)) {
            return Command.excuteCommandWithControllingTerminalByPipe(method_name, params, method_block, self.data);
        }
        else {
            return Command.executeCommand(method_name, params, method_block, self.data);
        }
    }
}
