#include "common.h"

#include "config.h"

#if defined(HAVE_CURSES_H)
#include <curses.h>
#elif defined(HAVE_NCURSES_H)
#include <ncurses.h>
#elif defined(HAVE_NCURSES_NCURSES_H)
#include <ncurses/ncurses.h>
#endif

#include <stdlib.h>
#include <limits.h>
#include <dirent.h>
#include <libgen.h>
#include <termios.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <termios.h>
#include <stdarg.h>
#include <time.h>
#include <ctype.h>
#include <locale.h>
#include <sys/types.h>
#include <pwd.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/types.h>
#include <grp.h>

void sDir_setmask(sDir* self, char* mask);
int sDir_read(sDir* self);

static char* mygetpwuid(struct stat64* statbuf)
{
    struct passwd* ud;
    
    ud = getpwuid(statbuf->st_uid);
        
    if(ud)
        return ud->pw_name;
    else
        return NULL;
}

static char* mygetgrgid(struct stat64* statbuf)
{
    struct group* gd;

    gd = getgrgid(statbuf->st_gid);
    if(gd)
        return gd->gr_name;
    else
        return NULL;
}

///////////////////////////////////////////////////
// sFile -- ファイルオブジェクト
///////////////////////////////////////////////////
sFile* sFile_new(char* name, char* name_view, char* linkto, struct stat64* stat_, struct stat64* lstat_, BOOL mark, char* user, char* group, int uid, int gid)
{
    sFile* self = (sFile*)MALLOC(sizeof(sFile));
    
    self->mName = STRING_NEW(name);
    self->mNameView = STRING_NEW(name_view);
    self->mLinkTo = STRING_NEW(linkto);
    self->mStat = *stat_;
    self->mLStat = *lstat_;
    self->mMark = mark;
    if(user == NULL) {
        char tmp[128];
        snprintf(tmp, 128, "%d", uid);
        self->mUser = STRING_NEW(tmp);
    }
    else {
        self->mUser = STRING_NEW(user);
    }

    if(group == NULL) {
        char tmp[128];
        snprintf(tmp, 128, "%d", gid);
        self->mGroup = STRING_NEW(tmp);
    }
    else {
        self->mGroup = STRING_NEW(group);
    }

    self->mSortRandom = 0;

    return self;
}

void sFile_delete(sFile* self) 
{
    string_delete(self->mName);
    string_delete(self->mNameView);
    string_delete(self->mLinkTo);
    string_delete(self->mUser);
    string_delete(self->mGroup);

    FREE(self);
}

///////////////////////////////////////////////////
// sDir -- ディレクトリオブジェクト
///////////////////////////////////////////////////
static void sDir_mask(sDir* self);

static sDir* sDir_new()
{
    sDir* self = (sDir*)MALLOC(sizeof(sDir));

    self->mPath = STRING_NEW("");

    self->mMask = STRING_NEW("");
    self->mActive = FALSE;

    self->mFiles = VECTOR_NEW(50);

    self->mScrollTop = 0;
    self->mCursor = 0;

    self->mHistory = VECTOR_NEW(10);
    vector_add(self->mHistory, STRING_NEW(string_c_str(self->mPath)));
    self->mHistoryCursor = 0;



#ifdef HAVE_ONIGURUMA_H
    self->mMaskReg = NULL;
#endif

    sDir_setmask(self, "");

    self->mVD = FALSE;

    return self;
}

void sDir_delete(sDir* self)
{
    string_delete(self->mPath);
    string_delete(self->mMask);
    int i;
    for(i=0; i<vector_size(self->mFiles); i++) {
        sFile_delete(vector_item(self->mFiles, i));
    }
    FREE(self->mFiles);

    for(i=0; i<vector_size(self->mHistory); i++){
        string_delete(vector_item(self->mHistory, i));
    }
    vector_delete(self->mHistory);

    FREE(self);
}

static void sDir_sort(sDir* self);

void sDir_setmask(sDir* self, char* mask) 
{
    if(self->mMaskReg) onig_free(self->mMaskReg);

    OnigUChar* regex = (OnigUChar*)mask;
    OnigErrorInfo err_info;

    int r = onig_new(&self->mMaskReg, regex
        , regex + strlen((char*)regex)
        , ONIG_OPTION_IGNORECASE
        , ONIG_ENCODING_UTF8
        , ONIG_SYNTAX_DEFAULT
        ,  &err_info);

    if(r == ONIG_NORMAL) {
        string_put(self->mMask, mask);
    }
    else {
        string_put(self->mMask, "");
        self->mMaskReg = NULL;
    }
}

static void sDir_mask(sDir* self)
{
    if(strcmp(string_c_str(self->mMask), "") != 0) {
        int i;
        for(i=0; i<vector_size(self->mFiles); i++) {
            sFile* file = vector_item(self->mFiles, i);
            char* fname = string_c_str(file->mName);

            if(!S_ISDIR(file->mStat.st_mode) 
                && strcmp(fname, ".index") != 0) 
            {
                OnigRegion* region = onig_region_new();

                int r2 = onig_search(self->mMaskReg, fname
                   , fname + strlen(fname)
                   , fname, fname + strlen(fname)
                   , region, ONIG_OPTION_IGNORECASE);

                if(r2 < 0) {
                    sFile* f = vector_item(self->mFiles, i);
                    sFile_delete(f);
                    vector_erase(self->mFiles, i);
                    i--;
                }

                onig_region_free(region, 1);
            } 
            else if(S_ISDIR(file->mStat.st_mode)) {
                if(strcmp(fname, "..") != 0 && fname[0] == '.' && self->mDotDirMask != 0) {
                    sFile* f = vector_item(self->mFiles, i);
                    sFile_delete(f);
                    vector_erase(self->mFiles, i);
                    i--;
                }
            }
        }
    }
}

static int convert_fname(char* src, char* des, int des_size) 
{
#if defined(__DARWIN__)
    if(is_all_ascii(src)) {
        strncpy(des, src, des_size);
    }
    else {
        /// コンバート ///
        if(kanji_convert(src, des, des_size, gKanjiCodeFileName, gKanjiCode) == -1) {
            return -1;
        }
    }
    return 0;
#else
    strncpy(des, src, des_size);
    return 0;
#endif
}

int sDir_read(sDir* self)
{
    if(self->mVD) {
        int i;
        for(i=0; i<vector_size(self->mFiles); i++) {
            sFile* file = vector_item(self->mFiles, i);
            char* fname1 = string_c_str(file->mName);

            char fname[4089];
            if(convert_fname(fname1, fname, 4089) == -1) {
                sFile* f = vector_item(self->mFiles, i);
                sFile_delete(f);
                vector_erase(self->mFiles, i);
                i--;
                continue;
            }

            char path[PATH_MAX];
            if(fname1[0] == '/') {
                strncpy(path, fname1, PATH_MAX);
            }
            else {
                snprintf(path, PATH_MAX, "%s%s", string_c_str(self->mPath),fname1);
            }
            
            struct stat64 lstat_;
            memset(&lstat_, 0, sizeof(struct stat64));
            if(lstat64(path, &lstat_) < 0) {
                sFile* f = vector_item(self->mFiles, i);
                sFile_delete(f);
                vector_erase(self->mFiles, i);
                i--;
                continue;
            }

            struct stat64 stat_;
            memset(&stat_, 0, sizeof(struct stat64));
            if(stat64(path, &stat_) < 0) {
                if(S_ISLNK(lstat_.st_mode)) {
                    stat_ = lstat_;
                }
                else {
                    sFile* f = vector_item(self->mFiles, i);
                    sFile_delete(f);
                    vector_erase(self->mFiles, i);
                    i--;
                    continue;
                }
            }
            
            char linkto[PATH_MAX];

            if(S_ISLNK(lstat_.st_mode)) {
                int bytes = readlink(path, linkto, PATH_MAX);
                if(bytes == -1) {
                    linkto[0] = 0;
                }
                else {
                    linkto[bytes] = 0;
                }
            }
            else {
                linkto[0] = 0;
            }

#if defined(__DARWIN__)
            char tmp[PATH_MAX + 1];
            if(kanji_convert(linkto, tmp, PATH_MAX, gKanjiCodeFileName, gKanjiCode) != -1) {
                strncpy(linkto, tmp, PATH_MAX);
            }
#endif

            char* user = mygetpwuid(&lstat_);
            char* group = mygetgrgid(&lstat_);

            /// refresh ///
            string_put(file->mLinkTo, linkto);
            file->mStat = stat_;
            file->mLStat = lstat_;
            if(user == NULL) {
                char tmp[128];
                snprintf(tmp, 128, "%d", lstat_.st_uid);
                string_put(file->mUser, tmp);
            }
            else {
                string_put(file->mUser, user);
            }
            if(group == NULL) {
                char tmp[128];
                snprintf(tmp, 128, "%d", lstat_.st_gid);
                string_put(file->mGroup, tmp);
            }
            else {
                string_put(file->mGroup, group);
            }

            file->mSortRandom = 0;
        }
    }
    else {
        if(access(string_c_str(self->mPath), F_OK) != 0) {
            string_put(self->mPath, "/");
            return sDir_read(self);
        }

        hash_obj* mark_files = HASH_NEW(10);
        int i;
        for(i=0; i<vector_size(self->mFiles); i++) {
            sFile* file = vector_item(self->mFiles, i);

            if(file->mMark) {
                hash_put(mark_files, string_c_str(file->mName), (void*)1);
            }
        }

        for(i=0; i<vector_size(self->mFiles); i++) {
            sFile_delete(vector_item(self->mFiles, i));
        }
        vector_clear(self->mFiles);

        DIR* dir = opendir(string_c_str(self->mPath));
        if(dir == NULL) {
            string_put(self->mPath, "/");
            return sDir_read(self);
        }
        
        struct dirent* entry;
        while(entry = readdir(dir)) {
            char fname[4089];
            if(convert_fname(entry->d_name, fname, 4089) == -1) {
                continue;
            }

            char path[PATH_MAX];
            snprintf(path, PATH_MAX, "%s%s", string_c_str(self->mPath), entry->d_name);

            
            struct stat64 lstat_;
            memset(&lstat_, 0, sizeof(struct stat64));
            if(lstat64(path, &lstat_) < 0) {
                continue;
            }

            struct stat64 stat_;
            memset(&stat_, 0, sizeof(struct stat64));
            if(stat64(path, &stat_) < 0) {
                if(S_ISLNK(lstat_.st_mode)) {
                    stat_ = lstat_;
                }
                else {
                    continue;
                }
            }
            
            char linkto[PATH_MAX];

            if(S_ISLNK(lstat_.st_mode)) {
                int bytes = readlink(path, linkto, PATH_MAX);
                if(bytes == -1) {
                    linkto[0] = 0;
                }
                else {
                    linkto[bytes] = 0;
                }
            }
            else {
                linkto[0] = 0;
            }

#if defined(__DARWIN__)
            char tmp[PATH_MAX + 1];
            if(kanji_convert(linkto, tmp, PATH_MAX, gKanjiCodeFileName, gKanjiCode) != -1) {
                strncpy(linkto, tmp, PATH_MAX);
            }
#endif

            char* user = mygetpwuid(&lstat_);
            char* group = mygetgrgid(&lstat_);

            if(strcmp(entry->d_name, ".") != 0) {
                BOOL mark = FALSE;

                if(hash_item(mark_files, entry->d_name) != NULL) {
                    mark = TRUE;
                }
                
                /// add ///
                vector_add(self->mFiles, sFile_new(entry->d_name, fname, linkto, &stat_, &lstat_, mark, user, group, lstat_.st_uid, lstat_.st_gid));
            }
        }
        hash_delete(mark_files);
        
        closedir(dir);
    }

    return 0;
}

void filer_vd_start(int dir)
{
    if(dir < 0 || dir >= vector_size(gDirs)) {
        return;
    }
    sDir* self = (sDir*)vector_item(gDirs, dir);

    self->mVD = TRUE;
    int i;
    for(i=0; i<vector_size(self->mFiles); i++) {
        sFile_delete(vector_item(self->mFiles, i));
    }
    vector_clear(self->mFiles);
}


void filer_vd_end(int dir)
{
    if(dir < 0 || dir >= vector_size(gDirs)) {
        return;
    }

    sDir* self = (sDir*)vector_item(gDirs, dir);

    self->mVD = FALSE;
    filer_reread(dir);
}

void filer_vd_add(int dir, char* fname)
{
    if(dir < 0 || dir >= vector_size(gDirs)) {
        return;
    }
    sDir* self = (sDir*)vector_item(gDirs, dir);

    char fname2[PATH_MAX];
    if(convert_fname(fname, fname2, PATH_MAX) == -1) {
        return;
    }

    char path[PATH_MAX];
    if(fname[0] == '/') {
        strncpy(path, fname, PATH_MAX);
    }
    else {
        snprintf(path, PATH_MAX, "%s%s", string_c_str(self->mPath), fname);
    }
    
    struct stat64 lstat_;
    memset(&lstat_, 0, sizeof(struct stat64));
    if(lstat64(path, &lstat_) < 0) {
        return;
    }

    struct stat64 stat_;
    memset(&stat_, 0, sizeof(struct stat64));
    if(stat64(path, &stat_) < 0) {
        if(S_ISLNK(lstat_.st_mode)) {
            stat_ = lstat_;
        }
        else {
            return;
        }
    }
    
    char linkto[PATH_MAX];

    if(S_ISLNK(lstat_.st_mode)) {
        int bytes = readlink(path, linkto, PATH_MAX);
        if(bytes == -1) {
            linkto[0] = 0;
        }
        else {
            linkto[bytes] = 0;
        }
    }
    else {
        linkto[0] = 0;
    }
#if defined(__DARWIN__)
    char tmp[PATH_MAX + 1];
    if(kanji_convert(linkto, tmp, PATH_MAX, gKanjiCodeFileName, gKanjiCode) != -1) {
        strncpy(linkto, tmp, PATH_MAX);
    }
#endif

    char* user = mygetpwuid(&lstat_);
    char* group = mygetgrgid(&lstat_);

    if(strcmp(fname, ".") != 0) {
        BOOL mark = FALSE;
        
        /// add ///
        vector_add(self->mFiles, sFile_new(fname, fname2, linkto, &stat_, &lstat_, mark, user, group, lstat_.st_uid, lstat_.st_gid));
    }
}

///////////////////////////////////////////////////
// ファイラー
///////////////////////////////////////////////////
vector_obj* gDirs;
enum eKanjiCode gKanjiCodeFileName = kUtf8;
hash_obj* gKeyCommand[2][KEY_MAX];          // キーとコマンドのマップ[0][キーコード] metaなし [1][キーコード] meta

BOOL filer_add_keycommand(int meta, int key, char* ftype, char* command, char* fname)
{
    if(gKeyCommand[meta][key] == NULL) {
        gKeyCommand[meta][key] = HASH_NEW(1);
    }

    sStatments* previous = hash_item(gKeyCommand[meta][key], ftype);
    if(previous) {
        sStatments_delete(previous);
        hash_erase(gKeyCommand[meta][key], ftype);
    }

    sStatments* statments = sStatments_new();
    if(!saphire_compile2(command, fname, statments)) {
        //merr_msg("%s", string_c_str(gErrMsg));
        return FALSE;
    }

    hash_put(gKeyCommand[meta][key], ftype, statments);

    return TRUE;
}

BOOL filer_add_keycommand2(int meta, int key, char* ftype, sBlock* block, char* fname)
{
    if(gKeyCommand[meta][key] == NULL) {
        gKeyCommand[meta][key] = HASH_NEW(1);
    }

    sStatments* previous = hash_item(gKeyCommand[meta][key], ftype);
    if(previous) {
        sStatments_delete(previous);
        hash_erase(gKeyCommand[meta][key], ftype);
    }

    sStatments* statments = sStatments_new2(block->mStatments);

    hash_put(gKeyCommand[meta][key], ftype, statments);

    return TRUE;
}

