<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0                                                      |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group             |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.0 of the PHP license,       |
// | that is bundled with this package in the file LICENSE, and is        |
// | available at through the world-wide-web at                           |
// | http://www.php.net/license/2_02.txt.                                 |
// | If you did not receive a copy of the PHP license and are unable to   |
// | obtain it through the world-wide-web, please send a note to          |
// | license@php.net so we can mail you a copy immediately.               |
// +----------------------------------------------------------------------+
// | Authors: Nishina <jj@suke.ne.jp>                                     |
// +----------------------------------------------------------------------+

// define
/**
 * 正常終了の結果コード
 * @const JJ_BATCH_OK 正常終了
 */
define("JJ_BATCH_OK", 0);
/**
 * 異常終了の結果コード
 * @const JJ_BATCH_ERR 異常終了
 */
define("JJ_BATCH_ERR", 1);

// オプションタイプ
/**
 * オプション引数を取らないオプション
 * @const JJ_BATCH_OPTION_TYPE_NONE_ARG オプション引数を取らない
 */
define("JJ_BATCH_OPTION_TYPE_NONE_ARG", 1);
/**
 * オプション引数を取るオプション
 * @const JJ_BATCH_OPTION_TYPE_ARG オプション引数を取る
 */
define("JJ_BATCH_OPTION_TYPE_ARG", 2);

// プリフィックス
/**
 * ショートプリフィックス
 * @const JJ_BATCH_PREFIX_SHORT ショートプリフィックス
 */
define("JJ_BATCH_PREFIX_SHORT", 1);
/**
 * フルプリフィックス
 * @const JJ_BATCH_PREFIX_FULL フルプリフィックス
 */
define("JJ_BATCH_PREFIX_FULL", 2);
/**
 * デフォルトプリフィックス「-」
 * @const JJ_BATCH_DEFAULT_PREFIX デフォルトプリフィックス
 */
define("JJ_BATCH_DEFAULT_PREFIX", "-");
/**
 * ハイフンプリフィックス「-」
 * @const JJ_BATCH_HYPHEN_PREFIX 「-」ハイフンプリフィックス
 */
define("JJ_BATCH_HYPHEN_PREFIX", "-");
/**
 * プラスプリフィックス「+」
 * @const JJ_BATCH_PLUS_PREFIX 「+」プラスプリフィックス
 */
define("JJ_BATCH_PLUS_PREFIX", "+");
/**
 * パーセントプリフィックス「%」
 * @const JJ_BATCH_PERCENT_PREFIX 「%」パーセントプリフィックス
 */
define("JJ_BATCH_PERCENT_PREFIX", "%");
/**
 * 脱字プリフィックス「^」
 * @const JJ_BATCH_OMISSION_PREFIX 「^」脱字プリフィックス
 */
define("JJ_BATCH_OMISSION_PREFIX", "^");
/**
 * アンパサンドプリフィックス「&」
 * @const JJ_BATCH_AMPERSAND_PREFIX 「&」アンパサンドプリフィックス
 */
define("JJ_BATCH_AMPERSAND_PREFIX", "&");
/**
 * 感嘆符プリフィックス「!」
 * @const JJ_BATCH_EXCLAIM_PREFIX 「!」感嘆符プリフィックス
 */
define("JJ_BATCH_EXCLAIM_PREFIX", "!");
/**
 * スラッシュプリフィックス「/」
 * @const JJ_BATCH_SLASH_PREFIX 「/」スラッシュプリフィックス
 */
define("JJ_BATCH_SLASH_PREFIX", "/");
/**
 * プリフィックスに使用可能な全ての文字
 * @const JJ_BATCH_ALL_PREFIX プリフィックスに使用可能な全ての文字
 */
define("JJ_BATCH_ALL_PREFIX", "-+%^&!\/");
/**
 * デフォルトファイル関数名
 * @const JJ_BATCH_FILE_FUNC_NAME_DEFAULT デフォルトのファイル関数名
 */
