#include "common.h"

extern "C" {
#include <libgen.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <pwd.h>
}

VALUE mf_keycommand(VALUE self, VALUE rmeta, VALUE rkeycode, VALUE rextension, VALUE rcommand)
{
TBEGIN();

    Check_Type(rmeta, T_FIXNUM);
    Check_Type(rkeycode, T_FIXNUM);
    Check_Type(rextension, T_STRING);
    Check_Type(rcommand, T_STRING);

    int meta = NUM2INT(rmeta);
    int keycode = NUM2INT(rkeycode);
    char* extension = RSTRING(rextension)->ptr;
    char* command = RSTRING(rcommand)->ptr;

    hash_put(gKeyCommand[meta][keycode], extension, STRDUP(command));

//M(("%d %d %s %s (%s)\n", meta, keycode, extension, command, RSTRING(gKeyCommand[meta][keycode][extension])->ptr));


TEND();                 
    return Qnil;
}

VALUE mf_exit(VALUE self)
{
TBEGIN();
    if(gCheckExit) {
        const char* str[] = {
            "Yes", "No"
        };

        int ret = select_str("exit ok?", (char**)str, 2, 1);

        if(ret == 1) return Qnil;
    }

    gMainLoop = false;

TEND();    
    return Qnil;
}

VALUE mf_cursor_move(VALUE self, VALUE rvalue)
{
TBEGIN();

    Check_Type(rvalue, T_FIXNUM);
    
    ActiveDir()->MoveCursor(NUM2INT(rvalue));

TEND();
    
    return Qnil;
}

VALUE mf_cursor_left(VALUE self)
{
TBEGIN();

    if(gRDir->mActive) gLDir->Activate(gRDir);
    
TEND();
    
    return Qnil;
}

VALUE mf_cursor_right(VALUE self)
{
TBEGIN();

    if(gLDir->mActive) gRDir->Activate(gLDir);

TEND();
    
    return Qnil;
}

VALUE mf_cursor_other(VALUE self)
{
TBEGIN();

    if(gLDir->mActive)
        gRDir->Activate(gLDir);
    else
        gLDir->Activate(gRDir); 

TEND();
    
    return Qnil;
}

VALUE mf_dir_move(VALUE self, VALUE rdir)
{
TBEGIN();

    Check_Type(rdir, T_STRING);
    
    ActiveDir()->Move(RSTRING(rdir)->ptr);

TEND();    

    return Qnil;
}

VALUE mf_sdir_move(VALUE self, VALUE rdir)
{
TBEGIN();

    Check_Type(rdir, T_STRING);
    
    SleepDir()->Move(RSTRING(rdir)->ptr);

TEND();    

    return Qnil;
}

VALUE mf_view_nameonly(VALUE self)
{
TBEGIN();

    cDirWnd::gViewNameOnly = !cDirWnd::gViewNameOnly;

    ActiveDir()->MoveCursor(0);
    SleepDir()->MoveCursor(0);

TEND();

    return Qnil;
}

VALUE mf_view_all(VALUE self)
{
TBEGIN();

    cDirWnd::gViewOption = cDirWnd::kAll;

    ActiveDir()->MoveCursor(0);
    SleepDir()->MoveCursor(0);

TEND();

    return Qnil;
}

VALUE mf_view_onedir(VALUE self)
{
TBEGIN();

    cDirWnd::gViewOption = cDirWnd::kOneDir;

    ActiveDir()->MoveCursor(0);
    SleepDir()->MoveCursor(0);

TEND();

    return Qnil;
}

VALUE mf_view_onedir2(VALUE self)
{
TBEGIN();

    cDirWnd::gViewOption = cDirWnd::kOneDir2;

    ActiveDir()->MoveCursor(0);
    SleepDir()->MoveCursor(0);

TEND();

    return Qnil;
}

VALUE mf_view_onedir3(VALUE self)
{
TBEGIN();

    cDirWnd::gViewOption = cDirWnd::kOneDir3;

    ActiveDir()->MoveCursor(0);
    SleepDir()->MoveCursor(0);

TEND();

    return Qnil;
}

VALUE mf_view_onedir5(VALUE self)
{
TBEGIN();

    cDirWnd::gViewOption = cDirWnd::kOneDir5;

    ActiveDir()->MoveCursor(0);
    SleepDir()->MoveCursor(0);

TEND();

    return Qnil;
}

VALUE mf_isearch(VALUE self)
{
TBEGIN();

    gISearch = !gISearch;
    
TEND();

    return Qnil;
}

VALUE mf_is_isearch_on(VALUE self)
{
    if(gISearch)
        return Qtrue;
    else
        return Qfalse;
}

VALUE mf_isearch_off(VALUE self)
{
TBEGIN();

    gISearch = false;
    
TEND();

    return Qnil;
}

VALUE mf_isearch_on(VALUE self)
{
TBEGIN();

    gISearch = true;
    
TEND();

    return Qnil;
}


VALUE mf_option_remain_marks(VALUE self, VALUE boolean)
{
TBEGIN();

    cDirWnd::gRemainMarks = (boolean == Qtrue);

TEND();

    return Qnil;
}


VALUE mf_option_color(VALUE self, VALUE boolean)
{
TBEGIN();

    gColor = (boolean == Qtrue);

TEND();

    return Qnil;
}

VALUE mf_option_bold_exe(VALUE self, VALUE boolean)
{
TBEGIN();

    gBoldExe = (boolean == Qtrue);

TEND();

    return Qnil;
}

VALUE mf_option_bold_dir(VALUE self, VALUE boolean)
{
TBEGIN();

    gBoldDir = (boolean == Qtrue);

TEND();

    return Qnil;
}

VALUE mf_option_color_mark(VALUE self, VALUE color)
{
TBEGIN();
    Check_Type(color, T_FIXNUM);

    gColorMark = NUM2INT(color);
TEND();    

    return Qnil;
}

VALUE mf_option_color_exe(VALUE self, VALUE color)
{
TBEGIN();
    Check_Type(color, T_FIXNUM);

    gColorExe = NUM2INT(color);
TEND();    

    return Qnil;
}

VALUE mf_option_color_dir(VALUE self, VALUE color)
{
TBEGIN();
    Check_Type(color, T_FIXNUM);

    gColorDir = NUM2INT(color);
TEND();    

    return Qnil;
}

VALUE mf_option_color_link(VALUE self, VALUE color)
{
TBEGIN();
    Check_Type(color, T_FIXNUM);

    gColorLink = NUM2INT(color);
TEND();    

    return Qnil;
}

VALUE mf_option_individual_cursor(VALUE self, VALUE boolean)
{
TBEGIN();

    gIndividualCursor = (boolean == Qtrue);

TEND();

    return Qnil;
}

VALUE mf_option_isearch_decision_way(VALUE self, VALUE way)
{
TBEGIN();

    Check_Type(way, T_STRING);

    if(strcmp(RSTRING(way)->ptr, "enter_decision") == 0) {
        gISearchMismatchFinish = false;
        gISearchEnterDecision = true;
    }
    else if(strcmp(RSTRING(way)->ptr, "mismatch_finish") == 0) {
        gISearchMismatchFinish = true;
        gISearchEnterDecision = true;
    }
    else  if(strcmp(RSTRING(way)->ptr, "slash_toggle") == 0) {
        gISearchMismatchFinish = false;
        gISearchEnterDecision = false;
    }

TEND();

    return Qnil;
}

VALUE mf_option_shift_isearch(VALUE self, VALUE boolean)
{
TBEGIN();

    gShiftISearch = (boolean == Qtrue);

TEND();

    return Qnil;
}

VALUE mf_option_check_delete_file(VALUE self, VALUE boolean)
{
TBEGIN();

    gCheckDeleteFile = (boolean == Qtrue);

TEND();

    return Qnil;
}

VALUE mf_option_check_copy_file(VALUE self, VALUE boolean)
{
TBEGIN();

    gCheckCopyFile = (boolean == Qtrue);

TEND();

    return Qnil;
}

VALUE mf_option_check_exit(VALUE self, VALUE boolean)
{
TBEGIN();

    gCheckExit = (boolean == Qtrue);

TEND();

    return Qnil;
}

VALUE mf_option_trashbox_name(VALUE self, VALUE name)
{
TBEGIN();

    Check_Type(name, T_STRING);

    strcpy(gTrashBoxName, RSTRING(name)->ptr);

TEND();

    return Qnil;
}

VALUE mf_option_kanjicode(VALUE self, VALUE name)
{
TBEGIN();

    Check_Type(name, T_STRING);

    if(strcmp(RSTRING(name)->ptr, "sjis") == 0){
        gKanjiCode = kSjis;
    }
    else if(strcmp(RSTRING(name)->ptr, "utf8") == 0) {
        gKanjiCode = kUtf;
    }
    else {
        gKanjiCode = kEuc;
    }

TEND();

    return Qnil;
}

VALUE mf_option_gnu_screen(VALUE self, VALUE boolean)
{
TBEGIN();

    gGnuScreen = (boolean == Qtrue);

TEND();

    return Qnil;
}

VALUE mf_option_xterm(VALUE self, VALUE boolean)
{
TBEGIN();

    gXterm = (boolean == Qtrue);

TEND();

    return Qnil;
}

VALUE mf_option_pty(VALUE self, VALUE boolean)
{
TBEGIN();

    gPty = (boolean == Qtrue);

TEND();

    return Qnil;
}

VALUE mf_option_remain_cursor(VALUE self, VALUE boolean)
{
TBEGIN();

    gRemainCursor = (boolean == Qtrue);

TEND();

    return Qnil;
}

VALUE mf_option_auto_rehash(VALUE self, VALUE boolean)
{
TBEGIN();

    gAutoRehash = (boolean == Qtrue);

TEND();

    return Qnil;
}

VALUE mf_option_select(VALUE self, VALUE boolean)
{
TBEGIN();

    gSelect = (boolean == Qtrue);

TEND();

    return Qnil;
}

VALUE mf_sort_toggle_dir_up(VALUE self)
{
TBEGIN();

    cDirWnd::gSortDirUp = !cDirWnd::gSortDirUp;

    gLDir->Sort();
    gRDir->Sort();

TEND();

    return Qnil;
}

VALUE mf_sort_name(VALUE self)
{
TBEGIN();

    cDirWnd::gSortKind = cDirWnd::kName;

    gLDir->Sort();
    gRDir->Sort();

TEND();    

    return Qnil;
}