BOOL gExtensionICase = TRUE;            // マークファイルの拡張子別実行で大文字小文字を区別するかどうか

void filer_init()
{
    gDirs = VECTOR_NEW(2);
    gKanjiCodeFileName = gKanjiCode;

    memset(gKeyCommand, 0, sizeof(hash_obj*)*2*KEY_MAX);
}

void filer_final()
{
    int i;
    for(i=0; i<vector_size(gDirs); i++) {
        sDir_delete(vector_item(gDirs, i));
    }
    vector_delete(gDirs);

    for(i=0; i<2; i++) {
        int j;
        for(j=0; j<KEY_MAX; j++) {
            hash_obj* item = (hash_obj*)gKeyCommand[i][j];
            if(item) {
                hash_it* it = hash_loop_begin(item);
                while(it != NULL) {
                    sStatments_delete(hash_loop_item(it));
                    it = hash_loop_next(it);
                }
                hash_delete(item);
            }
         }
    }
}

int filer_new_dir(char* path, BOOL dotdir_mask, char* mask)
{
    sDir* dir = sDir_new();

    string_put(dir->mPath, path);
    if(path[strlen(path)-1] != '/') {
        string_push_back2(dir->mPath, '/');
    }
    dir->mDotDirMask = dotdir_mask;
    sDir_setmask(dir, mask);

    if(sDir_read(dir) == 0) {
        sDir_mask(dir);
        sDir_sort(dir);        // ソート

        int i;
        for(i=vector_size(dir->mHistory)-1; i!=dir->mHistoryCursor; i--) {
            string_delete(vector_item(dir->mHistory, i));
            vector_erase(dir->mHistory, i);
        }
        vector_add(dir->mHistory, STRING_NEW(string_c_str(dir->mPath)));
        dir->mHistoryCursor++;

        vector_add(gDirs, dir);
    }
    else {
        return -1;
    }

    return 0;
}

void filer_del_dir(int dir)
{
    sDir_delete(vector_item(gDirs, dir));
    vector_erase(gDirs, dir);
}

int sDir_cd(sDir* self, char* path)
{
    if(self->mVD) {
        self->mVD = FALSE;
    }

    int dir;
    int i;
    for(i=0; i<vector_size(gDirs); i++) {
        if(self == vector_item(gDirs, i)) {
            dir = i;
            break;
        }
    }

    char fname[PATH_MAX];
    char buf[PATH_MAX];
    strncpy(buf, string_c_str(self->mPath), PATH_MAX);
    strncpy(fname, basename(buf), PATH_MAX);

    char path2[PATH_MAX];
    if(correct_path(string_c_str(self->mPath), path, path2, PATH_MAX) && access(path2, F_OK) == 0) {
        string_put(self->mPath, path2);
        if(string_c_str(self->mPath)[strlen(string_c_str(self->mPath))-1] != '/') {
            string_push_back(self->mPath, "/");
        }
        
        filer_reset_marks(dir);

        if(sDir_read(self) != 0) {
            return -1;
        }

        sDir_mask(self);
        sDir_sort(self); 

        if(strcmp(path, "..") == 0) {
            self->mScrollTop = 0;
            filer_cursor_move(dir, 0);

            int i;
            for(i=0; i<vector_size(self->mFiles); i++) {
                sFile* file = (sFile*)vector_item(self->mFiles, i);
                if(strcmp(string_c_str(file->mName), fname) == 0) {
                    self->mScrollTop = 0;
                    filer_cursor_move(dir, i);
                    break;
                }
            }
        }
        else {
            self->mScrollTop = 0;
            filer_cursor_move(dir, 0);
        }

        /// カレントディレクトリを変える ///
        if(dir == adir()) {
            if(chdir(string_c_str(self->mPath)) == 0) {
                setenv("PWD", string_c_str(self->mPath), 1);
            }
        }

        return 0;
    }
    else {
        return -1;
    }
}

int filer_history_forward(int dir)
{
    if(dir < 0 || dir >= vector_size(gDirs)) {
        return -1;
    }

    sDir* dir2 = vector_item(gDirs, dir);

    if(dir2->mHistoryCursor < vector_size(dir2->mHistory)-1) {
        string_obj* path = vector_item(dir2->mHistory, ++dir2->mHistoryCursor);
        sDir_cd(dir2, string_c_str(path));
    }
}

int filer_history_back(int dir)
{
    if(dir < 0 || dir >= vector_size(gDirs)) {
        return -1;
    }

    sDir* dir2 = vector_item(gDirs, dir);

    if(dir2->mHistoryCursor > 0) {
        string_obj* path = vector_item(dir2->mHistory, --dir2->mHistoryCursor);
        sDir_cd(dir2, string_c_str(path));
    }
}

int filer_cd(int dir, char* path) 
{
    if(dir < 0 || dir >= vector_size(gDirs)) {
        return -1;
    }
    sDir* dir2 = (sDir*)vector_item(gDirs, dir);

    if(sDir_cd(dir2, path) == 0) {
        int i;
        for(i=vector_size(dir2->mHistory)-1; i!=dir2->mHistoryCursor; i--) {
            string_delete(vector_item(dir2->mHistory, i));
            vector_erase(dir2->mHistory, i);
        }
        vector_add(dir2->mHistory, STRING_NEW(string_c_str(dir2->mPath)));
        dir2->mHistoryCursor++;
    }
    else {
        return -1;
    }

    return 0;
}

int filer_reread(int dir)
{
    if(dir < 0 || dir >= vector_size(gDirs)) {
        return -1;
    }

    sDir* dir2 = (sDir*)vector_item(gDirs, dir);
    sDir_read(dir2);
    sDir_mask(dir2);
    sDir_sort(dir2);

    filer_cursor_move(dir, dir2->mCursor);
}

BOOL filer_marking(int dir)
{
    if(dir < 0 || dir >= vector_size(gDirs)) {
        return FALSE;
    }
    
    if(filer_mark_file_num(dir) != 0) {
        return TRUE;
    }
    else {
        return FALSE;
    }
}


char* filer_mask(int dir)
{
    sDir* dir2 = filer_dir(dir);

    if(dir2) {
        return string_c_str(dir2->mMask);
    }
}

void filer_set_mask(int dir, char* mask)
{
    sDir* dir2 = filer_dir(dir);

    if(dir2) {
        sDir_setmask(dir2, mask);
    }
}

void filer_cursor_move(int dir, int num)
{
    const int maxy = filer_line_max(dir);

    sDir* dir2 = filer_dir(dir);
    dir2->mCursor = num;
    
    if(dir2->mCursor < 0) dir2->mCursor = 0;
    if(dir2->mCursor >= vector_size(dir2->mFiles)) 
        dir2->mCursor = vector_size(dir2->mFiles)-1;

    char* env_view_option = getenv("VIEW_OPTION");
    if(env_view_option == NULL) {
        fprintf(stderr, "VIEW_OPTION is NULL\n");
        exit(1);
    }

    if(strcmp(env_view_option, "2pain") == 0 
        || strcmp(env_view_option, "1pain") == 0) 
    {
         if(dir2->mCursor >= dir2->mScrollTop + maxy) {
             dir2->mScrollTop = (dir2->mCursor/maxy)*maxy;
         }
         if(dir2->mCursor < dir2->mScrollTop) {
             dir2->mScrollTop = (dir2->mCursor/maxy)*maxy;
         }
    }
    else if(strcmp(env_view_option, "1pain2") == 0) {
        if(dir2->mCursor >= dir2->mScrollTop + maxy*2) {
             dir2->mScrollTop = (dir2->mCursor/(maxy*2))*(maxy*2);
        }
        if(dir2->mCursor < dir2->mScrollTop) {
            dir2->mScrollTop = (dir2->mCursor/(maxy*2))*(maxy*2);
        }
    }
    else if(strcmp(env_view_option, "1pain3") == 0) {
        if(dir2->mCursor >= dir2->mScrollTop + maxy*3) {
             dir2->mScrollTop = (dir2->mCursor/(maxy*3))*(maxy*3);
        }
        if(dir2->mCursor < dir2->mScrollTop) {
            dir2->mScrollTop = (dir2->mCursor/(maxy*3))*(maxy*3);
        }
    }
    else if(strcmp(env_view_option, "1pain5") == 0) {
        if(dir2->mCursor >= dir2->mScrollTop + maxy*5) {
             dir2->mScrollTop = (dir2->mCursor/(maxy*5))*(maxy*5);
        }
        if(dir2->mCursor < dir2->mScrollTop) {
            dir2->mScrollTop = (dir2->mCursor/(maxy*5))*(maxy*5);
        }
    }
}

void filer_activate(int dir)
{
    if(dir == 0 || dir == 1) {
        sDir* ldir = filer_dir(0);
        sDir* rdir = filer_dir(1);

        if(dir == 0) {
            ldir->mActive = TRUE;
            rdir->mActive = FALSE;

            if(chdir(string_c_str(ldir->mPath)) == 0) {
                setenv("PWD", string_c_str(ldir->mPath), 1);
            }
        }
        else {
            ldir->mActive = FALSE;
            rdir->mActive = TRUE;

            if(chdir(string_c_str(rdir->mPath)) == 0) {
                setenv("PWD", string_c_str(rdir->mPath), 1);
            }
        }
    }
    else if(dir >= 2 && dir < vector_size(gDirs)) {
        sDir* adir_ = filer_dir(adir());
        sDir* dir_ = filer_dir(dir);

        vector_exchange(gDirs, adir(), dir_);
        vector_exchange(gDirs, dir, adir_);

        adir_->mActive = FALSE;
        dir_->mActive = TRUE;

        if(chdir(string_c_str(dir_->mPath)) == 0) {
            setenv("PWD", string_c_str(dir_->mPath), 1);
        }
    }
}

static BOOL is_same_extension_marked(int dir, char* result, int result_size)
{
    if(!filer_marking(dir)) return FALSE;

    sDir* self = filer_dir(dir);

    strncpy(result, "", result_size);
    int i;
    for(i=0; i<vector_size(self->mFiles); i++) {
        sFile* file = (sFile*)vector_item(self->mFiles, i);
        if(file->mMark) {
            char tmp[PATH_MAX];
            extname(tmp, PATH_MAX, string_c_str(file->mName));
            
            if(strcmp(result, "") == 0) {
                strncpy(result, tmp, result_size);
            }
            else {
                if(gExtensionICase) {
                    if(strcasecmp(result, tmp) != 0) {
                        strncpy(result, "", result_size);
                        return FALSE;
                    }
                }
                else {
                    if(strcmp(result, tmp) != 0) {
                        strncpy(result, "", result_size);
                        return FALSE;
                    }
                }
            }
        }
    }

    return TRUE;
}

static BOOL is_directory_marked(int dir)
{
    if(!filer_marking(dir)) return FALSE;

    sDir* self = filer_dir(dir);

    int i;
    for(i=0; i<vector_size(self->mFiles); i++) {
        sFile* file = (sFile*)vector_item(self->mFiles, i);
        if(file->mMark) {
            if(!S_ISDIR(file->mStat.st_mode)) {
                return FALSE;
            }
        }
    }
    
    return TRUE;
}

static BOOL is_executive_file_marked(int dir)
{
    if(!filer_marking(dir)) return FALSE;

    sDir* self = filer_dir(dir);

    int i;
    for(i=0; i<vector_size(self->mFiles); i++) {
        sFile* file = (sFile*)vector_item(self->mFiles, i);
        if(file->mMark) {
            if(!(file->mStat.st_mode&S_IXUSR) && !(file->mStat.st_mode&S_IXGRP) && !(file->mStat.st_mode&S_IXOTH))
            {
                return FALSE;
            }
        }
    }
    
    return TRUE;
}

static BOOL is_link_marked(int dir)
{
    if(!filer_marking(dir)) return FALSE;

    sDir* self = filer_dir(dir);

    int i;
    for(i=0; i<vector_size(self->mFiles); i++) {
        sFile* file = (sFile*)vector_item(self->mFiles, i);
        if(file->mMark) {
            if(!S_ISLNK(file->mLStat.st_mode))
            {
                return FALSE;
            }
        }
    }
    
    return TRUE;
}

