
// saphireのソースはUTF8でラインフィールド\nに固定

#include "config.h"
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <glob.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <pwd.h>

#include <limits.h>

#if defined(__DARWIN__)
#include <sys/syslimits.h>
#endif

#include "saphire.h"
#include "saphire_inner.h"

static void skip_spaces(char** p, string_obj* not_evaled)
{
    while(**p == ' ' || **p == '\t') {
        string_push_back2(not_evaled, **p);
        (*p)++;
    }
}

static BOOL read_until_next_bracket_end(char** p, string_obj* not_evaled, int* read_end_of_statment, BOOL line_inc, char* sname, int* line);
static BOOL read_until_next_paren_end(char** p, string_obj* not_evaled, int* read_end_of_statment, BOOL line_inc, char* sname, int* line);
static BOOL expand_line_field(char* str, string_obj* out, char* sname, int* line);

// {}内を丸ごと取りたい関数。ネストしていてもOK
// 中身はもう一度parseされる
// 変数展開も対応
BOOL read_until_next_cbrace_end(char** p, string_obj* not_evaled, int* read_end_of_statment, BOOL line_inc, char* sname, int* line)
{
    if(**p == '{') {
        string_push_back2(not_evaled, **p);
        (*p)++;

        int nest = 0;
        BOOL squote = FALSE;
        BOOL dquote = FALSE;
        while(1) {
            /// クォート ///
            if(!squote && !dquote && **p == '\\') {
                if(*(*p+1) == 't') {
                    string_push_back(not_evaled, "\\t");

                    (*p)+=2;
                }
                else if(*(*p+1) == 'n') {
                    string_push_back(not_evaled, "\\n");

                    (*p)+=2;
                }
                else if(*(*p+1) == 'r') {
                    string_push_back(not_evaled, "\\r");

                    (*p)+=2;
                }
                else {
                    string_push_back2(not_evaled, **p);
                    (*p)++;
                    if(**p == '\n') {
                        line_inc && (*line)++;
                        string_push_back2(not_evaled, **p);
                        (*p)++;
                    }
                    else if(**p != 0) {
                        string_push_back2(not_evaled, **p);
                        (*p)++;
                    }
                }
            }
            /// シングルクォート ///
            else if(!dquote && **p == '\'') {
                squote = !squote;
                string_push_back2(not_evaled, **p);
                (*p)++;
            }
            /// ダブルクォート ///
            else if(!squote && **p == '"') {
                dquote = !dquote;
                string_push_back2(not_evaled, **p);
                (*p)++;
            }
            /// 環境変数かコマンドライン展開
            else if(!squote && **p == '$') {
                // 変数 $
                if(*(*p+1) == '$' 
                            && (*(*p+2) == '{' || is_env_name_char(*(*p+2)))
                         || (*(*p+1) == '{' 
                         || is_env_name_char(*(*p+1))))
                {
                    string_push_back2(not_evaled, **p);
                    (*p)++;
                    if(**p == '$') {
                        string_push_back2(not_evaled, **p);
                        (*p)++;
                    }

                    if(**p == 0) {
                        err_msg("parse: invalid env name", sname, *line);
                        return FALSE;
                    }

                    if(**p == '{') {
                        if(!read_until_next_cbrace_end(p, not_evaled, read_end_of_statment,line_inc, sname, line))
                        {
                            return FALSE;
                        }
                    }
                    else {
                        char name[1024];
                        char* p3 = name;
                        while(is_env_name_char(**p)) {
                            *p3++ = **p;
                            (*p)++;
                        }
                        *p3 = 0;

                        string_push_back(not_evaled, name);
                    }

                    if(**p == '[') {
                        if(!read_until_next_bracket_end(p, not_evaled, read_end_of_statment, line_inc, sname, line)) {
                            return FALSE;
                        }

                        if(**p == '[') {
                            if(!read_until_next_bracket_end(p, not_evaled, read_end_of_statment, line_inc, sname, line))
                            {
                                return FALSE;
                            }
                        }
                    }
                    if(**p == '<') {
                        if(!read_until_next_ltgt_end(p, not_evaled, read_end_of_statment, line_inc, sname, line)) {
                            return FALSE;
                        }
                    }

                    *read_end_of_statment = 1;
                }

                // コマンド展開 $()
                else if(*(*p+1) == '$' && *(*p+2) == '('
                        || *(*p+1) == '(')
                {
                    if(*(*p+1) == '$') {
                        string_push_back2(not_evaled, **p);
                        (*p)++;
                    }
                    string_push_back2(not_evaled, **p);
                    (*p)++;

                    if(!read_until_next_paren_end(p, not_evaled, read_end_of_statment, line_inc, sname, line)) {
                        return FALSE;
                    }
                    
                    if(**p == '[') {
                        if(!read_until_next_bracket_end(p, not_evaled, read_end_of_statment, line_inc, sname, line)) {
                            return FALSE;
                        }
                    };

                    *read_end_of_statment = 1;
                }

                /// 算術演算 $(())
                else if(*(*p+1) == '(' && *(*p+2) == '(')
                {
                    string_push_back2(not_evaled, **p);
                    (*p)++;
                    string_push_back2(not_evaled, **p);
                    (*p)++;

                    if(!read_until_next_paren_end(p, not_evaled, read_end_of_statment, line_inc, sname, line)) {
                        return FALSE;
                    }

                    if(**p != ')') {
                        err_msg("parse: need ) in $(())", sname, *line);

                        return FALSE;
                    }

                    string_push_back2(not_evaled, **p);  // )
                    (*p)++;

                    *read_end_of_statment = 1;
                }
                else {
                    err_msg("invalid env name", sname, *line);
                    return FALSE;
                }
            }
            else if(squote || dquote) {
                if(**p == 0) {
                    err_msg("require ' or \"", sname, *line);
                    return FALSE;
                }
                else {
                    if(line_inc && **p == '\n') {
                        (*line)++;
                    }

                    string_push_back2(not_evaled, **p);
                    (*p)++;
                }
            }
            else if(**p == '{') {
                nest++;
                string_push_back2(not_evaled, **p);
                (*p)++;
            }
            else if(**p == '}') {
                string_push_back2(not_evaled, **p);
                (*p)++;

                if(nest == 0) {
                    break;
                }
                nest--;
            }
            else if(**p == 0) {
                err_msg("read_util_next_cbrace_end: unexpected end(0). need }", sname, *line);
                return FALSE;
            }
            else if(line_inc && **p == '\n') {
                (*line)++;
                string_push_back2(not_evaled, **p);
                (*p)++;
            }
            else {
                string_push_back2(not_evaled, **p);
                (*p)++;
            }
        }
    }
    
    return TRUE;
}

// <>内を丸ごと取りたい関数。ネストしていてもOK
// 中身はもう一度parseされる
// 変数展開も対応
BOOL read_until_next_ltgt_end(char** p, string_obj* not_evaled, int* read_end_of_statment, BOOL line_inc, char* sname, int* line)
{
    if(**p == '<') {
        string_push_back2(not_evaled, **p);
        (*p)++;

        int nest = 0;
        BOOL squote = FALSE;
        BOOL dquote = FALSE;
        while(1) {
            /// クォート ///
            if(!squote && !dquote && **p == '\\') {
                if(*(*p+1) == 't') {
                    string_push_back(not_evaled, "\\t");

                    (*p)+=2;
                }
                else if(*(*p+1) == 'n') {
                    string_push_back(not_evaled, "\\n");

                    (*p)+=2;
                }
                else if(*(*p+1) == 'r') {
                    string_push_back(not_evaled, "\\r");

                    (*p)+=2;
                }
                else {
                    string_push_back2(not_evaled, **p);
                    (*p)++;
                    if(line_inc && **p == '\n') {
                        (*line)++;
                        string_push_back2(not_evaled, **p);
                        (*p)++;
                    }
                    else if(**p != 0) {
                        string_push_back2(not_evaled, **p);
                        (*p)++;
                    }
                }
            }
            /// シングルクォート ///
            else if(!dquote && **p == '\'') {
                squote = !squote;
                string_push_back2(not_evaled, **p);
                (*p)++;
            }
            /// ダブルクォート ///
            else if(!squote && **p == '"') {
                dquote = !dquote;
                string_push_back2(not_evaled, **p);
                (*p)++;
            }
            /// 環境変数かコマンドライン展開
            else if(!squote && **p == '$') {
                // 変数 $
                if(*(*p+1) == '$' 
                            && (*(*p+2) == '{' || is_env_name_char(*(*p+2)))
                         || (*(*p+1) == '{' 
                         || is_env_name_char(*(*p+1))))
                {
                    string_push_back2(not_evaled, **p);
                    (*p)++;
                    if(**p == '$') {
                        string_push_back2(not_evaled, **p);
                        (*p)++;
                    }

                    if(**p == 0) {
                        err_msg("parse: invalid env name", sname, *line);
                        return FALSE;
                    }

                    if(**p == '{') {
                        if(!read_until_next_cbrace_end(p, not_evaled, read_end_of_statment, line_inc, sname, line))
                        {
                            return FALSE;
                        }
                    }
                    else {
                        char name[1024];
                        char* p3 = name;
                        while(is_env_name_char(**p)) {
                            *p3++ = **p;
                            (*p)++;
                        }
                        *p3 = 0;

                        string_push_back(not_evaled, name);
                    }

                    if(**p == '[') {
                        if(!read_until_next_bracket_end(p, not_evaled, read_end_of_statment, line_inc, sname, line)) {
                            return FALSE;
                        }

                        if(**p == '[') {
                            if(!read_until_next_bracket_end(p, not_evaled, read_end_of_statment, line_inc, sname, line))
                            {
                                return FALSE;
                            }
                        }
                    }
                    if(**p == '<') {
                        if(!read_until_next_ltgt_end(p, not_evaled, read_end_of_statment, line_inc, sname, line)) {
                            return FALSE;
                        }
                    }

                    *read_end_of_statment = 1;
                }

                // コマンド展開 $()
                else if(*(*p+1) == '$' && *(*p+2) == '('
                        || *(*p+1) == '(')
                {
                    if(*(*p+1) == '$') {
                        string_push_back2(not_evaled, **p);
                        (*p)++;
                    }
                    string_push_back2(not_evaled, **p);
                    (*p)++;

                    if(!read_until_next_paren_end(p, not_evaled, read_end_of_statment, line_inc, sname, line)) {
                        return FALSE;
                    }
                    
                    if(**p == '[') {
                        if(!read_until_next_bracket_end(p, not_evaled, read_end_of_statment, line_inc, sname, line)) {
                            return FALSE;
                        }
                    };

                    *read_end_of_statment = 1;
                }

                /// 算術演算 $(())
                else if(*(*p+1) == '(' && *(*p+2) == '(')
                {
                    string_push_back2(not_evaled, **p);
                    (*p)++;
                    string_push_back2(not_evaled, **p);
                    (*p)++;

                    if(!read_until_next_paren_end(p, not_evaled, read_end_of_statment, line_inc, sname, line)) {
                        return FALSE;
                    }

                    if(**p != ')') {
                        err_msg("parse: need ) in $(())", sname, *line);

                        return FALSE;
                    }

                    string_push_back2(not_evaled, **p);  // )
                    (*p)++;

                    *read_end_of_statment = 1;
                }
                else {
                    err_msg("invalid env name", sname, *line);
                    return FALSE;
                }
            }
            else if(squote || dquote) {
                if(**p == 0) {
                    err_msg("require ' or \"", sname, *line);
                    return FALSE;
                }
                else if(line_inc && **p =='\n') {
                    (*line)++;
                    string_push_back2(not_evaled, **p);
                    (*p)++;
                }
                else {
                    string_push_back2(not_evaled, **p);
                    (*p)++;
                }
            }
            else if(**p == '<') {
                nest++;
                string_push_back2(not_evaled, **p);
                (*p)++;
            }
            else if(**p == '>') {
                string_push_back2(not_evaled, **p);
                (*p)++;

                if(nest == 0) {
                    break;
                }
                nest--;
            }
            else if(**p == 0) {
                err_msg("read_util_next_cbrace_end: unexpected end(0). need }", sname, *line);
                return FALSE;
            }
            else if(line_inc && **p == '\n') {
                (*line)++;
                string_push_back2(not_evaled, **p);
                (*p)++;
            }
            else {
                string_push_back2(not_evaled, **p);
                (*p)++;
            }
        }
    }
    
    return TRUE;
}

// []内を丸ごと取りたい関数。ネストしていて丸ごと取る
// 中身はもう一度parseされる
// 変数展開も対応
static BOOL read_until_next_bracket_end(char** p, string_obj* not_evaled, int* read_end_of_statment, BOOL line_inc, char* sname, int* line)
{
    if(**p == '[') {
        string_push_back2(not_evaled, **p);
        (*p)++;

        int nest = 0;
        BOOL squote = FALSE;
        BOOL dquote = FALSE;
        while(1) {
            /// クォート ///
            if(!squote && !dquote && **p == '\\') {
                if(*(*p+1) == 't') {
                    string_push_back(not_evaled, "\\t");

                    (*p)+=2;
                }
                else if(*(*p+1) == 'n') {
                    string_push_back(not_evaled, "\\n");

                    (*p)+=2;
                }
                else if(*(*p+1) == 'r') {
                    string_push_back(not_evaled, "\\r");

                    (*p)+=2;
                }
                else {
                    string_push_back2(not_evaled, **p);
                    (*p)++;
                    if(line_inc && **p == '\n') {
                        (*line)++;
                        string_push_back2(not_evaled, **p);
                        (*p)++;
                    }
                    else if(**p != 0) {
                        string_push_back2(not_evaled, **p);
                        (*p)++;
                    }
                }
            }
            /// シングルクォート ///
            else if(!dquote && **p == '\'') {
                squote = !squote;
                string_push_back2(not_evaled, **p);
                (*p)++;
            }
            /// ダブルクォート ///
            else if(!squote && **p == '"') {
                dquote = !dquote;
                string_push_back2(not_evaled, **p);
                (*p)++;
            }
            /// 環境変数かコマンドライン展開
            else if(!squote && **p == '$') {
                // 変数 $
                if(*(*p+1) == '$' 
                            && (*(*p+2) == '{' || is_env_name_char(*(*p+2)))
                         || (*(*p+1) == '{' 
                         || is_env_name_char(*(*p+1))))
                {
                    string_push_back2(not_evaled, **p);
                    (*p)++;
                    if(**p == '$') {
                        string_push_back2(not_evaled, **p);
                        (*p)++;
                    }

                    if(**p == 0) {
                        err_msg("parse: invalid env name", sname, *line);
                        return FALSE;
                    }

                    if(**p == '{') {
                        if(!read_until_next_cbrace_end(p, not_evaled, read_end_of_statment, line_inc, sname, line))
                        {
                            return FALSE;
                        }
                    }
                    else {
                        char name[1024];
                        char* p3 = name;
                        while(is_env_name_char(**p)) {
                            *p3++ = **p;
                            (*p)++;
                        }
                        *p3 = 0;

                        string_push_back(not_evaled, name);
                    }

                    if(**p == '[') {
                        if(!read_until_next_bracket_end(p, not_evaled, read_end_of_statment, line_inc, sname, line)) {
                            return FALSE;
                        }

                        if(**p == '[') {
                            if(!read_until_next_bracket_end(p, not_evaled, read_end_of_statment, line_inc, sname, line)) {
                                return FALSE;
                            }
                        }
                    }
                    if(**p == '<') {
                        if(!read_until_next_ltgt_end(p, not_evaled, read_end_of_statment, line_inc, sname, line)) {
                            return FALSE;
                        }
                    }

                    *read_end_of_statment = 1;
                }

                // コマンド展開 $()
                else if(*(*p+1) == '$' && *(*p+2) == '('
                        || *(*p+1) == '(')
                {
                    if(*(*p+1) == '$') {
                        string_push_back2(not_evaled, **p);
                        (*p)++;
                    }
                    string_push_back2(not_evaled, **p);
                    (*p)++;

                    if(!read_until_next_paren_end(p, not_evaled, read_end_of_statment, line_inc, sname, line)) {
                        return FALSE;
                    }
                    
                    if(**p == '[') {
                        string_push_back2(not_evaled, **p);
                        (*p)++;
                        if(!read_until_next_bracket_end(p, not_evaled, read_end_of_statment, line_inc, sname, line)) {
                            return FALSE;
                        }
                    };

                    *read_end_of_statment = 1;
                }

                /// 算術演算 $(())
                else if(*(*p+1) == '(' && *(*p+2) == '(')
                {
                    string_push_back2(not_evaled, **p);
                    (*p)++;
                    string_push_back2(not_evaled, **p);
                    (*p)++;

                    if(!read_until_next_paren_end(p, not_evaled, read_end_of_statment, line_inc, sname, line)) {
                        return FALSE;
                    }

                    if(**p != ')') {
                        err_msg("parse: need ) in $(())", sname, *line);

                        return FALSE;
                    }

                    string_push_back2(not_evaled, **p);  // )
                    (*p)++;

                    *read_end_of_statment = 1;
                }
                else {
                    err_msg("invalid env name", sname, *line);
                    return FALSE;
                }
            }
            else if(squote || dquote) {
                if(**p == 0) {
                    err_msg("require ' or \"", sname, *line);
                    return FALSE;
                }
                else if(line_inc && **p == '\n') {
                    (*line)++;
                    string_push_back2(not_evaled, **p);
                    (*p)++;
                }
                else {
                    string_push_back2(not_evaled, **p);
                    (*p)++;
                }
            }
            else if(**p == '[') {
                nest++;
                string_push_back2(not_evaled, **p);
                (*p)++;
            }
            else if(**p == ']') {
                string_push_back2(not_evaled, **p);
                (*p)++;

                if(nest == 0) {
                    break;
                }
                nest--;
            }
            else if(**p == 0) {
                err_msg("parse skip next bracket: unexpected end(0). need ]", sname, *line);
                return FALSE;
            }
            else if(line_inc && **p == '\n') {
                (*line)++;
                string_push_back2(not_evaled, **p);
                (*p)++;
            }
            else {
                string_push_back2(not_evaled, **p);
                (*p)++;
            }
        }
    }
    
    return TRUE;
}