VALUE mf_sort_name_reverse(VALUE self)
{
TBEGIN();

    cDirWnd::gSortKind = cDirWnd::kNameReverse;

    gLDir->Sort();
    gRDir->Sort();

TEND();    

    return Qnil;
}

VALUE mf_sort_ext(VALUE self)
{
TBEGIN();

    cDirWnd::gSortKind = cDirWnd::kExt;

    gLDir->Sort();
    gRDir->Sort();

TEND();
    
    return Qnil;
}

VALUE mf_sort_ext_reverse(VALUE self)
{
TBEGIN();

    cDirWnd::gSortKind = cDirWnd::kExtReverse;

    gLDir->Sort();
    gRDir->Sort();

TEND();
    
    return Qnil;
}

VALUE mf_sort_size(VALUE self)
{
TBEGIN();

    cDirWnd::gSortKind = cDirWnd::kSize;

    gLDir->Sort();
    gRDir->Sort();

TEND();    

    return Qnil;
}

VALUE mf_sort_size_reverse(VALUE self)
{
TBEGIN();

    cDirWnd::gSortKind = cDirWnd::kSizeReverse;

    gLDir->Sort();
    gRDir->Sort();

TEND();    

    return Qnil;
}

VALUE mf_sort_time(VALUE self)
{
TBEGIN();

    cDirWnd::gSortKind = cDirWnd::kTime;

    gLDir->Sort();
    gRDir->Sort();

TEND();    

    return Qnil;
}

VALUE mf_sort_time_reverse(VALUE self)
{
TBEGIN();

    cDirWnd::gSortKind = cDirWnd::kTimeReverse;

    gLDir->Sort();
    gRDir->Sort();

TEND();    

    return Qnil;
}

VALUE mf_mark_all(VALUE self)
{
TBEGIN();

    ActiveDir()->MarkAll();

TEND();    

    return Qnil;
}

VALUE mf_mark_all_files(VALUE self)
{
TBEGIN();

    ActiveDir()->MarkAllFiles();

TEND();    

    return Qnil;
}

VALUE mf_mark(VALUE self)
{
TBEGIN();

    ActiveDir()->Mark();
    ActiveDir()->MoveCursor(ActiveDir()->Cursor() + 1);

TEND();    
    
    return Qnil;
}

VALUE mf_cmdline(VALUE self, VALUE command, VALUE position)
{
TBEGIN();

    Check_Type(command, T_STRING);
    Check_Type(position, T_FIXNUM);
    
    cmdline_start(RSTRING(command)->ptr, NUM2INT(position));

TEND();    
    
    return Qnil;
}

VALUE mf_shell(VALUE self, VALUE cmd, VALUE title)
{
TBEGIN();

    Check_Type(cmd, T_STRING);
    Check_Type(title, T_STRING);

    cmdline_run(RSTRING(cmd)->ptr, RSTRING(title)->ptr);

TEND();    

    return Qnil;
}

VALUE mf_defmenu(int argc, VALUE* argv, VALUE self)
{
TBEGIN();

    /// check arguments ///
    if(argc%3 != 1) {
        rb_raise(rb_eArgError, "wrong argument in mf_menu");
    }

    /// entry menu ///
    char* menu_name = RSTRING(argv[0])->ptr;
    
    if(hash_item(gMenu, menu_name)) {
        rb_raise(rb_eArgError, "already entried menu \"%s\"", menu_name);
    }

    cMenu* new_menu = new cMenu((char*)menu_name);

    for(int i=1; i<argc; i+=3) {
        Check_Type(argv[i], T_STRING);
        Check_Type(argv[i+1], T_FIXNUM);
        Check_Type(argv[i+2], T_STRING);

        new_menu->Append(RSTRING(argv[i])->ptr, NUM2INT(argv[i+1]), RSTRING(argv[i+2])->ptr);
    }
    
    hash_put(gMenu, menu_name, new_menu);

TEND();

    return Qnil;
}

VALUE mf_menu(VALUE self, VALUE menu_name)
{
TBEGIN();

    Check_Type(menu_name, T_STRING);

    gActiveMenu = (cMenu*)hash_item(gMenu, RSTRING(menu_name)->ptr);
    if(gActiveMenu == NULL) {
        gErrMsgCancel = false; 
        err_msg("not found menu name(%s)", RSTRING(menu_name)->ptr);
        gActiveMenu = NULL;
        return Qnil;
    }
    gActiveMenu->Show();

TEND();    

    return Qnil;
}

VALUE mf_dir_copy(VALUE self)
{
TBEGIN();

    ActiveDir()->Move(SleepDir()->Path());
    
TEND();    
    
    return Qnil;
}

VALUE mf_dir_exchange(VALUE self)
{
TBEGIN();

    cDirWnd* wnd = gLDir;
    gLDir = gRDir;
    gRDir = wnd;

TEND();    
    
    return Qnil;
}

VALUE mf_refresh(VALUE self)
{
TBEGIN();

    gLDir->Reread();
    gRDir->Reread(); 
   
    mclear_immediately();
    mclear();
    mrefresh();

TEND();
    
    return Qnil;
}

VALUE mf_reread(VALUE self)
{
TBEGIN();

    gLDir->Reread();
    gRDir->Reread();

TEND();
    
    return Qnil;
}

VALUE mf_dir_back(VALUE self)
{
TBEGIN();

    ActiveDir()->MoveBack();

TEND();    

    return Qnil;
}

VALUE mf_cursor_name(VALUE self)
{
    return rb_str_new2(ActiveDir()->CursorFile()->mName);
}

VALUE mf_cursor_path(VALUE self)
{
    char buf[512];
    sprintf(buf, "%s%s", ActiveDir()->Path(), ActiveDir()->CursorFile()->mName);
    
    return rb_str_new2(buf);
}

VALUE mf_cursor_ext(VALUE self)
{
TBEGIN();
    char* tmp = extname(ActiveDir()->CursorFile()->mName);
    VALUE result = rb_str_new2(tmp);
    FREE(tmp);
TEND();    

    return result;
}

VALUE mf_cursor_noext(VALUE self)
{
TBEGIN();

    char* tmp = noextname(ActiveDir()->CursorFile()->mName);
    VALUE result = rb_str_new2(tmp);
    FREE(tmp);

TEND();    

    return result;
}

VALUE mf_active_dir(VALUE self)
{
    char* tmp = STRDUP(ActiveDir()->Path());
    char* tmp2 = basename(tmp);
    FREE(tmp);
    return rb_str_new2(tmp2);
}

VALUE mf_sleep_dir(VALUE self)
{
    char* tmp = STRDUP(SleepDir()->Path());
    char* tmp2 = basename(tmp);
    FREE(tmp);
    return rb_str_new2(tmp2);
}

VALUE mf_left_dir(VALUE self)
{
    char* tmp = STRDUP(gLDir->Path());
    char* tmp2 = basename(tmp);
    FREE(tmp);
    return rb_str_new2(tmp2);
}

VALUE mf_right_dir(VALUE self)
{
    char* tmp = STRDUP(gRDir->Path());
    char* tmp2 = basename(tmp);
    FREE(tmp);
    return rb_str_new2(tmp2);
}

VALUE mf_adir_path(VALUE self)
{
    char buf[1024];
    strcpy(buf, ActiveDir()->Path());
    buf[strlen(buf)-1] = 0;

    return rb_str_new2(buf);
}

VALUE mf_sdir_path(VALUE self)
{
    char buf[1024];
    strcpy(buf, SleepDir()->Path());
    buf[strlen(buf)-1] = 0;

    return rb_str_new2(buf);
}

VALUE mf_ldir_path(VALUE self)
{
    char buf[1024];
    strcpy(buf, gLDir->Path());
    buf[strlen(buf)-1] = 0;

    return rb_str_new2(buf);
}

VALUE mf_rdir_path(VALUE self)
{
    char buf[1024];
    strcpy(buf, gRDir->Path());
    buf[strlen(buf)-1] = 0;

    return rb_str_new2(buf);
}

VALUE mf_adir_mark(VALUE self)
{
    return ActiveDir()->MarkFiles();
}

VALUE mf_sdir_mark(VALUE self)
{
    return SleepDir()->MarkFiles();
}

VALUE mf_is_adir_left(VALUE self)
{
    if(ActiveDir()->IsLeftDir()) {
        return Qtrue;
    }
    else {
        return Qfalse;
    }
}

VALUE mf_is_adir_right(VALUE self)
{
    if(ActiveDir()->IsRightDir()) {
        return Qtrue;
    }
    else {
        return Qfalse;
    }
}

VALUE mf_dir_new(VALUE self)
{
    ActiveDir()->PushBackDir();

    return Qnil;
}

VALUE mf_dir_close(VALUE self)
{
    ActiveDir()->PopDir();
    
    return Qnil;
}

VALUE mf_dir_up(VALUE self)
{
    ActiveDir()->PushBackDir();
    ActiveDir()->PopDir();

    return Qnil;
}

VALUE mf_copy(VALUE self, VALUE sdir, VALUE files, VALUE ddir)
{
TBEGIN();
    if(gCheckCopyFile) {
        const char* str[] = {
            "Yes", "No"
        };

        int ret = select_str("copy ok?", (char**)str, 2, 1);

        if(ret == 1) return Qnil;
    }

    int i = 0;

    gCopyOverride = kNone;
    gErrMsgCancel = false;

    Check_Type(sdir, T_STRING);
    Check_Type(files, T_ARRAY);
    Check_Type(ddir, T_STRING);
    
    /// check argument ///
    struct stat dstat;
    if(stat(RSTRING(ddir)->ptr, &dstat) >= 0) {
        if(S_ISDIR(dstat.st_mode) && RSTRING(ddir)->ptr[strlen(RSTRING(ddir)->ptr)-1] != '/') {
            char tmp[PATH_MAX];
            sprintf(tmp, "%s/", RSTRING(ddir)->ptr);

            ddir = rb_str_new2(tmp);
        }
    }
    
    if(RARRAY(files)->len > 1
        && RSTRING(ddir)->ptr[strlen(RSTRING(ddir)->ptr)-1] != '/')
    {
        err_msg("mf_copy: destination_err(%s)", RSTRING(ddir)->ptr);
        return Qnil;
    }
    if(RSTRING(ddir)->ptr[0] != '/') {
        char path[PATH_MAX];
        strcpy(path, RSTRING(mf_adir_path(self))->ptr);
        strcat(path, "/");
        strcat(path, RSTRING(ddir)->ptr);
        
        ddir = rb_str_new2(path);
    }

    /// go ///
    for(int i=0; i < RARRAY(files)->len; i++) {
        VALUE item = rb_ary_entry(files, i);
        Check_Type(item, T_STRING);

        if(strcmp(RSTRING(item)->ptr, ".") != 0
            && strcmp(RSTRING(item)->ptr, "..") != 0)
        {
            char spath[PATH_MAX];
            strcpy(spath, RSTRING(sdir)->ptr);
            strcat(spath, "/");
            strcat(spath, RSTRING(item)->ptr);
    
            char dpath[PATH_MAX];
            strcpy(dpath, RSTRING(ddir)->ptr);

            file_copy(spath, dpath, false);
        }
    }
    
    gLDir->Reread();
    gRDir->Reread();

TEND();    

    return Qnil;
}