define("JJ_BATCH_FILE_FUNC_NAME_DEFAULT", "_file_func");

// エラーコード
/**
 * エラーコード
 * @const JJ_BATCH_ERROR_INVALID_OPTION オプションエラー
 */
define("JJ_BATCH_ERROR_INVALID_OPTION", -1);

/**
 * バッチ基底クラス
 *
 * @author Nishina <jj@suke.ne.jp>
 * @copyright Copyright &copy; 2003, JJ.Nishina
 * @since Rev. 1.0 - 10-23-2003
 * @version $Id: CommandBase.php,v 1.1.1.1 2003/12/13 11:04:19 jjlehto Exp $
 * @package jj_batch
 * @abstract
 */
class Batch_CommandBase
{
    /**
     * @var int $__argc コマンドライン引数の数
     */
    var $__argc;

    /**
     * @var array $__argv コマンドライン引数の値
     */
    var $__argv;

    /**
     * @var string $__prefix オプションプリフィックス(Default[-])
     */
    var $__prefix = JJ_BATCH_DEFAULT_PREFIX;

    /**
     * @var string $__file_func_name ファイル処理用の関数名。コマンドラインでファイル名を入力した場合、この変数の名前の関数が呼ばれます。
     */
    var $__file_func_name = JJ_BATCH_FILE_FUNC_NAME_DEFAULT;

    /**
     * @var array $__option_list オプション情報が格納する配列
     */
    var $__option_list = array();

    /**
     * @var array $__called_option_list コール済みのオプションを格納する配列
     */
    var $__called_option_list = array();

    /**
     * @var int $__current_pos 現在処理中のコマンドライン引数の位置
     */
    var $__current_pos = 1;

    /**
     * @var int $__option_current_pos 現在処理中のオプションの位置
     */
    var $__option_current_pos = 0;

    /**
     * @var int $__result_code 処理結果コードが格納されている
     */
    var $__result_code;

    /**
     * @var object $__main_command 呼び出し元の親コマンド。Batch_Command継承クラスが格納されます。親コマンドがない場合はnullです。
     */
    var $__main_command;

    /**
     * @var array $__sub_command_list 呼び出し先の子コマンド。Keyに子コマンドに対応したメソッド名。ValueにBatch_Command継承クラスが格納されます。
     */
    var $__sub_command_list = array();

    /**
     * コンストラクタ
     * 
     * @param int   $argc コマンドライン引数の数。省略時自動的に$_SERVER['argc']をセットする
     * @param array $argv コマンドライン引数の配列。省略時自動的に$_SERVER['argv']をセットする
     * @return void
     * @access public
     */
    function Batch_CommandBase($argc = null, $argv = null)
    {
        if (is_null($argc)) {
            $this->__argc = $_SERVER['argc'];
        }
        if (is_null($argv)) {
            $this->__argv = $_SERVER['argv'];
        }
    }

    /**
     * バッチ処理Mainになりますので、継承したクラスは必ずオーバーライドしてください。
     *
     * @return boolean true=成功 / false=失敗
     * @access public
     * @see __optionProcess()
     */
    function exec()
    {
        // オプション処理
        if (!$this->__optionProcess()) {
            $this->__result_code = JJ_BATCH_ERROR_INVALID_OPTION;
            return false;
        }

        return true;
    }

    /**
     * コマンドライン引数を処理します
     *
     * @return boolean true=オプション処理成功 / false=オプション処理失敗
     * @access private
     * @see __fullOptionProcess(),__shortOptionProcess(),__subOptionProcess(),__fileOptionProcess()
     * @see __shortPrefixMatch(),__fullPrefixMatch(),__userOptionCheck(),__optionArgumentCheck(),__callOptionFunction()
     */
    function __optionProcess()
    {
        // コマンドライン引数をループ
        for (; $this->__current_pos < $this->__argc; $this->__current_pos++) {
            $option = $this->__argv[$this->__current_pos];    // コマンドライン引数を取得
            $this->__setCurrentOptionPos($this->__current_pos);  // オプション位置セット

            // オプション or オプション引数
            if ($this->__fullPrefixMatch ($option)) {
                // フルプリフィックス処理
                if (!$this->__fullOptionProcess($option)) {
                    return false;
                }

            } elseif ($this->__shortPrefixMatch ($option)) {
                // ショートプリフィックス処理
                if (!$this->__shortOptionProcess($option)) {
                    return false;
                }

            } elseif ($this->__sub_option_match ($option)) {
                // サブオプション処理
                return $this->__subOptionProcess($option);

            } else {
                break;
            }
        }

        return $this->__fileOptionProcess();
    }