// ()内をまるごと取りたい関数。ネストしていても全部とる
// 読み込みだけ。中身はもう一度パースされる
// 変数展開も対応
static BOOL read_until_next_paren_end(char** p, string_obj* not_evaled, int* read_end_of_statment, BOOL line_inc, char* sname, int* line)
{
    if(**p == '(') {
        string_push_back2(not_evaled, **p);
        (*p)++;

        int nest = 0;
        BOOL squote = FALSE;
        BOOL dquote = FALSE;
        while(1) {
            /// クォート ///
            if(!squote && !dquote && **p == '\\') {
                if(*(*p+1) == 't') {
                    string_push_back(not_evaled, "\\t");

                    (*p)+=2;
                }
                else if(*(*p+1) == 'n') {
                    string_push_back(not_evaled, "\\n");

                    (*p)+=2;
                }
                else if(*(*p+1) == 'r') {
                    string_push_back(not_evaled, "\\r");

                    (*p)+=2;
                }
                else {
                    string_push_back2(not_evaled, **p);
                    (*p)++;
                    if(**p == '\n') {
                        (*line)++;
                        string_push_back2(not_evaled, **p);
                        (*p)++;
                    }
                    else if(**p != 0) {
                        string_push_back2(not_evaled, **p);
                        (*p)++;
                    }
                }
            }
            /// シングルクォート ///
            else if(!dquote && **p == '\'') {
                squote = !squote;
                string_push_back2(not_evaled, **p);
                (*p)++;
            }
            /// ダブルクォート ///
            else if(!squote && **p == '"') {
                dquote = !dquote;
                string_push_back2(not_evaled, **p);
                (*p)++;
            }
            /// 環境変数かコマンドライン展開
            else if(!squote && **p == '$') {
                // 変数 $
                if(*(*p+1) == '$' 
                            && (*(*p+2) == '{' || is_env_name_char(*(*p+2)))
                         || (*(*p+1) == '{' 
                         || is_env_name_char(*(*p+1))))
                {
                    string_push_back2(not_evaled, **p);
                    (*p)++;
                    if(**p == '$') {
                        string_push_back2(not_evaled, **p);
                        (*p)++;
                    }

                    if(**p == 0) {
                        err_msg("parse: invalid env name", sname, *line);
                        return FALSE;
                    }

                    if(**p == '{') {
                        if(!read_until_next_cbrace_end(p, not_evaled, read_end_of_statment, line_inc, sname, line))
                        {
                            return FALSE;
                        }
                    }
                    else {
                        char name[1024];
                        char* p3 = name;
                        while(is_env_name_char(**p)) {
                            *p3++ = **p;
                            (*p)++;
                        }
                        *p3 = 0;

                        string_push_back(not_evaled, name);
                    }

                    if(**p == '[') {
                        if(!read_until_next_bracket_end(p, not_evaled, read_end_of_statment, line_inc, sname, line)) {
                            return FALSE;
                        }

                        if(**p == '[') {
                            if(!read_until_next_bracket_end(p, not_evaled, read_end_of_statment, line_inc, sname, line)) {
                                return FALSE;
                            }
                        }
                    }
                    if(**p == '<') {
                        if(!read_until_next_ltgt_end(p, not_evaled, read_end_of_statment, line_inc, sname, line)) {
                            return FALSE;
                        }
                    }

                    *read_end_of_statment = 1;
                }

                // コマンド展開 $()
                else if(*(*p+1) == '$' && *(*p+2) == '('
                        || *(*p+1) == '(')
                {
                    if(*(*p+1) == '$') {
                        string_push_back2(not_evaled, **p);
                        (*p)++;
                    }
                    string_push_back2(not_evaled, **p);
                    (*p)++;

                    if(!read_until_next_paren_end(p, not_evaled, read_end_of_statment, line_inc, sname, line)) {
                        return FALSE;
                    }
                    
                    if(**p == '[') {
                        string_push_back2(not_evaled, **p);
                        (*p)++;
                        if(!read_until_next_bracket_end(p, not_evaled, read_end_of_statment, line_inc, sname, line)) {
                            return FALSE;
                        }
                    };

                    *read_end_of_statment = 1;
                }

                /// 算術演算 $(())
                else if(*(*p+1) == '(' && *(*p+2) == '(')
                {
                    string_push_back2(not_evaled, **p);
                    (*p)++;
                    string_push_back2(not_evaled, **p);
                    (*p)++;

                    if(!read_until_next_paren_end(p, not_evaled, read_end_of_statment, line_inc, sname, line)) {
                        return FALSE;
                    }

                    if(**p != ')') {
                        err_msg("parse: need ) in $(())", sname, *line);

                        return FALSE;
                    }

                    string_push_back2(not_evaled, **p);  // )
                    (*p)++;

                    *read_end_of_statment = 1;
                }
                else {
                    err_msg("invalid env name", sname, *line);
                    return FALSE;
                }
            }
            /// シングルクォート、ダブルクォート中 ///
            else if(squote || dquote) {
                if(**p == 0) {
                    err_msg("require ' or \"", sname, *line);
                    return FALSE;
                }
                else if(line_inc && **p == '\n') {
                    (*line)++;
                    string_push_back2(not_evaled, **p);
                    (*p)++;
                }
                else {
                    string_push_back2(not_evaled, **p);
                    (*p)++;
                }
            }
            else if(**p == '(') {
                nest++;
                string_push_back2(not_evaled, **p);
                (*p)++;
            }
            else if(**p == ')') {
                string_push_back2(not_evaled, **p);
                (*p)++;

                if(nest == 0) {
                    break;
                }
                nest--;
            }
            else if(**p == 0) {
                err_msg("PArse skip next paren: unexpected end(0). need )", sname, *line);
                return FALSE;
            }
            else if(line_inc && **p == '\n') {
                string_push_back2(not_evaled, **p);
                (*p)++;
                (*line)++;
            }
            else {
                string_push_back2(not_evaled, **p);
                (*p)++;
            }
        }
    }
    
    return TRUE;
}

// ブロックを取りたい関数 contentsに入る。
// 中身はもう一回パースされる
// 環境変数は対応しない
static BOOL read_block(char** p, string_obj* contents, string_obj* not_evaled, BOOL line_inc, char* sname, int* line)
{
    int line_of_head = *line;
    string_push_back2(not_evaled, **p);
    (*p)++;
    
    while(1) {
        if(**p == ' ') {
            string_push_back2(not_evaled, **p);
            string_push_back2(contents, *((*p)++));
        }
        else if(**p == '\t') {
            string_push_back2(not_evaled, **p);
            string_push_back2(contents, *((*p)++));
        }
        else if(**p == '\n') {
            line_inc && (*line)++;
            string_push_back2(not_evaled, **p);
            string_push_back2(contents, *((*p)++));
        }
        else {
            break;
        }
    }

    BOOL squote = FALSE;
    BOOL dquote = FALSE;
    int nest = 0;
    while(1) {
        /// クォート
        if(!squote && !dquote && **p == '\\') {
            string_push_back2(not_evaled, **p);
            string_push_back2(contents, *((*p)++));
            if(**p == '\n') {
                line_inc && (*line)++;
                string_push_back2(not_evaled, **p);
                string_push_back2(contents, *((*p)++));
            }
            else if(*p != 0) {
                string_push_back2(not_evaled, **p);
                string_push_back2(contents, *((*p)++));
            }
        }
        /// シングルクォート
        else if(!dquote && **p == '\'') {
            string_push_back2(not_evaled, **p);
            string_push_back2(contents, *((*p)++));
            squote = !squote;
        }
        /// ダブルクォート
        else if(!squote && **p == '"') {
            string_push_back2(not_evaled, **p);
            string_push_back2(contents, *((*p)++));
            dquote = !dquote;
        }
        /// シングルクォート、ダブルクォート中 ///
        else if(squote || dquote) {
            if(**p == 0) {
                err_msg("get block: require \" or \'", sname, line_of_head);
                return FALSE;
            }
            else if(**p == '\n') {
                line_inc && (*line)++;
                string_push_back2(not_evaled, **p);
                string_push_back2(contents, *((*p)++));
            }
            else {
                string_push_back2(not_evaled, **p);
                string_push_back2(contents, *((*p)++));
            }
        }
        else if(**p == '{') {
            string_push_back2(not_evaled, **p);
            string_push_back2(contents, *((*p)++));
            nest++;
        }
        else if(**p == '}') {
            string_push_back2(not_evaled, **p);
            (*p)++;
            nest--;

            if(nest == -1) {
                break;
            }
            else {
                string_push_back2(contents, '}');
            }
        }
        else if(**p == 0) {
            err_msg("get block: found 0. require }", sname, line_of_head);
            return FALSE;
        }
        else if(**p == '\n') {
            line_inc && (*line)++;
            string_push_back2(not_evaled, **p);
            string_push_back2(contents, **p);
            (*p)++;
        }
        else {
            string_push_back2(not_evaled, **p);
            string_push_back2(contents, **p);
            (*p)++;
        }
    }

    return TRUE;
}

// ブロックを取りたい関数 contentsに入る。
// 中身はもう一回パースされる
// 環境変数は対応しない
static BOOL read_block2(char** p, string_obj* contents, vector_obj* args, string_obj* not_evaled, BOOL line_inc, char* sname, int* line)
{
    int line_of_head = *line;
    string_push_back2(not_evaled, **p);
    (*p)++;
    
    while(1) {
        if(**p == ' ') {
            string_push_back2(not_evaled, **p);
            string_push_back2(contents, *((*p)++));
        }
        else if(**p == '\t') {
            string_push_back2(not_evaled, **p);
            string_push_back2(contents, *((*p)++));
        }
        else if(**p == '\n') {
            line_inc && (*line)++;
            string_push_back2(not_evaled, **p);
            string_push_back2(contents, *((*p)++));
        }
        else {
            break;
        }
    }

    /// 引数
    if(**p == ':') {
        string_push_back2(not_evaled, **p);
        (*p)++;

        while(**p) {
            string_obj* str = STRING_NEW("");
            skip_spaces(p, not_evaled);
            while(**p >= 'a' && **p <= 'z'
                || **p >= 'A' && **p <= 'Z'
                || **p == '_')
            {
                string_push_back2(str, **p);
                string_push_back2(not_evaled, **p);
                (*p)++;
            }
            skip_spaces(p, not_evaled);

            vector_add(args, str);

            if(**p >= 'a' && **p <= 'z'
                || **p >= 'A' && **p <= 'Z'
                || **p == '_')
            {
            }
            else {
                if(**p == ':') {
                    string_push_back2(not_evaled, **p);
                    (*p)++;
                    break;
                }
                else {
                    char buf[1024];
                    snprintf(buf, 1024, "unexpected char(%c)", **p);
                    err_msg(buf, sname, line_of_head);
                    return FALSE;
                }
            }
        }
    }

    while(1) {
        if(**p == ' ') {
            string_push_back2(not_evaled, **p);
            string_push_back2(contents, *((*p)++));
        }
        else if(**p == '\t') {
            string_push_back2(not_evaled, **p);
            string_push_back2(contents, *((*p)++));
        }
        else if(**p == '\n') {
            line_inc && (*line)++;
            string_push_back2(not_evaled, **p);
            string_push_back2(contents, *((*p)++));
        }
        else {
            break;
        }
    }

    BOOL squote = FALSE;
    BOOL dquote = FALSE;
    int nest = 0;
    while(1) {
        /// クォート
        if(!squote && !dquote && **p == '\\') {
            string_push_back2(not_evaled, **p);
            string_push_back2(contents, *((*p)++));
            if(**p == '\n') {
                line_inc && (*line)++;
                string_push_back2(not_evaled, **p);
                string_push_back2(contents, *((*p)++));
            }
            else if(*p != 0) {
                string_push_back2(not_evaled, **p);
                string_push_back2(contents, *((*p)++));
            }
        }
        /// シングルクォート
        else if(!dquote && **p == '\'') {
            string_push_back2(not_evaled, **p);
            string_push_back2(contents, *((*p)++));
            squote = !squote;
        }
        /// ダブルクォート
        else if(!squote && **p == '"') {
            string_push_back2(not_evaled, **p);
            string_push_back2(contents, *((*p)++));
            dquote = !dquote;
        }
        /// シングルクォート、ダブルクォート中 ///
        else if(squote || dquote) {
            if(**p == 0) {
                err_msg("get block: require \" or \'", sname, line_of_head);
                return FALSE;
            }
            else if(**p == '\n') {
                line_inc && (*line)++;
                string_push_back2(not_evaled, **p);
                string_push_back2(contents, *((*p)++));
            }
            else {
                string_push_back2(not_evaled, **p);
                string_push_back2(contents, *((*p)++));
            }
        }
        else if(**p == '{') {
            string_push_back2(not_evaled, **p);
            string_push_back2(contents, *((*p)++));
            nest++;
        }
        else if(**p == '}') {
            string_push_back2(not_evaled, **p);
            (*p)++;
            nest--;

            if(nest == -1) {
                break;
            }
            else {
                string_push_back2(contents, '}');
            }
        }
        else if(**p == 0) {
            err_msg("get block: found 0. require }", sname, line_of_head);
            return FALSE;
        }
        else if(**p == '\n') {
            line_inc && (*line)++;
            string_push_back2(not_evaled, **p);
            string_push_back2(contents, **p);
            (*p)++;
        }
        else {
            string_push_back2(not_evaled, **p);
            string_push_back2(contents, **p);
            (*p)++;
        }
    }

    return TRUE;
}