VALUE mf_move(VALUE self, VALUE sdir, VALUE files, VALUE ddir)
{
TBEGIN();
    if(gCheckCopyFile) {
        const char* str[] = {
            "Yes", "No"
        };

        int ret = select_str("move ok?", (char**)str, 2, 1);

        if(ret == 1) return Qnil;
    }

    int i = 0;

    gCopyOverride = kNone;
    gErrMsgCancel = false;

    Check_Type(sdir, T_STRING);
    Check_Type(files, T_ARRAY);
    Check_Type(ddir, T_STRING);

    /// check argument ///
    struct stat dstat;
    if(stat(RSTRING(ddir)->ptr, &dstat) >= 0) {
        if(S_ISDIR(dstat.st_mode) && RSTRING(ddir)->ptr[strlen(RSTRING(ddir)->ptr)-1] != '/') {
            char tmp[PATH_MAX];
            sprintf(tmp, "%s/", RSTRING(ddir)->ptr);

            ddir = rb_str_new2(tmp);
        }
    }
    
    if(RARRAY(files)->len > 1
        && RSTRING(ddir)->ptr[strlen(RSTRING(ddir)->ptr)-1] != '/')
    {
        err_msg("mf_move: destination_err(%s)", RSTRING(ddir)->ptr);
        return Qnil;
    }
    if(RSTRING(ddir)->ptr[0] != '/') {
        char path[PATH_MAX];
        strcpy(path, RSTRING(mf_adir_path(self))->ptr);
        strcat(path, "/");
        strcat(path, RSTRING(ddir)->ptr);
        
        ddir = rb_str_new2(path);
    }
    
    /// go ///
    for(int i=0; i < RARRAY(files)->len; i++) {
        VALUE item = rb_ary_entry(files, i);

        Check_Type(item, T_STRING);

        if(strcmp(RSTRING(item)->ptr, ".") != 0
            && strcmp(RSTRING(item)->ptr, "..") != 0)
        {
            char spath[PATH_MAX];
            strcpy(spath, RSTRING(sdir)->ptr);
            strcat(spath, "/");
            strcat(spath, RSTRING(item)->ptr);

            char dpath[PATH_MAX];
            strcpy(dpath, RSTRING(ddir)->ptr);

            file_copy(spath, dpath, true);
        }
    }

    gLDir->Reread();
    gRDir->Reread();
    
TEND();    

    return Qnil;
}

VALUE mf_remove(VALUE self, VALUE sdir, VALUE files)
{
TBEGIN();

    gCopyOverride = kNone;
    gErrMsgCancel = false;

    if(gCheckDeleteFile) {
        const char* str[] = {
            "Yes", "No"
        };

        int ret = select_str("delete ok?", (char**)str, 2, 1);

        if(ret == 1) return Qnil;
    }

    Check_Type(sdir, T_STRING);
    Check_Type(files, T_ARRAY);
    
    for(int i= 0; i < RARRAY(files)->len; i++) {
        VALUE item = rb_ary_entry(files, i);
        Check_Type(item, T_STRING);

        if(strcmp(RSTRING(item)->ptr, ".") != 0
            && strcmp(RSTRING(item)->ptr, "..") != 0)
        {
            char spath[PATH_MAX];
            strcpy(spath, RSTRING(sdir)->ptr);
            strcat(spath, "/");
            strcat(spath, RSTRING(item)->ptr);

            file_remove(spath);
        }
    }

    gLDir->Reread();
    gRDir->Reread();

TEND();

    return Qnil;
}

VALUE mf_trashbox(VALUE self, VALUE sdir, VALUE files)
{
TBEGIN();

    gErrMsgCancel = false;
    
    char* home = getenv("HOME");
    if(home == NULL) {
        err_msg("trashbox: $HOME is NULL");
        return Qnil;
    }

    char tbpath[PATH_MAX];
    strcpy(tbpath, home);
    strcat(tbpath, "/");
    strcat(tbpath, gTrashBoxName);
    
    char tbpath2[PATH_MAX];
    strcpy(tbpath2, "/usr");
    strcat(tbpath2, home);
    strcat(tbpath2, "/");
    strcat(tbpath2, gTrashBoxName);

M(("tbpath %s", tbpath));
    
    if(gCheckDeleteFile) {
        const char* str[] = {
            "Yes", "No"
        };

        int ret;
        if(strcmp(RSTRING(sdir)->ptr, tbpath) == 0) {
            ret = select_str("delete ok?", (char**)str, 2, 1);
        }
        else {
            ret = select_str("move to the trashbox ok?", (char**)str, 2, 1);
        }

        if(ret == 1) return Qnil;
    }

    Check_Type(sdir, T_STRING);
    Check_Type(files, T_ARRAY);

    /// make mtrashbox ///
    if(access(tbpath, F_OK) == 0) {
        struct stat tbstat;
        if(stat(tbpath, &tbstat) < 0) {
            err_msg("trashbox: stat err(%s)", tbpath);
            return Qnil;
        }
        if(!S_ISDIR(tbstat.st_mode)) {
            char buf[256];
            sprintf(buf, "trashbox: $HOME/%s is not directory", gTrashBoxName);
            err_msg(buf);
            return Qnil;
        }
    }
    else {
        if(mkdir(tbpath, 0755) < 0) {
            char buf[256];
            sprintf(buf, "trashbox: can't make $HOME/%s", gTrashBoxName);
            err_msg(buf);
            return Qnil;
        }
    }

    /// in trashbox ///    
M(("%s %s", RSTRING(sdir)->ptr, tbpath));    
    if(strcmp(RSTRING(sdir)->ptr, tbpath) == 0
        || strcmp(RSTRING(sdir)->ptr, tbpath2) == 0) {
M(("in trashbox"));    
        for(int i= 0; i < RARRAY(files)->len; i++) {
            VALUE item = rb_ary_entry(files, i);
            Check_Type(item, T_STRING);
    
            if(strcmp(RSTRING(item)->ptr, ".") != 0
                && strcmp(RSTRING(item)->ptr, "..") != 0)
            {
                char spath[PATH_MAX];
                strcpy(spath, RSTRING(sdir)->ptr);
                strcat(spath, "/");
                strcat(spath, RSTRING(item)->ptr);

                file_remove(spath);
            }
        }
    }

    /// not in trash box ///
    else {
M(("not in trashbox"));    
        gCopyOverride = kYesAll;

        strcat(tbpath, "/");

        for(int i=0; i < RARRAY(files)->len; i++) {
            VALUE item = rb_ary_entry(files, i);
    
            Check_Type(item, T_STRING);
    
            if(strcmp(RSTRING(item)->ptr, ".") != 0
                && strcmp(RSTRING(item)->ptr, "..") != 0)
            {
                char spath[PATH_MAX];
                strcpy(spath, RSTRING(sdir)->ptr);
                strcat(spath, "/");
                strcat(spath, RSTRING(item)->ptr);

                char dpath[PATH_MAX];
                strcpy(dpath, tbpath);
                strcat(dpath, RSTRING(item)->ptr);

M(("dpath %s", dpath));
                
                if(access(dpath, F_OK) == 0) {
                    file_remove(dpath);
                }
                
                file_copy(spath, tbpath, true);
            }
        }
    }

    gLDir->Reread();
    gRDir->Reread();
    
TEND();

    return Qnil;
}

VALUE mf_select_pty(VALUE self, VALUE title)
{
    Check_Type(title, T_STRING);

    return INT2FIX(cmdline_select_pty(RSTRING(title)->ptr) + 1);
}

VALUE mf_kill_pty(VALUE self, VALUE n)
{
TBEGIN();

    Check_Type(n, T_FIXNUM);

    const int m = NUM2INT(n);
    if(m >= 1 && m <= vector_size(gTty)) {
        sMasterTty* tty = (sMasterTty*)vector_item(gTty, m-1);
        kill(tty->mPID, SIGKILL);

        FREE(tty);
        vector_erase(gTty, m-1);
    }

TEND();

    return Qnil;
}

VALUE mf_restore_pty(VALUE self, VALUE n)
{
TBEGIN();

    Check_Type(n, T_FIXNUM);

    const int m = NUM2INT(n);
    if(m >= 1 && m <= vector_size(gTty)) {
        cmdline_restore_pty(m-1);
    }

TEND();

    return Qnil;
}

VALUE mf_set_mask(VALUE self, VALUE mask)
{
    Check_Type(mask, T_STRING);

    ActiveDir()->ChangeMask(RSTRING(mask)->ptr);

    return Qnil;
}

VALUE mf_set_mask_sdir(VALUE self, VALUE mask)
{
    Check_Type(mask, T_STRING);

    SleepDir()->ChangeMask(RSTRING(mask)->ptr);

    return Qnil;
}

const char kCut = 0;
const char kCopy = 1;

VALUE mf_cut(VALUE self)
{
    char buf[8192];
    char* p = buf;

    gErrMsgCancel = false;
    
    const int pid = getpid();
    memcpy(p, &pid, sizeof(pid));
    p += sizeof(pid);
    
    memcpy(p, &kCut, sizeof(kCut));
    p += sizeof(kCut);

    VALUE path2 = mf_adir_path(self);
    sprintf(p, "%s%c", RSTRING(path2)->ptr, 0);
    p += RSTRING(path2)->len+1;

    VALUE files = ActiveDir()->MarkFiles();

    const int n = RARRAY(files)->len;
    memcpy(p, &n, sizeof(n));
    p += sizeof(n);

    for(int i=0; i < RARRAY(files)->len; i++) {
        VALUE item = rb_ary_entry(files, i);
        Check_Type(item, T_STRING);

        sprintf(p, "%s%c", RSTRING(item)->ptr, 0);
        p += RSTRING(item)->len + 1;
    }

    /// write ///    
    char* home = getenv("HOME");
    if(home == NULL) {
        err_msg("cut: $HOME is null");
        return Qnil;
    }

    char path[1024];
    sprintf(path, "%s/.mfiler-cutpast", home);

    int file = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0644);
    if(file < 0) {
        err_msg("cut: open err(%s)", path);
        return Qnil;
    }
    if(write(file, buf, p - buf) < 0) {
        err_msg("cut: write err");
        close(file);
        return Qnil;
    }
    close(file);
    
    ActiveDir()->ResetMarks();

    return Qnil;
}