    /**
     * フルプリフィックスオプションのチェック、実行を行います
     *
     * @param string $option オプション名
     * @return boolean true=オプション処理成功 / false=オプション処理失敗
     * @access private
     */
    function __fullOptionProcess($option)
    {
        $func_name = "";      // 関数名(オプション名)
        $func_argv = array(); // オプション引数

        // オプションから関数名を取得
        $func_name = substr ($option, strlen($this->__prefix.$this->__prefix), strlen($option));
        
        // オプションのチェック
        if (!$this->__userOptionCheck($func_name, JJ_BATCH_PREFIX_FULL)) {
            return false;
        }

        // オプション引数チェック
        if ($this->__optionArgumentCheck($func_name)) {
            if ($this->__current_pos+1 < $this->__argc && 
                !$this->__fullPrefixMatch ($this->__argv[$this->__current_pos+1]) && 
                !$this->__shortPrefixMatch ($this->__argv[$this->__current_pos+1]) &&
                !$this->__sub_option_match ($this->__argv[$this->__current_pos+1])) {

                // オプション引数を配列に格納
                array_push ($func_argv, $this->__argv[$this->__current_pos+1]);
                $this->__nextCurrentPos(); // カウント
            } else {
                // オプション引数が設定されていない場合
                return false;
            }
        }
        
        // オプション関数を呼ぶ
        if (!$this->__callOptionFunction($func_name, $func_argv, JJ_BATCH_PREFIX_FULL)) {
            // 関数が存在しなかった場合
            return false;
        }

        return true;
    }
 

    /**
     * ショートプリフィックスオプションのチェック、実行を行います
     *
     * @param string $option オプション名
     * @return boolean true=オプション処理成功 / false=オプション処理失敗
     * @access private
     */
    function __shortOptionProcess($option)
    {
        $func_name = "";      // 関数名(オプション名)
        $func_argv = array(); // オプション引数

        // オプションから関数名を取得
        $func_names = substr ($option, strlen($this->__prefix), strlen($option));
        
        // オプションをループ
        for ($j = 0; $j < strlen($func_names); $j++) {
            // ファンクション名を取得
            $func_name = substr($func_names, $j, 1);

            // オプションのチェック
            if (!$this->__userOptionCheck($func_name, JJ_BATCH_PREFIX_SHORT)) {
                return false;
            }
            
            // ショートプリフィックス指定で複数のオプションを同時に指定(-abc等)した場合は、オプション引数を取得しない。
            if (strlen($func_names) == 1) {
                // オプション引数チェック
                if ($this->__optionArgumentCheck($func_name)) {
                    // ショートプリフィックス指定で複数のオプションを同時に指定していなくてオプション引数がある場合
                    if ($this->__current_pos+1 < $this->__argc && 
                        !$this->__fullPrefixMatch ($this->__argv[$this->__current_pos+1]) && 
                        !$this->__shortPrefixMatch ($this->__argv[$this->__current_pos+1]) && 
                        !$this->__sub_option_match ($this->__argv[$this->__current_pos+1])) {
                        
                        // オプション引数を配列に格納
                        array_push ($func_argv, $this->__argv[$this->__current_pos+1]);
                        $this->__nextCurrentPos(); // カウント
                    } else {
                        // オプション引数が設定されていない場合
                        return false;
                    }
                }
            } else {
                // オプション引数チェック
                if ($this->__optionArgumentCheck($func_name)) {
                    // 引数を取るオプションを連続指定した場合はエラー
                    return false;
                }
            }
            
            // オプション関数を呼ぶ
            if (!$this->__callOptionFunction($func_name, $func_argv, JJ_BATCH_PREFIX_SHORT)) {
                // 関数が存在しなかった場合
                return false;
            }
        }

        return true;
    }