// 変数の添え字を取りたい関数 [3]の3や[1..2]の1と2など
BOOL parse_number(char* p, vector_obj* numbers, char* sname, int line)
{
    char number[256];
    char* p2 = number;
    while(*p) {
        /// 数字 ///
        if(*p>='0' && *p<='9' || *p == '-') {
            *p2++ = *p++;
            while(*p>='0' && *p<='9') {
                *p2++ = *p++;
            }
            *p2 = 0;
            p2 = number;

            if(*p == '.' && *(p+1) == '.') {
                p+=2;

                int number1 = atoi(number);

                if(*p>='0' && *p<='9' || *p == '-') {
                    *p2++ = *p++;
                    while(*p>='0' && *p<='9') {
                        *p2++ = *p++;
                    }
                    *p2 = 0;
                    p2 = number;
                    
                    vector_add(numbers
                        , sIndex_new(number1, atoi(number), 2));
                }
                else {
                    err_msg("invalid range", sname, line);
                    return FALSE;
                }
            }
            else {
                vector_add(numbers, sIndex_new(atoi(number), -1, 1));
            }
        }
        else if(*p == ',') {
            p++;
        }
        else if(*p == ' ' || *p == '\t') {
            p++;
        }
        else {
            err_msg("invalid range", sname, line);
            return FALSE;
        }
    }

    return TRUE;
}

static void expand_tilda(string_obj* buf, string_obj* path)
{
    char* p = string_c_str(buf);
    p++; // ~

    string_obj* user = STRING_NEW("");
    while(*p && *p != '/') {
        string_push_back2(user, *p);
        p++;
    }

    /// ユーザー名からホームディレクトリに展開
    if(string_length(user) == 0) {
        char* home = getenv("HOME");
        if(home) {
            string_push_back(path, home);
        }
        else {
            struct passwd* pw = getpwuid(getuid());
            if(pw) {
                string_push_back(path, pw->pw_dir);
            }
            else {
                string_push_back(path, "~");
            }
        }
    }
    else {
        struct passwd* pw = getpwnam(string_c_str(user));
        if(pw) {
            string_push_back(path, pw->pw_dir);
        }
        else {
            string_push_back2(path, '~');
            string_push_back(path, string_c_str(user));
        }
    }

    /// 残りを代入
    string_push_back(path, p);

    string_delete(user);
}

/// 一単語読み込み
static BOOL read_one_argument(char** p, string_obj* buf, string_obj* not_evaled, int* read_end_of_statment, sCommand* command, char* sname, int* line)
{
    /// 単語の区切り記号かどうかのテーブル 127以下なら
    static unsigned char table[] = { 
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
    1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 
    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0 };

    BOOL squote = FALSE;
    BOOL dquote = FALSE;
    while(**p) {
        if(gKitutukiSigInt) {
            gKitutukiSigInt = FALSE;
            err_msg("signal interrupt", sname, *line);

            return FALSE;
        }
        /// 空文字
        if(!squote && !dquote && **p == '"' && *(*p+1) == '"') {
            break;
        }
        else if(!dquote && !squote && **p =='\'' && *(*p+1) == '\'') {
            break;
        }
        else if(**p == '\\' && *(*p+1) == 't') {
            string_push_back2(not_evaled, **p);
            string_push_back2(not_evaled, *(*p+1));

            string_push_back2(buf, '\t');

            (*p)+=2;
        }
        else if(**p == '\\' && *(*p+1) == 'n') {
            string_push_back2(not_evaled, **p);
            string_push_back2(not_evaled, *(*p+1));

            string_push_back2(buf, '\n');

            (*p)+=2;
        }
        else if(**p == '\\' && *(*p+1) == 'r') {
            string_push_back2(not_evaled, **p);
            string_push_back2(not_evaled, *(*p+1));

            string_push_back2(buf, '\r');

            (*p)+=2;
        }
        else if(!squote && !dquote && **p == '\\') {
            string_push_back2(not_evaled, **p);
            (*p)++;

            if(**p == 0) {
                err_msg("unexpected end. can't quote null.", sname, *line);
                return FALSE;
            }
            else if(**p == '\n') {
                (*line)++;
            }

            string_push_back2(not_evaled, **p);
            string_push_back2(buf, **p);

            (*p)++;
        }
        else if(!dquote && **p == '\'') {
            string_push_back2(not_evaled, **p);
            (*p)++;
            squote = !squote;
        }
        else if(!squote && **p == '"') {
            dquote = !dquote;
            string_push_back2(not_evaled, **p);
            (*p)++;
        }
        /// 環境変数かコマンドライン展開
        else if(!squote && **p == '$') {
            // 変数 $
            if(*(*p+1) == '$' 
                        && (*(*p+2) == '{' || is_env_name_char(*(*p+2)))
                     || (*(*p+1) == '{' 
                     || is_env_name_char(*(*p+1))))
            {
                string_push_back2(not_evaled, **p);
                (*p)++;
                if(**p == '$') {
                    string_push_back2(not_evaled, **p);
                    (*p)++;
                }

                if(**p == 0) {
                    err_msg("parse: invalid env name", sname, *line);
                    return FALSE;
                }

                if(**p == '{') {
                    if(!read_until_next_cbrace_end(p, not_evaled, read_end_of_statment, TRUE, sname, line))
                    {
                        return FALSE;
                    }
                }
                else {
                    char name[1024];
                    char* p3 = name;
                    while(is_env_name_char(**p)) {
                        *p3++ = **p;
                        (*p)++;
                    }
                    *p3 = 0;

                    string_push_back(not_evaled, name);
                }

                if(**p == '[') {
                    if(!read_until_next_bracket_end(p, not_evaled, read_end_of_statment, TRUE, sname, line)) {
                        return FALSE;
                    }

                    if(**p == '[') {
                        if(!read_until_next_bracket_end(p, not_evaled, read_end_of_statment, TRUE, sname, line)) {
                            return FALSE;
                        }
                    }
                }
                if(**p == '<') {
                    if(!read_until_next_ltgt_end(p, not_evaled, read_end_of_statment, TRUE, sname, line)) {
                        return FALSE;
                    }
                }

                *read_end_of_statment = 1;
            }

            // コマンド展開 $()
            else if(*(*p+1) == '$' && *(*p+2) == '('
                    || *(*p+1) == '(')
            {
                if(*(*p+1) == '$') {
                    string_push_back2(not_evaled, **p);
                    (*p)++;
                }
                string_push_back2(not_evaled, **p);
                (*p)++;

                if(!read_until_next_paren_end(p, not_evaled, read_end_of_statment, TRUE, sname, line)) {
                    return FALSE;
                }
                
                if(**p == '[') {
                    if(!read_until_next_bracket_end(p, not_evaled, read_end_of_statment, TRUE, sname, line)) {
                        return FALSE;
                    }
                };

                *read_end_of_statment = 1;
            }

            /// 算術演算 $(())
            else if(*(*p+1) == '(' && *(*p+2) == '(')
            {
                string_push_back2(not_evaled, **p);
                (*p)++;
                string_push_back2(not_evaled, **p);
                (*p)++;

                if(!read_until_next_paren_end(p, not_evaled, read_end_of_statment, TRUE, sname, line)) {
                    return FALSE;
                }

                if(**p != ')') {
                    err_msg("parse: need ) in $(())", sname, *line);

                    return FALSE;
                }

                string_push_back2(not_evaled, **p);  // )
                (*p)++;

                *read_end_of_statment = 1;
            }
            else {
                err_msg("invalid env name", sname, *line);
                return FALSE;
            }
        }
        else if(squote || dquote) {
            if(**p == 0) {
                err_msg("close single quote or double quote", sname, *line);
                return FALSE;
            }
            else if(**p == '\n') {
                string_push_back2(not_evaled, **p);
                string_push_back2(buf, **p);
                (*line)++;

                (*p)++;
            }
            else {
                string_push_back2(not_evaled, **p);
                string_push_back2(buf, **p);

                (*p)++;
            }
        }
        /// チルダ展開 ///
        else if(string_length(buf) == 0 && **p == '~') {
            string_push_back2(not_evaled, **p);
            string_push_back2(buf, **p);
            (*p)++;

            if(command) {
                if(!read_one_argument(p, buf, not_evaled, read_end_of_statment, NULL, sname, line))
                {
                    return FALSE;
                }

                string_obj* path = STRING_NEW("");
                expand_tilda(buf, path);
                vector_add(command->mArgTmps, sArgTmp_new(0, path));
                string_put(buf, ""); // チルダ展開のパターンはmArgTmpsに追加しない
                break;
            }
        }
        /// グロブ ///
        else if(**p == '*' || command && vector_size(command->mArgTmps) > 0 && **p == '[' || **p == '?') {
            string_push_back2(not_evaled, **p);
            string_push_back2(buf, **p);
            (*p)++;

            if(command) {
                if(!read_one_argument(p, buf, not_evaled, read_end_of_statment, NULL, sname, line))
                {
                    return FALSE;
                }

                glob_t result;
                int rc = glob(string_c_str(buf), 0, NULL, &result);
                if(rc == GLOB_NOSPACE) {
                    err_msg("read_one_argument: out of space during glob operation", sname, *line);
                    return FALSE;
                }
                else if(rc == GLOB_NOMATCH) {
                }
                else {
                    int i;
                    for(i=0; i<result.gl_pathc; i++) {
                        char* file = result.gl_pathv[i];
                        if(strcmp(file, ".") != 0 && strcmp(file, "..") != 0)
                        {
                            vector_add(command->mArgTmps, sArgTmp_new(0, STRING_NEW(file)));
                        }
                    }

                    string_put(buf, ""); // グロブのパターンはmArgTmpsに追加しない
                }
                break;
            }
        }
        else if(((unsigned char)**p) > 127) {
            string_push_back2(not_evaled, **p);
            string_push_back2(buf, **p);

            (*p)++;
        }
        else if(table[**p]) {
            break;
        }
        else {
            string_push_back2(not_evaled, **p);
            string_push_back2(buf, **p);

            (*p)++;
        }
    }

    return TRUE;
}

/// if文読み込み
static BOOL read_command_parse_if_statment(char** p, sCommand* command, sStatment* statment, string_obj* not_evaled, int* read_end_of_statment, char* sname, int* line)
{
    skip_spaces(p, not_evaled);

    if(**p != '(') {
        err_msg("expected (", sname, *line);
        return FALSE;
    }

    /// 条件式読み込み ///
    string_obj* str = STRING_NEW("");
    int read_end_of_statment2 = -1;
    if(!read_until_next_paren_end(p, str, &read_end_of_statment2, FALSE, sname, line)) {
        string_delete(str);
        return FALSE;
    }
    string_push_back(not_evaled, string_c_str(str));

    string_erase(str, 0, 1);
    string_trunc(str, string_length(str)-1);

    sStatments* condition = STATMENTS_NEW();

    if(!parse(string_c_str(str), sname, line, condition))
    {
        string_delete(str);
        sStatments_delete(condition);

        return FALSE;
    }

    string_delete(str);

    skip_spaces(p, not_evaled);

    /// 実行文 ///
    sStatments* loop = STATMENTS_NEW();

    if(**p == '{') {
        string_obj* str = STRING_NEW("");
        if(!read_block(p, str, not_evaled, FALSE, sname, line)) {
            sStatments_delete(condition);
            sStatments_delete(loop);
            string_delete(str);
            return FALSE;
        }

        if(!parse(string_c_str(str), sname, line, loop))
        {
            string_delete(str);
            sStatments_delete(condition);
            sStatments_delete(loop);
            return FALSE;
        }
        string_delete(str);
    }
    else {
        err_msg("expected block.", sname, *line);
        sStatments_delete(condition);
        sStatments_delete(loop);
        return FALSE;
    }

    skip_spaces(p, not_evaled);

    vector_obj* conditions = VECTOR_NEW(30);
    vector_obj* loops = VECTOR_NEW(30);
    
    vector_add(conditions, condition);
    vector_add(loops, loop);

    /// elif 開始 ///
    if(**p == 'e' && *(*p+1) == 'l' 
        && *(*p+2) == 'i' && *(*p+3) == 'f' 
        && (*(*p+4) == ' ' || *(*p+4) == '\t' || *(*p+4) == '('))
    {
        while(**p == 'e' && *(*p+1) == 'l' && *(*p+2) == 'i' 
            && *(*p+3) == 'f' 
            && (*(*p+4) == ' ' || *(*p+4) == '\t' || *(*p+4) == '('))
        {
            string_push_back2(not_evaled, **p);
            string_push_back2(not_evaled, **p);
            string_push_back2(not_evaled, **p);
            string_push_back2(not_evaled, **p);

            (*p)+=4;

            skip_spaces(p, not_evaled);

            if(**p != '(') {
                err_msg("expected (", sname, *line);
                int k;
                for(k=0; k<vector_size(conditions); k++)
                {
                    sStatments_delete(vector_item(conditions, k));
                }
                vector_delete(conditions);

                for(k=0; k<vector_size(loops); k++)
                {
                    sStatments_delete(vector_item(loops, k));
                }
                vector_delete(loops);

                return FALSE;
            }

            /// 条件式 ///
            string_obj* str = STRING_NEW("");
            int read_end_of_statment = -1;
            if(!read_until_next_paren_end(p, str, &read_end_of_statment, FALSE, sname, line)) {
                string_delete(str);
                int k;
                for(k=0; k<vector_size(conditions); k++)
                {
                    sStatments_delete(vector_item(conditions, k));
                }
                vector_delete(conditions);

                for(k=0; k<vector_size(loops); k++)
                {
                    sStatments_delete(vector_item(loops, k));
                }
                vector_delete(loops);

                return FALSE;
            }

            sStatments* condition = STATMENTS_NEW();
            if(!parse(string_c_str(str), sname, line, condition))
            {
                string_delete(str);
                sStatments_delete(condition);
                int k;
                for(k=0; k<vector_size(conditions); k++)
                {
                    sStatments_delete(vector_item(conditions, k));
                }
                vector_delete(conditions);

                for(k=0; k<vector_size(loops); k++)
                {
                    sStatments_delete(vector_item(loops, k));
                }
                vector_delete(loops);

                return FALSE;
            }

            string_delete(str);
            vector_add(conditions, condition);

            skip_spaces(p, not_evaled);

            /// 実行文 ///
            sStatments* loop = STATMENTS_NEW();

            if(**p == '{') {
                string_obj* str = STRING_NEW("");
                if(!read_block(p, str, not_evaled, FALSE, sname, line)) {
                    string_delete(str);
                    sStatments_delete(loop);
                    int k;
                    for(k=0; k<vector_size(conditions); k++)
                    {
                        sStatments_delete(vector_item(conditions, k));
                    }
                    vector_delete(conditions);

                    for(k=0; k<vector_size(loops); k++)
                    {
                        sStatments_delete(vector_item(loops, k));
                    }
                    vector_delete(loops);

                    return FALSE;
                }

                if(!parse(string_c_str(str), sname, line, loop))
                {
                    string_delete(str);
                    sStatments_delete(loop);
                    int k;
                    for(k=0; k<vector_size(conditions); k++)
                    {
                        sStatments_delete(vector_item(conditions, k));
                    }
                    vector_delete(conditions);

                    for(k=0; k<vector_size(loops); k++)
                    {
                        sStatments_delete(vector_item(loops, k));
                    }
                    vector_delete(loops);

                    return FALSE;
                }
                string_delete(str);
            }
            else {
                err_msg("expected block.", sname, *line);
                sStatments_delete(loop);
                int k;
                for(k=0; k<vector_size(conditions); k++)
                {
                    sStatments_delete(vector_item(conditions, k));
                }
                vector_delete(conditions);

                for(k=0; k<vector_size(loops); k++)
                {
                    sStatments_delete(vector_item(loops, k));
                }
                vector_delete(loops);

                return FALSE;
            }

            skip_spaces(p, not_evaled);

            vector_add(loops, loop);
        }
    }

    /// else 開始 ///
    if(**p == 'e' && *(*p+1) == 'l' && *(*p+2) == 's' && *(*p+3) == 'e' && (*(*p+4) == ' ' || *(*p+4) == '\t' || *(*p+4) == '('))
    {
        string_push_back2(not_evaled, **p);
        string_push_back2(not_evaled, **p);
        string_push_back2(not_evaled, **p);
        string_push_back2(not_evaled, **p);
        (*p)+=4;

        skip_spaces(p, not_evaled);
        
        /// 実行文 ///
        sStatments* loop = STATMENTS_NEW();

        if(**p == '{') {
            string_obj* str = STRING_NEW("");
            if(!read_block(p, str, not_evaled, FALSE, sname, line)) {
                string_delete(str);
                sStatments_delete(loop);
                int k;
                for(k=0; k<vector_size(conditions); k++)
                {
                    sStatments_delete(vector_item(conditions, k));
                }
                vector_delete(conditions);

                for(k=0; k<vector_size(loops); k++)
                {
                    sStatments_delete(vector_item(loops, k));
                }
                vector_delete(loops);

                return FALSE;
            }

            if(!parse(string_c_str(str), sname, line, loop))
            {
                string_delete(str);
                sStatments_delete(loop);
                int k;
                for(k=0; k<vector_size(conditions); k++)
                {
                    sStatments_delete(vector_item(conditions, k));
                }
                vector_delete(conditions);

                for(k=0; k<vector_size(loops); k++)
                {
                    sStatments_delete(vector_item(loops, k));
                }
                vector_delete(loops);

                return FALSE;
            }
            string_delete(str);
        }
        else {
            err_msg("expected block.", sname, *line);
            sStatments_delete(loop);
            int k;
            for(k=0; k<vector_size(conditions); k++)
            {
                sStatments_delete(vector_item(conditions, k));
            }
            vector_delete(conditions);

            for(k=0; k<vector_size(loops); k++)
            {
                sStatments_delete(vector_item(loops, k));
            }
            vector_delete(loops);

            return FALSE;
        }

        skip_spaces(p, not_evaled);

        vector_add(loops, loop);
    }
    
    command->mKind = kIf;
    command->mExtra = sIf_new(conditions, loops);

    return TRUE;
}