VALUE mf_copy2(VALUE self)
{
    char buf[8192];
    char* p = buf;

    gErrMsgCancel = false;

    const int pid = getpid();
    memcpy(p, &pid, sizeof(pid));
    p += sizeof(pid);
    
    memcpy(p, &kCopy, sizeof(kCopy));
    p += sizeof(kCopy);

    VALUE path2 = mf_adir_path(self);
    sprintf(p, "%s%c", RSTRING(path2)->ptr, 0);
    p += RSTRING(path2)->len+1;

    VALUE files = ActiveDir()->MarkFiles();

    const int n = RARRAY(files)->len;
    memcpy(p, &n, sizeof(n));
    p += sizeof(n);

    for(int i=0; i < RARRAY(files)->len; i++) {
        VALUE item = rb_ary_entry(files, i);
        Check_Type(item, T_STRING);

        sprintf(p, "%s%c", RSTRING(item)->ptr, 0);
        p += RSTRING(item)->len + 1;
    }

    /// write ///    
    char* home = getenv("HOME");
    if(home == NULL) {
        err_msg("copy2: $HOME is null");
        return Qnil;
    }

    char path[1024];
    sprintf(path, "%s/.mfiler-cutpast", home);

    int file = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0644);
    if(file < 0) {
        err_msg("copy2: open err(%s)", path);
        return Qnil;
    }
    if(write(file, buf, p - buf) < 0) {
        err_msg("copy2: write err");
        close(file);
        return Qnil;
    }
    close(file);
    
    ActiveDir()->ResetMarks();

    return Qnil;
}

VALUE mf_past(VALUE self)
{
    char buf[8192];

    gErrMsgCancel = false;
        
    /// read ///
    char* home = getenv("HOME");
    if(home == NULL) {
        err_msg("past: $HOME is null");
        return Qnil;
    }

    char path[1024];
    sprintf(path, "%s/.mfiler-cutpast", home);

    if(access(path, F_OK) != 0) {
        err_msg("past: there are no cutted or copied files");
        return Qnil;
    }
    
    struct stat stat_;
    if(stat(path, &stat_) < 0) {
        err_msg("past: stat err");
        return Qnil;
    }
        
    int file = open(path, O_RDONLY);
    if(file < 0) {
        err_msg("past: open err");
        return Qnil;
    }
    
    if(read(file, buf, stat_.st_size) < 0) {
        err_msg("past: read err");
        close(file);
        return Qnil;
    }
    close(file);
    
    /// reconstruct from file buffer ///
    char* p = buf;

    int pid = *(int*)p;
    p += sizeof(int);

    char cut_mode = *(char*)p;
    p++;

M(("CutMode %d", cut_mode));    

    char buf2[PATH_MAX];
    char* p2 = buf2;
    while(*p) {
        *p2++ = *p++;
    }
    *p2 = 0;
    p++;
    
    VALUE cut_dir = rb_str_new2(buf2);

M(("CutDir %s", buf2));    

    VALUE cut_files = rb_ary_new();

    int len = *(int*)p;
    p += sizeof(int);

M(("Len %d", len));    

    for(int i=0; i < len; i++) {
        char buf3[PATH_MAX];
        char* p3 = buf3;
        while(*p) {
            *p3++ = *p++;
        }
        *p3 = 0;
        p++;

M(("File %s", buf3));            
        rb_ary_push(cut_files, rb_str_new2(buf3));
    }

    
    switch(cut_mode) {
    case kCopy:
        mf_copy(self, cut_dir, cut_files, mf_adir_path(self));
        break;

    case kCut: {
        mf_move(self, cut_dir, cut_files, mf_adir_path(self));
        }
        break;
    }

    if(unlink(path) < 0) {
        err_msg("past: unlink err(%s)", path);
        return Qnil;
    }

    /// refresh ///
    char buf3[256];

    sprintf(buf3, "mfiler -r %d", pid);
    system(buf3);

    return Qnil;
}

VALUE mf_malias(VALUE self, VALUE alias, VALUE arg_num, VALUE command)
{
TBEGIN();
    Check_Type(alias, T_STRING);
    Check_Type(arg_num, T_FIXNUM);
    Check_Type(command, T_STRING);

    cmdline_alias_add(RSTRING(alias)->ptr, NUM2INT(arg_num), RSTRING(command)->ptr);
    
TEND();
    
    return Qnil;
}

VALUE mf_rehash(VALUE self)
{
TBEGIN();

    cmdline_rehash();
    
TEND();
    
    return Qnil;
}

VALUE mf_help(VALUE self)
{
TBEGIN();

    help_start();
    
TEND();
    
    return Qnil;
}

VALUE mf_set_xterm(VALUE self, VALUE xterm, VALUE opt_title, VALUE opt_eval, VALUE opt_extra)
{
TBEGIN();
    Check_Type(xterm, T_STRING);
    Check_Type(opt_title, T_STRING);
    Check_Type(opt_eval, T_STRING);
   Check_Type(opt_extra, T_STRING);

    gXtermPrgName = xterm;
    gXtermOptTitle = opt_title;
    gXtermOptEval = opt_eval;
    gXtermOptExtra = opt_extra;

TEND();
    
    return Qnil;
}

VALUE mf_view_option(VALUE self)
{
    switch(cDirWnd::gViewOption) {
    case cDirWnd::kAll:
        return rb_str_new2("all");

    case cDirWnd::kOneDir:
        return rb_str_new2("one_dir");

    case cDirWnd::kOneDir2:
        return rb_str_new2("one_dir2");

    case cDirWnd::kOneDir3:
        return rb_str_new2("one_dir3");

    case cDirWnd::kOneDir5:
        return rb_str_new2("one_dir5");
    }
}

VALUE mf_cursor()
{
    return INT2FIX(ActiveDir()->Cursor());
}

VALUE mf_cursor_max(VALUE self)
{
    return INT2FIX(ActiveDir()->CursorMax());
}

VALUE mf_scrolltop()
{
    return INT2FIX(ActiveDir()->ScrollTop());
}

VALUE mf_set_scrolltop(VALUE self, VALUE value)
{
    Check_Type(value, T_FIXNUM);

    ActiveDir()->SetScrollTop(NUM2INT(value));
    
    return Qnil;
}

VALUE mf_cursor_x(VALUE self)
{
    return INT2FIX(ActiveDir()->CursorX());
}

VALUE mf_cursor_y(VALUE self)
{
    return INT2FIX(ActiveDir()->CursorY());
}

VALUE mf_cursor_maxx(VALUE self)
{
    return INT2FIX(ActiveDir()->CursorMaxX());
}

VALUE mf_cursor_maxy(VALUE self)
{
    return INT2FIX(ActiveDir()->CursorMaxY());
}

VALUE mf_xterm_next(VALUE self)
{
    gXtermNext = !gXtermNext;

    return Qnil;
}

VALUE mf_keymap_up(VALUE self, VALUE p1, VALUE p2, VALUE p3, VALUE p4, VALUE p5, VALUE p6)
{
    Check_Type(p1, T_FIXNUM);
    Check_Type(p2, T_FIXNUM);
    Check_Type(p3, T_FIXNUM);
    Check_Type(p4, T_FIXNUM);
    Check_Type(p5, T_FIXNUM);
    Check_Type(p6, T_FIXNUM);
    
    gKeyMap[kKeyMapUp][0] = NUM2INT(p1);
    gKeyMap[kKeyMapUp][1] = NUM2INT(p2);
    gKeyMap[kKeyMapUp][2] = NUM2INT(p3);
    gKeyMap[kKeyMapUp][3] = NUM2INT(p4);
    gKeyMap[kKeyMapUp][4] = NUM2INT(p5);
    gKeyMap[kKeyMapUp][5] = NUM2INT(p6);
    
    return Qnil;
}

VALUE mf_keymap_down(VALUE self, VALUE p1, VALUE p2, VALUE p3, VALUE p4, VALUE p5, VALUE p6)
{
    Check_Type(p1, T_FIXNUM);
    Check_Type(p2, T_FIXNUM);
    Check_Type(p3, T_FIXNUM);
    Check_Type(p4, T_FIXNUM);
    Check_Type(p5, T_FIXNUM);
    Check_Type(p6, T_FIXNUM);
    
    gKeyMap[kKeyMapDown][0] = NUM2INT(p1);
    gKeyMap[kKeyMapDown][1] = NUM2INT(p2);
    gKeyMap[kKeyMapDown][2] = NUM2INT(p3);
    gKeyMap[kKeyMapDown][3] = NUM2INT(p4);
    gKeyMap[kKeyMapDown][4] = NUM2INT(p5);
    gKeyMap[kKeyMapDown][5] = NUM2INT(p6);
    
    return Qnil;
}

VALUE mf_keymap_right(VALUE self, VALUE p1, VALUE p2, VALUE p3, VALUE p4, VALUE p5, VALUE p6)
{
    Check_Type(p1, T_FIXNUM);
    Check_Type(p2, T_FIXNUM);
    Check_Type(p3, T_FIXNUM);
    Check_Type(p4, T_FIXNUM);
    Check_Type(p5, T_FIXNUM);
    Check_Type(p6, T_FIXNUM);
    
    gKeyMap[kKeyMapRight][0] = NUM2INT(p1);
    gKeyMap[kKeyMapRight][1] = NUM2INT(p2);
    gKeyMap[kKeyMapRight][2] = NUM2INT(p3);
    gKeyMap[kKeyMapRight][3] = NUM2INT(p4);
    gKeyMap[kKeyMapRight][4] = NUM2INT(p5);
    gKeyMap[kKeyMapRight][5] = NUM2INT(p6);
    
    return Qnil;
}