void filer_input(int meta, int key)
{
    sDir* dir = filer_dir(adir());
    sFile* cursor = (sFile*)vector_item(dir->mFiles, dir->mCursor);

    /// ファイル名を得る ///
    const char* name = string_c_str(cursor->mName);
    char fname[1024];
    
    strncpy(fname, name, 1024);
    if(gExtensionICase && is_all_ascii((char*)name)) {
        mystrtolower(fname);
    }
    /// 拡張子名を得る ///
    char extension[256];

    char tmp[PATH_MAX];
    extname(tmp, PATH_MAX, string_c_str(cursor->mName));
    if(gExtensionICase) {
        mystrtolower(tmp);
    }

    snprintf(extension, 256, ".%s", tmp);

    /// マーク中ならその状態を調べる ///
    BOOL is_extension_marked = FALSE;           // 同一拡張子のファイルをマーク中
    char marked_extension[1024];                // マーク中の拡張子
    BOOL is_directory_marked_ = FALSE;           // ディレクトリをマーク中
    BOOL is_executive_file_marked_ = FALSE;      // 実行ファイルをマーク中
    BOOL is_link_marked_ = FALSE;                // リンクをマーク中

    if(filer_marking(adir())) {
        char tmp[1024];
        is_extension_marked = is_same_extension_marked(adir(), tmp, 1024);
        if(is_extension_marked) {
            if(gExtensionICase) {   // 大文字小文字を区別しない場合
                mystrtolower(tmp);
            }
            snprintf(marked_extension, 1024, ".mark-%s", tmp);
        }
        
        is_directory_marked_ = is_directory_marked(adir());
        is_executive_file_marked_ = is_executive_file_marked(adir());
        is_link_marked_ = is_link_marked(adir());
    }

    char title[128];
    snprintf(title, 128, "keycommand(%d, %d):", meta, key);


    /// 同一拡張子のファイルをマーク中 ///
    if(is_extension_marked
            && key >= 0 && key < KEY_MAX
            && gKeyCommand[meta][key] && hash_item(gKeyCommand[meta][key], marked_extension))
    {
        sStatments* command = hash_item(gKeyCommand[meta][key],  marked_extension);
        saphire_set_signal();
        sRFd* pipein = sRFd_new(STDIN_FILENO);
        sWFd* pipeout = sWFd_new(STDOUT_FILENO);
        int rcode = saphire_run(command, title, pipeout, pipein, STDERR_FILENO);
        sRFd_delete(pipein);
        sWFd_flash(pipeout);
        sWFd_delete(pipeout);
        set_signal_mfiler();
        ISearchClear();
        if(rcode < 0) { merr_msg(string_c_str(gErrMsg)); }
    }

    /// リンクをマーク中 ///
    else if(is_link_marked_
            && key >= 0 && key < KEY_MAX
            && gKeyCommand[meta][key] && hash_item(gKeyCommand[meta][key], ".mark-link"))
    {
        sStatments* command = hash_item(gKeyCommand[meta][key],  ".mark-link");
        saphire_set_signal();
        sRFd* pipein = sRFd_new(STDIN_FILENO);
        sWFd* pipeout = sWFd_new(STDOUT_FILENO);
        int rcode = saphire_run(command, title, pipeout, pipein, STDERR_FILENO);
        sRFd_delete(pipein);
        sWFd_flash(pipeout);
        sWFd_delete(pipeout);
        set_signal_mfiler();
        ISearchClear();
        if(rcode < 0) { merr_msg(string_c_str(gErrMsg)); }
    }

    /// ディレクトリをマーク中 ///
    else if(is_directory_marked_
            && key >= 0 && key < KEY_MAX
            && gKeyCommand[meta][key] && hash_item(gKeyCommand[meta][key], ".mark-directory"))
    {
        sStatments* command = hash_item(gKeyCommand[meta][key],  ".mark-directory");
        saphire_set_signal();
        sRFd* pipein = sRFd_new(STDIN_FILENO);
        sWFd* pipeout = sWFd_new(STDOUT_FILENO);
        int rcode = saphire_run(command, title, pipeout, pipein, STDERR_FILENO);
        sRFd_delete(pipein);
        sWFd_flash(pipeout);
        sWFd_delete(pipeout);
        set_signal_mfiler();
        ISearchClear();
        if(rcode < 0) { merr_msg(string_c_str(gErrMsg)); }
    }

    /// 実行ファイルをマーク中 ///
    else if(is_executive_file_marked_
            && key >= 0 && key < KEY_MAX
            && gKeyCommand[meta][key] && hash_item(gKeyCommand[meta][key], ".mark-execute"))
    {
        sStatments* command = hash_item(gKeyCommand[meta][key],  ".mark-execute");
        saphire_set_signal();
        sRFd* pipein = sRFd_new(STDIN_FILENO);
        sWFd* pipeout = sWFd_new(STDOUT_FILENO);
        int rcode = saphire_run(command, title, pipeout, pipein, STDERR_FILENO);
        sRFd_delete(pipein);
        sWFd_flash(pipeout);
        sWFd_delete(pipeout);
        set_signal_mfiler();
        ISearchClear();
        if(rcode < 0) { merr_msg(string_c_str(gErrMsg)); }
    }

    /// マーク中 ///
    else if(filer_marking(adir())
        && key >= 0 && key < KEY_MAX 
        && gKeyCommand[meta][key] && hash_item(gKeyCommand[meta][key], ".mark"))
    {
        sStatments* command = hash_item(gKeyCommand[meta][key],  ".mark");
        saphire_set_signal();
        sRFd* pipein = sRFd_new(STDIN_FILENO);
        sWFd* pipeout = sWFd_new(STDOUT_FILENO);
        int rcode = saphire_run(command, title, pipeout, pipein, STDERR_FILENO);
        sRFd_delete(pipein);
        sWFd_flash(pipeout);
        sWFd_delete(pipeout);
        set_signal_mfiler();
        ISearchClear();
        if(rcode < 0) { merr_msg(string_c_str(gErrMsg)); }
    }

    /// リンクを選択中 ///
    else if(S_ISLNK(cursor->mLStat.st_mode)
        && key >= 0 && key < KEY_MAX 
        && gKeyCommand[meta][key] && hash_item(gKeyCommand[meta][key], ".link"))
    {
        sStatments* command = hash_item(gKeyCommand[meta][key],  ".link");
        saphire_set_signal();
        sRFd* pipein = sRFd_new(STDIN_FILENO);
        sWFd* pipeout = sWFd_new(STDOUT_FILENO);
        int rcode = saphire_run(command, title, pipeout, pipein, STDERR_FILENO);
        sRFd_delete(pipein);
        sWFd_flash(pipeout);
        sWFd_delete(pipeout);
        set_signal_mfiler();
        ISearchClear();
        if(rcode < 0) { merr_msg(string_c_str(gErrMsg)); }
    }

    /// ファイル名で指定されている場合 ///
    else if(key >= 0 && key < KEY_MAX  
          && gKeyCommand[meta][key] && hash_item(gKeyCommand[meta][key], fname))
    {
        sStatments* command = hash_item(gKeyCommand[meta][key],  fname);
        saphire_set_signal();
        sRFd* pipein = sRFd_new(STDIN_FILENO);
        sWFd* pipeout = sWFd_new(STDOUT_FILENO);
        int rcode = saphire_run(command, title, pipeout, pipein, STDERR_FILENO);
        sRFd_delete(pipein);
        sWFd_flash(pipeout);
        sWFd_delete(pipeout);
        set_signal_mfiler();
        ISearchClear();
        if(rcode < 0) { merr_msg(string_c_str(gErrMsg)); }
    }

    /// 拡張子名で指定されている場合 ///
    else if(key >= 0 && key < KEY_MAX 
           && gKeyCommand[meta][key] && hash_item(gKeyCommand[meta][key], extension))
    {
        sStatments* command = hash_item(gKeyCommand[meta][key],  extension);
        saphire_set_signal();
        sRFd* pipein = sRFd_new(STDIN_FILENO);
        sWFd* pipeout = sWFd_new(STDOUT_FILENO);
        int rcode = saphire_run(command, title, pipeout, pipein, STDERR_FILENO);
        sRFd_delete(pipein);
        sWFd_flash(pipeout);
        sWFd_delete(pipeout);
        set_signal_mfiler();
        ISearchClear();
        if(rcode < 0) { merr_msg(string_c_str(gErrMsg)); }
    }

    /// ディレクトリを選択中 ///
    else if(S_ISDIR(cursor->mLStat.st_mode)
        && key >= 0 && key < KEY_MAX 
        && gKeyCommand[meta][key] && hash_item(gKeyCommand[meta][key], ".directory"))
    {
        sStatments* command = hash_item(gKeyCommand[meta][key],  ".directory");
        saphire_set_signal();
        sRFd* pipein = sRFd_new(STDIN_FILENO);
        sWFd* pipeout = sWFd_new(STDOUT_FILENO);
        int rcode = saphire_run(command, title, pipeout, pipein, STDERR_FILENO);
        sRFd_delete(pipein);
        sWFd_flash(pipeout);
        sWFd_delete(pipeout);
        set_signal_mfiler();
        ISearchClear();
        if(rcode < 0) { merr_msg(string_c_str(gErrMsg)); }
    }

    /// 実行ファイルを選択中 ///
    else if((cursor->mStat.st_mode&S_IXUSR
         || cursor->mStat.st_mode&S_IXGRP || cursor->mStat.st_mode&S_IXOTH)
        && key >= 0 && key < KEY_MAX 
        && gKeyCommand[meta][key] && hash_item(gKeyCommand[meta][key], ".execute"))
    {
        sStatments* command = hash_item(gKeyCommand[meta][key],  ".execute");
        saphire_set_signal();
        sRFd* pipein = sRFd_new(STDIN_FILENO);
        sWFd* pipeout = sWFd_new(STDOUT_FILENO);
        int rcode = saphire_run(command, title, pipeout, pipein, STDERR_FILENO);
        sRFd_delete(pipein);
        sWFd_flash(pipeout);
        sWFd_delete(pipeout);
        set_signal_mfiler();
        ISearchClear();
        if(rcode < 0) { merr_msg(string_c_str(gErrMsg)); }
    }
    /// その他のファイル ///
    else if(key >= 0 && key < KEY_MAX 
        && gKeyCommand[meta][key] && hash_item(gKeyCommand[meta][key], "*")) 
    {
        sStatments* command = hash_item(gKeyCommand[meta][key],  "*");
        saphire_set_signal();
        sRFd* pipein = sRFd_new(STDIN_FILENO);
        sWFd* pipeout = sWFd_new(STDOUT_FILENO);
        int rcode = saphire_run(command, title, pipeout, pipein, STDERR_FILENO);
        sRFd_delete(pipein);
        sWFd_flash(pipeout);
        sWFd_delete(pipeout);
        set_signal_mfiler();
        ISearchClear();
        if(rcode < 0) merr_msg(string_c_str(gErrMsg));
    }
}

int adir()
{
    sDir* dir0 = (sDir*)vector_item(gDirs, 0);
    sDir* dir1 = (sDir*)vector_item(gDirs, 1);

    if(dir0->mActive)
        return 0;
    else
        return 1;
}

int sdir()
{
    sDir* dir0 = (sDir*)vector_item(gDirs, 0);
    sDir* dir1 = (sDir*)vector_item(gDirs, 1);

    if(!dir0->mActive)
        return 0;
    else
        return 1;
}

sDir* filer_dir(int dir)
{
    if(dir < 0 || dir >= vector_size(gDirs)) {
        return NULL;
    }
    
    return (sDir*)vector_item(gDirs, dir);
}

sFile* filer_cursor_file(int dir)
{
    if(dir < 0 || dir >= vector_size(gDirs)) {
        return NULL;
    }
    
    sDir* dir2 = (sDir*)vector_item(gDirs, dir);

    return (sFile*)vector_item(dir2->mFiles, dir2->mCursor);
}

void filer_toggle_mark(int dir, int num)
{
    if(dir < 0 || dir >= vector_size(gDirs)) {
        return;
    }
    
    sDir* dir2 = (sDir*)vector_item(gDirs, dir);

    if(num < 0 || num >= vector_size(dir2->mFiles)) {
        return;
    }

    sFile* file = vector_item(dir2->mFiles, num);

    file->mMark = !file->mMark;
}

void filer_set_mark(int dir, int num, int mark)
{
    if(dir < 0 || dir >= vector_size(gDirs)) {
        return;
    }
    
    sDir* dir2 = (sDir*)vector_item(gDirs, dir);

    if(num < 0 || num >= vector_size(dir2->mFiles)) {
        return;
    }

    sFile* file = vector_item(dir2->mFiles, num);

    file->mMark = mark;
}

BOOL filer_mark(int dir, int num)
{
    if(dir < 0 || dir >= vector_size(gDirs)) {
        return FALSE;
    }
    
    sDir* dir2 = (sDir*)vector_item(gDirs, dir);

    if(num < 0 || num >= vector_size(dir2->mFiles)) {
        return FALSE;
    }

    sFile* file = vector_item(dir2->mFiles, num);

    return file->mMark;
}

int filer_mark_file_num(int dir)
{
    if(dir < 0 || dir >= vector_size(gDirs)) {
        return -1;
    }
    
    sDir* dir2 = (sDir*)vector_item(gDirs, dir);

    int result = 0;
    int i;
    for(i=0; i<vector_size(dir2->mFiles); i++) {
        sFile* file = (sFile*)vector_item(dir2->mFiles, i);

        if(file->mMark) {
            result++;
        }
    }

    return result;
}

double filer_mark_file_size(int dir)
{
    if(dir < 0 || dir >= vector_size(gDirs)) {
        return -1;
    }
    
    sDir* dir2 = (sDir*)vector_item(gDirs, dir);

    double size = 0;
    int i;
    for(i=0; i<vector_size(dir2->mFiles); i++) {
        sFile* file = (sFile*)vector_item(dir2->mFiles, i);

        if(file->mMark && !S_ISDIR(file->mStat.st_mode)) {
            size += file->mLStat.st_size;
        }
    }

    return size;
}

void filer_reset_marks(int dir)
{
    if(dir < 0 || dir >= vector_size(gDirs)) {
        return;
    }
    
    sDir* dir2 = (sDir*)vector_item(gDirs, dir);
    int i;
    for(i=0; i<vector_size(dir2->mFiles); i++) {
        sFile* file = (sFile*)vector_item(dir2->mFiles, i);
        file->mMark = FALSE;
    }
}

///////////////////////////////////////////////////
// ファイラ描写
///////////////////////////////////////////////////
#if defined(__CYGWIN__) 
int filer_make_size_str(char* result, __off64_t size)
{
    char* file_size = getenv("VIEW_FILE_SIZE");
    if(strcmp(file_size, "Human") == 0) {
        char tmp[256];
        __off64_t size2;
        if(size < 1024) {
            size2 = size;
            snprintf(tmp, 256, "%ld", size2);

            char* end = tmp + strlen(tmp);

            char* p = tmp;
            char* p2 = result;
            
            while(*p) {
                if(end - p == 7) {
                    *p2++ = *p++;
                    *p2++ = ',';
                }
                else if(end - p == 4) {
                    *p2++ = *p++;
                    *p2++ = ',';
                }
                else {
                    *p2++ = *p++;
                }
            }

            *p2 = 0;
        }
        else if(size < 1024*1024) {
            size2 = size / 1024;
            snprintf(tmp, 256, "%ld", size2);

            char* end = tmp + strlen(tmp);

            char* p = tmp;
            char* p2 = result;
            
            while(*p) {
                if(end - p == 9) {
                    *p2++ = *p++;
                    *p2++ = ',';
                }
                else if(end - p == 6) {
                    *p2++ = *p++;
                    *p2++ = ',';
                }
                else {
                    *p2++ = *p++;
                }
            }

            *p2++ = 'k';
            *p2 = 0;
        }
        else if(size < 1024*1024*1024) {
            size2 = size / (1024*1024);
            snprintf(tmp, 256, "%ld", size2);

            char* end = tmp + strlen(tmp);

            char* p = tmp;
            char* p2 = result;
            
            while(*p) {
                if(end - p == 9) {
                    *p2++ = *p++;
                    *p2++ = ',';
                }
                else if(end - p == 6) {
                    *p2++ = *p++;
                    *p2++ = ',';
                }
                else {
                    *p2++ = *p++;
                }
            }

            *p2++ = 'M';
            *p2 = 0;
        }
        else {
            size2 = size / (1024*1024*1024);
            snprintf(tmp, 256, "%ld", size2);

            char* end = tmp + strlen(tmp);

            char* p = tmp;
            char* p2 = result;
            
            while(*p) {
                if(end - p == 9) {
                    *p2++ = *p++;
                    *p2++ = ',';
                }
                else if(end - p == 6) {
                    *p2++ = *p++;
                    *p2++ = ',';
                }
                else {
                    *p2++ = *p++;
                }
            }

            *p2++ = 'G';
            *p2 = 0;
        }

        return 7;
    }
    else if(strcmp(file_size, "Normal") == 0) {
        if(size < 1024*1024) {
            char tmp[256];
            snprintf(tmp, 256, "%ld", size);
            char* end = tmp + strlen(tmp);

            char* p = tmp;
            char* p2 = result;
            
            while(*p) {
                if(end - p == 7) {
                    *p2++ = *p++;
                    *p2++ = ',';
                }
                else if(end - p == 4) {
                    *p2++ = *p++;
                    *p2++ = ',';
                }
                else {
                    *p2++ = *p++;
                }
            }
            *p2 = 0;
        }
        else {
            size = size / (1024*1024);

            char tmp[256];
            snprintf(tmp, 256, "%ld", size);
            char* end = tmp + strlen(tmp);

            char* p = tmp;
            char* p2 = result;
            
            while(*p) {
                if(end - p == 9) {
                    *p2++ = *p++;
                    *p2++ = ',';
                }
                else if(end - p == 6) {
                    *p2++ = *p++;
                    *p2++ = ',';
                }
                else {
                    *p2++ = *p++;
                }
            }
            *p2++ = 'M';
            *p2 = 0;
        }

        return 9;
    }
    else if(strcmp(file_size, "Plane") == 0) {
        char tmp[256];
        snprintf(tmp, 256, "%ld", size);
        char* end = tmp + strlen(tmp);

        char* p = tmp;
        char* p2 = result;
        
        while(*p) {
            if(end - p == 10) {
                *p2++ = *p++;
                *p2++ = ',';
            }
            else if(end - p == 7) {
                *p2++ = *p++;
                *p2++ = ',';
            }
            else if(end - p == 4) {
                *p2++ = *p++;
                *p2++ = ',';
            }
            else {
                *p2++ = *p++;
            }
        }
        *p2 = 0;

        return 14;
    }
    else {
        fprintf(stderr, "VIEW_FILE_SIZE is Normal or Human or Plane.\n");
        exit(1);
    }
}
#else
int filer_make_size_str(char* result, __off64_t size)
{
    char* file_size = getenv("VIEW_FILE_SIZE");
    if(strcmp(file_size, "Human") == 0) {
        char tmp[256];
        __off64_t size2;
        if(size < 1024) {
            size2 = size;
            snprintf(tmp, 256, "%lld", size2);

            char* end = tmp + strlen(tmp);

            char* p = tmp;
            char* p2 = result;
            
            while(*p) {
                if(end - p == 7) {
                    *p2++ = *p++;
                    *p2++ = ',';
                }
                else if(end - p == 4) {
                    *p2++ = *p++;
                    *p2++ = ',';
                }
                else {
                    *p2++ = *p++;
                }
            }

            *p2 = 0;
        }
        else if(size < 1024*1024) {
            size2 = size / 1024;
            snprintf(tmp, 256, "%lld", size2);

            char* end = tmp + strlen(tmp);

            char* p = tmp;
            char* p2 = result;
            
            while(*p) {
                if(end - p == 9) {
                    *p2++ = *p++;
                    *p2++ = ',';
                }
                else if(end - p == 6) {
                    *p2++ = *p++;
                    *p2++ = ',';
                }
                else {
                    *p2++ = *p++;
                }
            }

            *p2++ = 'k';
            *p2 = 0;
        }
        else if(size < 1024*1024*1024) {
            size2 = size / (1024*1024);
            snprintf(tmp, 256, "%lld", size2);

            char* end = tmp + strlen(tmp);

            char* p = tmp;
            char* p2 = result;
            
            while(*p) {
                if(end - p == 9) {
                    *p2++ = *p++;
                    *p2++ = ',';
                }
                else if(end - p == 6) {
                    *p2++ = *p++;
                    *p2++ = ',';
                }
                else {
                    *p2++ = *p++;
                }
            }

            *p2++ = 'M';
            *p2 = 0;
        }
        else {
            size2 = size / (1024*1024*1024);
            snprintf(tmp, 256, "%lld", size2);

            char* end = tmp + strlen(tmp);

            char* p = tmp;
            char* p2 = result;
            
            while(*p) {
                if(end - p == 9) {
                    *p2++ = *p++;
                    *p2++ = ',';
                }
                else if(end - p == 6) {
                    *p2++ = *p++;
                    *p2++ = ',';
                }
                else {
                    *p2++ = *p++;
                }
            }

            *p2++ = 'G';
            *p2 = 0;
        }

        return 7;
    }
    else if(strcmp(file_size, "Normal") == 0) {
        if(size < 1024*1024) {
            char tmp[256];
            snprintf(tmp, 256, "%lld", size);
            char* end = tmp + strlen(tmp);

            char* p = tmp;
            char* p2 = result;
            
            while(*p) {
                if(end - p == 7) {
                    *p2++ = *p++;
                    *p2++ = ',';
                }
                else if(end - p == 4) {
                    *p2++ = *p++;
                    *p2++ = ',';
                }
                else {
                    *p2++ = *p++;
                }
            }
            *p2 = 0;
        }
        else {
            size = size / (1024*1024);

            char tmp[256];
            snprintf(tmp, 256, "%lld", size);
            char* end = tmp + strlen(tmp);

            char* p = tmp;
            char* p2 = result;
            
            while(*p) {
                if(end - p == 9) {
                    *p2++ = *p++;
                    *p2++ = ',';
                }
                else if(end - p == 6) {
                    *p2++ = *p++;
                    *p2++ = ',';
                }
                else {
                    *p2++ = *p++;
                }
            }
            *p2++ = 'M';
            *p2 = 0;
        }

        return 9;
    }
    else if(strcmp(file_size, "Plane") == 0) {
        char tmp[256];
        snprintf(tmp, 256, "%lld", size);
        char* end = tmp + strlen(tmp);

        char* p = tmp;
        char* p2 = result;
        
        while(*p) {
            if(end - p == 10) {
                *p2++ = *p++;
                *p2++ = ',';
            }
            else if(end - p == 7) {
                *p2++ = *p++;
                *p2++ = ',';
            }
            else if(end - p == 4) {
                *p2++ = *p++;
                *p2++ = ',';
            }
            else {
                *p2++ = *p++;
            }
        }
        *p2 = 0;

        return 14;
    }
    else {
        fprintf(stderr, "VIEW_FILE_SIZE is Normal or Human or Plane.\n");
        exit(1);
    }
}
#endif