/// try文読み込み
static BOOL read_command_parse_try_statment(char** p, sCommand* command, sStatment* statment, string_obj* not_evaled, int* read_end_of_statment, char* sname, int* line)
{
    skip_spaces(p, not_evaled);

    /// 文読み込み ///
    sStatments* loops = STATMENTS_NEW();

    if(**p == '{') {
        string_obj* str = STRING_NEW("");
        if(!read_block(p, str, not_evaled, FALSE, sname, line)) {
            sStatments_delete(loops);
            string_delete(str);
            return FALSE;
        }

        if(!parse(string_c_str(str), sname, line, loops))
        {
            string_delete(str);
            sStatments_delete(loops);
            return FALSE;
        }
        string_delete(str);
    }
    else {
        err_msg("expected block.", sname, *line);
        sStatments_delete(loops);
        return FALSE;
    }

    skip_spaces(p, not_evaled);

    sStatments* loops2 = STATMENTS_NEW();
    if(strstr(*p, "catch") == *p) {
        (*p)+=5;

        skip_spaces(p, not_evaled);

        if(**p == '{') {
            string_obj* str = STRING_NEW("");
            if(!read_block(p, str, not_evaled, FALSE, sname, line)) {
                sStatments_delete(loops);
                sStatments_delete(loops2);
                string_delete(str);
                return FALSE;
            }

            if(!parse(string_c_str(str), sname, line, loops2))
            {
                string_delete(str);
                sStatments_delete(loops);
                sStatments_delete(loops2);
                return FALSE;
            }
            string_delete(str);
        }
        else {
            err_msg("expected block.", sname, *line);
            sStatments_delete(loops);
            return FALSE;
        }
    }
    else {
        err_msg("expected catch word", sname, *line);
        sStatments_delete(loops);

    }

    command->mKind = kTry;
        // これが無いとmNotEvaledの場合（変数がある場合）
        // 正しくcommandが消されない
    command->mExtra = sTry_new(loops, loops2);

    return TRUE;
}

/// while文読み込み
static BOOL read_command_parse_while_statment(char** p, sCommand* command, sStatment* statment, string_obj* not_evaled, int* read_end_of_statment, char* sname, int* line)
{
    skip_spaces(p, not_evaled);

    if(**p != '(') {
        err_msg("expected (", sname, *line);
        return FALSE;
    }

    /// 条件式読み込み ///
    string_obj* str = STRING_NEW("");
    int read_end_of_statment2 = -1;
    if(!read_until_next_paren_end(p, str, &read_end_of_statment2, FALSE, sname, line)) {
        string_delete(str);
        return FALSE;
    }
    string_push_back(not_evaled, string_c_str(str));

    string_erase(str, 0, 1);
    string_trunc(str, string_length(str)-1);

    sStatments* conditions = STATMENTS_NEW();
    if(!parse(string_c_str(str), sname, line, conditions))
    {
        string_delete(str);
        sStatments_delete(conditions);
        return FALSE;
    }
    string_delete(str);

    while(**p) {
        if(**p == '\n') {
            (*line)++;
            string_push_back2(not_evaled, **p);
            (*p)++;
        }
        else if(**p == ' ' || **p == '\t') {
            string_push_back2(not_evaled, **p);
            (*p)++;
        }
        else {
            break;
        }
    }

    /// ループ文読み込み ///
    sStatments* loops = STATMENTS_NEW();

    if(**p == '{') {
        string_obj* str = STRING_NEW("");
        if(!read_block(p, str, not_evaled, FALSE, sname, line)) {
            sStatments_delete(conditions);
            sStatments_delete(loops);
            string_delete(str);
            return FALSE;
        }

        if(!parse(string_c_str(str), sname, line, loops))
        {
            string_delete(str);
            sStatments_delete(conditions);
            sStatments_delete(loops);
            return FALSE;
        }
        string_delete(str);
    }
    else {
        err_msg("expected block.", sname, *line);
        sStatments_delete(conditions);
        sStatments_delete(loops);
        return FALSE;
    }

    command->mKind = kWhile;
        // これが無いとmNotEvaledの場合（変数がある場合）
        // 正しくcommandが消されない
    command->mExtra = sWhile_new(conditions, loops);

    return TRUE;
}

/// def文読み込み
static BOOL read_command_parse_def_statment(char** p, sCommand* command, sStatment* statment, string_obj* not_evaled, int* read_end_of_statment, char* sname, int* line)
{
    skip_spaces(p, not_evaled);

    /// 関数名を得る ///
    string_obj* name = STRING_NEW("");
    while(**p >= 'a' && **p <= 'z' 
            || **p >= 'A' && **p <= 'Z'
            || **p == '_' 
            || **p >= '0' && **p <= '9')
    {
        string_push_back2(not_evaled, **p);
        string_push_back2(name, **p);
        (*p)++;
    }

    /// 引数名指定 ///
    string_obj* arg_name = STRING_NEW("");
    if(**p == '(') {
        string_push_back2(not_evaled, **p);
        (*p)++;

        skip_spaces(p, not_evaled);

        while(**p >= 'a' && **p <= 'z' 
            || **p >= 'A' && **p <= 'Z'
            || **p == '_' 
            || **p >= '0' && **p <= '9')
        {
            string_push_back2(not_evaled, **p);
            string_push_back2(arg_name, **p);
            (*p)++;
        }

        skip_spaces(p, not_evaled);

        if(**p != ')') {
            err_msg("require )", sname, *line);

            string_delete(name);
            string_delete(arg_name);

            return FALSE;
        }

        string_push_back2(not_evaled, **p);
        (*p)++;
    }

    while(**p) {
        if(**p == '\n') {
            (*line)++;
            string_push_back2(not_evaled, **p);
            (*p)++;
        }
        else if(**p == ' ' || **p == '\t') {
            string_push_back2(not_evaled, **p);
            (*p)++;
        }
        else {
            break;
        }
    }

    string_obj* contents = STRING_NEW("");
    if(**p == '{') {
        if(!read_block(p, contents, not_evaled, FALSE, sname, line)) {
            string_delete(name);
            string_delete(arg_name);
            string_delete(contents);
            return FALSE;
        }
    }
    else {
        err_msg("unexpected token at def statment", sname, *line);
        string_delete(name);
        string_delete(arg_name);
        string_delete(contents);
        return FALSE;
    }

    sStatments* statments = STATMENTS_NEW();

    if(!parse(string_c_str(contents), sname, line, statments)) 
    {
        string_delete(name);
        string_delete(arg_name);
        string_delete(contents);
        sStatments_delete(statments);

        return FALSE;
    }

    string_delete(contents);

    command->mKind = kDef;
        // これが無いとmNotEvaledの場合（変数がある場合）
        // 正しくcommandが消されない
    command->mExtra = sFunction_new(string_c_str(name), statments, string_c_str(arg_name));

    string_delete(name);
    string_delete(arg_name);

    return TRUE;
}

/// １コマンド読み込み
static BOOL read_command(char** p, sCommand* command, sStatment* statment, string_obj* not_evaled, int* read_end_of_statment, BOOL block_termination, char* sname, int* line)
{
    while(**p) {
        string_obj* buf = STRING_NEW("");

        if(!read_one_argument(p, buf, not_evaled, read_end_of_statment, command, sname, line)) {
            string_delete(buf);
            return FALSE;
        }

        /// コマンドに追加 ///
        if(strcmp(string_c_str(buf), "") != 0) {
            if(vector_size(command->mArgTmps) == 0) {
                if(strcmp(string_c_str(buf), "if") == 0) {
                    vector_add(command->mArgTmps, sArgTmp_new(0, buf));
                    string_push_back(statment->mTitle, string_c_str(buf));
                    string_push_back(statment->mTitle, " ");

                    if(!read_command_parse_if_statment(p, command, statment, not_evaled, read_end_of_statment, sname, line))
                    {
                        return FALSE;
                    }
                }
                else if(strcmp(string_c_str(buf), "while") == 0) {
                    vector_add(command->mArgTmps, sArgTmp_new(0, buf));
                    string_push_back(statment->mTitle, string_c_str(buf));
                    string_push_back(statment->mTitle, " ");

                    if(!read_command_parse_while_statment(p, command, statment, not_evaled, read_end_of_statment, sname, line))
                    {
                        return FALSE;
                    }
                }
                else if(strcmp(string_c_str(buf), "try") == 0) {
                    vector_add(command->mArgTmps, sArgTmp_new(0, buf));
                    string_push_back(statment->mTitle, string_c_str(buf));
                    string_push_back(statment->mTitle, " ");

                    if(!read_command_parse_try_statment(p, command, statment, not_evaled, read_end_of_statment, sname, line))
                    {
                        return FALSE;
                    }
                }
                else if(strcmp(string_c_str(buf), "def") == 0) {
                    vector_add(command->mArgTmps, sArgTmp_new(0, buf));
                    string_push_back(statment->mTitle, string_c_str(buf));
                    string_push_back(statment->mTitle, " ");

                    if(!read_command_parse_def_statment(p, command, statment, not_evaled, read_end_of_statment, sname, line))
                    {
                        return FALSE;
                    }
                }
                else {
                    vector_add(command->mArgTmps, sArgTmp_new(0, buf));
                    string_push_back(statment->mTitle, string_c_str(buf));
                    string_push_back(statment->mTitle, " ");
                }
            }
            else {
                vector_add(command->mArgTmps, sArgTmp_new(0, buf));
                string_push_back(statment->mTitle, string_c_str(buf));
                string_push_back(statment->mTitle, " ");
            }
        }
        else {
            /// 空文字なら
            if(**p == '\'') {
                string_push_back(not_evaled, "''");
                (*p)+=2;
                vector_add(command->mArgTmps, sArgTmp_new(0, buf));
                string_push_back(statment->mTitle, "'");
                string_push_back(statment->mTitle, " ");

                continue;
            }
            else if(**p == '"') {
                string_push_back(not_evaled, "\"\"");
                (*p)+=2;
                vector_add(command->mArgTmps, sArgTmp_new(0, buf));
                string_push_back(statment->mTitle, "\"\"");
                string_push_back(statment->mTitle, " ");

                continue;
            }
            else {
                string_delete(buf);
            }
        }
        
        /// クィック変数 ///
        if(**p == '@') {
            BOOL double_;
            if(*(*p+1) == '@') {
                double_ = TRUE;
                (*p)++;
            }
            else {
                double_ = FALSE;
            }

            /// クィックコマンド展開 ///
            if(*(*p+1) == '(') {
                string_push_back2(not_evaled, **p);
                (*p)++;

                string_obj* str = STRING_NEW("");
                int read_end_of_statment = -1;
                if(!read_until_next_paren_end(p, str, &read_end_of_statment, FALSE, sname, line)) {
                    string_delete(str);
                    return FALSE;
                }
                string_push_back(not_evaled, string_c_str(str));
                string_push_back(statment->mTitle, string_c_str(str));

                string_erase(str, 0, 1);
                string_trunc(str, string_length(str)-1);

                sStatments* statments = STATMENTS_NEW();
                if(!parse(string_c_str(str), sname, line, statments))
                {
                    string_delete(str);
                    sStatments_delete(statments);
                    return FALSE;
                }

                if(double_) {
                    vector_add(command->mArgTmps, sArgTmp_new(5, statments));
                }
                else {
                    vector_add(command->mArgTmps, sArgTmp_new(3, statments));
                }

                string_delete(str);
            }

            /// クィック変数 ///
            else {
                string_push_back2(not_evaled, **p);
                (*p)++;

                string_obj* var_name = STRING_NEW("");
                while(**p >= 'a' && **p <= 'z' 
                        || **p >= 'A' && **p <= 'Z'
                        || **p == '_' 
                        || **p >= '0' && **p <= '9')
                {
                    string_push_back2(var_name, **p);
                    string_push_back2(not_evaled, **p);
                    (*p)++;
                }

                if(string_c_str(var_name)[0] == 0) {
                    err_msg("invalid quick var", sname, *line);
                    string_delete(var_name);
                    return FALSE;
                }

                string_obj* index = STRING_NEW("");
                if(**p == '[') {
                    if(!read_until_next_bracket_end(p, index, read_end_of_statment, TRUE, sname, line))
                    {
                        string_delete(index);
                        string_delete(var_name);
                        return FALSE;
                    }
                    string_push_back(not_evaled, string_c_str(index));

                    string_erase(index, 0, 1);
                    string_trunc(index, string_length(index)-1);
                }

                string_obj* index2 = STRING_NEW("");
                if(**p == '[') {
                    if(!read_until_next_bracket_end(p, index2, read_end_of_statment, TRUE, sname, line))
                    {
                        string_delete(index);
                        string_delete(index2);
                        string_delete(var_name);
                        return FALSE;
                    }
                    string_push_back(not_evaled, string_c_str(index2));

                    string_erase(index2, 0, 1);
                    string_trunc(index2, string_length(index2)-1);
                }

                string_obj* delimiter;
                if(**p == '<') {
                    delimiter = STRING_NEW("");
                    if(!read_until_next_ltgt_end(p, delimiter, read_end_of_statment, TRUE, sname, line))
                    {
                        string_delete(var_name);
                        string_delete(delimiter);
                        string_delete(index);
                        string_delete(index2);

                        return FALSE;
                    }

                    string_push_back(not_evaled, string_c_str(delimiter));

                    string_erase(delimiter, 0, 1);
                    string_trunc(delimiter, string_length(delimiter)-1);

                    string_obj* delimiter_ = STRING_NEW("");
                    if(!expand_line_field(string_c_str(delimiter), delimiter_, sname, line)) {
                        string_delete(var_name);
                        string_delete(delimiter);
                        string_delete(delimiter_);
                        string_delete(index);
                        string_delete(index2);

                        return FALSE;
                    }

                    string_delete(delimiter);
                    delimiter = delimiter_;
                }
                else {
                    delimiter = STRING_NEW("\n");
                }

                if(double_) {
                    vector_add(command->mArgTmps, sArgTmp_new(4
                        , sVar_new(var_name, index, index2, delimiter)));
                }
                else {
                    vector_add(command->mArgTmps, sArgTmp_new(1
                        , sVar_new(var_name, index, index2, delimiter)));
                }
            }
        }
        /// リダイレクト・プロセス置換
        else if(**p == '>') {
            /// プロセス置換 ///
            if(*(*p+1) == '(') {
                string_push_back2(not_evaled, **p);
                (*p)++;

                if(!read_until_next_paren_end(p, not_evaled, read_end_of_statment, TRUE, sname, line)) {
                    return FALSE;
                }
                
                *read_end_of_statment = 1;
            }
            else if(*(*p+1) == '>') {
                string_push_back(not_evaled, ">>");
                (*p)+=2;
                int fd = 1;
                enum eRedirect type = kRedirectAppend;
                vector_add(command->mArgTmps
                        , sArgTmp_new(2, sRedirectTmp_new(type, fd)));

                skip_spaces(p, not_evaled);
            }
            else {
                string_push_back(not_evaled, ">");
                (*p)++;
                int fd = 1;
                enum eRedirect type = kRedirectOverwrite;
                vector_add(command->mArgTmps
                        , sArgTmp_new(2, sRedirectTmp_new(type, fd)));

                skip_spaces(p, not_evaled);
            }
        }
        /// リダイレクト・プロセス置換 ///
        else if(**p == '<') {
            /// プロセス置換 ///
            if(*(*p+1) == '(') {
                string_push_back2(not_evaled, **p);
                (*p)++;

                if(!read_until_next_paren_end(p, not_evaled, read_end_of_statment, TRUE, sname, line)) {
                    return FALSE;
                }
                
                *read_end_of_statment = 1;
            }
            else if(*(*p+1) == '>') {
                (*p)+=2;

                string_push_back(not_evaled, "read");
                string_push_back(statment->mTitle, "read");

                vector_add(command->mArgTmps, sArgTmp_new(0, STRING_NEW("read")));
            }
            else {
                (*p)++;
                string_push_back(not_evaled, "<");
                int fd = 0;
                enum eRedirect type = kRedirectInput;
                vector_add(command->mArgTmps
                        , sArgTmp_new(2, sRedirectTmp_new(type, fd)));

                skip_spaces(p, not_evaled);
            }
        }
        /// リダイレクト ///
        else if(**p == '%') {
            if(*(*p+1) == '>' && *(*p+2) == '>') {
                string_push_back(not_evaled, "%>>");
                break;
            }
            else if(*(*p+1) == '2' && *(*p+2) == '>' && *(*p+3) == '>') 
            {
                string_push_back(not_evaled, "%2>>");
                (*p)+=4;
                int fd = 2;
                enum eRedirect type = kRedirectAppend;
                vector_add(command->mArgTmps
                        , sArgTmp_new(2, sRedirectTmp_new(type, fd)));

                skip_spaces(p, not_evaled);
            }
            else if(*(*p+1) == '2' && *(*p+2) == '>') {
                string_push_back(not_evaled, "%2>");
                (*p)+=3;
                int fd = 2;
                enum eRedirect type = kRedirectOverwrite;
                vector_add(command->mArgTmps
                        , sArgTmp_new(2, sRedirectTmp_new(type, fd)));

                skip_spaces(p, not_evaled);
            }
            else if(*(*p+1) == '>') {
                string_push_back(not_evaled, "%>");
                (*p)+=2;

                int fd = 0;
                enum eRedirect type = kRedirectErrAndOutput;
                vector_add(command->mArgTmps
                        , sArgTmp_new(2, sRedirectTmp_new(type, fd)));

                skip_spaces(p, not_evaled);
            }
            else {
                char buf[128];
                snprintf(buf, 128, "unexpected token1 --> %c", **p);
                err_msg(buf, sname, *line);
                return FALSE;
            }
        }
        /// 空白 ///
        else if(**p == ' ' || **p == '\t') {
            skip_spaces(p, not_evaled);
        }
        /// サブシェル ///
        else if(**p == '(') {
            if(vector_size(command->mArgTmps) == 0) {
                string_obj* str = STRING_NEW("");
                int read_end_of_statment = -1;
                if(!read_until_next_paren_end(p, str, &read_end_of_statment, TRUE, sname, line)) {
                    string_delete(str);
                    return FALSE;
                }
                string_push_back(not_evaled, string_c_str(str));
                string_push_back(statment->mTitle, string_c_str(str));

                string_erase(str, 0, 1);
                string_trunc(str, string_length(str)-1);

                sStatments* statments = STATMENTS_NEW();
                if(!parse(string_c_str(str), sname, line, statments))
                {
                    string_delete(str);
                    sStatments_delete(statments);
                    return FALSE;
                }

                command->mKind= kSubshell;
                vector_add(command->mArgTmps, sArgTmp_new(0, STRING_NEW("subshell")));
                command->mExtra = sSubshell_new(statments);

                string_delete(str);
            }
            else {
                char buf[128];
                snprintf(buf, 128, "unexpected token2 --> %c", **p);
                err_msg(buf, sname, *line);
                return FALSE;
            }
        }
        /// ブロック ///
        else if(**p == '{') {
            string_obj* str = STRING_NEW("");
            vector_obj* args = VECTOR_NEW(10);
            if(!read_block2(p, str, args, not_evaled, FALSE, sname, line)) {
                string_delete(str);
                int i;
                for(i=0; i<vector_size(args); i++) {
                    string_delete(vector_item(args, i));
                }
                vector_delete(args);
                return FALSE;
            }

            sStatments* block = STATMENTS_NEW();
            if(!parse(string_c_str(str), sname, line, block))
            {
                string_delete(str);
                sStatments_delete(block);
                int i;
                for(i=0; i<vector_size(args); i++) {
                    string_delete(vector_item(args, i));
                }
                vector_delete(args);
                return FALSE;
            }

            vector_add(command->mArgTmps, sArgTmp_new(6, sBlock_new(block, args)));

            string_push_back(statment->mTitle, string_c_str(str));
            string_push_back(statment->mTitle, " ");

            skip_spaces(p, not_evaled);
            string_delete(str);
        }
        else {
            break;
        }
    }

    return TRUE;
}