    /**
     * サブオプションのチェック、実行を行います
     *
     * @param string $option オプション名
     * @return boolean true=オプション処理成功 / false=オプション処理失敗
     * @access private
     */
    function __subOptionProcess($option)
    {
        $command = $this->getSubCommand($option);
        $command->setCommandArg($this->getSubCommandArgv());
        $command->__main_command =& $this;
        
        // メソッドをコール
        $this->__callSubOptionFunction($option);

        return $command->exec();
    }

    /**
     * ファイルオプションのチェック、実行を行います
     *
     * @param string $option オプション名
     * @return boolean true=オプション処理成功 / false=オプション処理失敗
     * @access private
     */
    function __fileOptionProcess()
    {
        $func_argv = array();      // オプション引数を初期化

        // 以降にオプション指定が無い場合はコマンドライン引数をfileとして評価
        for ($i = $this->__current_pos; $i < $this->__argc; $i++ ) {
            // オプション指定されているか調べる
            if ($this->__fullPrefixMatch ($this->__argv[$i]) || 
                $this->__shortPrefixMatch ($this->__argv[$i])) {
                // オプションが指定されていればエラー
                return false;
            } else {
                // オプション引数を配列に格納
                array_push ($func_argv, $this->__argv[$i]);
                $this->__nextCurrentPos(); // カウント
            }
        }

        // ファイル関数をコール
        if (!$this->__callFileFunction($func_argv)) {
            return false;
        }

        return true;
    }

    /**
     * プリフィックスを設定します。<BR>
     *
     * 設定出来る文字列は「-+%&!^/」です。<BR>
     * 引数には1文字のみ渡してください。<BR>
     * 1文字でなければエラーとなります。<BR>
     * 引数を省略すると、デフォルト(-)のプリフィックスが設定されます。
     * ショートプリフィックスは設定された文字になり、<BR>
     * フルプリフィックスは文字列を2回繋げた物になります。<BR>
     * 例えば、「+」を引数で渡された場合は、
     * ショートプリフィックス:+<BR>
     * フルプリフィックス    :++<BR>
     * となります。<BR>
     *
     * @param string $short_prefix ショートプリフィックス
     * @access public
     * @see JJ_BATCH_ALL_PREFIX,JJ_BATCH_DEFAULT_PREFIX,JJ_BATCH_HYPHEN_PREFIX,JJ_BATCH_PLUS_PREFIX,JJ_BATCH_PERCENT_PREFIX
     * @see JJ_BATCH_OMISSION_PREFIX,JJ_BATCH_AMPERSAND_PREFIX,JJ_BATCH_EXCLAIM_PREFIX,JJ_BATCH_SLASH_PREFIX
     */
    function setPrefix($prefix=JJ_BATCH_DEFAULT_PREFIX) {
        if (!preg_match ("/^[".JJ_BATCH_ALL_PREFIX."]$/", $prefix)) {
            die("[CommandBase::setPrefix]不正なプリフィックスが指定されました\n");
        }
        $this->__prefix = $prefix;
    }