static void make_size_str2(char* result, __off64_t size)
{
    char tmp[256];
#if defined(__CYGWIN__)
    snprintf(tmp, 256, "%ld", size);
#else
    snprintf(tmp, 256, "%lld", size);
#endif
    char* end = tmp + strlen(tmp);

    char* p = tmp;
    char* p2 = result;
    
    while(*p) {
        if(end - p == 13) {
            *p2++ = *p++;
            *p2++ = ',';
        }
        else if(end - p == 10) {
            *p2++ = *p++;
            *p2++ = ',';
        }
        else if(end - p == 7) {
            *p2++ = *p++;
            *p2++ = ',';
        }
        else if(end - p == 4) {
            *p2++ = *p++;
            *p2++ = ',';
        }
        else {
            *p2++ = *p++;
        }
    }
    *p2 = 0;
}

/// buf は充分なスペースが必要 ///
void make_file_stat(sFile* file, char* buf, int buf_size)
{
    strncpy(buf, "", buf_size);

    char* env_permission = getenv("VIEW_PERMISSION");
    if(env_permission && strcmp(env_permission, "1") == 0) {
        char permission[12];
        strncpy(permission, "----------", 12);
        if(S_ISDIR(file->mLStat.st_mode)) permission[0] = 'd';
        if(S_ISCHR(file->mLStat.st_mode)) permission[0] = 'c';
        if(S_ISBLK(file->mLStat.st_mode)) permission[0] = 'b';
        if(S_ISFIFO(file->mLStat.st_mode)) permission[0] = 'p';
        if(S_ISLNK(file->mLStat.st_mode)) permission[0] = 'l';
        if(S_ISSOCK(file->mLStat.st_mode)) permission[0] = 's';
    
        mode_t smode = file->mLStat.st_mode;
        if(smode & S_IRUSR) permission[1] = 'r';
        if(smode & S_IWUSR) permission[2] = 'w';
        if(smode & S_IXUSR) permission[3] = 'x';
        if(smode & S_IRGRP) permission[4] = 'r';
        if(smode & S_IWGRP) permission[5] = 'w';
        if(smode & S_IXGRP) permission[6] = 'x';
        if(smode & S_IROTH) permission[7] = 'r';
        if(smode & S_IWOTH) permission[8] = 'w';
        if(smode & S_IXOTH) permission[9] = 'x';
        if(smode & S_ISUID) permission[3] = 's';
        if(smode & S_ISGID) permission[6] = 's';
#if defined(S_ISTXT)
        if(smode & S_ISTXT) permission[9] = 't';
#endif
#if defined(S_ISVTX)
        if(smode & S_ISVTX) permission[9] = 't';
#endif

        snprintf(buf + strlen(buf), buf_size - strlen(buf), " %s", permission);
    }

    char* env_nlink = getenv("VIEW_NLINK");
    if(env_nlink && strcmp(env_nlink, "1") == 0) {
        snprintf(buf + strlen(buf), buf_size -strlen(buf), " %3d", file->mStat.st_nlink);
    }

    char* env_owner = getenv("VIEW_OWNER");
    if(env_owner && strcmp(env_owner, "1") == 0) {
        char owner[256];
        char* tmp = string_c_str(file->mUser);
        if(tmp) {
            str_cut2(kUtf8, tmp, 8, owner, 256);
        }
        else {
            snprintf(owner, 256, "%d", file->mLStat.st_uid);
        }

        snprintf(buf + strlen(buf), buf_size - strlen(buf), " %-8s", owner);
    }

    char* env_group = getenv("VIEW_GROUP");
    if(env_group && strcmp(env_group, "1") == 0) {
        char group[256];
        char* tmp = string_c_str(file->mGroup);
        if(tmp) {
            str_cut2(kUtf8, tmp, 8, group, 256);
        }
        else {
            snprintf(group, 256, "%d", file->mLStat.st_gid);
        }

        snprintf(buf + strlen(buf), buf_size - strlen(buf), " %-8s", group);
    }

    char* env_size = getenv("VIEW_SIZE");
    if(env_size && strcmp(env_size, "1") == 0) {
        char size[256];
        int width = filer_make_size_str(size, file->mLStat.st_size);

        if(S_ISDIR(file->mStat.st_mode)) {
            strncpy(size, "<DIR>", 256);
        }

        char format[128];
        strncpy(format, "%", 128);
        snprintf(format + strlen(format), 126, "%d", width);
        xstrncat(format, "s", 128);

        snprintf(buf + strlen(buf), 256, format, size);
    }

    char* env_mtime = getenv("VIEW_MTIME");
    if(env_mtime && strcmp(env_mtime, "1") == 0) {
        time_t t = file->mLStat.st_mtime;
        struct tm* tm_ = (struct tm*)localtime(&t);

        int year = tm_->tm_year-100;
        if(year < 0) year+=100;
        while(year > 100) year-=100;

        snprintf(buf + strlen(buf), buf_size - strlen(buf), " %02d-%02d-%02d %02d:%02d"
               , year, tm_->tm_mon+1
               , tm_->tm_mday, tm_->tm_hour, tm_->tm_min);
    }

    snprintf(buf + strlen(buf), buf_size - strlen(buf), " ");
}

sFile* filer_file(int dir, int num)
{
    if(dir < 0 || dir >= vector_size(gDirs)) {
        return NULL;
    }
    
    sDir* dir2 = vector_item(gDirs, dir);

    if(num < 0 || num >= vector_size(dir2->mFiles)) {
        return NULL;
    }

    return vector_item(dir2->mFiles, num);
}

vector_obj* filer_mark_files(int dir) 
{
    if(dir < 0 || dir >= vector_size(gDirs)) {
        return NULL;
    }
    
    sDir* dir2 = vector_item(gDirs, dir);
    vector_obj* result = VECTOR_NEW(10);
    
    int i;
    for(i=0; i<vector_size(dir2->mFiles); i++) {
        sFile* file = vector_item(dir2->mFiles, i);

        if(file->mMark) {
            vector_add(result, file);
        }
    }

    return result;
}

int filer_file2(int dir, char* name)
{
    if(dir < 0 || dir >= vector_size(gDirs)) {
        return -1;
    }
    
    sDir* dir2 = vector_item(gDirs, dir);
    int i;
    for(i=0; i<vector_size(dir2->mFiles); i++) {
        sFile* file = vector_item(dir2->mFiles, i);
        if(strcmp(string_c_str(file->mName), name) == 0) {
            return i;
        }
    }

    return -1;
}

/// fnameは充分なスペースが必要
void make_file_name(sFile* file, char* fname, int fname_size, char* ext, int ext_size, char* dot, int name_len)
{
    char* env_divide_ext = getenv("VIEW_DIVIDE_EXTENSION");
    BOOL view_divide_ext = FALSE;
    if(env_divide_ext && strcmp(env_divide_ext, "1") == 0) {
        view_divide_ext = TRUE;
    }

    strncpy(fname, string_c_str(file->mNameView), fname_size);

    char* env_add_star_exe = getenv("VIEW_ADD_STAR_EXE");

    if(S_ISDIR(file->mStat.st_mode)) {
         xstrncat(fname, "/", fname_size);
    }
    else if(S_ISFIFO(file->mLStat.st_mode)) {
        xstrncat(fname, "|", fname_size);
    }
    else if(S_ISSOCK(file->mLStat.st_mode)) {
        xstrncat(fname, "=", fname_size);
    }
    else if(env_add_star_exe && strcmp(env_add_star_exe, "1") == 0
             &&(file->mStat.st_mode&S_IXUSR
                || file->mStat.st_mode&S_IXGRP
                || file->mStat.st_mode&S_IXGRP))
    {
         xstrncat(fname, "*", fname_size);
    }
    else if(S_ISLNK(file->mLStat.st_mode)) {
        xstrncat(fname, "@", fname_size);
    }

    if(S_ISLNK(file->mLStat.st_mode)) {
        snprintf(fname + strlen(fname), fname_size - strlen(fname), " -> %s", string_c_str(file->mLinkTo));
    }

    if(S_ISDIR(file->mStat.st_mode) || !view_divide_ext) {
        strncpy(ext, "", ext_size);
        *dot = ' ';
    }
    else {
        extname(ext, PATH_MAX, fname);

        *dot = ' ';

        if(strcmp(ext, "") != 0) {
            fname[strlen(fname) - strlen(ext) -1] = 0;
            *dot = '.';
        }
        char tmp[128];
        str_cut2(kUtf8, ext, 4, tmp, 128);
        strncpy(ext, tmp, ext_size);
    }

    if(name_len > 0) {
        char* env_focusback = getenv("VIEW_FOCUSBACK");
        if(env_focusback && strcmp(env_focusback, "1") == 0) {
            str_cut3(kUtf8, fname, name_len, fname, PATH_MAX);
        }
        else {
            str_cut2(kUtf8, fname, name_len, fname, PATH_MAX);
        }
    }
    else {
        strncpy(fname, "", fname_size);
    }
}

static const int kMaxYMinus = 4;