/// read_statmentの子関数
static BOOL read_statment_add_command_to_statment(int* read_end_of_statment, sCommand* command, sStatment* statment, char* sname, int* line)
{
    /// 文に追加 ///
    if(*read_end_of_statment == -1 
        && vector_size((command)->mArgTmps) > 0) 
    {
        /// mArgTmps --> mArgsの変換とリダイレクトをmRedirectsに展開 ///
        /// コマンド名が!かチェック
        int k;
        for(k=0; k<vector_size(command->mArgTmps); k++) {
            sArgTmp* arg = vector_item(command->mArgTmps, k);

            // 普通の文字列の引数
            if(arg->mKind == 0) {
                if(vector_size(statment->mCommands) == 0 && strcmp(string_c_str(arg->mBody), "!") == 0 && k==0) 
                {
                    statment->mRCodeReverse = TRUE;
                }
                else {
                    vector_add(command->mArgs
                        , sArg_new(0, STRING_NEW(string_c_str(arg->mBody))));
                }
            }
            /// 変数
            else if(arg->mKind == 1) {
                vector_add(command->mArgs, sArg_new(1, arg->mBody));
                arg->mBody = NULL; // FREEされないように
            }
            /// 変数2
            else if(arg->mKind == 4) {
                vector_add(command->mArgs, sArg_new(3, arg->mBody));
                arg->mBody = NULL; // FREEされないように
            }
            // リダイレクトの引数
            else if(arg->mKind == 2) {
                sRedirectTmp* redirect2 = arg->mBody;

                if(redirect2->mType == kRedirectErrAndOutput) {
                    vector_add(command->mRedirects
                        , sRedirect_new(kRedirectErrAndOutput, 0, ""));
                }
                else {
                    if(k+1 >= vector_size(command->mArgTmps)) {
                        err_msg("invalid redirect file name", sname, *line);
                        return FALSE;
                    }
                    sArgTmp* next_arg = vector_item(command->mArgTmps, k+1);
                    if(next_arg->mKind != 0) {
                        err_msg("invalid redirect file name", sname, *line);
                        return FALSE;
                    }
                    vector_add(command->mRedirects
                        , sRedirect_new(redirect2->mType
                            , redirect2->mFd
                                    , string_c_str(next_arg->mBody)));
                    k++;
                }
            }
            else if(arg->mKind == 3) {
                vector_add(command->mArgs, sArg_new(2, arg->mBody));
                arg->mBody = NULL; // FREEされないように
            }
            else if(arg->mKind == 6) {
                vector_add(command->mArgs, sArg_new(5, arg->mBody));
                arg->mBody = NULL; // FREEされないように
            }
            else {
                vector_add(command->mArgs, sArg_new(4, arg->mBody));
                arg->mBody = NULL; // FREEされないように
            }
        }

        /// コマンド名からコマンド種別を得る ///
        sArg* arg = vector_item(command->mArgs, 0);
        if(arg->mKind == 0) {
            command->mKind = get_command_kind(string_c_str(arg->mBody));
        }
        else {
err_msg("invalid command name", sname, *line);
return FALSE;
        }

        vector_add(statment->mCommands, command);
    }
    else {
        sCommand_delete(command);
    }
    
    return TRUE;
}

/// 一文読み込み
static BOOL read_statment(char**p, sStatment* statment, string_obj* not_evaled, int* read_end_of_statment, BOOL block_termination, char* sname, int* line)
{
    /// 反転 ///
    if(**p == '!') {
        string_push_back2(not_evaled, '!');
        (*p)++;
        statment->mRCodeReverse = TRUE;

        skip_spaces(p, not_evaled);
    }

    /// グローバルパイプ, STDINパイプ ///
    if(**p == '|' && *(*p+1) == '>') {
        string_push_back2(not_evaled, **p);
        (*p)++;
        string_push_back2(not_evaled, **p);
        (*p)++;

        statment->mGlobalPipeIn = 1;

        if(**p >= '0' && **p <= '9'|| **p == '-') {
            string_obj* number = STRING_NEW("");
            if(**p == '-') {
                string_push_back2(number, **p);
                (*p)++;
            }
            while(**p >= '0' && **p <= '9') {
                string_push_back2(number, **p);
                (*p)++;
            }

            skip_spaces(p, not_evaled);

            sCommand* command = COMMAND_NEW();
            vector_add(command->mArgTmps, sArgTmp_new(0, STRING_NEW("lines")));
            vector_add(command->mArgTmps, sArgTmp_new(0, number));
            if(!read_statment_add_command_to_statment(read_end_of_statment, command, statment, sname, line)) 
            {
                sCommand_delete(command);
                return FALSE;
            }

            command = COMMAND_NEW();
            vector_add(command->mArgTmps, sArgTmp_new(0, STRING_NEW("chomp")));
            if(!read_statment_add_command_to_statment(read_end_of_statment, command, statment, sname, line)) 
            {
                sCommand_delete(command);
                return FALSE;
            }
        }

        skip_spaces(p, not_evaled);
    }
    else if(**p == '|' && *(*p+1) == '-') {
        string_push_back2(not_evaled, **p);
        (*p)++;
        string_push_back2(not_evaled, **p);
        (*p)++;

        statment->mGlobalPipeIn = 2;

        skip_spaces(p, not_evaled);
    }
    else if(**p == '|' && *(*p+1) == '~') {
        string_push_back2(not_evaled, **p);
        (*p)++;
        string_push_back2(not_evaled, **p);
        (*p)++;

        statment->mGlobalPipeIn = 3;

        skip_spaces(p, not_evaled);
    }
    else if(**p == '|' && *(*p+1) >= '0' && *(*p+1) <= '9') {
        string_push_back2(not_evaled, **p);
        (*p)++;
        int num = **p - '0';
        string_push_back2(not_evaled, **p);
        (*p)++;

        statment->mGlobalPipeIn = 4;
        statment->mGlobalPipeInNum = num;

        skip_spaces(p, not_evaled);
    }
    else if(**p == '|' && *(*p+1) != '|') {
        string_push_back2(not_evaled, **p);
        (*p)++;

        skip_spaces(p, not_evaled);

        sCommand* command = COMMAND_NEW();

        vector_add(command->mArgTmps, sArgTmp_new(0, STRING_NEW("read")));
        vector_add(command->mArgTmps, sArgTmp_new(0, STRING_NEW("-p")));
        vector_add(command->mArgTmps, sArgTmp_new(0, STRING_NEW("-a")));

        if(!read_statment_add_command_to_statment(read_end_of_statment, command, statment, sname, line)) 
        {
            sCommand_delete(command);
            return FALSE;
        }
    }

    while(**p) {
        sCommand* command = COMMAND_NEW();
        if(!read_command(p, command, statment, not_evaled, read_end_of_statment, block_termination, sname, line)) 
        {
            sCommand_delete(command);
            return FALSE;
        }

        if(!read_statment_add_command_to_statment(read_end_of_statment, command, statment, sname, line)) 
        {
            sCommand_delete(command);
            return FALSE;
        }
        else if(**p == '|' && *(*p+1) != '~' && *(*p+1) != '-' && *(*p+1) != '>' && (*(*p+1) < '0' || *(*p+1) > '9') && *(*p+1) != '|')
        {
            string_push_back(not_evaled, "|");
            (*p)++;
        }
        else {
            break;
        }
    }

    return TRUE;
}