    /**
     * オプションを追加します。<BR>
     *
     * ショートプリフィックス、フルプリフィックス両方省略可能ですが、どちらか一方指定しないとエラーとなります。<BR>
     * オプションタイプを省略した場合はデフォルトでJJ_BATCH_OPTION_TYPE_NONE_ARGになります。<BR>
     * 指定されたショートプリフィックスとフルプリフィックスは同一オプションとして関連付けられます。<BR>
     * ショートプリフィックスorフルプリフィックスを指定しない場合はnullを入力してください。<BR>
     * 但し、どちらか一方を指定しなければエラーとなります。
     *
     * @param string $short_opt ショートプリフィックスに指定するオプション。半角一文字のみ指定可能。
     * @param string $full_opt  フルプリフィックスに指定するオプション。一文字以上指定可能。(デフォルト:null)
     * @param int    $opt_type  オプションのタイプを指定。(デフォルト:JJ_BATCH_OPTION_TYPE_NONE_ARG)
     * @return void
     * @access public
     * @see __systemOptionCheck(),JJ_BATCH_OPTION_TYPE_NONE_ARG,JJ_BATCH_OK,JJ_BATCH_ERR
     */
    function addOption($short_opt=null, $full_opt=null, $opt_type=JJ_BATCH_OPTION_TYPE_NONE_ARG)
    {
        static $co = 0;
        // オプション文字をチェック
        if (!$this->__systemOptionCheck($short_opt, $full_opt)) {
            die("[CommandBase::addOption]不正なオプションが追加されました\n");
        }
        $this->__option_list[$co]['short_option'] = $short_opt;
        $this->__option_list[$co]['full_option']  = $full_opt;
        $this->__option_list[$co]['option_type']  = $opt_type;
        $co++;
    }

    /**
     * ファイル処理用関数名を設定します。<BR>
     *
     * @param  string $func_file_name ファイル処理関数名(デフォルト:_func_file)
     * @return void
     * @access public
     */
    function setFuncFileName($func_file_name=JJ_BATCH_FILE_FUNC_NAME_DEFAULT)
    {
        $this->__file_func_name = $func_file_name;
    }

    /**
     * 引数で指定されたファンクションをコールします。<BR>
     *
     * 第一引数に指定された関数名の関数を呼ぶ関数<BR>
     * 第二引数は関数の引数として渡されます。
     *
     * @param  string  $func_name 関数名
     * @param  array   $func_argv 関数引数
     * @param  int     $prefix   ショートプリフィックスorフルプリフィックス
     * @return boolean true=関数呼び出し成功 / false=関数呼び出し失敗
     * @access private
     */
    function __callOptionFunction($func_name, $func_argv, $prefix)
    {
        // 関数名、関連オプションを取得
        foreach ($this->__option_list as $option) {
            if ($prefix == JJ_BATCH_PREFIX_FULL && $option['full_option'] == $func_name) {
                if (!method_exists ($this, $func_name)) {
                    $func_name = $option['short_option'];
                }
                $full_func_name  = $option['full_option'];
                $short_func_name = $option['short_option'];
                break;
            }
            if ($prefix == JJ_BATCH_PREFIX_SHORT && $option['short_option'] == $func_name) {
                if (!method_exists ($this, $func_name)) {
                    $func_name = $option['full_option'];
                }
                $full_func_name  = $option['full_option'];
                $short_func_name = $option['short_option'];
                break;
            }
        }

        // 同一オプション、関連オプションがコールされているか
        if (!in_array($full_func_name, $this->__called_option_list) && 
            !in_array($short_func_name, $this->__called_option_list)) {
            // コール済みリストに追加
            array_push($this->__called_option_list, $func_name);
        } else {
            // 同一オプションが２回コールされた
            return false;
        }

        // オプションに対応した関数を呼ぶ
        if (!is_null($func_argv) && count($func_argv)) {
            $this->$func_name($func_argv);
        } else {
            $this->$func_name();
        }
        return true;

    }

    /**
     * 引数で指定されたサブオプション名に対応した関数をコールします。<BR>
     *
     * @param string $func_name オプション名
     * @private
     */
    function __callSubOptionFunction($func_name)
    {
        // ファイル関数が定義されているか
        if (method_exists ($this, $func_name)) {
            // ファイル関数を呼ぶ
            $this->{$func_name}(); 
        }
    }