VALUE mf_keymap_left(VALUE self, VALUE p1, VALUE p2, VALUE p3, VALUE p4, VALUE p5, VALUE p6)
{
    Check_Type(p1, T_FIXNUM);
    Check_Type(p2, T_FIXNUM);
    Check_Type(p3, T_FIXNUM);
    Check_Type(p4, T_FIXNUM);
    Check_Type(p5, T_FIXNUM);
    Check_Type(p6, T_FIXNUM);
    
    gKeyMap[kKeyMapLeft][0] = NUM2INT(p1);
    gKeyMap[kKeyMapLeft][1] = NUM2INT(p2);
    gKeyMap[kKeyMapLeft][2] = NUM2INT(p3);
    gKeyMap[kKeyMapLeft][3] = NUM2INT(p4);
    gKeyMap[kKeyMapLeft][4] = NUM2INT(p5);
    gKeyMap[kKeyMapLeft][5] = NUM2INT(p6);
    
    return Qnil;
}

VALUE mf_keymap_insert(VALUE self, VALUE p1, VALUE p2, VALUE p3, VALUE p4, VALUE p5, VALUE p6)
{
    Check_Type(p1, T_FIXNUM);
    Check_Type(p2, T_FIXNUM);
    Check_Type(p3, T_FIXNUM);
    Check_Type(p4, T_FIXNUM);
    Check_Type(p5, T_FIXNUM);
    Check_Type(p6, T_FIXNUM);
    
    gKeyMap[kKeyMapInsert][0] = NUM2INT(p1);
    gKeyMap[kKeyMapInsert][1] = NUM2INT(p2);
    gKeyMap[kKeyMapInsert][2] = NUM2INT(p3);
    gKeyMap[kKeyMapInsert][3] = NUM2INT(p4);
    gKeyMap[kKeyMapInsert][4] = NUM2INT(p5);
    gKeyMap[kKeyMapInsert][5] = NUM2INT(p6);
    
    return Qnil;
}

VALUE mf_keymap_delete(VALUE self, VALUE p1, VALUE p2, VALUE p3, VALUE p4, VALUE p5, VALUE p6)
{
    Check_Type(p1, T_FIXNUM);
    Check_Type(p2, T_FIXNUM);
    Check_Type(p3, T_FIXNUM);
    Check_Type(p4, T_FIXNUM);
    Check_Type(p5, T_FIXNUM);
    Check_Type(p6, T_FIXNUM);
    
    gKeyMap[kKeyMapDelete][0] = NUM2INT(p1);
    gKeyMap[kKeyMapDelete][1] = NUM2INT(p2);
    gKeyMap[kKeyMapDelete][2] = NUM2INT(p3);
    gKeyMap[kKeyMapDelete][3] = NUM2INT(p4);
    gKeyMap[kKeyMapDelete][4] = NUM2INT(p5);
    gKeyMap[kKeyMapDelete][5] = NUM2INT(p6);
    
    return Qnil;
}

VALUE mf_keymap_home(VALUE self, VALUE p1, VALUE p2, VALUE p3, VALUE p4, VALUE p5, VALUE p6)
{
    Check_Type(p1, T_FIXNUM);
    Check_Type(p2, T_FIXNUM);
    Check_Type(p3, T_FIXNUM);
    Check_Type(p4, T_FIXNUM);
    Check_Type(p5, T_FIXNUM);
    Check_Type(p6, T_FIXNUM);
    
    gKeyMap[kKeyMapHome][0] = NUM2INT(p1);
    gKeyMap[kKeyMapHome][1] = NUM2INT(p2);
    gKeyMap[kKeyMapHome][2] = NUM2INT(p3);
    gKeyMap[kKeyMapHome][3] = NUM2INT(p4);
    gKeyMap[kKeyMapHome][4] = NUM2INT(p5);
    gKeyMap[kKeyMapHome][5] = NUM2INT(p6);
    
    return Qnil;
}

VALUE mf_keymap_end(VALUE self, VALUE p1, VALUE p2, VALUE p3, VALUE p4, VALUE p5, VALUE p6)
{
    Check_Type(p1, T_FIXNUM);
    Check_Type(p2, T_FIXNUM);
    Check_Type(p3, T_FIXNUM);
    Check_Type(p4, T_FIXNUM);
    Check_Type(p5, T_FIXNUM);
    Check_Type(p6, T_FIXNUM);
    
    gKeyMap[kKeyMapEnd][0] = NUM2INT(p1);
    gKeyMap[kKeyMapEnd][1] = NUM2INT(p2);
    gKeyMap[kKeyMapEnd][2] = NUM2INT(p3);
    gKeyMap[kKeyMapEnd][3] = NUM2INT(p4);
    gKeyMap[kKeyMapEnd][4] = NUM2INT(p5);
    gKeyMap[kKeyMapEnd][5] = NUM2INT(p6);
    
    return Qnil;
}

VALUE mf_keymap_page_up(VALUE self, VALUE p1, VALUE p2, VALUE p3, VALUE p4, VALUE p5, VALUE p6)
{
    Check_Type(p1, T_FIXNUM);
    Check_Type(p2, T_FIXNUM);
    Check_Type(p3, T_FIXNUM);
    Check_Type(p4, T_FIXNUM);
    Check_Type(p5, T_FIXNUM);
    Check_Type(p6, T_FIXNUM);
    
    gKeyMap[kKeyMapPageUp][0] = NUM2INT(p1);
    gKeyMap[kKeyMapPageUp][1] = NUM2INT(p2);
    gKeyMap[kKeyMapPageUp][2] = NUM2INT(p3);
    gKeyMap[kKeyMapPageUp][3] = NUM2INT(p4);
    gKeyMap[kKeyMapPageUp][4] = NUM2INT(p5);
    gKeyMap[kKeyMapPageUp][5] = NUM2INT(p6);
    
    return Qnil;
}

VALUE mf_keymap_page_down(VALUE self, VALUE p1, VALUE p2, VALUE p3, VALUE p4, VALUE p5, VALUE p6)
{
    Check_Type(p1, T_FIXNUM);
    Check_Type(p2, T_FIXNUM);
    Check_Type(p3, T_FIXNUM);
    Check_Type(p4, T_FIXNUM);
    Check_Type(p5, T_FIXNUM);
    Check_Type(p6, T_FIXNUM);
    
    gKeyMap[kKeyMapPageDown][0] = NUM2INT(p1);
    gKeyMap[kKeyMapPageDown][1] = NUM2INT(p2);
    gKeyMap[kKeyMapPageDown][2] = NUM2INT(p3);
    gKeyMap[kKeyMapPageDown][3] = NUM2INT(p4);
    gKeyMap[kKeyMapPageDown][4] = NUM2INT(p5);
    gKeyMap[kKeyMapPageDown][5] = NUM2INT(p6);
    
    return Qnil;
}

VALUE mf_keymap_f1(VALUE self, VALUE p1, VALUE p2, VALUE p3, VALUE p4, VALUE p5, VALUE p6)
{
    Check_Type(p1, T_FIXNUM);
    Check_Type(p2, T_FIXNUM);
    Check_Type(p3, T_FIXNUM);
    Check_Type(p4, T_FIXNUM);
    Check_Type(p5, T_FIXNUM);
    Check_Type(p6, T_FIXNUM);
    
    gKeyMap[kKeyMapF1][0] = NUM2INT(p1);
    gKeyMap[kKeyMapF1][1] = NUM2INT(p2);
    gKeyMap[kKeyMapF1][2] = NUM2INT(p3);
    gKeyMap[kKeyMapF1][3] = NUM2INT(p4);
    gKeyMap[kKeyMapF1][4] = NUM2INT(p5);
    gKeyMap[kKeyMapF1][5] = NUM2INT(p6);
    
    return Qnil;
}

VALUE mf_keymap_f2(VALUE self, VALUE p1, VALUE p2, VALUE p3, VALUE p4, VALUE p5, VALUE p6)
{
    Check_Type(p1, T_FIXNUM);
    Check_Type(p2, T_FIXNUM);
    Check_Type(p3, T_FIXNUM);
    Check_Type(p4, T_FIXNUM);
    Check_Type(p5, T_FIXNUM);
    Check_Type(p6, T_FIXNUM);
    
    gKeyMap[kKeyMapF2][0] = NUM2INT(p1);
    gKeyMap[kKeyMapF2][1] = NUM2INT(p2);
    gKeyMap[kKeyMapF2][2] = NUM2INT(p3);
    gKeyMap[kKeyMapF2][3] = NUM2INT(p4);
    gKeyMap[kKeyMapF2][4] = NUM2INT(p5);
    gKeyMap[kKeyMapF2][5] = NUM2INT(p6);
    
    return Qnil;
}

VALUE mf_keymap_f3(VALUE self, VALUE p1, VALUE p2, VALUE p3, VALUE p4, VALUE p5, VALUE p6)
{
    Check_Type(p1, T_FIXNUM);
    Check_Type(p2, T_FIXNUM);
    Check_Type(p3, T_FIXNUM);
    Check_Type(p4, T_FIXNUM);
    Check_Type(p5, T_FIXNUM);
    Check_Type(p6, T_FIXNUM);
    
    gKeyMap[kKeyMapF3][0] = NUM2INT(p1);
    gKeyMap[kKeyMapF3][1] = NUM2INT(p2);
    gKeyMap[kKeyMapF3][2] = NUM2INT(p3);
    gKeyMap[kKeyMapF3][3] = NUM2INT(p4);
    gKeyMap[kKeyMapF3][4] = NUM2INT(p5);
    gKeyMap[kKeyMapF3][5] = NUM2INT(p6);
    
    return Qnil;
}

VALUE mf_keymap_f4(VALUE self, VALUE p1, VALUE p2, VALUE p3, VALUE p4, VALUE p5, VALUE p6)
{
    Check_Type(p1, T_FIXNUM);
    Check_Type(p2, T_FIXNUM);
    Check_Type(p3, T_FIXNUM);
    Check_Type(p4, T_FIXNUM);
    Check_Type(p5, T_FIXNUM);
    Check_Type(p6, T_FIXNUM);
    
    gKeyMap[kKeyMapF4][0] = NUM2INT(p1);
    gKeyMap[kKeyMapF4][1] = NUM2INT(p2);
    gKeyMap[kKeyMapF4][2] = NUM2INT(p3);
    gKeyMap[kKeyMapF4][3] = NUM2INT(p4);
    gKeyMap[kKeyMapF4][4] = NUM2INT(p5);
    gKeyMap[kKeyMapF4][5] = NUM2INT(p6);
    
    return Qnil;
}