/// エラー時はgErrMsgにエラーメッセージがあるので出力してください
BOOL parse(char* cmdline, char* sname, int* line, sStatments* statments)
{
    char* p = cmdline;

    while(*p) {
        /// 行前のスペースを削除 ///
        while(*p == ' ' || *p == '\t' || *p == '\n' && (*line)++) { p++; }

        /// 開始 ///
        sStatment* statment = STATMENT_NEW();
        string_obj* not_evaled = STRING_NEW("");
        int read_end_of_statment = -1;
            // このフラグに行番号が入っていたら環境変数
            // かコマンドライン展開があったので行末まで読み込む
        int line_of_head = *line;

        if(!read_statment(&p, statment, not_evaled, &read_end_of_statment, FALSE, sname, line))
        {
            sStatment_delete(statment);
            string_delete(not_evaled);
            return FALSE;
        }

        /// グローバルパイプ
        if(*p == '|' && *(p+1) == '~') {
            string_push_back(not_evaled, "|");
            p++;
            string_push_back(not_evaled, "~");
            p++;

            if(*p == '>') {
                string_push_back(not_evaled, ">");
                p++;
                statment->mGlobalPipeOut = 0x18;
            }
            else {
                statment->mGlobalPipeOut = 8;
            }

            skip_spaces(&p, not_evaled);

        }
        else if(*p == '|' && *(p+1) == '-') {
            string_push_back(not_evaled, "|");
            p++;
            string_push_back(not_evaled, "-");
            p++;

            if(*p == '>') {
                string_push_back(not_evaled, ">");
                p++;
                statment->mGlobalPipeOut = 0x12;
            }
            else {
                statment->mGlobalPipeOut = 2;
            }

            skip_spaces(&p, not_evaled);
        }
        else if(*p == '|' && *(p+1) >= '0' && *(p+1) <= '9') {
            string_push_back(not_evaled, "|");
            p++;
            int num = *p - '0';
            string_push_back2(not_evaled, *p);
            p++;

            if(*p == '>') {
                string_push_back(not_evaled, ">");
                p++;
                statment->mGlobalPipeOut = 0x14;
                statment->mGlobalPipeOutNum = num;
            }
            else {
                statment->mGlobalPipeOut = 4;
                statment->mGlobalPipeOutNum = num;
            }

            skip_spaces(&p, not_evaled);
        }

        else if(*p == '|' && *(p+1) == '>') {
            string_push_back(not_evaled, "|");
            p++;
            string_push_back(not_evaled, ">");
            p++;

            if(*p == '>') {
                string_push_back(not_evaled, ">");
                p++;
                statment->mGlobalPipeOut = 0x11;
            }
            else {
                statment->mGlobalPipeOut = 0x01;
            }

            skip_spaces(&p, not_evaled);
        }

        /// 文の区切り
        if(*p == '&' && *(p+1) == '&') {
            string_push_back(not_evaled, "&&");
            p+=2;
            statment->mTerminated = kTAndAnd;
            statment->mLine = line_of_head;
            string_put(statment->mFName, sname);

            skip_spaces(&p, not_evaled);
        }
        else if(*p == '|' && *(p+1) == '|') {
            string_push_back(not_evaled, "||");
            p+=2;

            statment->mTerminated = kTOrOr;
            statment->mLine = line_of_head;
            string_put(statment->mFName, sname);

            skip_spaces(&p, not_evaled);
        }
        else if(*p == '&') {
            string_push_back2(not_evaled, '&');
            p++;

            statment->mBackground = TRUE;
            statment->mTerminated = kTNormal;
            statment->mLine = line_of_head;
            string_put(statment->mFName, sname);

            skip_spaces(&p, not_evaled);
        }
        else if(*p == '\n') {
            statment->mTerminated = kTNormal;
            statment->mLine = line_of_head;
            string_put(statment->mFName, sname);

            (*line)++;
            string_push_back2(not_evaled, '\n');
            p++; 
            skip_spaces(&p, not_evaled);
        }
        else if(*p == ';') {
            statment->mTerminated = kTNormal;
            statment->mLine = line_of_head;
            string_put(statment->mFName, sname);

            string_push_back2(not_evaled, ';');
            p++;
            skip_spaces(&p, not_evaled);
        }
        else if(*p == 0) {
            statment->mTerminated = kTNormal;
            statment->mLine = line_of_head;
            string_put(statment->mFName, sname);
        }
        else {
            char buf[128];
            snprintf(buf, 128, "unexpected token3 -->%c\n", *p);
            err_msg(buf, sname, *line);
            sStatment_delete(statment);
            string_delete(not_evaled);
            return FALSE;
        }

        if(read_end_of_statment != -1) {
            statment->mNotEvaled = not_evaled;
        }
        else {
            string_delete(not_evaled);
        }

        if(vector_size(statment->mCommands) > 0 
            || statment->mNotEvaled != NULL) 
        {
            vector_add(statments->mStatments, statment);
        }
        else {
            sStatment_delete(statment);
        }
    }

    return TRUE;
}

sIndex* sIndex_new(int num, int num2, int num_num)
{
    sIndex* self = MALLOC(sizeof(sIndex));

    self->number = num;
    self->number2 = num2;
    self->number_num = num_num;

    return self;
}

void sIndex_delete(sIndex* self)
{
    FREE(self);
}

static BOOL expand_line_field(char* str, string_obj* out, char* sname, int* line)
{
    char* p = str;
    while(*p) {
        if(gKitutukiSigInt) {
            gKitutukiSigInt = FALSE;
            err_msg("signal interrupt", sname, *line);
            return FALSE;
        }
        if(*p == '\\') {
            p++;
            if(*p == 'n') {
                string_push_back2(out, '\n');
                p++;
            }
            else if(*p == 'r') {
                string_push_back2(out, '\r');
                p++;
            }
            else if(*p == 't') {
                string_push_back2(out, '\t');
                p++;
            }
            else {
                string_push_back2(out, *p++);
            }
        }
        else {
            string_push_back2(out, *p++);
        }
    }

    return TRUE;
}

// 文字列をクォートして返す
static BOOL expand_env_get_quoted_str(char* fname, string_obj* quoted_fname, char* sname, int* line)
{
    char* p = fname;
    while(*p) {
        if(gKitutukiSigInt) {
            gKitutukiSigInt = FALSE;
            err_msg("signal interrupt", sname, *line);
            return FALSE;
        }
        if(*p == '\n') {
            string_push_back(quoted_fname, "\\n");
            p++;
        }
        else if(*p == '\r') {
            string_push_back(quoted_fname, "\\r");
            p++;
        }
        else if(*p == '\t') {
            string_push_back(quoted_fname, "\\t");
            p++;
        }
        else if(*p==' ' || *p=='*' || *p=='>' || *p=='&' || *p=='~'
                || *p=='#' || *p =='$' || *p=='(' || *p==')'
                || *p=='\\' || *p=='|' || *p=='[' || *p==']' || *p=='{' 
                || *p=='}' || *p==';'
                || *p=='\'' || *p=='"' || *p=='<' || *p=='>' || *p=='?' 
                || *p=='%' || *p=='@')
        {
            string_push_back2(quoted_fname, '\\');
            string_push_back2(quoted_fname, *p++);
        }
        else {
            string_push_back2(quoted_fname, *p++);
        }
    }

    return TRUE;
}

// 添え字を元にコマンドラインに実際に変数を展開したい関数(クォートする)
static BOOL expand_env_expand_env_quoted(string_obj* cmdline2, char* env, vector_obj* numbers, char* sname, int* line)
{
    /// 添え字なし ///
    if(vector_size(numbers) == 0)
    {
        string_obj* env2 = STRING_NEW("");
        if(!expand_env_get_quoted_str(env, env2, sname, line)) {
            string_delete(env2);
            return FALSE;
        }
        string_push_back(cmdline2, string_c_str(env2));
        string_delete(env2);
    }
    /// 添え字あり ///
    else {
        int i;
        for(i=0; i<vector_size(numbers); i++) {
            sIndex* index = vector_item(numbers, i);

            /// 添え字がふたつ ///
            if(index->number_num == 2) {
                int n = index->number;
                int n2 = index->number2;

                if(n < 0) {
                    n = str_kanjilen(gKanjiCode, env) + n;
                }

                if(n2 < 0) {
                    n2 = str_kanjilen(gKanjiCode, env) + n2;
                }

                if(n< 0) { n = 0; }
                if(n>=str_kanjilen(gKanjiCode, env)) {
                    n = str_kanjilen(gKanjiCode, env) -1;
                }

                if(n2< 0) { n2 = 0; }
                if(n2>=str_kanjilen(gKanjiCode, env)) {
                    n2 = str_kanjilen(gKanjiCode, env) -1;
                }

                if(n <= n2)
                {
                    char* p1 = str_kanjipos2pointer(gKanjiCode, env, n);
                    char* p2 = str_kanjipos2pointer(gKanjiCode, env, n2+1);

                    char* buf = MALLOC(p2-p1+1);
                    memcpy(buf, p1, p2-p1);
                    buf[p2-p1] = 0;
           
                    string_obj* str2 = STRING_NEW("");
                    if(!expand_env_get_quoted_str(buf, str2, sname, line)) {
                        string_delete(str2);
                        return FALSE;
                    }
                    string_push_back(cmdline2, string_c_str(str2));
                    string_delete(str2);

                    FREE(buf);
                }
                else {
                    err_msg("expand env: invalid [] range", sname, *line);
                    return FALSE;
                }
            }
            /// 添え字が一つ ///
            else {
                int n = index->number;

                if(n < 0) {
                    n = str_kanjilen(gKanjiCode, env) + n;
                }

                if(n< 0) { n = 0; }
                if(n>=str_kanjilen(gKanjiCode, env)) {
                    n = str_kanjilen(gKanjiCode, env) -1;
                }

                char str[MB_CUR_MAX+1];
                char* p1 = str_kanjipos2pointer(gKanjiCode, env, n);
                char* p2 = str_kanjipos2pointer(gKanjiCode, env, n + 1);

                memcpy(str, p1, p2-p1);
                str[p2-p1] = 0;

                string_obj* str2 = STRING_NEW("");
                if(!expand_env_get_quoted_str(str, str2, sname, line))  {
                    string_delete(str2);
                    return FALSE;
                }
                string_push_back(cmdline2, string_c_str(str2));
                string_delete(str2);
            }
        }
    }

    return TRUE;
}

// 添え字を元に変数をコマンドラインに展開したい関数(クォートしない)
static BOOL expand_env_expand_env(string_obj* cmdline2, char* env, vector_obj* numbers, char* sname, int* line)
{
    if(vector_size(numbers) == 0)
    {
        string_obj* env3 = STRING_NEW("");
        get_quoted_linefield(env, env3);
        string_push_back(cmdline2, string_c_str(env3));
        string_delete(env3);
    }
    else {
        int i;
        for(i=0; i<vector_size(numbers); i++) {
            sIndex* index = vector_item(numbers, i);

            if(index->number_num == 2) {
                int n = index->number;
                int n2 = index->number2;

                if(n < 0) {
                    n = str_kanjilen(gKanjiCode, env) + n;
                }

                if(n2 < 0) {
                    n2 = str_kanjilen(gKanjiCode, env) + n2;
                }

                if(n< 0) { n = 0; }
                if(n>=str_kanjilen(gKanjiCode, env)) {
                    n = str_kanjilen(gKanjiCode, env) -1;
                }
                if(n2< 0) { n2 = 0; }
                if(n2>=str_kanjilen(gKanjiCode, env)) {
                    n2 = str_kanjilen(gKanjiCode, env) -1;
                }

                if(n <= n2) {
                    char* p1 = str_kanjipos2pointer(gKanjiCode, env, n);
                    char* p2 = str_kanjipos2pointer(gKanjiCode, env, n2+1);

                    char* buf = MALLOC(p2-p1+1);
                    memcpy(buf, p1, p2-p1);
                    buf[p2-p1] = 0;
            
                    string_obj* env3 = STRING_NEW("");
                    get_quoted_linefield(buf, env3);
                    string_push_back(cmdline2, string_c_str(env3));
                    string_delete(env3);

                    FREE(buf);
                }
                else {
                    err_msg("expand_env: invalid [] range", sname, *line);
                    return FALSE;
                }
            }
            else {
                int n = index->number;

                if(n < 0) {
                    n = str_kanjilen(gKanjiCode, env) + n;
                }

                if(n< 0) { n = 0; }
                if(n>=str_kanjilen(gKanjiCode, env)) {
                    n = str_kanjilen(gKanjiCode, env) -1;
                }

                char str[MB_CUR_MAX+1];
                char* p1 = str_kanjipos2pointer(gKanjiCode, env, n);
                char* p2 = str_kanjipos2pointer(gKanjiCode, env, n + 1);

                memcpy(str, p1, p2-p1);
                str[p2-p1] = 0;

                string_obj* env3 = STRING_NEW("");
                get_quoted_linefield(str, env3);
                string_push_back(cmdline2, string_c_str(env3));
                string_delete(env3);
            }
        }
    }

    return TRUE;
}