    /**
     * ファイル関数をコールします。<BR>
     * 引数の配列をファイル関数の引数として渡します。
     *
     * @param array $func_argv ファイル名の配列
     * @return boolean true=ファイル関数コール成功/false=ファイル関数コール失敗
     * @private
     */
    function __callFileFunction($func_argv)
    {
        // ファイル関数が定義されているか
        if (method_exists ($this, $this->__file_func_name)) {
            // ファイル関数を呼ぶ
            $this->{$this->__file_func_name}($func_argv); 
        } else {
            if (count($func_argv) > 0) {
                // ファイル関数が定義されていなくてオプション引数がある場合はエラー
                return false;
            }
        }
        return true;
    }

    /**
     * ショートプリフィックスが含まれるか調べる<BR>
     *
     * @param  string  $opt オプション値
     * @return boolean true=ショートプリフィックスが含まれる。/ false=ショートプリフィックスが含まれない。
     * @access private
     */
    function __shortPrefixMatch($opt)
    {
        return preg_match ("/^\\".$this->__prefix.".+$/", $opt);
    }

    /**
     * フルプリフィックスが含まれるか調べる<BR>
     *
     * @param  string  $opt オプション値
     * @return boolean true=フルプリフィックスが含まれる。/ false=フルプリフィックスが含まれない。
     * @access private
     */
    function __fullPrefixMatch($opt)
    {
        return preg_match ("/^\\".$this->__prefix."\\".$this->__prefix.".+$/", $opt);
    }

    /**
     * addOptionされたオプションの整合性をチェックします。
     *
     * @param string  $short_opt ショートプリフィックスに指定するオプション。半角一文字のみ指定可能。
     * @param string  $full_opt  フルプリフィックスに指定するオプション。一文字以上指定可能。
     * @return boolean true=正常 / false=エラー
     * @access private
     * @see __optionCharCheck(),__optionDuplicationCheck()
     */
    function __systemOptionCheck($short_opt, $full_opt)
    {
        // オプション名チェック
        if (!$this->__optionCharCheck($short_opt, $full_opt)) {
            return false;
        }

        // 重複チェック
        return $this->__optionDuplicationCheck($short_opt, $full_opt);
    }

    /**
     * オプション名をチェックします。
     *
     * @param string  $short_opt ショートプリフィックスに指定するオプション。半角一文字のみ指定可能。（デフォルト:null）
     * @param string  $full_opt  フルプリフィックスに指定するオプション。一文字以上指定可能。(デフォルト:null)
     * @return boolean true=正常なオプション名 / false=不正なオプション名
     * @access private
     */
    function __optionCharCheck($short_opt=null, $full_opt=null)
    {
        // ショートプリフィックスチェック。半角英数字1文字
        if (!is_null($short_opt) && 
            !preg_match ("/^[0-9a-zA-Z]$/", $short_opt)) {
            return false;
        }
        // フルプリフィックスチェック。半角英数字,=[イコール]2文字以上
        if (!is_null($full_opt) && 
            !preg_match ("/^[0-9a-zA-Z=]{2,}$/", $full_opt)) {
            return false;
        }
        return true;
    }

    /**
     * オプションの重複チェックします。
     *
     * @param string  $short_opt ショートプリフィックスに指定するオプション。半角一文字のみ指定可能。
     * @param string  $full_opt  フルプリフィックスに指定するオプション。一文字以上指定可能。
     * @return boolean true=重複無し / false=重複有り
     * @access private
     */
    function __optionDuplicationCheck($short_opt, $full_opt)
    {
        if (is_null($short_opt) && is_null($full_opt)) {
            return false;
        }
        if ($short_opt == $full_opt) {
            return false;
        }

        // 重複チェック
        foreach ($this->__option_list as $option_info) {
            if (!is_null($full_opt) && 
                $option_info['full_option']  == $full_opt) {
                return false;
            }
            if (!is_null($short_opt) && 
                $option_info['short_option'] == $short_opt) {
                return false;
            }
        }

        return true;
    }