void filer_view(int dir)
{
    sDir* self = (sDir*)vector_item(gDirs, dir);

    char* env_divide_ext = getenv("VIEW_DIVIDE_EXTENSION");
    BOOL view_divide_ext = FALSE;
    if(env_divide_ext && strcmp(env_divide_ext, "1") == 0) {
        view_divide_ext = TRUE;
    }

    char* env_color_dir = getenv("COLOR_DIR");
    int color_dir = 0;
    if(env_color_dir) {
        color_dir = atoi(env_color_dir);
    }

    char* env_color_exe = getenv("COLOR_EXE");
    int color_exe = 0;
    if(env_color_exe) {
        color_exe = atoi(env_color_exe);
    }

    char* env_color_link = getenv("COLOR_LINK");
    int color_link = 0;
    if(env_color_link) {
        color_link = atoi(env_color_link);
    }

    char* env_color_mark = getenv("COLOR_MARK");
    int color_mark = 0;
    if(env_color_mark) {
        color_mark = atoi(env_color_mark);
    }

    const int maxx = mgetmaxx();
    const int maxy = mgetmaxy();

    const int jobs_exist = (saphire_job_num() > 0) ? 1 : 0;
    const int dstack_exist = vector_size(gDirs) > 2 ? 1 : 0;

    char* env_page_view_way = getenv("VIEW_PAGE");
    BOOL page_view_way = FALSE;
    if(env_page_view_way && strcmp(env_page_view_way, "1") == 0) {
        page_view_way = TRUE;
    }

    char* env_view_option = getenv("VIEW_OPTION");
    if(env_view_option == NULL) {
        fprintf(stderr, "VIEW_OPTION is NULL\n");
        exit(1);
    }

    ////////////////////////////////////////////////////////////
    // １画面１行
    ////////////////////////////////////////////////////////////
    if(strcmp(env_view_option, "1pain") == 0) {
        if(self->mActive) {
            mbox(dstack_exist, 0, maxx-1, maxy-2-dstack_exist-jobs_exist);

            char path[PATH_MAX];
            
            char* ftp_site = getenv("FTP_SITE");
            char* ssh_site = getenv("SSH_SITE");
            if(ftp_site && strcmp(ftp_site, "") != 0) {
                char* ftp_path = getenv("FTP_PATH");

                snprintf(path, PATH_MAX, "ftp://%s/%s", ftp_site, ftp_path);
            }
            else if(ssh_site && strcmp(ssh_site, "") != 0) {
                char* ssh_path = getenv("SSH_PATH");

                snprintf(path, PATH_MAX, "ssh://%s/%s", ssh_site, ssh_path);
            }
            else {
                strncpy(path, string_c_str(self->mPath), PATH_MAX);
            }

            xstrncat(path, string_c_str(self->mMask), PATH_MAX);

#if defined(__DARWIN__)
            char tmp[PATH_MAX];
            if(kanji_convert(path, tmp, PATH_MAX, gKanjiCodeFileName, gKanjiCode) != -1) {
                strncpy(path, tmp, PATH_MAX);
            }
#endif

            const int len = strlen(path);
            if(len < maxx-4) {
                mattron(kCABold);
                mmvprintw(0 + dstack_exist, 2, "%s", path);
                mattroff();
            }
            else {
                char buf[PATH_MAX];

                str_cut3(kUtf8, path, maxx-4, buf, PATH_MAX);

                mattron(kCABold);
                mmvprintw(0 + dstack_exist, 2, "%s", buf);
                mattroff();
            }

            int i;
            for(i=self->mScrollTop; 
                i-self->mScrollTop 
                    < maxy-kMaxYMinus
                        -dstack_exist-jobs_exist&&i<vector_size(self->mFiles);
                i++)
            {
                int attr = 0;
                sFile* file = (sFile*)vector_item(self->mFiles, i);

                int red = -1;
                int green = -1;
                int blue = -1;
                if(self->mCursor == i && self->mActive) {
                     attr |= kCAReverse;
                }
        
                if(S_ISDIR(file->mStat.st_mode)) {
                     if(!file->mMark) attr |= color_dir;
                }
                else if(file->mStat.st_mode&S_IXUSR
                            || file->mStat.st_mode&S_IXGRP
                            || file->mStat.st_mode&S_IXGRP)
                {
                     if(!file->mMark) attr |= color_exe;
                }
                else if(S_ISLNK(file->mLStat.st_mode)) {
                    if(!file->mMark) attr |= color_link;
                }

                char buf[1024];
                make_file_stat(file, buf, 1024);

                int name_len;
                if(S_ISDIR(file->mStat.st_mode) || !view_divide_ext) {
                    name_len = maxx-2-2-strlen(buf);
                }
                else {
                    name_len = maxx-2-5-2-strlen(buf);
                }

                char fname[1024];
                char ext[PATH_MAX];
                char dot;
                make_file_name(file, fname, 1024, ext, PATH_MAX, &dot, name_len);

                if(file->mMark) {
                    attr |= color_mark;
                }
                
                mattron(attr);
/*
                if(red != -1) {
                    mattron_256color(red, green, blue);
                }
*/
                if(file->mMark) {
                    mmvprintw(i-self->mScrollTop + 1 + dstack_exist, 1, "*");
                }
                else {
                    mmvprintw(i-self->mScrollTop + 1 + dstack_exist, 1, " ");
                }

                if(S_ISDIR(file->mStat.st_mode) || !view_divide_ext) {
                    mmvprintw(i-self->mScrollTop + 1 + dstack_exist, 2, "%s%s", fname,buf);
                }
                else {
                    mmvprintw(i-self->mScrollTop + 1 + dstack_exist, 2, "%s%c%-4s%s", fname, dot, ext,buf);
                }
                
                mattroff();
            }

            char size[256];
            make_size_str2(size, filer_mark_file_size(dir));
            if(page_view_way) {
                const int p = (((float)self->mCursor+1)
                                    /((float)vector_size(self->mFiles)))*100;
                mmvprintw(maxy - kMaxYMinus+1-jobs_exist, 2
                        , "(%d/%d)-%sbytes-(%3d%%)", filer_mark_file_num(dir)
                        , vector_size(self->mFiles)-1, size, p);
            }
            else {
                const int cur_page = self->mCursor/filer_line_max(adir()) + 1;
                const int max_page = vector_size(self->mFiles)/filer_line_max(adir()) + 1;

                mmvprintw(maxy - kMaxYMinus+1-jobs_exist, 2
                        , "(%d/%d)-%sbytes-(%d/%d)", filer_mark_file_num(dir)
                        , vector_size(self->mFiles)-1, size, cur_page, max_page);
            }
       }
    }
    //////////////////////////////////////////////////////////// 
    // １画面２行
    //////////////////////////////////////////////////////////// 
    else if(strcmp(env_view_option, "1pain2") == 0) {
        if(self->mActive) {
            mbox(dstack_exist, 0, maxx-1, maxy-2-dstack_exist-jobs_exist);

            char path[PATH_MAX];

            char* ftp_site = getenv("FTP_SITE");
            char* ssh_site = getenv("SSH_SITE");
            if(ftp_site && strcmp(ftp_site, "") != 0) {
                char* ftp_path = getenv("FTP_PATH");

                snprintf(path, PATH_MAX, "ftp://%s/%s", ftp_site, ftp_path);
            }
            else if(ssh_site && strcmp(ssh_site, "") != 0) {
                char* ssh_path = getenv("SSH_PATH");

                snprintf(path, PATH_MAX, "ssh://%s/%s", ssh_site, ssh_path);
            }
            else {
                strncpy(path, string_c_str(self->mPath), PATH_MAX);
            }
            xstrncat(path, string_c_str(self->mMask), PATH_MAX);

#if defined(__DARWIN__)
            char tmp[PATH_MAX];
            if(kanji_convert(path, tmp, PATH_MAX, gKanjiCodeFileName, gKanjiCode) != -1) {
                strncpy(path, tmp, PATH_MAX);
            }
#endif

            const int len = strlen(path);
            if(len < maxx-4) {
                mattron(kCABold);
                mmvprintw(0 + dstack_exist, 2, "%s", path);
                mattroff();
            }
            else {
                char buf[PATH_MAX];

                str_cut3(kUtf8, path, maxx-4, buf, PATH_MAX);

                mattron(kCABold);
                mmvprintw(0 + dstack_exist, 2, "%s", buf);
                mattroff();
            }
            int i;
            for(i=self->mScrollTop;
                i-self->mScrollTop<(maxy-kMaxYMinus-dstack_exist-jobs_exist)*2
                            && i<vector_size(self->mFiles);
                i++)
            {
                int attr = 0;
                sFile* file = (sFile*)vector_item(self->mFiles, i);


                int red = -1;
                int green = -1;
                int blue = -1;

                if(self->mCursor == i && self->mActive) {
                     attr |= kCAReverse;
                }
        
                if(S_ISDIR(file->mStat.st_mode)) {
                     if(!file->mMark) attr |= color_dir;
                }
                else if(file->mStat.st_mode&S_IXUSR
                            || file->mStat.st_mode&S_IXGRP
                            || file->mStat.st_mode&S_IXGRP)
                {
                     if(!file->mMark) attr |= color_exe;
                }
                else if(S_ISLNK(file->mLStat.st_mode)) {
                    if(!file->mMark) attr |= color_link;
                }

                char buf[1024];
                make_file_stat(file, buf, 1024);

                int name_len;
                if(S_ISDIR(file->mStat.st_mode) || !view_divide_ext) {
                    name_len = maxx/2-2-2-strlen(buf);
                }
                else {
                    name_len = maxx/2-2-5-2-strlen(buf);
                }

                char fname[1024];
                char ext[PATH_MAX];
                char dot;
                make_file_name(file, fname, 1024, ext, PATH_MAX, &dot, name_len);

                const int x = (i-self->mScrollTop)
                                /(maxy-kMaxYMinus-dstack_exist-jobs_exist)
                                *(maxx/2) + 1;
                const int y = (i-self->mScrollTop)
                                %(maxy-kMaxYMinus-dstack_exist-jobs_exist)
                                    + 1 + dstack_exist;

                if(file->mMark) {
                    attr |= color_mark;
                }
                
                mattron(attr);
/*
                if(red != -1) {
                    mattron_256color(red, green, blue);
                }
*/
                if(file->mMark) {
                    mmvprintw(y, x, "*");
                }
                else {
                    mmvprintw(y, x, " ");
                }

                if(S_ISDIR(file->mStat.st_mode) || !view_divide_ext) {
                    mmvprintw(y, x+1, "%s%s", fname,buf);
                }
                else {
                    mmvprintw(y, x+1, "%s%c%-4s%s", fname, dot, ext,buf);
                }
                
                mattroff();
            }

            char size[256];
            make_size_str2(size, filer_mark_file_size(dir));

            if(page_view_way) {
                const int p = (((float)self->mCursor+1)/((float)vector_size(self->mFiles)))*100;
                
                mmvprintw(maxy - kMaxYMinus+1-jobs_exist, 2
                        , "(%d/%d)-%sbytes-(%3d%%)"
                        , filer_mark_file_num(dir), vector_size(self->mFiles)-1, size, p);
            }
            else {
                const int cur_page = self->mCursor/(filer_line_max(adir())*2) + 1;
                const int max_page = vector_size(self->mFiles)/(filer_line_max(adir())*2) + 1;

                mmvprintw(maxy - kMaxYMinus+1-jobs_exist, 2
                      , "(%d/%d)-%sbytes-(%d/%d)", filer_mark_file_num(dir)
                      , vector_size(self->mFiles)-1, size, cur_page, max_page);
            }
        }
    }
    //////////////////////////////////////////////
    // １画面３行
    //////////////////////////////////////////////
    else if(strcmp(env_view_option, "1pain3") == 0) {
        if(self->mActive) {
            mbox(dstack_exist, 0, maxx-1, maxy-2-dstack_exist-jobs_exist);

            char path[PATH_MAX];

            char* ftp_site = getenv("FTP_SITE");
            char* ssh_site = getenv("SSH_SITE");
            if(ftp_site && strcmp(ftp_site, "") != 0) {
                char* ftp_path = getenv("FTP_PATH");

                snprintf(path, PATH_MAX, "ftp://%s/%s", ftp_site, ftp_path);
            }
            else if(ssh_site && strcmp(ssh_site, "") != 0) {
                char* ssh_path = getenv("SSH_PATH");

                snprintf(path, PATH_MAX, "ssh://%s/%s", ssh_site, ssh_path);
            }
            else {
                strncpy(path, string_c_str(self->mPath), PATH_MAX);
            }
            xstrncat(path, string_c_str(self->mMask), PATH_MAX);

#if defined(__DARWIN__)
            char tmp[PATH_MAX];
            if(kanji_convert(path, tmp, PATH_MAX, gKanjiCodeFileName, gKanjiCode) != -1) {
                strncpy(path, tmp, PATH_MAX);
            }
#endif

            const int len = strlen(path);
            if(len < maxx-4) {
                mattron(kCABold);
                mmvprintw(0 + dstack_exist, 2, "%s", path);
                mattroff();
            }
            else {
                char buf[PATH_MAX];

                str_cut3(kUtf8, path, maxx-4, buf, PATH_MAX);

                mattron(kCABold);
                mmvprintw(0 + dstack_exist, 2, "%s", buf);
                mattroff();
            }

            int i;
            for(i=self->mScrollTop;
                i-self->mScrollTop<(maxy-kMaxYMinus-dstack_exist-jobs_exist)*3
                            && i<vector_size(self->mFiles);
                i++)
            {
                int attr = 0;
                sFile* file = (sFile*)vector_item(self->mFiles, i);

                int red = -1;
                int green = -1;
                int blue = -1;

                if(self->mCursor == i && self->mActive) {
                     attr |= kCAReverse;
                }
        
                if(S_ISDIR(file->mStat.st_mode)) {
                     if(!file->mMark) attr |= color_dir;
                }
                else if(file->mStat.st_mode&S_IXUSR
                            || file->mStat.st_mode&S_IXGRP
                            || file->mStat.st_mode&S_IXGRP)
                {
                     if(!file->mMark) attr |= color_exe;
                }
                else if(S_ISLNK(file->mLStat.st_mode)) {
                    if(!file->mMark) attr |= color_link;
                }

                char buf[1024];
                make_file_stat(file, buf, 1024);

                int name_len;
                if(S_ISDIR(file->mStat.st_mode) || !view_divide_ext) {
                    name_len = maxx/3-2-2-strlen(buf);
                }
                else {
                    name_len = maxx/3-2-5-2-strlen(buf);
                }

                char fname[1024];
                char ext[PATH_MAX];
                char dot;
                make_file_name(file, fname, 1024, ext, PATH_MAX, &dot, name_len);

                const int x = (i-self->mScrollTop)
                                /(maxy-kMaxYMinus-dstack_exist-jobs_exist)
                                *(maxx/3) + 1;
                const int y = (i-self->mScrollTop)
                                %(maxy-kMaxYMinus-dstack_exist-jobs_exist)
                                    + 1 + dstack_exist;

                if(file->mMark) {
                    attr != kCABold;
                }
                
                mattron(attr);
/*
                if(red != -1) {
                    mattron_256color(red, green, blue);
                }
*/
                if(file->mMark) {
                    mmvprintw(y, x, "*");
                }
                else {
                    mmvprintw(y, x, " ");
                }

                if(S_ISDIR(file->mStat.st_mode) || !view_divide_ext) {
                    mmvprintw(y, x+1, "%s%s", fname,buf);
                }
                else {
                    mmvprintw(y, x+1, "%s%c%-4s%s", fname, dot, ext,buf);
                }
                
                mattroff();
            }
            
            char size[256];
            make_size_str2(size, filer_mark_file_size(dir));

            if(page_view_way) {
                const int p = (((float)self->mCursor+1)/((float)vector_size(self->mFiles)))*100;
                
                mmvprintw(maxy - kMaxYMinus+1-jobs_exist, 2
                        , "(%d/%d)-%sbytes-(%3d%%)", filer_mark_file_num(dir), vector_size(self->mFiles)-1, size, p);
            }
            else {
                const int cur_page = self->mCursor/(filer_line_max(adir())*3) + 1;
                const int max_page = vector_size(self->mFiles)/(filer_line_max(adir())*3) + 1;

                mmvprintw(maxy - kMaxYMinus+1-jobs_exist, 2
                        , "(%d/%d)-%sbytes-(%d/%d)", filer_mark_file_num(dir)
                        , vector_size(self->mFiles)-1, size, cur_page, max_page);
            }
        }
    }
    
    //////////////////////////////////////////////
    // １画面５行
    //////////////////////////////////////////////
    else if(strcmp(env_view_option, "1pain5") == 0) {
        if(self->mActive) {
            mbox(dstack_exist, 0, maxx-1, maxy-2-dstack_exist-jobs_exist);

            char path[PATH_MAX];

            char* ftp_site = getenv("FTP_SITE");
            char* ssh_site = getenv("SSH_SITE");
            if(ftp_site && strcmp(ftp_site, "") != 0) {
                char* ftp_path = getenv("FTP_PATH");

                snprintf(path, PATH_MAX, "ftp://%s/%s", ftp_site, ftp_path);
            }
            else if(ssh_site && strcmp(ssh_site, "") != 0) {
                char* ssh_path = getenv("SSH_PATH");

                snprintf(path, PATH_MAX, "ssh://%s/%s", ssh_site, ssh_path);
            }
            else {
                strncpy(path, string_c_str(self->mPath), PATH_MAX);
            }
            xstrncat(path, string_c_str(self->mMask), PATH_MAX);

#if defined(__DARWIN__)
            char tmp[PATH_MAX];
            if(kanji_convert(path, tmp, PATH_MAX, gKanjiCodeFileName, gKanjiCode) != -1) {
                strncpy(path, tmp, PATH_MAX);
            }
#endif

            const int len = strlen(path);
            if(len < maxx-4) {
                mattron(kCABold);
                mmvprintw(0 + dstack_exist, 2, "%s", path);
                mattroff();
            }
            else {
                char buf[PATH_MAX];

                str_cut3(kUtf8, path, maxx-4, buf, PATH_MAX);

                mattron(kCABold);
                mmvprintw(0 + dstack_exist, 2, "%s", buf);
                mattroff();
            }

            int i;
            for(i=self->mScrollTop;
                i-self->mScrollTop<(maxy-kMaxYMinus-dstack_exist-jobs_exist)*5
                            && i<vector_size(self->mFiles);
                i++)
            {
                int attr = 0;
                sFile* file = (sFile*)vector_item(self->mFiles, i);

                int red = -1;
                int green = -1;
                int blue = -1;

                if(self->mCursor == i && self->mActive) {
                     attr |= kCAReverse;
                }
        
                if(S_ISDIR(file->mStat.st_mode)) {
                     if(!file->mMark) attr |= color_dir;
                }
                else if(file->mStat.st_mode&S_IXUSR
                            || file->mStat.st_mode&S_IXGRP
                            || file->mStat.st_mode&S_IXGRP)
                {
                     if(!file->mMark) attr |= color_exe;
                }
                else if(S_ISLNK(file->mLStat.st_mode)) {
                    if(!file->mMark) attr |= color_link;
                }

                char buf[1024];
                make_file_stat(file, buf, 1024);

                int name_len;
                if(S_ISDIR(file->mStat.st_mode) || !view_divide_ext) {
                    name_len = maxx/5-2-2-strlen(buf);
                }
                else {
                    name_len = maxx/5-2-5-2-strlen(buf);
                }
                char fname[1024];
                char ext[PATH_MAX];
                char dot;
                make_file_name(file, fname, 1024, ext, PATH_MAX, &dot, name_len);

                if(file->mMark) {
                    attr != kCABold;
                }

                mattron(attr);
/*
                if(red != -1) {
                    mattron_256color(red, green, blue);
                }
*/
                const int x = (i-self->mScrollTop)
                                /(maxy-kMaxYMinus-dstack_exist-jobs_exist)
                                *(maxx/5) + 1;
                const int y = (i-self->mScrollTop)
                                %(maxy-kMaxYMinus-dstack_exist-jobs_exist)
                                    + 1 + dstack_exist;
                if(file->mMark) {
                    mmvprintw(y, x, "*");
                }
                else {
                    mmvprintw(y, x, " ");
                }
                if(S_ISDIR(file->mStat.st_mode) || !view_divide_ext) {
                    mmvprintw(y, x+1, "%s%s", fname, buf);
                }
                else {
                    mmvprintw(y, x+1, "%s%c%-4s%s", fname, dot, ext, buf);
                }
                
                mattroff();
            }

            char size[256];
            make_size_str2(size, filer_mark_file_size(dir));

            if(page_view_way) {
                const int p = (((float)self->mCursor+1)/((float)vector_size(self->mFiles)))*100;
                
                mmvprintw(maxy - kMaxYMinus+1-jobs_exist, 2
                        , "(%d/%d)-%sbytes-(%3d%%)", filer_mark_file_num(dir), vector_size(self->mFiles)-1, size, p);
            }
            else {
                const int cur_page = self->mCursor/(filer_line_max(adir())*5) + 1;
                const int max_page = vector_size(self->mFiles)/(filer_line_max(adir())*5) + 1;

                mmvprintw(maxy - kMaxYMinus+1-jobs_exist, 2
                        , "(%d/%d)-%sbytes-(%d/%d)", filer_mark_file_num(dir)
                        , vector_size(self->mFiles)-1, size, cur_page, max_page);
            }
        }
    }

    //////////////////////////////////////////////
    // ２画面
    //////////////////////////////////////////////
    else {
        int x;
        if(dir == 0)
            x = 0;
        else
            x = maxx / 2; 

        int line = 0;
        mbox(dstack_exist, x, maxx/2-1, maxy-2-dstack_exist-jobs_exist);

        char path[PATH_MAX];

        char* ftp_site = getenv("FTP_SITE");
        char* ssh_site = getenv("SSH_SITE");
        if(ftp_site && strcmp(ftp_site, "") != 0) {
            char* ftp_path = getenv("FTP_PATH");

            snprintf(path, PATH_MAX, "ftp://%s/%s", ftp_site, ftp_path);
        }
        else if(ssh_site && strcmp(ssh_site, "") != 0) {
            char* ssh_path = getenv("SSH_PATH");

            snprintf(path, PATH_MAX, "ssh://%s/%s", ssh_site, ssh_path);
        }
        else {
            strncpy(path, string_c_str(self->mPath), PATH_MAX);
        }
        xstrncat(path, string_c_str(self->mMask), PATH_MAX);

#if defined(__DARWIN__)
        char tmp[PATH_MAX];
        if(kanji_convert(path, tmp, PATH_MAX, gKanjiCodeFileName, gKanjiCode) != -1) {
            strncpy(path, tmp, PATH_MAX);
        }
#endif

        const int len = strlen(path);
        if(len < maxx/2-5) {
            if(self->mActive) mattron(kCABold);
            mmvprintw(0 + dstack_exist, x+2, "%s", path);
            if(self->mActive) mattroff();
        }
        else {
            char buf[PATH_MAX];

            str_cut3(kUtf8, path, maxx/2-5, buf, PATH_MAX);

            if(self->mActive) mattron(kCABold);
            mmvprintw(0 + dstack_exist, x+2, "%s", buf);
            if(self->mActive) mattroff();
        }

        int i;
        for(i=self->mScrollTop;
                i-self->mScrollTop<maxy-kMaxYMinus-dstack_exist-jobs_exist
                        && i<vector_size(self->mFiles);
                i++)
            {
                int attr = 0;
                sFile* file = (sFile*)vector_item(self->mFiles, i);
                
                int red = -1;
                int green = -1;
                int blue = -1;

                if(self->mCursor == i && self->mActive) {
                     attr |= kCAReverse;
                }
        
                if(S_ISDIR(file->mStat.st_mode)) {
                     if(!file->mMark) attr |= color_dir;
                }
                else if(file->mStat.st_mode&S_IXUSR
                            || file->mStat.st_mode&S_IXGRP
                            || file->mStat.st_mode&S_IXGRP)
                {
                     if(!file->mMark) attr |= color_exe;
                }
                else if(S_ISLNK(file->mLStat.st_mode)) {
                    if(!file->mMark) attr |= color_link;
                }

                char buf[1024];
                make_file_stat(file, buf, 1024);

                int name_len;
                if(S_ISDIR(file->mStat.st_mode) || !view_divide_ext) {
                    name_len = maxx/2-2-2-strlen(buf);
                }
                else {
                    name_len = maxx/2-2-5-2-strlen(buf);
                }

                char fname[1024];
                char ext[PATH_MAX];
                char dot;
                make_file_name(file, fname, 1024, ext, PATH_MAX, &dot, name_len);

                if(file->mMark) {
                    attr |= color_mark;
                }
                
                mattron(attr);
/*
                if(red != -1) {
                    mattron_256color(red, green, blue);
                }
*/
                if(file->mMark) {
                    mmvprintw(i-self->mScrollTop + 1 + dstack_exist, x+1, "*");
                }
                else {
                    mmvprintw(i-self->mScrollTop + 1 + dstack_exist, x+1, " ");
                }

                if(S_ISDIR(file->mStat.st_mode) || !view_divide_ext) {
                    mmvprintw(i-self->mScrollTop + 1 + dstack_exist, x+2, "%s%s", fname,buf);
                }
                else {
                    mmvprintw(i-self->mScrollTop + 1 + dstack_exist, x+2, "%s%c%-4s%s", fname, dot, ext,buf);
                }
                
                mattroff();
        }

        char size[256];
        make_size_str2(size, filer_mark_file_size(dir));
        
        mmvprintw(maxy - kMaxYMinus+1-jobs_exist, x + 2
                    , "(%d/%d)-%sbytes", filer_mark_file_num(dir), vector_size(self->mFiles)-1, size);
        
        if(self->mActive) {
            if(page_view_way) {
                const int p = (((float)self->mCursor+1)/((float)vector_size(self->mFiles)))*100;
                mprintw("-(%3d%%)", p);
            }
            else {
                const int cur_page = self->mCursor/filer_line_max(adir()) + 1;
                const int max_page = vector_size(self->mFiles)/(filer_line_max(adir())) + 1;

                mprintw("-(%d/%d)", cur_page, max_page);
            }
        }
    }

    /// draw gDirStack ///
    if(dstack_exist) {
        const int width = maxx / (vector_size(gDirs)-2);
        int i;
        for(i=2; i<vector_size(gDirs); i++) {
            sDir* dir = vector_item(gDirs, i);
            char* item = string_c_str(dir->mPath);
            
            char item2[256];
            strncpy(item2, "", 256);
            const int len2 = strlen(item);
            int k;
            for(k=len2-2; k>=0; k--) {
                if(item[k] == '/') {
                    int l;
                    for(l=k+1; l<len2-1; l++) {
                        item2[l-k-1] = item[l];
                    }
                    item2[l-k-1] = 0;
                    break;
                }
            }

            xstrncat(item2, "/", 256);
            
            char buf2[256];
            
            str_cut2(kUtf8, item2, width-6, buf2, 256);
            
            char buf[256];
            snprintf(buf, 256, "[%d.%s]", i, buf2);

            mmvprintw(0, width * (i-2), "%s", buf);
        }
    }
}