VALUE mf_keymap_f5(VALUE self, VALUE p1, VALUE p2, VALUE p3, VALUE p4, VALUE p5, VALUE p6)
{
    Check_Type(p1, T_FIXNUM);
    Check_Type(p2, T_FIXNUM);
    Check_Type(p3, T_FIXNUM);
    Check_Type(p4, T_FIXNUM);
    Check_Type(p5, T_FIXNUM);
    Check_Type(p6, T_FIXNUM);
    
    gKeyMap[kKeyMapF5][0] = NUM2INT(p1);
    gKeyMap[kKeyMapF5][1] = NUM2INT(p2);
    gKeyMap[kKeyMapF5][2] = NUM2INT(p3);
    gKeyMap[kKeyMapF5][3] = NUM2INT(p4);
    gKeyMap[kKeyMapF5][4] = NUM2INT(p5);
    gKeyMap[kKeyMapF5][5] = NUM2INT(p6);
    
    return Qnil;
}

VALUE mf_keymap_f6(VALUE self, VALUE p1, VALUE p2, VALUE p3, VALUE p4, VALUE p5, VALUE p6)
{
    Check_Type(p1, T_FIXNUM);
    Check_Type(p2, T_FIXNUM);
    Check_Type(p3, T_FIXNUM);
    Check_Type(p4, T_FIXNUM);
    Check_Type(p5, T_FIXNUM);
    Check_Type(p6, T_FIXNUM);
    
    gKeyMap[kKeyMapF6][0] = NUM2INT(p1);
    gKeyMap[kKeyMapF6][1] = NUM2INT(p2);
    gKeyMap[kKeyMapF6][2] = NUM2INT(p3);
    gKeyMap[kKeyMapF6][3] = NUM2INT(p4);
    gKeyMap[kKeyMapF6][4] = NUM2INT(p5);
    gKeyMap[kKeyMapF6][5] = NUM2INT(p6);
    
    return Qnil;
}

VALUE mf_keymap_f7(VALUE self, VALUE p1, VALUE p2, VALUE p3, VALUE p4, VALUE p5, VALUE p6)
{
    Check_Type(p1, T_FIXNUM);
    Check_Type(p2, T_FIXNUM);
    Check_Type(p3, T_FIXNUM);
    Check_Type(p4, T_FIXNUM);
    Check_Type(p5, T_FIXNUM);
    Check_Type(p6, T_FIXNUM);
    
    gKeyMap[kKeyMapF7][0] = NUM2INT(p1);
    gKeyMap[kKeyMapF7][1] = NUM2INT(p2);
    gKeyMap[kKeyMapF7][2] = NUM2INT(p3);
    gKeyMap[kKeyMapF7][3] = NUM2INT(p4);
    gKeyMap[kKeyMapF7][4] = NUM2INT(p5);
    gKeyMap[kKeyMapF7][5] = NUM2INT(p6);
    
    return Qnil;
}

VALUE mf_keymap_f8(VALUE self, VALUE p1, VALUE p2, VALUE p3, VALUE p4, VALUE p5, VALUE p6)
{
    Check_Type(p1, T_FIXNUM);
    Check_Type(p2, T_FIXNUM);
    Check_Type(p3, T_FIXNUM);
    Check_Type(p4, T_FIXNUM);
    Check_Type(p5, T_FIXNUM);
    Check_Type(p6, T_FIXNUM);
    
    gKeyMap[kKeyMapF8][0] = NUM2INT(p1);
    gKeyMap[kKeyMapF8][1] = NUM2INT(p2);
    gKeyMap[kKeyMapF8][2] = NUM2INT(p3);
    gKeyMap[kKeyMapF8][3] = NUM2INT(p4);
    gKeyMap[kKeyMapF8][4] = NUM2INT(p5);
    gKeyMap[kKeyMapF8][5] = NUM2INT(p6);
    
    return Qnil;
}

VALUE mf_keymap_f9(VALUE self, VALUE p1, VALUE p2, VALUE p3, VALUE p4, VALUE p5, VALUE p6)
{
    Check_Type(p1, T_FIXNUM);
    Check_Type(p2, T_FIXNUM);
    Check_Type(p3, T_FIXNUM);
    Check_Type(p4, T_FIXNUM);
    Check_Type(p5, T_FIXNUM);
    Check_Type(p6, T_FIXNUM);
    
    gKeyMap[kKeyMapF9][0] = NUM2INT(p1);
    gKeyMap[kKeyMapF9][1] = NUM2INT(p2);
    gKeyMap[kKeyMapF9][2] = NUM2INT(p3);
    gKeyMap[kKeyMapF9][3] = NUM2INT(p4);
    gKeyMap[kKeyMapF9][4] = NUM2INT(p5);
    gKeyMap[kKeyMapF9][5] = NUM2INT(p6);
    
    return Qnil;
}

VALUE mf_keymap_f10(VALUE self, VALUE p1, VALUE p2, VALUE p3, VALUE p4, VALUE p5, VALUE p6)
{
    Check_Type(p1, T_FIXNUM);
    Check_Type(p2, T_FIXNUM);
    Check_Type(p3, T_FIXNUM);
    Check_Type(p4, T_FIXNUM);
    Check_Type(p5, T_FIXNUM);
    Check_Type(p6, T_FIXNUM);
    
    gKeyMap[kKeyMapF10][0] = NUM2INT(p1);
    gKeyMap[kKeyMapF10][1] = NUM2INT(p2);
    gKeyMap[kKeyMapF10][2] = NUM2INT(p3);
    gKeyMap[kKeyMapF10][3] = NUM2INT(p4);
    gKeyMap[kKeyMapF10][4] = NUM2INT(p5);
    gKeyMap[kKeyMapF10][5] = NUM2INT(p6);
    
    return Qnil;
}

VALUE mf_keymap_f11(VALUE self, VALUE p1, VALUE p2, VALUE p3, VALUE p4, VALUE p5, VALUE p6)
{
    Check_Type(p1, T_FIXNUM);
    Check_Type(p2, T_FIXNUM);
    Check_Type(p3, T_FIXNUM);
    Check_Type(p4, T_FIXNUM);
    Check_Type(p5, T_FIXNUM);
    Check_Type(p6, T_FIXNUM);
    
    gKeyMap[kKeyMapF11][0] = NUM2INT(p1);
    gKeyMap[kKeyMapF11][1] = NUM2INT(p2);
    gKeyMap[kKeyMapF11][2] = NUM2INT(p3);
    gKeyMap[kKeyMapF11][3] = NUM2INT(p4);
    gKeyMap[kKeyMapF11][4] = NUM2INT(p5);
    gKeyMap[kKeyMapF11][5] = NUM2INT(p6);
    
    return Qnil;
}

VALUE mf_keymap_f12(VALUE self, VALUE p1, VALUE p2, VALUE p3, VALUE p4, VALUE p5, VALUE p6)
{
    Check_Type(p1, T_FIXNUM);
    Check_Type(p2, T_FIXNUM);
    Check_Type(p3, T_FIXNUM);
    Check_Type(p4, T_FIXNUM);
    Check_Type(p5, T_FIXNUM);
    Check_Type(p6, T_FIXNUM);
    
    gKeyMap[kKeyMapF12][0] = NUM2INT(p1);
    gKeyMap[kKeyMapF12][1] = NUM2INT(p2);
    gKeyMap[kKeyMapF12][2] = NUM2INT(p3);
    gKeyMap[kKeyMapF12][3] = NUM2INT(p4);
    gKeyMap[kKeyMapF12][4] = NUM2INT(p5);
    gKeyMap[kKeyMapF12][5] = NUM2INT(p6);
    
    return Qnil;
}

VALUE mf_completion(VALUE self, VALUE all_candidate, VALUE editing, VALUE sqort, VALUE dqort)
{
TBEGIN();
    Check_Type(all_candidate, T_ARRAY);
    Check_Type(editing, T_STRING);

    bool sqort2 = sqort == Qtrue ? true: false;
    bool dqort2 = dqort == Qtrue ? true: false;

    cmdline_completion(all_candidate, RSTRING(editing)->ptr, sqort2, dqort2);

TEND();    

    return Qnil;
}

VALUE mf_completion2(VALUE self, VALUE all_candidate, VALUE editing, VALUE sqort, VALUE dqort)
{
TBEGIN();
    Check_Type(all_candidate, T_ARRAY);
    Check_Type(editing, T_STRING);

    bool sqort2 = sqort == Qtrue ? true: false;
    bool dqort2 = dqort == Qtrue ? true: false;

    cmdline_completion2(all_candidate, RSTRING(editing)->ptr, sqort2, dqort2);

TEND();    

    return Qnil;
}

VALUE mf_minitscr(VALUE self)
{
TBEGIN();

    minitscr();

TEND();

    return Qnil;
}

VALUE mf_mendwin(VALUE self)
{
TBEGIN();

    mendwin();

TEND();

    return Qnil;
}

VALUE mf_mmove(VALUE self, VALUE y, VALUE x)
{
TBEGIN();

    Check_Type(y, T_FIXNUM);
    Check_Type(x, T_FIXNUM);

    mmove(NUM2INT(y), NUM2INT(x));

TEND();

    return Qnil;
}

VALUE mf_mmove_immediately(VALUE self, VALUE y, VALUE x)
{
TBEGIN();

    Check_Type(y, T_FIXNUM);
    Check_Type(x, T_FIXNUM);

    mmove_immediately(NUM2INT(y), NUM2INT(x));

TEND();

    return Qnil;
}

VALUE mf_mprintw(int argc, VALUE* argv, VALUE self)
{
TBEGIN();

    if(argc < 1) {
        fprintf(stderr, "invalid arguments in mprintw(%d)", argc);
        exit(1);
    }

    /// get str ///
    VALUE str = rb_f_sprintf(argc, argv);
    int ret = mprintw("%s", RSTRING(str)->ptr);

TEND();

    return INT2NUM(ret);
}

//%r minitscr(); mclear(); mmvprintw(0,0,"aaa"); mrefresh(); mgetch(); mendwin();