    /**
     * ユーザーが入力したオプションが正常かチェックします。
     *
     * @param  string  $func_name オプション名
     * @param  int     $prefix   ショートプリフィックスorフルプリフィックス
     * @return boolean true=正常なオプションが指定されている。/ false 不正なオプションが指定されている。
     * @access private
     * @see __optionCharCheck()
     */
    function __userOptionCheck($func_name, $prefix)
    {
        // 指定されたオプションを保持
        static $func_name_list = array();
        // オプション名チェック
        if ($prefix == JJ_BATCH_PREFIX_SHORT) {
            if (!$this->__optionCharCheck($func_name)) {
                return false;
            }
        } elseif ($prefix == JJ_BATCH_PREFIX_FULL) {
            if (!$this->__optionCharCheck(null,$func_name)) {
                return false;
            }
        } else {
            return false;
        }

        // オプションが定義されているかチェック
        $key = null;
        for ($i = 0; $i < count($this->__option_list); $i++) {
            if ($this->__option_list[$i]['short_option'] == $func_name ||
                $this->__option_list[$i]['full_option'] == $func_name) {
                $key = $i;
                break;
            }
        }
        if (is_null($key)) {
            return false;
        }

        // 同一オプションが指定されていないかチェック
        if (!in_array($func_name, $func_name_list)) {
            array_push ($func_name_list, $func_name);
        } else {
            return false;
        }

        return true;
    }