int filer_line(int dir)
{
    const int maxx = mgetmaxx();
    const int maxy = mgetmaxy();

    const int dstack_exist = vector_size(gDirs) > 2 ? 1 : 0;
    const int jobs_exist = saphire_job_num() > 0 ? 1 : 0;

    sDir* dir2 = vector_item(gDirs, dir);

    char* env_view_option = getenv("VIEW_OPTION");
    if(env_view_option == NULL) {
        fprintf(stderr, "VIEW_OPTION is NULL\n");
        exit(1);
    }

    if(dir2) {
        if(strcmp(env_view_option, "2pain") == 0)
        {
            return dir2->mCursor - dir2->mScrollTop;
        }
        else {
             return (dir2->mCursor - dir2->mScrollTop)
                         % (maxy-kMaxYMinus-dstack_exist-jobs_exist);
        }
    }

    return -1;
}

int filer_line_max(int dir)
{
    const int jobs_exist = saphire_job_num() > 0 ? 1 : 0;
    const int dstack_exist = vector_size(gDirs) > 2 ? 1 : 0;
       
    return mgetmaxy() - kMaxYMinus - jobs_exist - dstack_exist;
}

int filer_row(int dir)
{
    const int maxx = mgetmaxx();
    const int maxy = mgetmaxy();

    const int dstack_exist = vector_size(gDirs) > 2 ? 1 : 0;
    const int jobs_exist = saphire_job_num() > 0 ? 1 : 0;

    sDir* dir2 = vector_item(gDirs, dir);

    char* env_view_option = getenv("VIEW_OPTION");
    if(env_view_option == NULL) {
        fprintf(stderr, "VIEW_OPTION is NULL\n");
        exit(1);
    }

    if(dir2) {
        if(strcmp(env_view_option, "2pain") == 0)
        {
            return 0;
        }
        else {
            return dir2->mCursor/(maxy-kMaxYMinus-dstack_exist-jobs_exist);
        }
    }

    return -1;
}

int filer_row_max(int dir)
{
    const int maxx = mgetmaxx();
    const int maxy = mgetmaxy();

    const int jobs_exist = saphire_job_num() > 0 ? 1 : 0;
    const int dstack_exist = vector_size(gDirs) > 2 ? 1 : 0;

    sDir* dir2 = vector_item(gDirs, dir);

    char* env_view_option = getenv("VIEW_OPTION");
    if(env_view_option == NULL) {
        fprintf(stderr, "VIEW_OPTION is NULL\n");
        exit(1);
    }
    if(dir2) {
        if(strcmp(env_view_option, "2pain") == 0) {
            return 1;
        }
        else {
            return (vector_size(dir2->mFiles)-1)
                    /(maxy-kMaxYMinus-dstack_exist-jobs_exist) + 1;
        }
    }

    return -1;
}

///////////////////////////////////////////////////
// ソート
///////////////////////////////////////////////////
BOOL sort_name(void* left, void* right)
{
    sFile* l = (sFile*) left;
    sFile* r = (sFile*) right;

    char* lfname = string_c_str(l->mName);
    char* rfname = string_c_str(r->mName);

    if(strcmp(lfname, ".") == 0) return TRUE;
    if(strcmp(lfname, "..") == 0) {
        if(strcmp(rfname, ".") == 0) return FALSE;

        return TRUE;          
    }
    if(strcmp(rfname, ".") == 0) return FALSE;
    if(strcmp(rfname, "..") == 0) return FALSE;
    
    char* mark_up = getenv("SORT_MARK_UP");
    if(mark_up && strcmp(mark_up,"1") == 0) {
        if(l->mMark && !r->mMark) {
            return TRUE;
        }
        if(!l->mMark && r->mMark) {
            return FALSE;
        }
    }

    char* dir_up = getenv("SORT_DIR_UP");
    if(dir_up && strcmp(dir_up, "1") == 0) {
        if(!S_ISDIR(l->mStat.st_mode) && !S_ISDIR(r->mStat.st_mode)
            || S_ISDIR(l->mStat.st_mode) && S_ISDIR(r->mStat.st_mode) )
        {
            return strcasecmp(lfname, rfname) < 0;
        }

    
        if(S_ISDIR(l->mStat.st_mode))
            return TRUE;
        else
            return FALSE;
    }
    else {
        return strcasecmp(lfname, rfname) < 0;
    }
}

BOOL sort_name_reverse(void* left, void* right)
{
    sFile* l = (sFile*) left;
    sFile* r = (sFile*) right;

    char* lfname = string_c_str(l->mName);
    char* rfname = string_c_str(r->mName);

    if(strcmp(lfname, ".") == 0) return TRUE;
    if(strcmp(lfname, "..") == 0) {
        if(strcmp(rfname, ".") == 0) return FALSE;

        return TRUE;          
    }
    if(strcmp(rfname, ".") == 0) return FALSE;
    if(strcmp(rfname, "..") == 0) return FALSE;

    char* mark_up = getenv("SORT_MARK_UP");
    if(mark_up && strcmp(mark_up, "1") == 0) {
        if(!l->mMark && r->mMark) {
            return TRUE;
        }
        if(l->mMark && !r->mMark) {
            return FALSE;
        }
    }
    char* dir_up = getenv("SORT_DIR_UP");
    if(dir_up && strcmp(dir_up, "1") == 0) {
        if(!S_ISDIR(l->mStat.st_mode) && !S_ISDIR(r->mStat.st_mode)
            || S_ISDIR(l->mStat.st_mode) && S_ISDIR(r->mStat.st_mode) )
            {
            return strcasecmp(lfname, rfname) > 0;
            }

    
        if(S_ISDIR(r->mStat.st_mode)) return FALSE;
        return TRUE;
    }
    else {
        return strcasecmp(lfname, rfname) > 0;
    }
}
    
BOOL sort_ext(void* left, void* right)
{
     sFile* l = (sFile*) left;
     sFile* r = (sFile*) right;

     char* lfname = string_c_str(l->mName);
     char* rfname = string_c_str(r->mName);

     if(strcmp(lfname, ".") == 0) return TRUE;
     if(strcmp(lfname, "..") == 0) {
          if(strcmp(rfname, ".") == 0) return FALSE;

          return TRUE;          
     }
     if(strcmp(rfname, ".") == 0) return FALSE;
     if(strcmp(rfname, "..") == 0) return FALSE;

    char* mark_up = getenv("SORT_MARK_UP");
    if(mark_up && strcmp(mark_up, "1") == 0) {
        if(l->mMark && !r->mMark) {
            return TRUE;
        }
        if(!l->mMark && r->mMark) {
            return FALSE;
        }
    }
     char lext[PATH_MAX];
     extname(lext, PATH_MAX, lfname);
     char rext[PATH_MAX];
     extname(rext, PATH_MAX, rfname);
    
    BOOL result;
    char* dir_up = getenv("SORT_DIR_UP");
    if(dir_up && strcmp(dir_up, "1") == 0) {
         if(S_ISDIR(l->mStat.st_mode)) {
              if(S_ISDIR(r->mStat.st_mode))
                    result = strcasecmp(lfname, rfname) < 0;
              else
                    result = TRUE;
         }
         else if(S_ISDIR(r->mStat.st_mode)) {
              result = FALSE;
         }
         else {
              const int cmp = strcasecmp(lext, rext);
              if(cmp == 0) {
                  result = strcasecmp(lfname, rfname) < 0;
              }
              else {
                  result = cmp < 0;
              }
         }
     }
     else {
         const int cmp = strcasecmp(lext, rext);
         if(cmp == 0) {
             result = strcasecmp(lfname, rfname) < 0;
         }
         else {
             result = cmp < 0;
         }
     }
    
     return result;
}
    