BOOL expand_env_main(char** p, string_obj* out, sRFd* rfd, char* sname, int* line)
{
    BOOL quote;

    if(*(*p+1) == '$') {
        (*p)+=2;
        quote = FALSE;
    }
    else {
        (*p)++;
        quote = TRUE;
    }

    string_obj* name = STRING_NEW("");
    if(**p == '{') {
        int read_end_of_statment = -1;
        if(!read_until_next_cbrace_end(p, name, &read_end_of_statment, FALSE, sname, line)) {
            string_delete(name);
            return FALSE;
        }

        string_erase(name, 0, 1);
        string_trunc(name, string_length(name)-1);

        if(read_end_of_statment != -1) {
            string_obj* name2 = STRING_NEW("");
            if(!expand_env(string_c_str(name), name2, rfd, sname, line)) {
                string_delete(name);
                string_delete(name2);
                return FALSE;
            }

            string_delete(name);
            name = name2;
        }
    }
    else {
        while(is_env_name_char(**p)) {
            string_push_back2(name, **p);
            (*p)++;
        }
    }

    string_obj* index = STRING_NEW("");
    BOOL exist_index = FALSE;
    if(**p == '[') {
        exist_index = TRUE;
        int read_end_of_statment = -1;
        if(!read_until_next_bracket_end(p, index, &read_end_of_statment, FALSE, sname, line))
        {
            string_delete(name);
            string_delete(index);
            return FALSE;
        }

        string_erase(index, 0, 1);
        string_trunc(index, string_length(index)-1);
        
        if(read_end_of_statment != -1) {
            string_obj* index_ = STRING_NEW("");
            if(!expand_env(string_c_str(index), index_, rfd, sname, line)) {
                string_delete(index);
                string_delete(index_);
                string_delete(name);
                return FALSE;
            }

            string_delete(index);
            index = index_;
        }
    }

    string_obj* index2 = STRING_NEW("");
    if(**p == '[') {
        int read_end_of_statment = -1;
        if(!read_until_next_bracket_end(p, index2, &read_end_of_statment, FALSE, sname, line))
        {
            string_delete(name);
            string_delete(index);
            string_delete(index2);
            return FALSE;
        }

        string_erase(index2, 0, 1);
        string_trunc(index2, string_length(index2)-1);
        
        if(read_end_of_statment != -1) {
            string_obj* index2_ = STRING_NEW("");
            if(!expand_env(string_c_str(index2), index2_, rfd, sname, line)) {
                string_delete(index);
                string_delete(index2);
                string_delete(index2_);
                string_delete(name);
                return FALSE;
            }

            string_delete(index2);
            index2 = index2_;
        }
    }

    string_obj* delimiter = STRING_NEW("");
    if(**p == '<') {
        int read_end_of_statment = -1;
        if(!read_until_next_ltgt_end(p, delimiter, &read_end_of_statment, FALSE, sname, line))
        {
            string_delete(name);
            string_delete(delimiter);
            string_delete(index);
            string_delete(index2);
            return FALSE;
        }

        string_erase(delimiter, 0, 1);
        string_trunc(delimiter, string_length(delimiter)-1);

        if(read_end_of_statment != -1) {
            string_obj* delimiter2 = STRING_NEW("");
            if(!expand_env(string_c_str(delimiter), delimiter2, rfd, sname, line)) {
                string_delete(name);
                string_delete(delimiter);
                string_delete(delimiter2);
                string_delete(index);
                string_delete(index2);
                return FALSE;
            }

            string_delete(delimiter);
            delimiter = delimiter2;
        }
    }
    else {
        string_put(delimiter, "\\n");
    }

    /// ローカル変数を参照
    string_obj* var;
    if(vector_size(gStackFrame) == 0) {
        /// グローバル変数を参照 ///
        var = hash_item(gGlobals, string_c_str(name));
    }
    else {
        /// ローカル変数を参照 ///
        hash_obj* top_stack
             = vector_item(gStackFrame, vector_size(gStackFrame)-1);
        var = hash_item(top_stack, string_c_str(name));
        /// グローバル変数を参照 ///
        if(var == NULL) {
            var = hash_item(gGlobals, string_c_str(name));
        }
    }

    /// グローバル変数かローカル変数 //
    if(var) {
        vector_obj* numbers = VECTOR_NEW(10);
        if(!parse_number(string_c_str(index), numbers, sname, *line)) {
            string_delete(name);
            string_delete(delimiter);
            string_delete(index);
            string_delete(index2);
            int k;
            for(k=0; k<vector_size(numbers); k++) {
                sIndex_delete(vector_item(numbers, k));
            }
            vector_delete(numbers);
            return FALSE;
        }

        if(quote) {
            if(!expand_env_expand_env_quoted(out, string_c_str(var), numbers, sname, line))
            {
                string_delete(name);
                string_delete(delimiter);
                string_delete(index);
                string_delete(index2);
                int k;
                for(k=0; k<vector_size(numbers); k++) {
                    sIndex_delete(vector_item(numbers, k));
                }
                vector_delete(numbers);
                return FALSE;
            }
        }
        else {
            if(!expand_env_expand_env(out, string_c_str(var) , numbers, sname, line)) {
                string_delete(name);
                string_delete(delimiter);
                string_delete(index);
                string_delete(index2);
                int k;
                for(k=0; k<vector_size(numbers); k++) {
                    sIndex_delete(vector_item(numbers, k));
                }
                vector_delete(numbers);
                return FALSE;
            }
        }

        int k;
        for(k=0; k<vector_size(numbers); k++) {
            sIndex_delete(vector_item(numbers, k));
        }
        vector_delete(numbers);
    }
    else {
        /// 環境変数を参照 ///
        char* env = getenv(string_c_str(name));

        if(env) {
            vector_obj* numbers = VECTOR_NEW(10);
            if(!parse_number(string_c_str(index), numbers, sname, *line)) {
                string_delete(name);
                string_delete(delimiter);
                string_delete(index);
                string_delete(index2);
                int k;
                for(k=0; k<vector_size(numbers); k++) {
                    sIndex_delete(vector_item(numbers, k));
                }
                vector_delete(numbers);
                return FALSE;
            }

            if(quote) {
                if(!expand_env_expand_env_quoted(out, env, numbers, sname, line)) {
                    string_delete(name);
                    string_delete(delimiter);
                    string_delete(index);
                    string_delete(index2);
                    int k;
                    for(k=0; k<vector_size(numbers); k++) {
                        sIndex_delete(vector_item(numbers, k));
                    }
                    vector_delete(numbers);
                    return FALSE;
                }
            }
            else {
                if(!expand_env_expand_env(out, env, numbers, sname, line))
                {
                    string_delete(name);
                    string_delete(delimiter);
                    string_delete(index);
                    string_delete(index2);
                    int k;
                    for(k=0; k<vector_size(numbers); k++) {
                        sIndex_delete(vector_item(numbers, k));
                    }
                    vector_delete(numbers);
                    return FALSE;
                }
            }

            int k;
            for(k=0; k<vector_size(numbers); k++) {
                sIndex_delete(vector_item(numbers, k));
            }
            vector_delete(numbers);
        }
        else {
            vector_obj* array = hash_item(gArrays, string_c_str(name));

            /// 配列 ///
            if(array) {
                vector_obj* numbers = VECTOR_NEW(10);
                if(!parse_number(string_c_str(index), numbers, sname, *line)) {
                    string_delete(name);
                    string_delete(delimiter);
                    string_delete(index);
                    string_delete(index2);
                    int k;
                    for(k=0; k<vector_size(numbers); k++) {
                        sIndex_delete(vector_item(numbers, k));
                    }
                    vector_delete(numbers);
                    return FALSE;
                }

                vector_obj* numbers2 = VECTOR_NEW(10);
                if(!parse_number(string_c_str(index2), numbers2, sname, *line)) {
                    string_delete(name);
                    string_delete(delimiter);
                    string_delete(index);
                    string_delete(index2);
                    int k;
                    for(k=0; k<vector_size(numbers); k++) {
                        sIndex_delete(vector_item(numbers, k));
                    }
                    vector_delete(numbers);
                    for(k=0; k<vector_size(numbers2); k++) {
                        sIndex_delete(vector_item(numbers2, k));
                    }
                    vector_delete(numbers2);
                    return FALSE;
                }

                /// 添え字なし ///
                if(vector_size(numbers) == 0) {
                    if(quote) {
                        int k;
                        for(k=0; k<vector_size(array); k++) {
                            string_obj* str = vector_item(array, k);
                            string_obj* str2 = STRING_NEW("");
                            if(!expand_env_get_quoted_str(string_c_str(str), str2, sname, line)) {
                                string_delete(str2);
                                string_delete(name);
                                string_delete(delimiter);
                                string_delete(index);
                                string_delete(index2);
                                int k;
                                for(k=0; k<vector_size(numbers); k++) {
                                    sIndex_delete(vector_item(numbers, k));
                                }
                                vector_delete(numbers);
                                for(k=0; k<vector_size(numbers2); k++) {
                                    sIndex_delete(vector_item(numbers2, k));
                                }
                                vector_delete(numbers2);
                                return FALSE;
                            }
                            string_push_back(out, string_c_str(str2));
                            if(k<vector_size(array)-1)
                                string_push_back(out
                                    , string_c_str(delimiter));

                            string_delete(str2);
                        }
                    }
                    else {
                        int k;
                        for(k=0; k<vector_size(array); k++) {
                            string_obj* str = vector_item(array, k);
                            if(str == NULL) {
                                err_msg("expand_env: invalid array range", sname, *line);
                                string_delete(name);
                                string_delete(delimiter);
                                string_delete(index);
                                string_delete(index2);
                                int k;
                                for(k=0; k<vector_size(numbers); k++) {
                                    sIndex_delete(vector_item(numbers, k));
                                }
                                vector_delete(numbers);
                                for(k=0; k<vector_size(numbers2); k++) {
                                    sIndex_delete(vector_item(numbers2, k));
                                }
                                vector_delete(numbers2);
                                return FALSE;
                            }

                            string_obj* str2 = STRING_NEW("");
                            get_quoted_linefield(string_c_str(str)
                                    , str2);
                            string_push_back(out, string_c_str(str2));
                            string_delete(str2);

                            if(k<vector_size(array)-1)
                                string_push_back(out
                                        , string_c_str(delimiter));
                        }
                    }
                }
                /// 添え字あり ///
                else {
                    int i;
                    for(i=0; i<vector_size(numbers); i++) {
                        sIndex* index_ = vector_item(numbers, i);

                        if(index_->number_num == 1) { // 添え字が一つ
                            int n = index_->number;

                            if(n < 0) {
                                n = vector_size(array) + n;
                            }

                            if(n >= 0 && n < vector_size(array)) {
                                string_obj* str 
                                    = vector_item(array, n);
                                BOOL ret;
                                if(quote) {
                                    ret = !expand_env_expand_env_quoted
                                        (out, string_c_str(str)
                                            , numbers2, sname, line);
                                }
                                else {
                                    ret = !expand_env_expand_env
                                        (out, string_c_str(str)
                                            , numbers2, sname, line);
                                }


                                if(ret) {
                                    string_delete(name);
                                    string_delete(delimiter);
                                    string_delete(index);
                                    string_delete(index2);
                                    int k;
                                    for(k=0; k<vector_size(numbers); k++) {
                                        sIndex_delete(vector_item(numbers, k));
                                    }
                                    vector_delete(numbers);
                                    for(k=0; k<vector_size(numbers2); k++) {
                                        sIndex_delete(vector_item(numbers2, k));
                                    }
                                    vector_delete(numbers2);
                                    return FALSE;
                                }
                            }
                        }
                        else { // 添え字が範囲
                            int n = index_->number;
                            int m = index_->number2;

                            if(n < 0) n = vector_size(array) + n;
                            if(m < 0) m = vector_size(array) + m;

                            if(n >= vector_size(array)) n = vector_size(array)-1;
                            if(m >= vector_size(array)) m = vector_size(array)-1;

                            if(n < 0) n = 0;
                            if(m < 0) m = 0;

                            if(quote) {
                                if(n < m) {
                                    int k;
                                    for(k=n; k<=m; k++) {
                                        string_obj* str = vector_item(array, k);

                                        if(!expand_env_expand_env_quoted
                                            (out, string_c_str(str), numbers2, sname, line))
                                        {
                                            string_delete(name);
                                            string_delete(delimiter);
                                            string_delete(index);
                                            string_delete(index2);
                                            int k;
                                            for(k=0; k<vector_size(numbers); k++) {
                                                sIndex_delete(vector_item(numbers, k));
                                            }
                                            vector_delete(numbers);
                                            for(k=0; k<vector_size(numbers2); k++) {
                                                sIndex_delete(vector_item(numbers2, k));
                                            }
                                            vector_delete(numbers2);

                                            return FALSE;
                                        }

                                        if(k<=m-1) 
                                            string_push_back(out
                                               , string_c_str(delimiter));

                                    }
                                }
                                else {
                                    int k;
                                    for(k=n; k>=m; k--) {
                                        string_obj* str = vector_item(array, k);

                                        if(!expand_env_expand_env_quoted
                                            (out, string_c_str(str), numbers2, sname, line))
                                        {
                                            string_delete(name);
                                            string_delete(delimiter);
                                            string_delete(index);
                                            string_delete(index2);
                                            int k;
                                            for(k=0; k<vector_size(numbers); k++) {
                                                sIndex_delete(vector_item(numbers, k));
                                            }
                                            vector_delete(numbers);
                                            for(k=0; k<vector_size(numbers2); k++) {
                                                sIndex_delete(vector_item(numbers2, k));
                                            }
                                            vector_delete(numbers2);

                                            return FALSE;
                                        }

                                        if(k>m) 
                                            string_push_back(out
                                               , string_c_str(delimiter));

                                    }
                                }
                            }
                            else {
                                if(n < m) {
                                    int k;
                                    for(k=n; k<=m; k++) {
                                        string_obj* str = vector_item(array, k);

                                        if(!expand_env_expand_env
                                            (out, string_c_str(str), numbers2, sname, line))
                                        {
                                            string_delete(name);
                                            string_delete(delimiter);
                                            string_delete(index);
                                            string_delete(index2);
                                            int k;
                                            for(k=0; k<vector_size(numbers); k++) {
                                                sIndex_delete(vector_item(numbers, k));
                                            }
                                            vector_delete(numbers);
                                            for(k=0; k<vector_size(numbers2); k++) {
                                                sIndex_delete(vector_item(numbers2, k));
                                            }
                                            vector_delete(numbers2);
                                            return FALSE;
                                        }

                                        if(k<=m-1) 
                                          string_push_back(out
                                                        , string_c_str(delimiter));
                                    }
                                }
                                else {
                                    int k;
                                    for(k=n; k>=m; k--) {
                                        string_obj* str = vector_item(array, k);

                                        if(!expand_env_expand_env
                                            (out, string_c_str(str), numbers2, sname, line))
                                        {
                                            string_delete(name);
                                            string_delete(delimiter);
                                            string_delete(index);
                                            string_delete(index2);
                                            int k;
                                            for(k=0; k<vector_size(numbers); k++) {
                                                sIndex_delete(vector_item(numbers, k));
                                            }
                                            vector_delete(numbers);
                                            for(k=0; k<vector_size(numbers2); k++) {
                                                sIndex_delete(vector_item(numbers2, k));
                                            }
                                            vector_delete(numbers2);
                                            return FALSE;
                                        }

                                        if(k>m)
                                          string_push_back(out
                                                        , string_c_str(delimiter));
                                    }
                                }
                            }
                        }

                        if(i!=vector_size(numbers)-1)
                            string_push_back(out
                                , string_c_str(delimiter));
                    }
                }

                int k;
                for(k=0; k<vector_size(numbers); k++) {
                    sIndex_delete(vector_item(numbers, k));
                }
                vector_delete(numbers);

                for(k=0; k<vector_size(numbers2); k++) {
                    sIndex_delete(vector_item(numbers2, k));
                }
                vector_delete(numbers2);
            }
            else {
                /// [ 演算子 ///
                hash_obj* hash = hash_item(gHashs, string_c_str(name));

                /// ハッシュ ///
                if(hash) {
                    if(exist_index == FALSE) {
                        if(quote) {
                            hash_it* it = hash_loop_begin(hash);
                            int k = 0;
                            while(it != NULL) {
                                string_obj* str = hash_loop_item(it);
                                char* key = hash_loop_key(it);

                                string_obj* str2 = STRING_NEW("");
                                if(!expand_env_get_quoted_str(key, str2, sname, line)) {
                                    string_delete(str2);
                                    string_delete(name);
                                    string_delete(delimiter);
                                    string_delete(index);
                                    string_delete(index2);
                                    return FALSE;
                                }
                                string_push_back(out, string_c_str(str2));
                                string_delete(str2);

                                string_push_back(out, string_c_str(delimiter));

                                string_obj* str3 = STRING_NEW("");
                                if(!expand_env_get_quoted_str(string_c_str(str), str3, sname, line)) {
                                    string_delete(str3);
                                    string_delete(name);
                                    string_delete(delimiter);
                                    string_delete(index);
                                    string_delete(index2);
                                    return FALSE;
                                }
                                string_push_back(out, string_c_str(str3));
                                string_delete(str3);

                                if(k < hash_count(hash)-1)
                                    string_push_back
                                        (out, string_c_str(delimiter));

                                it = hash_loop_next(it);
                                k++;
                            }
                        }
                        else {
                            hash_it* it = hash_loop_begin(hash);
                            int k = 0;
                            while(it != NULL) {
                                string_obj* str = hash_loop_item(it);
                                string_obj* str2 = STRING_NEW("");
                                get_quoted_linefield(string_c_str(str), str2);
                                string_push_back(out, string_c_str(str2));
                                if(k < hash_count(hash)-1)
                                    string_push_back
                                        (out, string_c_str(delimiter));

                                string_delete(str2);

                                it = hash_loop_next(it);
                                k++;
                            }
                        }
                    }
                    else {
                        vector_obj* numbers = VECTOR_NEW(10);
                        if(!parse_number(string_c_str(index2), numbers, sname, *line)) {
                            string_delete(name);
                            string_delete(delimiter);
                            string_delete(index);
                            string_delete(index2);
                            int k;
                            for(k=0; k<vector_size(numbers); k++) {
                                sIndex_delete(vector_item(numbers, k));
                            }
                            vector_delete(numbers);
                            return FALSE;
                        }

                        string_obj* str = hash_item(hash, string_c_str(index));

                        if(str) {
                            if(quote) {
                                if(!expand_env_expand_env_quoted(out
                                            , string_c_str(str)
                                            , numbers, sname, line))
                                {
                                    string_delete(name);
                                    string_delete(delimiter);
                                    string_delete(index);
                                    string_delete(index2);
                                    int k;
                                    for(k=0; k<vector_size(numbers); k++) {
                                        sIndex_delete(vector_item(numbers, k));
                                    }
                                    vector_delete(numbers);
                                    return FALSE;
                                }
                            }
                            else {
                                if(!expand_env_expand_env(out
                                    , string_c_str(str)
                                    , numbers, sname, line))
                                {
                                    string_delete(name);
                                    string_delete(delimiter);
                                    string_delete(index);
                                    string_delete(index2);
                                    int k;
                                    for(k=0; k<vector_size(numbers); k++) {
                                        sIndex_delete(vector_item(numbers, k));
                                    }
                                    vector_delete(numbers);
                                    return FALSE;
                                }
                            }
                        }

                        int k;
                        for(k=0; k<vector_size(numbers); k++) {
                            sIndex_delete(vector_item(numbers, k));
                        }
                        vector_delete(numbers);
                    }
                }
            }
        }
    }

    string_delete(name);
    string_delete(delimiter);
    string_delete(index);
    string_delete(index2);

    return TRUE;
}