VALUE mf_mmvprintw(int argc, VALUE* argv, VALUE self)
{
TBEGIN();

    if(argc < 3) {
        fprintf(stderr, "invalid arguments in mmvprintw(%d)", argc);
        exit(1);
    }
        
    /// get x, y ///
    Check_Type(argv[0], T_FIXNUM);
    Check_Type(argv[1], T_FIXNUM);

    int x = NUM2INT(argv[0]);
    int y = NUM2INT(argv[1]);

    /// get str ///
    int new_argc = argc-2;
    VALUE* new_argv = argv + 2;
    
    VALUE str = rb_f_sprintf(new_argc, new_argv);
    int ret = mmvprintw(x, y, "%s", RSTRING(str)->ptr);

TEND();

    return INT2NUM(ret);
}

VALUE mf_mattron(VALUE self, VALUE attrs)
{
TBEGIN();

    Check_Type(attrs, T_FIXNUM);

    mattron(NUM2INT(attrs));

TEND();
    return Qnil;
}

VALUE mf_mattroff(VALUE self)
{
TBEGIN();

    mattroff();

TEND();
    return Qnil;
}

VALUE mf_mgetmaxx(VALUE self)
{
TBEGIN();

    int ret = mgetmaxx();
    
TEND();
    return INT2NUM(ret);
}

VALUE mf_mgetmaxy(VALUE self)
{
TBEGIN();

    int ret = mgetmaxy();
    
TEND();
    return INT2NUM(ret);
}

VALUE mf_mclear_immediately(VALUE self)
{
TBEGIN();

    mclear_immediately();
    
TEND();
    return Qnil;
}

VALUE mf_mclear(VALUE self)
{
TBEGIN();

    mclear();
    
TEND();
    return Qnil;
}

VALUE mf_mclear_online(VALUE self, VALUE y)
{
TBEGIN();

    Check_Type(y, T_FIXNUM);

    mclear_online(NUM2INT(y));
    
TEND();
    return Qnil;
}

VALUE mf_mbox(VALUE self, VALUE y, VALUE x, VALUE width, VALUE height)
{
TBEGIN();

    Check_Type(y, T_FIXNUM);
    Check_Type(x, T_FIXNUM);
    Check_Type(width, T_FIXNUM);
    Check_Type(height, T_FIXNUM);

    mbox(NUM2INT(y), NUM2INT(x), NUM2INT(width), NUM2INT(height));
    
TEND();
    return Qnil;
}

VALUE mf_mrefresh(VALUE self)
{
TBEGIN();

    mrefresh();
    
TEND();
    return Qnil;
}

VALUE mf_mkbuf_exist(VALUE self)
{
TBEGIN();

    int result = mkbuf_exist();
    
TEND();
    return INT2NUM(result);
}

VALUE mf_mgetch(VALUE self)
{
TBEGIN();

    int meta;
    int key = mgetch(&meta);
    
    VALUE result = rb_ary_new();
    rb_ary_push(result, INT2NUM(meta));
    rb_ary_push(result, INT2NUM(key));
    
TEND();

    return result;
}

VALUE mf_mis_curses(VALUE self)
{
TBEGIN();

    int result = mis_curses();
    
TEND();

    return result ? Qtrue:Qfalse;
}

VALUE mf_hostname(VALUE self)
{
TBEGIN();
    char hname[256];
    gethostname(hname, 256);
TEND();

    return rb_str_new2(hname);
}

VALUE mf_username(VALUE self)
{
TBEGIN();
    struct passwd* uname = getpwuid(getuid());
TEND();

    return rb_str_new2(uname->pw_name);
}

VALUE mf_set_shell(VALUE self, VALUE name, VALUE path, VALUE opt_eval)
{
TBEGIN();
    Check_Type(name, T_STRING);
    Check_Type(path, T_STRING);
    Check_Type(opt_eval, T_STRING);

    strcpy(gShellName, RSTRING(name)->ptr);
    strcpy(gShellPath, RSTRING(path)->ptr);
    strcpy(gShellOptEval, RSTRING(opt_eval)->ptr);
    
TEND();

    return Qnil;
}

VALUE mf_message(int argc, VALUE* argv, VALUE self)
{
TBEGIN();

    if(argc < 1) {
        fprintf(stderr, "invalid arguments in message(%d)", argc);
        exit(1);
    }

    /// get str ///
    VALUE str = rb_f_sprintf(argc, argv);
    int ret = err_msg("%s", RSTRING(str)->ptr);

TEND();

    return INT2NUM(ret);
}