BOOL sort_ext_reverse(void* left, void* right)
{
     sFile* l = (sFile*) left;
     sFile* r = (sFile*) right;

     char* lfname = string_c_str(l->mName);
     char* rfname = string_c_str(r->mName);

     if(strcmp(lfname, ".") == 0) return TRUE;
     if(strcmp(lfname, "..") == 0) {
          if(strcmp(rfname, ".") == 0) return FALSE;

          return TRUE;          
     }
     if(strcmp(rfname, ".") == 0) return FALSE;
     if(strcmp(rfname, "..") == 0) return FALSE;

    char* mark_up = getenv("SORT_MARK_UP");
    if(mark_up && strcmp(mark_up, "1") == 0) {
        if(!l->mMark && r->mMark) {
            return TRUE;
        }
        if(l->mMark && !r->mMark) {
            return FALSE;
        }
    }
     char lext[PATH_MAX];
     extname(lext, PATH_MAX, lfname);
     char rext[PATH_MAX];
     extname(rext, PATH_MAX, rfname);
    
     BOOL result;
    char* dir_up = getenv("SORT_DIR_UP");
    if(dir_up && strcmp(dir_up, "1") == 0) {
         if(S_ISDIR(r->mStat.st_mode)) {
            if(S_ISDIR(l->mStat.st_mode))
                result= strcasecmp(lfname, rfname) >0;
            else
                result = FALSE;
         }
         else if(S_ISDIR(l->mStat.st_mode)) {
              result = TRUE;
         }
         else {
              const int cmp = strcasecmp(lext, rext);
              if(cmp == 0) {
                  result = strcasecmp(lfname, rfname) > 0;
              }
              else {
                  result = cmp > 0;
              }
         }
     }
     else {
         const int cmp = strcmp(lext, rext);
         if(cmp == 0) {
             result = strcasecmp(lfname, rfname) > 0;
         }
         else {
             result = cmp > 0;
         }
     }
    
     return result;
}

BOOL sort_size(void* left, void* right)
{
     sFile* l = (sFile*) left;
     sFile* r = (sFile*) right;

     char* lfname = string_c_str(l->mName);
     char* rfname = string_c_str(r->mName);

     if(strcmp(lfname, ".") == 0) return TRUE;
     if(strcmp(lfname, "..") == 0) {
          if(strcmp(rfname, ".") == 0) return FALSE;

          return TRUE;          
     }
     if(strcmp(rfname, ".") == 0) return FALSE;
     if(strcmp(rfname, "..") == 0) return FALSE;
     
    char* mark_up = getenv("SORT_MARK_UP");
    if(mark_up && strcmp(mark_up, "1") == 0) {
        if(l->mMark && !r->mMark) {
            return TRUE;
        }
        if(!l->mMark && r->mMark) {
            return FALSE;
        }
    }
    char* dir_up = getenv("SORT_DIR_UP");
    if(dir_up && strcmp(dir_up, "1") == 0) {
         if(S_ISDIR(l->mStat.st_mode)) {
             if(S_ISDIR(r->mStat.st_mode)) return strcasecmp(lfname, rfname) < 0;
             return TRUE;
         }
         if(S_ISDIR(r->mStat.st_mode)) return FALSE;
     }
     
     const int lsize = S_ISDIR(l->mStat.st_mode) ? 0 : l->mLStat.st_size; 
     const int rsize = S_ISDIR(r->mStat.st_mode) ? 0 : r->mLStat.st_size;
    
     if(lsize == rsize) {
         return strcasecmp(lfname, rfname) < 0;
     }
     else {
         return lsize < rsize;
     }
}
  
BOOL sort_size_reverse(void* left, void* right)
{
     sFile* l = (sFile*) left;
     sFile* r = (sFile*) right;

     char* lfname = string_c_str(l->mName);
     char* rfname = string_c_str(r->mName);

     if(strcmp(lfname, ".") == 0) return TRUE;
     if(strcmp(lfname, "..") == 0) {
          if(strcmp(rfname, ".") == 0) return FALSE;

          return TRUE;          
     }
     if(strcmp(rfname, ".") == 0) return FALSE;
     if(strcmp(rfname, "..") == 0) return FALSE;

    char* mark_up = getenv("SORT_MARK_UP");
    if(mark_up && strcmp(mark_up, "1") == 0) {
        if(!l->mMark && r->mMark) {
            return TRUE;
        }
        if(l->mMark && !r->mMark) {
            return FALSE;
        }
    }
    char* dir_up = getenv("SORT_DIR_UP");
    if(dir_up && strcmp(dir_up, "1") == 0) {
         if(S_ISDIR(r->mStat.st_mode)) {
             if(S_ISDIR(l->mStat.st_mode)) return strcasecmp(lfname, rfname) > 0;
             return FALSE;
         }
         if(S_ISDIR(l->mStat.st_mode)) return TRUE;
     }
     
     const int lsize = S_ISDIR(l->mStat.st_mode) ? 0 : l->mLStat.st_size; 
     const int rsize = S_ISDIR(r->mStat.st_mode) ? 0 : r->mLStat.st_size;

     if(lsize == rsize) {
         return strcasecmp(lfname, rfname) > 0;
     }
     else {
         return lsize > rsize;
     }
}
    
BOOL sort_time(void* left, void* right)
{ 
     sFile* l = (sFile*) left;
     sFile* r = (sFile*) right;

     char* lfname = string_c_str(l->mName);
     char* rfname = string_c_str(r->mName);

     if(strcmp(lfname, ".") == 0) return TRUE;
     if(strcmp(lfname, "..") == 0) {
          if(strcmp(rfname, ".") == 0) return FALSE;

          return TRUE;
     }
     if(strcmp(rfname, ".") == 0) return FALSE;
     if(strcmp(rfname, "..") == 0) return FALSE;

    char* mark_up = getenv("SORT_MARK_UP");
    if(mark_up && strcmp(mark_up, "1") == 0) {
        if(l->mMark && !r->mMark) {
            return TRUE;
        }
        if(!l->mMark && r->mMark) {
            return FALSE;
        }
    }
    char* dir_up = getenv("SORT_DIR_UP");
    if(dir_up && strcmp(dir_up, "1") == 0) {
         if(S_ISDIR(l->mStat.st_mode)) {
             if(S_ISDIR(r->mStat.st_mode)) {
                 double cmp = difftime(l->mLStat.st_mtime, r->mLStat.st_mtime);
                 if(cmp == 0) {
                     return strcasecmp(lfname, rfname) < 0;
                 }
                 else {
                    return cmp < 0;
                }
             }
             return TRUE;
         }
         if(S_ISDIR(r->mStat.st_mode)) return FALSE;
     }
     
     double cmp = difftime(l->mLStat.st_mtime, r->mLStat.st_mtime);
     if(cmp == 0) {
         return strcasecmp(lfname, rfname) < 0;
     }
     else {
        return cmp < 0;
     }
}
    
BOOL sort_time_reverse(void* left, void* right)
{ 
     sFile* l = (sFile*) left;
     sFile* r = (sFile*) right;

     char* lfname = string_c_str(l->mName);
     char* rfname = string_c_str(r->mName);

     if(strcmp(lfname, ".") == 0) return TRUE;
     if(strcmp(lfname, "..") == 0) {
          if(strcmp(rfname, ".") == 0) return FALSE;

          return TRUE;
     }
     if(strcmp(rfname, ".") == 0) return FALSE;
     if(strcmp(rfname, "..") == 0) return FALSE;

    char* mark_up = getenv("SORT_MARK_UP");
    if(mark_up && strcmp(mark_up, "1") == 0) {
        if(!l->mMark && r->mMark) {
            return TRUE;
        }
        if(l->mMark && !r->mMark) {
            return FALSE;
        }
    }
    char* dir_up = getenv("SORT_DIR_UP");
    if(dir_up && strcmp(dir_up, "1") == 0) {
         if(S_ISDIR(r->mStat.st_mode)) {
             if(S_ISDIR(l->mStat.st_mode)) {
                 double cmp = difftime(l->mLStat.st_mtime, r->mLStat.st_mtime);
                 if(cmp == 0) {
                     return strcasecmp(lfname, rfname) > 0;
                 }
                 else {
                    return cmp > 0;
                 }
             }
             return FALSE;
         }
         if(S_ISDIR(l->mStat.st_mode)) return TRUE;
     }
     
     double cmp = difftime(l->mLStat.st_mtime, r->mLStat.st_mtime);
     if(cmp == 0) {
         return strcasecmp(lfname, rfname) > 0;
     }
     else {
        return cmp > 0;
    }
}

BOOL sort_user(void* left, void* right)
{ 
     sFile* l = (sFile*) left;
     sFile* r = (sFile*) right;

     char* lfname = string_c_str(l->mName);
     char* rfname = string_c_str(r->mName);

     if(strcmp(lfname, ".") == 0) return TRUE;
     if(strcmp(lfname, "..") == 0) {
          if(strcmp(rfname, ".") == 0) return FALSE;

          return TRUE;
     }
     if(strcmp(rfname, ".") == 0) return FALSE;
     if(strcmp(rfname, "..") == 0) return FALSE;

    char* mark_up = getenv("SORT_MARK_UP");
    if(mark_up && strcmp(mark_up, "1") == 0) {
        if(l->mMark && !r->mMark) {
            return TRUE;
        }
        if(!l->mMark && r->mMark) {
            return FALSE;
        }
    }
    char* dir_up = getenv("SORT_DIR_UP");
    if(dir_up && strcmp(dir_up, "1") == 0) {
         if(S_ISDIR(l->mStat.st_mode)) {
             if(S_ISDIR(r->mStat.st_mode)) {
                 if(l->mLStat.st_uid == r->mLStat.st_uid) {
                     return strcasecmp(lfname, rfname) < 0;
                 }
                 else {
                     return l->mLStat.st_uid < r->mLStat.st_uid;
                 }
             }
             return TRUE;
         }
         if(S_ISDIR(r->mStat.st_mode)) return FALSE;
     }
     
     if(l->mLStat.st_uid == r->mLStat.st_uid) {
         return strcasecmp(lfname, rfname) < 0;
     }
     else {
         return l->mLStat.st_uid < r->mLStat.st_uid;
     }
}
    
BOOL sort_user_reverse(void* left, void* right)
{ 
     sFile* l = (sFile*) left;
     sFile* r = (sFile*) right;

     char* lfname = string_c_str(l->mName);
     char* rfname = string_c_str(r->mName);

     if(strcmp(lfname, ".") == 0) return TRUE;
     if(strcmp(lfname, "..") == 0) {
          if(strcmp(rfname, ".") == 0) return FALSE;

          return TRUE;
     }
     if(strcmp(rfname, ".") == 0) return FALSE;
     if(strcmp(rfname, "..") == 0) return FALSE;

    char* mark_up = getenv("SORT_MARK_UP");
    if(mark_up && strcmp(mark_up, "1") == 0) {
        if(!l->mMark && r->mMark) {
            return TRUE;
        }
        if(l->mMark && !r->mMark) {
            return FALSE;
        }
    }
    char* dir_up = getenv("SORT_DIR_UP");
    if(dir_up && strcmp(dir_up, "1") == 0) {
         if(S_ISDIR(r->mStat.st_mode)) {
             if(S_ISDIR(l->mStat.st_mode)) {
                 if(l->mLStat.st_uid == r->mLStat.st_uid) {
                     return strcasecmp(lfname, rfname) > 0;
                 }
                 else {
                    return l->mLStat.st_uid > r->mLStat.st_uid;
                 }
             }
//             if(S_ISDIR(l->mLStat.st_mode)) return strcasecmp(rfname, lfname) < 0;
             return FALSE;
         }
         if(S_ISDIR(l->mStat.st_mode)) return TRUE;
     }
     
     if(l->mLStat.st_uid == r->mLStat.st_uid) {
         return strcasecmp(lfname, rfname) > 0;
     }
     else {
        return l->mLStat.st_uid > r->mLStat.st_uid;
     }
}

BOOL sort_group(void* left, void* right)
{ 
     sFile* l = (sFile*) left;
     sFile* r = (sFile*) right;

     char* lfname = string_c_str(l->mName);
     char* rfname = string_c_str(r->mName);

     if(strcmp(lfname, ".") == 0) return TRUE;
     if(strcmp(lfname, "..") == 0) {
          if(strcmp(rfname, ".") == 0) return FALSE;

          return TRUE;
     }
     if(strcmp(rfname, ".") == 0) return FALSE;
     if(strcmp(rfname, "..") == 0) return FALSE;

    char* mark_up = getenv("SORT_MARK_UP");
    if(mark_up && strcmp(mark_up, "1") == 0) {
        if(l->mMark && !r->mMark) {
            return TRUE;
        }
        if(!l->mMark && r->mMark) {
            return FALSE;
        }
    }
    char* dir_up = getenv("SORT_DIR_UP");
    if(dir_up && strcmp(dir_up, "1") == 0) {
         if(S_ISDIR(l->mStat.st_mode)) {
             if(S_ISDIR(r->mStat.st_mode)) {
                 if(l->mLStat.st_gid == r->mLStat.st_gid) {
                     return strcasecmp(lfname, rfname) < 0;
                 }
                 else {
                    return l->mLStat.st_gid < r->mLStat.st_gid;
                 }
             }
//             if(S_ISDIR(r->mLStat.st_mode)) return strcasecmp(lfname, rfname) < 0;
             return TRUE;
         }
         if(S_ISDIR(r->mStat.st_mode)) return FALSE;
     }
     
     if(l->mLStat.st_gid == r->mLStat.st_gid) {
         return strcasecmp(lfname, rfname) < 0;
     }
     else {
        return l->mLStat.st_gid < r->mLStat.st_gid;
     }
}
    
BOOL sort_group_reverse(void* left, void* right)
{ 
     sFile* l = (sFile*) left;
     sFile* r = (sFile*) right;

     char* lfname = string_c_str(l->mName);
     char* rfname = string_c_str(r->mName);

     if(strcmp(lfname, ".") == 0) return TRUE;
     if(strcmp(lfname, "..") == 0) {
          if(strcmp(rfname, ".") == 0) return FALSE;

          return TRUE;
     }
     if(strcmp(rfname, ".") == 0) return FALSE;
     if(strcmp(rfname, "..") == 0) return FALSE;

    char* mark_up = getenv("SORT_MARK_UP");
    if(mark_up && strcmp(mark_up, "1") == 0) {
        if(!l->mMark && r->mMark) {
            return TRUE;
        }
        if(l->mMark && !r->mMark) {
            return FALSE;
        }
    }
    char* dir_up = getenv("SORT_DIR_UP");
    if(dir_up && strcmp(dir_up, "1") == 0) {
         if(S_ISDIR(r->mStat.st_mode)) {
             if(S_ISDIR(l->mStat.st_mode)) {
                 if(l->mLStat.st_gid == r->mLStat.st_gid) {
                     return strcasecmp(lfname, rfname) > 0;
                 }
                 else {
                    return l->mLStat.st_gid > r->mLStat.st_gid;
                 }
             }
//             if(S_ISDIR(l->mLStat.st_mode)) return strcasecmp(rfname, lfname) < 0;
             return FALSE;
         }
         if(S_ISDIR(l->mStat.st_mode)) return TRUE;
     }
     
     if(l->mLStat.st_gid == r->mLStat.st_gid) {
         return strcasecmp(lfname, rfname) > 0;
     }
     else {
        return l->mLStat.st_gid > r->mLStat.st_gid;
     }
}