BOOL expand_env(char* p, string_obj* out, sRFd* rfd, char* sname, int* line)
{
    BOOL squote = FALSE;
    BOOL dquote = FALSE;
    vector_obj* psub_statments = VECTOR_NEW(10);

    while(*p) {
        if(gKitutukiSigInt) {
            err_msg("signal interrupt", sname, *line);
            gKitutukiSigInt = FALSE;
            int i;
            for(i=0; i<vector_size(psub_statments); i++) {
                string_delete(vector_item(psub_statments, i));
            }
            vector_delete(psub_statments);
            return FALSE;
        }

        /// クォート ///
        if(!squote && !dquote && *p == '\\') {
            string_push_back2(out, *p++);
            if(*p != 0) {
                string_push_back2(out, *p++);
            }
        }
        /// シングルクォート ///
        else if(!dquote && *p == '\'') {
            squote = !squote;
            string_push_back2(out, *p++);
        }
        /// ダブルクォート ///
        else if(!squote && *p == '"') {
            dquote = !dquote;
            string_push_back2(out, *p++);
        }
        /// 変数
        else if(!squote && *p == '$') {
            if((*(p+1) == '$' 
                    && (*(p+2) == '{' || is_env_name_char(*(p+2)))
                    || (*(p+1) == '{' || is_env_name_char(*(p+1)))
                ))
            {
                if(!expand_env_main(&p, out, rfd, sname, line)) {
                    int i;
                    for(i=0; i<vector_size(psub_statments); i++) {
                        string_delete(vector_item(psub_statments, i));
                    }
                    vector_delete(psub_statments);

                    return FALSE;
                }
            }
            /// 算術演算
            else if(*(p+1) == '(' && *(p+2) == '(') {
                p+=2;

                string_obj* str = STRING_NEW("");
                int read_end_of_statment = -1;
                if(!read_until_next_paren_end(&p, str, &read_end_of_statment, FALSE,  sname, line)) 
                {
                    string_delete(str);
                    int i;
                    for(i=0; i<vector_size(psub_statments); i++) {
                        string_delete(vector_item(psub_statments, i));
                    }
                    vector_delete(psub_statments);
                    return FALSE;
                }

                if(*p != ')') {
                    err_msg("expand_env: need ) in $(())", sname, *line);
                    string_delete(str);
                    int i;
                    for(i=0; i<vector_size(psub_statments); i++) {
                        string_delete(vector_item(psub_statments, i));
                    }
                    vector_delete(psub_statments);
                    return FALSE;
                }

                p++;

                string_erase(str, 0,1);
                string_trunc(str, string_length(str)-1);
                
                string_insert(str, 0, " calc \"");
                string_push_back(str, "\"");

                string_obj* ret = STRING_NEW("");
                char fname[128];
                snprintf(fname, 128, "%s %d: expand command", sname, *line);
                if(saphire_shell3(ret, string_c_str(str), fname, rfd) == -1) {
                    string_delete(ret);
                    string_delete(str);
                    int i;
                    for(i=0; i<vector_size(psub_statments); i++) {
                        string_delete(vector_item(psub_statments, i));
                    }
                    vector_delete(psub_statments);
                    return FALSE;
                }

                string_push_back(out, string_c_str(ret));

                string_delete(ret);
                string_delete(str);
            }
            /// コマンド置換 $( ///
            else if(*(p+1) == '$' && *(p+2) == '(' || *(p+1) == '(')
            {
                BOOL quote;
                if(*(p+1) == '$') {
                    p+=2;
                    quote = FALSE;
                }
                else {
                    p++;
                    quote = TRUE;
                }

                string_obj* str = STRING_NEW("");
                int read_end_of_statment = -1;
                if(!read_until_next_paren_end(&p, str, &read_end_of_statment, FALSE, sname, line)) 
                {
                    string_delete(str);
                    int i;
                    for(i=0; i<vector_size(psub_statments); i++) {
                        string_delete(vector_item(psub_statments, i));
                    }
                    vector_delete(psub_statments);
                    return FALSE;
                }

                string_erase(str, 0, 1); // (をとる
                string_trunc(str, string_length(str)-1); // )をとる

                string_obj* ret = STRING_NEW("");
                char* fname = MALLOC(strlen(sname) + 256);
                snprintf(fname, strlen(sname) + 256, "%s %d: expand command", sname, *line);
                int rcode = saphire_shell3(ret, string_c_str(str), fname, rfd);
                FREE(fname);

                if(rcode < 0) {
                    string_delete(str);
                    string_delete(ret);

                    int i;
                    for(i=0; i<vector_size(psub_statments); i++) {
                        string_delete(vector_item(psub_statments, i));
                    }
                    vector_delete(psub_statments);
                    return FALSE;
                }

                /// [ 演算子 ///
                string_obj* index = STRING_NEW("");
                if(*p == '[') {
                    int read_end_of_statment = -1;
                    if(!read_until_next_bracket_end(&p, index, &read_end_of_statment, FALSE, sname, line))
                    {
                        string_delete(str);
                        string_delete(ret);

                        int i;
                        for(i=0; i<vector_size(psub_statments); i++) {
                            string_delete(vector_item(psub_statments, i));
                        }
                        vector_delete(psub_statments);
                        string_delete(index);
                        return FALSE;
                    }

                    string_erase(index, 0, 1);
                    string_trunc(index, string_length(index)-1);

                    if(read_end_of_statment != -1) {
                        string_obj* index_ = STRING_NEW("");
                        if(!expand_env(string_c_str(index), index_, rfd, sname, line)) {
                            string_delete(str);
                            string_delete(ret);

                            int i;
                            for(i=0; i<vector_size(psub_statments); i++) {
                                string_delete(vector_item(psub_statments, i));
                            }
                            vector_delete(psub_statments);
                            string_delete(index);
                            string_delete(index_);
                            return FALSE;
                        }

                        string_delete(index);
                        index = index_;
                    }
                }

                vector_obj* numbers = VECTOR_NEW(10);

                if(!parse_number(string_c_str(index), numbers, sname, *line)) {
                    string_delete(str);
                    string_delete(ret);
                    string_delete(index);

                    int k;
                    for(k=0; k<vector_size(numbers); k++) {
                        sIndex_delete(vector_item(numbers, k));
                    }
                    vector_delete(numbers);
                    int i;
                    for(i=0; i<vector_size(psub_statments); i++) {
                        string_delete(vector_item(psub_statments, i));
                    }
                    vector_delete(psub_statments);
                    return FALSE;
                }

                if(quote) {
                    if(!expand_env_expand_env_quoted(out
                                , string_c_str(ret)
                                , numbers, sname, line))
                    {
                        string_delete(ret);
                        string_delete(str);
                        string_delete(index);

                        int k;
                        for(k=0; k<vector_size(numbers); k++) {
                            sIndex_delete(vector_item(numbers, k));
                        }
                        vector_delete(numbers);

                        int i;
                        for(i=0; i<vector_size(psub_statments); i++) {
                            string_delete(vector_item(psub_statments, i));
                        }
                        vector_delete(psub_statments);
                        return FALSE;
                    }
                }
                else {
                    if(!expand_env_expand_env(out, string_c_str(ret)
                                , numbers, sname, line))
                    {
                        string_delete(ret);
                        string_delete(str);
                        string_delete(index);

                        int k;
                        for(k=0; k<vector_size(numbers); k++) {
                            sIndex_delete(vector_item(numbers, k));
                        }
                        vector_delete(numbers);
                        int i;
                        for(i=0; i<vector_size(psub_statments); i++) {
                            string_delete(vector_item(psub_statments, i));
                        }
                        vector_delete(psub_statments);
                        return FALSE;
                    }
                }

                string_delete(str);
                string_delete(ret);
                int k;
                for(k=0; k<vector_size(numbers); k++) {
                    sIndex_delete(vector_item(numbers, k));
                }
                vector_delete(numbers);

                string_delete(index);

//printf("p (%s)\n", p);
            }
            else {
                err_msg("unexpected token after $", sname, *line);
                int i;
                for(i=0; i<vector_size(psub_statments); i++) {
                    string_delete(vector_item(psub_statments, i));
                }
                vector_delete(psub_statments);
                return FALSE;
            }
        }
        else if(squote || dquote) {
            if(*p == 0) {
                err_msg("require ' or \"", sname, *line);
                int i;
                for(i=0; i<vector_size(psub_statments); i++) {
                    string_delete(vector_item(psub_statments, i));
                }
                vector_delete(psub_statments);
                return FALSE;
            }
            else {
                string_push_back2(out, *p++);
            }
        }

        /// プロセス置換 ///
        else if(*p == '<' && *(p+1) == '(') {
            p++;

            string_obj* cmd = STRING_NEW("");
            int read_end_of_statment = -1;
            if(!read_until_next_paren_end(&p, cmd, &read_end_of_statment, FALSE, sname, line)) {
                string_delete(cmd);
                int i;
                for(i=0; i<vector_size(psub_statments); i++) {
                    string_delete(vector_item(psub_statments, i));
                }
                vector_delete(psub_statments);
                return FALSE;
            }
            string_erase(cmd, 0, 1); // (を取る
            string_trunc(cmd, string_length(cmd)-1); // )をとる

            /// 一時ファイルを作る ///
            char fname[PATH_MAX];
            snprintf(fname, PATH_MAX, "%s/kifile%d", gTmpDir, vector_size(gPSubTmpFiles));

            string_push_back(out, fname);
            vector_add(gPSubTmpFiles, STRING_NEW(fname));

            int fd = open(fname, O_WRONLY|O_CREAT, 0600);

            if(fd < 0) { perror("open"); exit(1); }

            /// 実行 ///
            sWFd* pipeout = sWFd_new(fd);
            sRFd* pipein = sRFd_new(STDIN_FILENO);
            char* title = MALLOC(strlen(sname) + 256);
            snprintf(title, strlen(sname) + 256, "%s %d: process substitution"
                    , sname, *line);
            int rcode = saphire_shell(string_c_str(cmd)
                            , title, pipeout
                            , pipein, STDERR_FILENO);
            FREE(title);
            string_delete(cmd);
            if(!sWFd_close(pipeout)) {
                int i;
                for(i=0; i<vector_size(psub_statments); i++) {
                    string_delete(vector_item(psub_statments, i));
                }
                vector_delete(psub_statments);
                return FALSE;
            }
            sWFd_delete(pipeout);
            sRFd_delete(pipein);

            if(rcode < 0) {
                int i;
                for(i=0; i<vector_size(psub_statments); i++) {
                    string_delete(vector_item(psub_statments, i));
                }
                vector_delete(psub_statments);
                return FALSE;
            }
        }

        /// プロセス置換２ ///
        else if(*p == '>' && *(p+1) == '(') {
            p++;

            string_obj* cmd = STRING_NEW("");
            int read_end_of_statment = -1;
            if(!read_until_next_paren_end(&p, cmd, &read_end_of_statment, FALSE, sname, line)) {
                string_delete(cmd);
                int i;
                for(i=0; i<vector_size(psub_statments); i++) {
                    string_delete(vector_item(psub_statments, i));
                }
                vector_delete(psub_statments);
                return FALSE;
            }
            string_erase(cmd, 0, 1);
            string_trunc(cmd, string_length(cmd)-1); // )をとる

            /// 一時ファイルを作る ///
            char fname[PATH_MAX];
            snprintf(fname, PATH_MAX, "%s/kifile%d", gTmpDir, vector_size(gPSubTmpFiles));

            string_push_back(out, fname);
            vector_add(gPSubTmpFiles, STRING_NEW(fname));

            /// 実行 ///
            char buf[PATH_MAX*2];
            snprintf(buf, PATH_MAX*2, "; var __a=$RCODE; cat %s |", fname);
            string_insert(cmd, 0, buf);
            string_push_back(cmd, "; if([ $__a = 0 ]){ true } else { false };");

            vector_add(psub_statments, cmd);
        }
        /// ブロックは飛ばす
        else if(*p == '{') {
            string_obj* dummy = STRING_NEW("");
            if(!read_block(&p, dummy, out, FALSE, sname, line)) {
                string_delete(dummy);
                int i;
                for(i=0; i<vector_size(psub_statments); i++) {
                    string_delete(vector_item(psub_statments, i));
                }
                vector_delete(psub_statments);
                return FALSE;
            }
            string_delete(dummy);
        }
        /// サブシェル、条件式は飛ばす
        else if(*p == '(') {
            int read_end_of_statment = -1;
            if(!read_until_next_paren_end(&p, out, &read_end_of_statment, FALSE, sname, line))
            {
                int i;
                for(i=0; i<vector_size(psub_statments); i++) {
                    string_delete(vector_item(psub_statments, i));
                }
                vector_delete(psub_statments);
                return FALSE;
            }
        }
        else {
            string_push_back2(out, *p++);
        }
    }

    int i;
    for(i=0; i<vector_size(psub_statments); i++) {
        string_obj* psub_statment = vector_item(psub_statments, i);
        string_push_back(out, string_c_str(psub_statment));
        string_delete(psub_statment);
    }
    vector_delete(psub_statments);

    return TRUE;
}

// コメントも除去する
// 読み込みだけ。この後パースする
BOOL read_expand_brace_expansion(char* p, string_obj* cmdline2, char* separator, char* sname, int* line)
{
    BOOL squote = FALSE;
    BOOL dquote = FALSE;

    while(*p) {
        if(!dquote && !squote && *p == '\\') {
            string_push_back2(cmdline2, *p++);
            string_push_back2(cmdline2, *p++);
        }
        else if(!dquote && *p == '\'') {
            string_push_back2(cmdline2, *p++);
            squote = !squote;
        }
        else if(!squote && *p == '"') {
            string_push_back2(cmdline2, *p++);
            dquote = !dquote;
        }
        else if(squote || dquote) {
            if(*p == 0) {
                err_msg("require \" or \'", sname, *line);
                return FALSE;
            }
            else {
                string_push_back2(cmdline2, *p++);
            }
        }
        /// コメント ///
        else if(*p == '#') {
            p++;

            while(*p) {
                if(*p == '\n') {
                    string_push_back2(cmdline2, '\n');
                    p++;

                    break;
                }
                else {
                    p++; 
                }
            }
        }
        else {
            string_push_back2(cmdline2, *p++);
        }
    }

    return TRUE;
}

// スクリプトファイルを読み込んでコンパイルして
// ファイルとして書き込む関数。
// エラー時はgErrMsgにエラーメッセージが入っている
BOOL saphire_compile(char* fname, char* out_fname)
{
    /// 読み込み ///
    string_obj* str = STRING_NEW("");

    int f = open(fname, O_RDONLY);
    if(f < 0) {
        string_delete(str);
        return FALSE;
    }

    char buf[BUFSIZ];
    while(1) {
        int size = read(f, buf, BUFSIZ-1);
        if(size == 0) {
            break;
        }
        if(size < 0) {
            string_delete(str);
            close(f);
            return FALSE;
        }

        buf[size] = 0;

        string_push_back(str, buf);
    }
    close(f);
    
    /// パース ///
    sStatments* statments = STATMENTS_NEW();

    int line = 1;

    string_obj* str2 = STRING_NEW("");
    if(!read_expand_brace_expansion(string_c_str(str), str2, " ", fname, &line)) {

        sStatments_delete(statments);
        string_delete(str2);
        string_delete(str);
        return FALSE;
    }

    line = 1;

    if(!parse(string_c_str(str2), fname, &line, statments)) {
        sStatments_delete(statments);
        
        string_delete(str);
        string_delete(str2);
        return FALSE;
    }
    
    string_delete(str);
    string_delete(str2);

    /// コンパイル結果を保存 ///
    int fd = open(out_fname, O_WRONLY|O_TRUNC|O_CREAT, 0644);
    if(write(fd, gMagicNumber, strlen(gMagicNumber)) < 0) {
        perror("write");
        exit(1);
    }

    sStatments_save(statments, fd);

    close(fd);

    sStatments_delete(statments);
    
    return TRUE;
}

// オブジェクトファイル(コンパイルされたファイル)を読み込む関数。
// 実行もする。
// 戻り値が-1ならエラーメッセージがgErrMsgに入っているので出力してください
int saphire_load_obj(char* fname, sWFd* pipeout, sRFd* pipein, int pipeerr, vector_obj* parent_blocks)
{
    gKitutukiSigInt = FALSE;
    int fd = open(fname, O_RDONLY);
    if(fd < 0) {
        return -1;
    }
    
    char magic_number[64];
    if(read(fd, magic_number, strlen(gMagicNumber)) < 0) {
        perror("read");
        exit(1);
    }
    magic_number[strlen(gMagicNumber)] = 0;
    
    if(strcmp(magic_number, gMagicNumber) != 0) {
        return -1;
    }
    
    /// オブジェクトファイルをロード ///
    sStatments* statments = sStatments_load(fd);

//sStatments_view(statments);
    
    /// 実行 ///
    int return_ = FALSE;
    int rcode = run(statments, fname
                , pipeout, pipein, pipeerr
                , gAppType == kATOptC, FALSE, &return_, parent_blocks, FALSE);

    /// 解放 ///
    close(fd);

    sStatments_delete(statments);

    return rcode;
}