    /**
     * 指定のオプションが引数を取るかチェックする
     *
     * @param  string  $func_name    オプション名
     * @return boolean true オプション引数有り/ false オプション引数無し
     * @access private
     * @see JJ_BATCH_OPTION_TYPE_NONE_ARG
     */
    function __optionArgumentCheck($func_name)
    {
        // オプションタイプの取得
        foreach ($this->__option_list as $option) {
            if ($option['short_option'] == $func_name || $option['full_option'] == $func_name) {
                if ($option['option_type'] == JJ_BATCH_OPTION_TYPE_NONE_ARG) {
                    // 引数をとらないオプション
                    return false;
                } elseif ($option['option_type'] == JJ_BATCH_OPTION_TYPE_ARG) {
                    // 引数をとらないオプション
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * サブコマンド移行のオプションの配列を返す
     *
     * @param array $sub_argv サブコマンド移行のオプションの配列
     * @access public
     */
    function getSubCommandArgv()
    {
        $sub_argv = array();
        for ($i = $this->__option_current_pos; $i < count($this->__argv); $i++) {
            array_push($sub_argv, $this->__argv[$i]);
        }
        return $sub_argv;
    }

    /**
     * サブコマンドとそのサブコマンドに対応したメソッド名を設定します。
     *
     * @param string $name サブコマンドに対応した関数名&オプション名
     * @param object $command サブコマンドのオブジェクト。Batch_CommandBaseを継承したクラス
     * @access public
     */
    function setSubCommand($name, $command)
    {
        $this->__sub_command_list[$name] =& $command;
    }

    /**
     * サブコマンドの関数名を返します。
     *
     * @param string $name サブコマンドに対応した関数名&オプション名
     * @access public
     */
    function &getSubCommand($name)
    {
        return $this->__sub_command_list[$name];
    }

    /**
     * 親コマンドのオブジェクトを設定します
     * オブジェクトはBatch_CommandBaseを継承したクラス。
     *
     * @param object $main_command 親コマンドのオブジェクト。
     * @access public
     */
    function setMainCommand($main_command)
    {
        $this->__main_command =& $main_command;
    }

    /**
     * 親コマンドのオブジェクトを返します。
     * オブジェクトはBatch_CommandBaseを継承したクラス。
     *
     * @return object 親コマンドのオブジェクト。
     * @access public
     */
    function &getMainCommand()
    {
        return $this->__main_command;
    }

    /**
     * サブオプション名か調べる<BR>
     *
     * @param  string  $opt オプション値
     * @return boolean true=ショートプリフィックスが含まれる。/ false=ショートプリフィックスが含まれない。
     * @access private
     */
    function __sub_option_match($opt)
    {
        return array_key_exists($opt, $this->__sub_command_list);
    }

    /**
     * コマンドライン引数をセットします<BR>
     * コマンドライン引数の数も自動的にセットされます
     *
     * @param array $argv コマンドライン引数の配列
     * @access public
     */
    function setCommandArg($argv)
    {
        $this->__argv = $argv;
        $this->__argc = count($argv);
    }

    /**
     * 現在処理中のコマンドライン引数の位置。
     * 処理が始まっていない場合は0を返します。
     * 第一引数が処理中の場合は1を返します。
     * 
     * @return int 現在処理中のオプションの位置
     * @access public
     */
    function getCurrentPos()
    {
        return $this->__current_pos;
    }

    /**
     * 現在処理中のコマンドライン引数の位置を１移動します(+1する)。
     *
     * @return void
     * @access private
     */
    function __nextCurrentPos()
    {
        $this->__current_pos++;
    }

    /**
     * 現在処理中のオプション名を返します。
     * 処理が始まっていない場合は空文字を返します。
     * 
     * @return string 現在処理中のオプション名
     * @access public
     */
    function getCurrentOptionName()
    {
        if ($this->__option_current_pos <= 0) {
            return "";
        }
        return $this->__argv[$this->__option_current_pos];
    }

    /**
     * 現在処理中のオプションの位置。
     * 処理が始まっていない場合は0を返します。
     * 第一オプションが処理中の場合は1を返します。
     * 
     * @return int 現在処理中のオプションの位置
     * @access public
     */
    function getCurrentOptionPos()
    {
        return $this->__option_current_pos;
    }

    /**
     * 現在処理中のオプションの位置を１移動します(+1する)。
     *
     * @return void
     * @access private
     */
    function __nextCurrentOptionPos()
    {
        $this->__option_current_pos++;
    }

    /**
     * 現在処理中のオプションの位置を設定します。
     *
     * @param int $pos 設定したいオプション位置
     * @return void
     * @access private
     */
    function __setCurrentOptionPos($pos)
    {
        $this->__option_current_pos = $pos;
    }

    /**
     * 結果メッセージを返します。
     *
     * @return string 結果メッセージ
     * @access public
     */
    function getMessage()
    {
        $msg = null;
        switch ($this->__result_code) {
        case JJ_BATCH_ERROR_INVALID_OPTION: 
            $msg = "不正なオプションが指定されました。";
            break;
        default:
            $msg = "unKnown";
        }
        return $msg;
    }

    /**
     * 引数の値でフォーマットしたusage文字列を返します
     *
     * @param string $cmd_name コマンド名
     * @param string $option   オプションの使用法
     * @param string $cmd_help コマンドの説明
     * @param string $option_help オプションの説明
     * @param string $note 備考
     * @return string フォーマットされたusage文字列
     * @access public
     */
    function getUsage($cmd_name = "command", $option = "[options]...", $cmd_help = "command help", $option_help = "option help", $note = "note")
    {

// usageテンプレート
$usage = <<<EOD
usage: %cmd_name% %option%
%cmd_help%

%option_help%

%note%

EOD;
        $usage = preg_replace("/%cmd_name%/",    $cmd_name,    $usage);
        $usage = preg_replace("/%option%/",      $option,      $usage);
        $usage = preg_replace("/%cmd_help%/",    $cmd_help,    $usage);
        $usage = preg_replace("/%option_help%/", $option_help, $usage);
        $usage = preg_replace("/%note%/",        $note,        $usage);

        return $usage;
    }

    /**
     * 引数の値でフォーマットしたusage文字列を表示します
     *
     * @param string $cmd_name コマンド名
     * @param string $option   オプションの使用法
     * @param string $cmd_help コマンドの説明
     * @param string $option_help オプションの説明
     * @param string $note 備考
     * @access public
     */
    function showUsage($cmd_name = "command", $option = "[options]...", $cmd_help = "command help", $option_help = "option help", $note = "note")
    {
        print $this->getUsage($cmd_name, $option, $cmd_help, $option_help, $note);
    }
}


?>