BOOL sort_permission(void* left, void* right)
{ 
     sFile* l = (sFile*) left;
     sFile* r = (sFile*) right;

     char* lfname = string_c_str(l->mName);
     char* rfname = string_c_str(r->mName);

     if(strcmp(lfname, ".") == 0) return TRUE;
     if(strcmp(lfname, "..") == 0) {
          if(strcmp(rfname, ".") == 0) return FALSE;

          return TRUE;
     }
     if(strcmp(rfname, ".") == 0) return FALSE;
     if(strcmp(rfname, "..") == 0) return FALSE;

    char* mark_up = getenv("SORT_MARK_UP");
    if(mark_up && strcmp(mark_up, "1") == 0) {
        if(l->mMark && !r->mMark) {
            return TRUE;
        }
        if(!l->mMark && r->mMark) {
            return FALSE;
        }
    }
    char* dir_up = getenv("SORT_DIR_UP");
    if(dir_up && strcmp(dir_up, "1") == 0) {
         if(S_ISDIR(l->mStat.st_mode)) {
             if(S_ISDIR(r->mStat.st_mode)) {
                 if((l->mLStat.st_mode&S_ALLPERM) == (r->mLStat.st_mode&S_ALLPERM)) {
                     return strcasecmp(lfname, rfname) < 0;
                 }
                 else {
                     return (l->mLStat.st_mode&S_ALLPERM) < (r->mLStat.st_mode&S_ALLPERM);
                 }
             }
             return TRUE;
         }
         if(S_ISDIR(r->mStat.st_mode)) return FALSE;
     }
     
     if((l->mLStat.st_mode&S_ALLPERM) == (r->mLStat.st_mode&S_ALLPERM)) {
         return strcasecmp(lfname, rfname) < 0;
     }
     else {
         return (l->mLStat.st_mode&S_ALLPERM) < (r->mLStat.st_mode&S_ALLPERM);
     }
}
    
BOOL sort_permission_reverse(void* left, void* right)
{ 
     sFile* l = (sFile*) left;
     sFile* r = (sFile*) right;

     char* lfname = string_c_str(l->mName);
     char* rfname = string_c_str(r->mName);

     if(strcmp(lfname, ".") == 0) return TRUE;
     if(strcmp(lfname, "..") == 0) {
          if(strcmp(rfname, ".") == 0) return FALSE;

          return TRUE;
     }
     if(strcmp(rfname, ".") == 0) return FALSE;
     if(strcmp(rfname, "..") == 0) return FALSE;

    char* mark_up = getenv("SORT_MARK_UP");
    if(mark_up && strcmp(mark_up, "1") == 0) {
        if(!l->mMark && r->mMark) {
            return TRUE;
        }
        if(l->mMark && !r->mMark) {
            return FALSE;
        }
    }
    char* dir_up = getenv("SORT_DIR_UP");
    if(dir_up && strcmp(dir_up, "1") == 0) {
         if(S_ISDIR(r->mStat.st_mode)) {
             if(S_ISDIR(l->mStat.st_mode)) {
                 if((l->mLStat.st_mode&S_ALLPERM) == (r->mLStat.st_mode&S_ALLPERM)) {
                     return strcasecmp(lfname, rfname) > 0;
                 }
                 else {
                     return (l->mLStat.st_mode&S_ALLPERM) > (r->mLStat.st_mode&S_ALLPERM);
                 }
             }
             return FALSE;
         }
         if(S_ISDIR(l->mStat.st_mode)) return TRUE;
     }
     
     if((l->mLStat.st_mode&S_ALLPERM) == (r->mLStat.st_mode&S_ALLPERM)) {
         return strcasecmp(lfname, rfname) > 0;
     }
     else {
         return (l->mLStat.st_mode&S_ALLPERM) > (r->mLStat.st_mode&S_ALLPERM);
     }
}

BOOL sort_random(void* left, void* right)
{
    sFile* l = (sFile*) left;
    sFile* r = (sFile*) right;

    char* lfname = string_c_str(l->mName);
    char* rfname = string_c_str(r->mName);

    if(strcmp(lfname, ".") == 0) return TRUE;
    if(strcmp(lfname, "..") == 0) {
        if(strcmp(rfname, ".") == 0) return FALSE;

        return TRUE;          
    }
    if(strcmp(rfname, ".") == 0) return FALSE;
    if(strcmp(rfname, "..") == 0) return FALSE;

    char* mark_up = getenv("SORT_MARK_UP");
    if(mark_up && strcmp(mark_up, "1") == 0) {
        if(l->mMark && !r->mMark) {
            return TRUE;
        }
        if(!l->mMark && r->mMark) {
            return FALSE;
        }
    }

    char* dir_up = getenv("SORT_DIR_UP");
    if(dir_up && strcmp(dir_up, "1") == 0) {
        if(!S_ISDIR(l->mStat.st_mode) && !S_ISDIR(r->mStat.st_mode)
            || S_ISDIR(l->mStat.st_mode) && S_ISDIR(r->mStat.st_mode) )
        {
            return l->mSortRandom < r->mSortRandom;
        }

    
        if(S_ISDIR(l->mStat.st_mode))
            return TRUE;
        else
            return FALSE;
    }
    else {
        return l->mSortRandom < r->mSortRandom;
    }
}

void filer_sort(int dir)
{
    if(dir < 0 || dir >= vector_size(gDirs)) {
        return;
    }
    sDir* self = (sDir*)vector_item(gDirs, dir);

    sDir_sort(self);
}



static void sDir_sort(sDir* self)
{
    char* sort_kind = getenv("SORT_KIND");

    if(sort_kind == NULL || strcmp(sort_kind, "name") == 0) {
        vector_sort(self->mFiles, sort_name);
    }
    else if(strcmp(sort_kind, "random") == 0) {
        int i;
        for(i=0; i<vector_size(self->mFiles); i++) {
            sFile* f = (sFile*)vector_item(self->mFiles, i);

            f->mSortRandom = random()%vector_size(self->mFiles);
        }

        vector_sort(self->mFiles, sort_random);
    }
    else if(strcmp(sort_kind, "name_rev") == 0) {
        vector_sort(self->mFiles, sort_name_reverse);
    }
    else if(strcmp(sort_kind, "ext") == 0) {
        vector_sort(self->mFiles, sort_ext);
    }
    else if(strcmp(sort_kind, "ext_rev") == 0) {
        vector_sort(self->mFiles, sort_ext_reverse);
    }
    else if(strcmp(sort_kind, "size") == 0) {
        vector_sort(self->mFiles, sort_size);
    }
    else if(strcmp(sort_kind, "size_rev") == 0) {
        vector_sort(self->mFiles, sort_size_reverse);
    }
    else if(strcmp(sort_kind, "time") == 0) {
        vector_sort(self->mFiles, sort_time);
    }
    else if(strcmp(sort_kind, "time_rev") == 0) {
        vector_sort(self->mFiles, sort_time_reverse);
    }
    else if(strcmp(sort_kind, "user") == 0) {
        vector_sort(self->mFiles, sort_user);
    }
    else if(strcmp(sort_kind, "user_rev") == 0) {
        vector_sort(self->mFiles, sort_user_reverse);
    }
    else if(strcmp(sort_kind, "group") == 0) {
        vector_sort(self->mFiles, sort_group);
    }
    else if(strcmp(sort_kind, "group_rev") == 0) {
        vector_sort(self->mFiles, sort_group_reverse);
    }
    else if(strcmp(sort_kind, "perm") == 0) {
        vector_sort(self->mFiles, sort_permission);
    }
    else if(strcmp(sort_kind, "perm_rev") == 0) {
        vector_sort(self->mFiles, sort_permission_reverse);
    }
}

void filer_set_dotdir_mask(int dir, BOOL flg)
{
    sDir* dir2 = filer_dir(dir);

    if(dir2) {
        dir2->mDotDirMask = flg;
    }
}
BOOL filer_dotdir_mask(int dir)
{
    sDir* dir2 = filer_dir(dir);

    if(dir2) {
        return dir2->mDotDirMask;
    }
}

//////////////////////////////////////////////////////////////////////
// mbsから端末上の文字列分(termsize)のみ残して残りを捨てた文字列を
// dest_mbsに返す dest_byte: dest_mbsのサイズ
//////////////////////////////////////////////////////////////////////
void str_cut(enum eKanjiCode code, char* mbs, int termsize, SPACE char* dest_mbs, int dest_byte)
{
    if(code == kUtf8) {
        wchar_t* wcs;
        wchar_t* wcs_tmp;
        int i;

        wcs = (wchar_t*)MALLOC(sizeof(wchar_t)*(termsize+1)*MB_CUR_MAX);
        wcs_tmp = (wchar_t*)MALLOC(sizeof(wchar_t)*(termsize+1)*MB_CUR_MAX);
        if(mbstowcs(wcs, mbs, (termsize+1)*MB_CUR_MAX) == -1) {
            mbstowcs(wcs, "?????", (termsize+1)*MB_CUR_MAX);
        }

        for(i=0; i<wcslen(wcs); i++) {
            wcs_tmp[i] = wcs[i];
            wcs_tmp[i+1] = 0;

            if(wcswidth(wcs_tmp, wcslen(wcs_tmp)) > termsize) {
                wcs_tmp[i] = 0;
                break;
            }
        }

        wcstombs(dest_mbs, wcs_tmp, dest_byte);

        FREE(wcs);
        FREE(wcs_tmp);
    }
    else {
        int n;
        BOOL kanji = FALSE;
        for(n=0; n<termsize && n<dest_byte-1; n++) {
            if(!kanji && is_kanji(code, mbs[n])) {
                kanji = TRUE;
            }
            else {
                kanji = FALSE;
            }

            dest_mbs[n] = mbs[n];
        }
        
        if(kanji)
            dest_mbs[n-1] = 0;
        else
            dest_mbs[n] = 0;
    }
}
//////////////////////////////////////////////////////////////////////
// mbsから端末上の文字列分(termsize)のみ残して残りを捨てた文字列を
// dest_mbsに返す dest_byte: dest_mbsのサイズ
// 切り捨てた文字列をスペースで埋める
//////////////////////////////////////////////////////////////////////
#include <stdio.h>

void str_cut2(enum eKanjiCode code, char* mbs, int termsize, SPACE char* dest_mbs, int dest_byte)
{
    if(code == kUtf8) {
        int i;
        int n;

        wchar_t* wcs 
            = (wchar_t*)MALLOC(sizeof(wchar_t)*(termsize+1)*MB_CUR_MAX);
        wchar_t* tmp 
            = (wchar_t*)MALLOC(sizeof(wchar_t)*(termsize+1)*MB_CUR_MAX);

        if(mbstowcs(wcs, mbs, (termsize+1)*MB_CUR_MAX) == -1) {
            mbstowcs(wcs, "?????", (termsize+1)*MB_CUR_MAX);
        }

        i = 0;
        while(1) {
            if(i < wcslen(wcs)) {
                tmp[i] = wcs[i];
                tmp[i+1] = 0;
            }
            else {
                tmp[i] = ' ';
                tmp[i+1] = 0;
            }

            n = wcswidth(tmp, wcslen(tmp));
            if(n < 0) {
                strncpy(dest_mbs, "?????", dest_byte);

                FREE(wcs);
                FREE(tmp);

                return;
            }
            else {
                if(n > termsize) {
                    tmp[i] = 0;

                    if(wcswidth(tmp, wcslen(tmp)) != termsize) {
                        tmp[i] = ' ';
                        tmp[i+1] = 0;
                    }
                    break;
                }
            }

            i++;
        }

        wcstombs(dest_mbs, tmp, dest_byte);

        FREE(wcs);
        FREE(tmp);
    }
    else {
        int n;
        BOOL tmpend = FALSE;
        BOOL kanji = FALSE;
        for(n=0; n<termsize && n<dest_byte-1; n++) {
            if(kanji)
                kanji = FALSE;
            else if(!tmpend && is_kanji(code, mbs[n])) {
                kanji = TRUE;
            }

            if(!tmpend && mbs[n] == 0) tmpend = TRUE;
                        
            if(tmpend)
                dest_mbs[n] = ' ';
            else
                dest_mbs[n] = mbs[n];
        }
        
        if(kanji) dest_mbs[n-1] = ' ';
        dest_mbs[n] = 0;
    }
}

//////////////////////////////////////////////////////////////////////
// mbsから端末上の文字列分(termsize)のみ残して残りを捨てた文字列を
// dest_mbsに返す 
// dest_byte: dest_mbsのサイズ
// 切り捨てた文字列をスペースで埋める
// 切り捨てるのは文字列の前から
//////////////////////////////////////////////////////////////////////
void str_cut3(enum eKanjiCode code, char* mbs, int termsize, SPACE char* dest_mbs, int dest_byte)
{
    if(code == kUtf8) {
        wchar_t* wcs;
        wchar_t* tmp;
        int i;
        int j;

        wcs = (wchar_t*)MALLOC(sizeof(wchar_t)*(strlen(mbs)+1)*MB_CUR_MAX);
        tmp = (wchar_t*)MALLOC(sizeof(wchar_t)*(strlen(mbs)+1)*MB_CUR_MAX);

        if(str_termlen(code, mbs) <= termsize) {
            str_cut2(code, mbs, termsize, dest_mbs, dest_byte);
        }
        else {
            if(mbstowcs(wcs, mbs, (termsize+1)*MB_CUR_MAX) == -1) {
                mbstowcs(wcs, "?????", (termsize+1)*MB_CUR_MAX);
            }

            i = wcslen(wcs)-1;
            j = 0;
            while(1) {
                tmp[j++] = wcs[i--];
                tmp[j] = 0;

                if(wcswidth(tmp, wcslen(tmp)) > termsize) {
                    tmp[j-1] = 0;
                    i+=2;

                    if(wcswidth(tmp, wcslen(tmp)) == termsize) {
                        wcscpy(tmp, wcs + i);
                        break;
                    }
                    else {
                        tmp[0] = ' ';
                        wcscpy(tmp + 1, wcs + i);
                        break;
                    }
                }
            }

            wcstombs(dest_mbs, tmp, dest_byte);
        }

        FREE(wcs);
        FREE(tmp);
    }
    else {
        BOOL* kanji;
        int i;
        const int len = strlen(mbs);
        char* buf;

        if(len < termsize) {
            strncpy(dest_mbs, mbs, dest_byte);
            for(i=len; i<termsize; i++) {
                xstrncat(dest_mbs, " ", dest_byte);
            }
        }
        else {
            kanji = MALLOC(sizeof(BOOL)*len);
            for(i=0; i<len; i++) {
                if(is_kanji(code, mbs[i])) {
                    kanji[i] = TRUE;
                    i++;
                    kanji[i] = FALSE;
                }
                else {
                    kanji[i] = FALSE;
                }
            }

            if(kanji[len-termsize-1]) {
                int i;
                for(i=len-termsize; i<len; i++) {
                    dest_mbs[i-len+termsize] = mbs[i];
                }
                dest_mbs[i-len+termsize] = 0;
                dest_mbs[0] = ' ';
            }
            else {
                int i;
                for(i=len-termsize; i<len; i++) {
                    dest_mbs[i-len+termsize] = mbs[i];
                }
                dest_mbs[i-len+termsize] = 0;
            }

            FREE(kanji);
        }
    }
}