void command_init()
{
TBEGIN();

    rb_define_global_function("mf_exit", RUBY_METHOD_FUNC(mf_exit), 0);
    rb_define_global_function("keycommand", RUBY_METHOD_FUNC(mf_keycommand), 4);
    rb_define_global_function("cursor_move", RUBY_METHOD_FUNC(mf_cursor_move), 1);
    rb_define_global_function("cursor_left", RUBY_METHOD_FUNC(mf_cursor_left), 0);
    rb_define_global_function("cursor_right", RUBY_METHOD_FUNC(mf_cursor_right), 0);
    rb_define_global_function("cursor_other", RUBY_METHOD_FUNC(mf_cursor_other), 0);
    rb_define_global_function("dir_move", RUBY_METHOD_FUNC(mf_dir_move), 1);
    rb_define_global_function("sdir_move", RUBY_METHOD_FUNC(mf_sdir_move), 1);
    
    rb_define_global_function("sort_name", RUBY_METHOD_FUNC(mf_sort_name), 0);
    rb_define_global_function("sort_name_reverse", RUBY_METHOD_FUNC(mf_sort_name_reverse), 0);
    rb_define_global_function("sort_ext", RUBY_METHOD_FUNC(mf_sort_ext), 0);
    rb_define_global_function("sort_ext_reverse", RUBY_METHOD_FUNC(mf_sort_ext_reverse), 0);
    rb_define_global_function("sort_size_reverse", RUBY_METHOD_FUNC(mf_sort_size_reverse), 0);
    rb_define_global_function("sort_size", RUBY_METHOD_FUNC(mf_sort_size), 0);
    rb_define_global_function("sort_time", RUBY_METHOD_FUNC(mf_sort_time), 0);
    rb_define_global_function("sort_time_reverse", RUBY_METHOD_FUNC(mf_sort_time_reverse), 0);
    rb_define_global_function("sort_toggle_dir_up", RUBY_METHOD_FUNC(mf_sort_toggle_dir_up), 0);
    
    rb_define_global_function("view_all", RUBY_METHOD_FUNC(mf_view_all), 0);
    rb_define_global_function("view_nameonly", RUBY_METHOD_FUNC(mf_view_nameonly), 0);
    rb_define_global_function("view_onedir", RUBY_METHOD_FUNC(mf_view_onedir), 0);
    rb_define_global_function("view_onedir2", RUBY_METHOD_FUNC(mf_view_onedir2), 0);
    rb_define_global_function("view_onedir3", RUBY_METHOD_FUNC(mf_view_onedir3), 0);
    rb_define_global_function("view_onedir5", RUBY_METHOD_FUNC(mf_view_onedir5), 0);

    rb_define_global_function("isearch", RUBY_METHOD_FUNC(mf_isearch), 0);

    rb_define_global_function("option_individual_cursor", RUBY_METHOD_FUNC(mf_option_individual_cursor), 1);
    rb_define_global_function("option_isearch_decision_way", RUBY_METHOD_FUNC(mf_option_isearch_decision_way), 1);
 
    rb_define_global_function("option_remain_marks", RUBY_METHOD_FUNC(mf_option_remain_marks), 1);
   rb_define_global_function("option_color", RUBY_METHOD_FUNC(mf_option_color), 1);
    rb_define_global_function("option_check_delete_file", RUBY_METHOD_FUNC(mf_option_check_delete_file), 1);
    rb_define_global_function("option_check_copy_file", RUBY_METHOD_FUNC(mf_option_check_copy_file), 1);
    rb_define_global_function("option_check_exit", RUBY_METHOD_FUNC(mf_option_check_exit), 1);
    rb_define_global_function("option_shift_isearch", RUBY_METHOD_FUNC(mf_option_shift_isearch), 1);
    rb_define_global_function("option_bold_exe", RUBY_METHOD_FUNC(mf_option_bold_exe), 1);
    rb_define_global_function("option_bold_dir", RUBY_METHOD_FUNC(mf_option_bold_dir), 1);
    rb_define_global_function("option_color_mark", RUBY_METHOD_FUNC(mf_option_color_mark), 1);
    rb_define_global_function("option_color_exe", RUBY_METHOD_FUNC(mf_option_color_exe), 1);
    rb_define_global_function("option_color_dir", RUBY_METHOD_FUNC(mf_option_color_dir), 1);
    rb_define_global_function("option_color_link", RUBY_METHOD_FUNC(mf_option_color_link), 1);
    
    rb_define_global_function("option_trashbox_name", RUBY_METHOD_FUNC(mf_option_trashbox_name), 1);
    rb_define_global_function("option_gnu_screen", RUBY_METHOD_FUNC(mf_option_gnu_screen), 1);
    rb_define_global_function("option_xterm", RUBY_METHOD_FUNC(mf_option_xterm), 1);
    rb_define_global_function("option_pty", RUBY_METHOD_FUNC(mf_option_pty), 1);
    rb_define_global_function("option_kanjicode", RUBY_METHOD_FUNC(mf_option_kanjicode), 1);
    rb_define_global_function("option_remain_cursor", RUBY_METHOD_FUNC(mf_option_remain_cursor), 1);
    rb_define_global_function("option_auto_rehash", RUBY_METHOD_FUNC(mf_option_auto_rehash), 1);
    rb_define_global_function("option_select", RUBY_METHOD_FUNC(mf_option_select), 1);
    rb_define_global_function("mark_all", RUBY_METHOD_FUNC(mf_mark_all), 0);
    rb_define_global_function("mark_all_files", RUBY_METHOD_FUNC(mf_mark_all_files), 0);
    rb_define_global_function("mark", RUBY_METHOD_FUNC(mf_mark), 0);
    rb_define_global_function("cmdline", RUBY_METHOD_FUNC(mf_cmdline), 2);
    rb_define_global_function("shell", RUBY_METHOD_FUNC(mf_shell), 2);
    rb_define_global_function("menu", RUBY_METHOD_FUNC(mf_menu), 1);
    rb_define_global_function("defmenu", RUBY_METHOD_FUNC(mf_defmenu), -1);
    
    rb_define_global_function("dir_exchange", RUBY_METHOD_FUNC(mf_dir_exchange), 0);
    rb_define_global_function("dir_copy", RUBY_METHOD_FUNC(mf_dir_copy), 0);
    rb_define_global_function("refresh", RUBY_METHOD_FUNC(mf_refresh), 0);
    rb_define_global_function("reread", RUBY_METHOD_FUNC(mf_reread), 0);
    rb_define_global_function("dir_back", RUBY_METHOD_FUNC(mf_dir_back), 0);

    rb_define_global_function("dir_new", RUBY_METHOD_FUNC(mf_dir_new), 0);
    rb_define_global_function("dir_close", RUBY_METHOD_FUNC(mf_dir_close), 0);
    rb_define_global_function("dir_up", RUBY_METHOD_FUNC(mf_dir_up), 0);

    rb_define_global_function("cursor_name", RUBY_METHOD_FUNC(mf_cursor_name), 0);
    rb_define_global_function("cursor_path", RUBY_METHOD_FUNC(mf_cursor_path), 0);
    rb_define_global_function("cursor_ext", RUBY_METHOD_FUNC(mf_cursor_ext), 0);
    rb_define_global_function("cursor_noext", RUBY_METHOD_FUNC(mf_cursor_noext), 0);
    rb_define_global_function("active_dir", RUBY_METHOD_FUNC(mf_active_dir), 0);
    rb_define_global_function("sleep_dir", RUBY_METHOD_FUNC(mf_sleep_dir), 0);
    rb_define_global_function("adir_path", RUBY_METHOD_FUNC(mf_adir_path), 0);
    rb_define_global_function("sdir_path", RUBY_METHOD_FUNC(mf_sdir_path), 0);
    rb_define_global_function("left_dir", RUBY_METHOD_FUNC(mf_left_dir), 0);
    rb_define_global_function("right_dir", RUBY_METHOD_FUNC(mf_right_dir), 0);
    rb_define_global_function("ldir_path", RUBY_METHOD_FUNC(mf_ldir_path), 0);
    rb_define_global_function("rdir_path", RUBY_METHOD_FUNC(mf_rdir_path), 0);
    
    rb_define_global_function("adir_mark", RUBY_METHOD_FUNC(mf_adir_mark), 0);
    rb_define_global_function("sdir_mark", RUBY_METHOD_FUNC(mf_sdir_mark), 0);
    
    rb_define_global_function("copy", RUBY_METHOD_FUNC(mf_copy), 3);
    rb_define_global_function("remove", RUBY_METHOD_FUNC(mf_remove), 2);
    rb_define_global_function("move", RUBY_METHOD_FUNC(mf_move), 3);
    rb_define_global_function("trashbox", RUBY_METHOD_FUNC(mf_trashbox), 2);
    
    rb_define_global_function("select_pty", RUBY_METHOD_FUNC(mf_select_pty), 1);
    rb_define_global_function("kill_pty", RUBY_METHOD_FUNC(mf_kill_pty), 1);
    rb_define_global_function("restore_pty", RUBY_METHOD_FUNC(mf_restore_pty), 1);
    rb_define_global_function("set_mask", RUBY_METHOD_FUNC(mf_set_mask), 1);
    rb_define_global_function("set_mask_sdir", RUBY_METHOD_FUNC(mf_set_mask_sdir), 1);
    rb_define_global_function("cut", RUBY_METHOD_FUNC(mf_cut), 0);
    rb_define_global_function("copy2", RUBY_METHOD_FUNC(mf_copy2), 0);
    rb_define_global_function("past", RUBY_METHOD_FUNC(mf_past), 0);

    rb_define_global_function("is_adir_right", RUBY_METHOD_FUNC(mf_is_adir_right), 0);
    rb_define_global_function("is_adir_left", RUBY_METHOD_FUNC(mf_is_adir_left), 0);

    rb_define_global_function("is_isearch_on", RUBY_METHOD_FUNC(mf_is_isearch_on), 0);
    rb_define_global_function("isearch_off", RUBY_METHOD_FUNC(mf_isearch_off), 0);
    rb_define_global_function("isearch_on", RUBY_METHOD_FUNC(mf_isearch_on), 0);
    rb_define_global_function("view_option", RUBY_METHOD_FUNC(mf_view_option), 0);
    rb_define_global_function("malias", RUBY_METHOD_FUNC(mf_malias), 3);
    rb_define_global_function("rehash", RUBY_METHOD_FUNC(mf_rehash), 0);

    rb_define_global_function("help", RUBY_METHOD_FUNC(mf_help), 0);
    rb_define_global_function("set_xterm", RUBY_METHOD_FUNC(mf_set_xterm), 4);
    rb_define_global_function("cursor", RUBY_METHOD_FUNC(mf_cursor), 0);
    rb_define_global_function("cursor_max", RUBY_METHOD_FUNC(mf_cursor_max), 0);
    rb_define_global_function("scrolltop", RUBY_METHOD_FUNC(mf_scrolltop), 0);
    rb_define_global_function("set_scrolltop", RUBY_METHOD_FUNC(mf_set_scrolltop), 1);
    rb_define_global_function("cursor_x", RUBY_METHOD_FUNC(mf_cursor_x), 0);
    rb_define_global_function("cursor_y", RUBY_METHOD_FUNC(mf_cursor_y), 0);
    rb_define_global_function("cursor_maxx", RUBY_METHOD_FUNC(mf_cursor_maxx), 0);
    rb_define_global_function("cursor_maxy", RUBY_METHOD_FUNC(mf_cursor_maxy), 0);
    rb_define_global_function("xterm_next", RUBY_METHOD_FUNC(mf_xterm_next), 0);
    rb_define_global_function("keymap_up", RUBY_METHOD_FUNC(mf_keymap_up), 6);
    rb_define_global_function("keymap_down", RUBY_METHOD_FUNC(mf_keymap_down), 6);
    rb_define_global_function("keymap_right", RUBY_METHOD_FUNC(mf_keymap_right), 6);
    rb_define_global_function("keymap_left", RUBY_METHOD_FUNC(mf_keymap_left), 6);
    rb_define_global_function("keymap_insert", RUBY_METHOD_FUNC(mf_keymap_insert), 6);
    rb_define_global_function("keymap_delete", RUBY_METHOD_FUNC(mf_keymap_delete), 6);
    rb_define_global_function("keymap_home", RUBY_METHOD_FUNC(mf_keymap_home), 6);
    rb_define_global_function("keymap_end", RUBY_METHOD_FUNC(mf_keymap_end), 6);
    rb_define_global_function("keymap_page_up", RUBY_METHOD_FUNC(mf_keymap_page_up), 6);
    rb_define_global_function("keymap_page_down", RUBY_METHOD_FUNC(mf_keymap_page_down), 6);
    rb_define_global_function("keymap_f1", RUBY_METHOD_FUNC(mf_keymap_f1), 6);
    rb_define_global_function("keymap_f2", RUBY_METHOD_FUNC(mf_keymap_f2), 6);
    rb_define_global_function("keymap_f3", RUBY_METHOD_FUNC(mf_keymap_f3), 6);
    rb_define_global_function("keymap_f4", RUBY_METHOD_FUNC(mf_keymap_f4), 6);
    rb_define_global_function("keymap_f5", RUBY_METHOD_FUNC(mf_keymap_f5), 6);
    rb_define_global_function("keymap_f6", RUBY_METHOD_FUNC(mf_keymap_f6), 6);
    rb_define_global_function("keymap_f7", RUBY_METHOD_FUNC(mf_keymap_f7), 6);
    rb_define_global_function("keymap_f8", RUBY_METHOD_FUNC(mf_keymap_f8), 6);
    rb_define_global_function("keymap_f9", RUBY_METHOD_FUNC(mf_keymap_f9), 6);
    rb_define_global_function("keymap_f10", RUBY_METHOD_FUNC(mf_keymap_f10), 6);
    rb_define_global_function("keymap_f11", RUBY_METHOD_FUNC(mf_keymap_f11), 6);
    rb_define_global_function("keymap_f12", RUBY_METHOD_FUNC(mf_keymap_f12), 6);
    rb_define_global_function("completion", RUBY_METHOD_FUNC(mf_completion), 4);
    rb_define_global_function("completion2", RUBY_METHOD_FUNC(mf_completion2), 4);
    rb_define_global_function("minitscr", RUBY_METHOD_FUNC(mf_minitscr), 0);
    rb_define_global_function("mendwin", RUBY_METHOD_FUNC(mf_mendwin), 0);
    rb_define_global_function("mmove", RUBY_METHOD_FUNC(mf_mmove), 2);
    rb_define_global_function("mmove_immediately", RUBY_METHOD_FUNC(mf_mmove_immediately), 2);
    rb_define_global_function("mmvprintw", RUBY_METHOD_FUNC(mf_mmvprintw), -1);
    rb_define_global_function("mprintw", RUBY_METHOD_FUNC(mf_mprintw), -1);
    rb_define_global_function("mattron", RUBY_METHOD_FUNC(mf_mattron), 1);
    rb_define_global_function("mattroff", RUBY_METHOD_FUNC(mf_mattroff), 0);
    rb_define_global_function("mgetmaxx", RUBY_METHOD_FUNC(mf_mgetmaxx), 0);
    rb_define_global_function("mgetmaxy", RUBY_METHOD_FUNC(mf_mgetmaxy), 0);
    rb_define_global_function("mclear_immediately", RUBY_METHOD_FUNC(mf_mclear_immediately), 0);
    rb_define_global_function("mclear", RUBY_METHOD_FUNC(mf_mclear), 0);
    rb_define_global_function("mclear_online", RUBY_METHOD_FUNC(mf_mclear_online), 1);
    rb_define_global_function("mbox", RUBY_METHOD_FUNC(mf_mbox), 4);
    rb_define_global_function("mrefresh", RUBY_METHOD_FUNC(mf_mrefresh), 0);
    rb_define_global_function("mkbuf_exist", RUBY_METHOD_FUNC(mf_mkbuf_exist), 0);
    rb_define_global_function("mgetch", RUBY_METHOD_FUNC(mf_mgetch), 0);
    rb_define_global_function("mis_curses", RUBY_METHOD_FUNC(mf_mis_curses), 0);
    rb_define_global_function("hostname", RUBY_METHOD_FUNC(mf_hostname), 0);
    rb_define_global_function("username", RUBY_METHOD_FUNC(mf_username), 0);
    rb_define_global_function("set_shell", RUBY_METHOD_FUNC(mf_set_shell), 3);
    rb_define_global_function("message", RUBY_METHOD_FUNC(mf_message), -1);
        
TEND();    
}

void command_final()
{
TBEGIN();

TEND();
}
