/*! * \brief 全変数のダンプ * \param[in] line 行番号 * \param[in] arg_list マクロ実引数リスト * \param[in] p_ctx マクロコンテキスト * \retval マクロ返却値 * マクロ実引数を指定した場合、その文字列属性で指定したファイルにダンプした文字列を追記する。 * ファイル名として、"stdout"を指定した場合は標準出力、"stderr"を指定した場合は標準エラーに出力する。 * ファイル名を省略した場合は"stderr"を指定したものとして振舞う。 */ var_t bf_dump( text_line const& line, std::vector< var_t > const& arg_list, context const* p_ctx ) { std::size_t arity = arg_list.size(); if ( arity > 1 ) { error( line, _( "too many arguments for `%1%\'" ), "DUMP" ); } std::string dump_str; // 全変数をなめる for ( std::map< std::string, var_t >::const_iterator iter( p_ctx->var_map.begin() ), last( p_ctx->var_map.end() ); iter != last; ++iter ) { dump_str += "$" + iter->first + "$ = { "; if ( !iter->second.empty() ) { // 各変数の全要素 for ( var_t::const_iterator iter2( iter->second.begin() ), last2( iter->second.end() ); iter2 != last2; ++iter2 ) { dump_str += "\"" + iter2->s + "\"("; if ( iter2->i ) // 値属性があれば... { dump_str += boost::lexical_cast< std::string >( *iter2->i ); } dump_str += "), "; } } dump_str += " }\n"; } std::string filename( "stderr" ); if ( arity == 1 ) { filename = get_s( arg_list[0], p_ctx ); } if ( filename == "stdout" ) { fputs( dump_str.c_str(), stdout ); } else if ( filename == "stderr" ) { fputs( dump_str.c_str(), stderr ); } else { std::FILE* stream = std::fopen( filename.c_str(), "a" ); if ( stream != 0 ) { fputs( dump_str.c_str(), stream ); std::fclose( stream ); } } element e; return var_t( 1, e ); }
/*! * \brief 変数群の交換 * \param[in] line 行番号 * \param[in] arg_list マクロ実引数リスト * \param[in] p_ctx マクロコンテキスト * \retval マクロ返却値 * 第一引数および第二引数で指定したプレフィックスを持つ変数群を入れ替える。 * ‘ADDAPI’関数で、別のプレフィックスを持つ連想配列を組み立てたあとは、この関数を用いることで、 * API.をプレフィックスに持つ連想配列と交換することができる。 */ var_t bf_swapprefix( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx ) { if ( macro_processor::check_arity( line, arg_list.size(), 2, "SWAPPREFIX" ) ) { std::string list1_name = get_s( arg_list[ 0 ], p_ctx ) + "."; // 一方のAPIリストの識別名. std::string list2_name = get_s( arg_list[ 1 ], p_ctx ) + "."; // 他方のAPIリストの識別名. std::string::size_type list1_size = list1_name.size(); std::string::size_type list2_size = list2_name.size(); std::map< std::string, var_t > temp; for ( std::map< std::string, var_t >::const_iterator iter = p_ctx->var_map.begin(), last = p_ctx->var_map.end(); iter != last; ++iter ) { std::pair< std::string, var_t > element = *iter; if ( std::strncmp( iter->first.c_str(), list1_name.c_str(), list1_size ) == 0 ) { element.first = list2_name + ( iter->first.c_str() + list1_size ); } else if ( std::strncmp( iter->first.c_str(), list2_name.c_str(), list2_size ) == 0 ) { element.first = list1_name + ( iter->first.c_str() + list2_size ); } temp.insert( element ); } p_ctx->var_map.swap( temp ); } return var_t(); }
/*! * \brief 文字列の連結 * \param[in] line 行番号 * \param[in] arg_list マクロ実引数リスト * \param[in] p_ctx マクロコンテキスト * \retval マクロ返却値 * 第1マクロ実引数と第2マクロ実引数を連結して新しい文字列を生成する。 */ var_t bf_concat( text_line const& line, std::vector< var_t > const& arg_list, context const* p_ctx ) { element e; if ( macro_processor::check_arity( line, arg_list.size(), 2, "CAT" ) ) { e.s = get_s( arg_list[0], p_ctx ) + get_s( arg_list[1], p_ctx ); } return var_t( 1, e ); }
/*! * \brief 指定した連想配列群に静的APIを追加する * \param[in] line 行番号 * \param[in] arg_list マクロ実引数リスト * \param[in] p_ctx マクロコンテキスト * \retval マクロ返却値 * API.で始まる連想配列群を、必要に応じて適切に変換を行った上で、別のプレフィックスで始まる * 連想配列群に追加する。想定する使用方法としては、特定のソフトウェア部品で理解可能な静的API * に関しては、追加を行わないか、他の静的APIに置き換えて追加を行う。理解できない静的APIに関して * はそのまま追加を行う。 * この関数の第一引数にはAPI.で始まる連想配列の連番を、第二引数には追加先に連想配列群の * プレフィックスを、第三引数には対象とする静的API名を、第四引数には追加するパラメータシンボルの * 並びを、第五引数にはパラメータの並びを指定する。 */ var_t bf_addapi( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx ) { element e; if ( macro_processor::check_arity( line, arg_list.size(), 5, "ADDAPI" ) ) { itronx::factory* factory = get_global< itronx::factory* >( "factory" ); std::map< std::string, itronx::static_api::info > const* info_map = factory->get_static_api_info_map(); std::tr1::int64_t order = get_i( arg_list[ 0 ], p_ctx ); // 元の静的APIの連番 std::string list_name = get_s( arg_list[ 1 ], p_ctx ); // 出力先リストの識別名 std::string api_name = get_s( arg_list[ 2 ], p_ctx ); // 静的API名 var_t params = arg_list[ 3 ]; // パラメータシンボルの並び var_t args = arg_list[ 4 ]; // パラメータの並び std::map< std::string, itronx::static_api::info >::const_iterator it = info_map->find( api_name ); if ( it != info_map->end() ) { itronx::static_api::info info = it->second; std::string str_order = boost::lexical_cast< std::string >( order ); p_ctx->var_map[ list_name + ".TEXT_LINE[" + str_order + "]" ] = p_ctx->var_map[ "API.TEXT_LINE[" + str_order + "]" ]; e.s = api_name; p_ctx->var_map[ list_name + ".NAME[" + str_order + "]" ] = var_t( 1, e ); e.s = info.type; p_ctx->var_map[ list_name + ".TYPE[" + str_order + "]" ] = var_t( 1, e ); p_ctx->var_map[ list_name + ".PARAMS[" + str_order + "]" ] = params; p_ctx->var_map[ list_name + ".ARGS[" + str_order + "]" ] = args; e.s.clear(); if ( !p_ctx->var_map[ list_name + ".ORDER_LIST" ].empty() ) { e.i = *p_ctx->var_map[ list_name + ".ORDER_LIST" ].back().i + 1; } else { e.i = 1; } p_ctx->var_map[ list_name + ".ORDER_LIST" ].push_back( e ); e.s.clear(); e.i = 1; } } return var_t( 1, e ); }
/*! * \brief 順序付きリスト内の探索 * \param[in] line 行番号 * \param[in] arg_list マクロ実引数リスト * \param[in] p_ctx マクロコンテキスト * \retval マクロ返却値 * 第1マクロ実引数で指定した順序付きリストに含まれる第2マクロ実引数で指定した値に等しい要素を、 * 先頭から順に探索する。 * 等しい要素が見つかればその要素へのインデックスを、そうでなければ空値を返す。 */ var_t bf_find( text_line const& line, std::vector< var_t > const& arg_list, context const* p_ctx ) { element e; if ( macro_processor::check_arity( line, arg_list.size(), 2, "FIND" ) ) { var_t list( arg_list[0] ); std::tr1::int64_t value( get_i( arg_list[1], p_ctx ) ); for ( var_t::const_iterator iter( list.begin() ), last( list.end() ); iter != last; ++iter ) { if ( iter->i.get() == value ) // 発見! { e.i = iter - list.begin(); // iter は RandomAccessIterator return var_t( 1, e ); } } } return var_t(); }
/*! * \brief テキストの翻訳 * \param[in] line 行番号 * \param[in] arg_list マクロ実引数リスト * \param[in] p_ctx マクロコンテキスト * \retval マクロ返却値 * 第1マクロ実引数で指定した文字列を翻訳する。 */ var_t bf_gettext( text_line const& line, std::vector< var_t > const& arg_list, context const* p_ctx ) { element e; if ( macro_processor::check_arity( line, arg_list.size(), 1, "GETTEXT" ) ) { std::string message = get_s( arg_list[0], p_ctx ); e.s = gettext( message ); } return var_t( 1, e ); }
/*! * \brief 順序リストの長さ * \param[in] line 行番号 * \param[in] arg_list マクロ実引数リスト * \param[in] p_ctx マクロコンテキスト * \retval マクロ返却値 * 第1マクロ実引数として指定した順序付きリストの要素数を返す。 * 第1マクロ実引数が順序付きリストでない場合は1を返す。また、第1マクロ実引数が無効な変数の場合は0を返す。 */ var_t bf_length( text_line const& line, std::vector< var_t > const& arg_list, context const* p_ctx ) { element e; if ( macro_processor::check_arity( line, arg_list.size(), 1, "LENGTH" ) ) { std::tr1::int64_t size = arg_list.front().size(); e.i = size; } return var_t( 1, e ); }
/*! * \brief 変数のトレース * \param[in] line 行番号 * \param[in] arg_list マクロ実引数リスト * \param[in] p_ctx マクロコンテキスト * \retval マクロ返却値 * 第1マクロ実引数で指定した変数の内容をトレースする。 * 第2マクロ実引数を指定した場合、その文字列属性で指定したファイルにトレース内容を追記する。 * ファイル名として、"stdout"を指定した場合は標準出力、"stderr"を指定した場合は標準エラーに出力する。 * ファイル名を省略した場合は"stderr"を指定したものとして振舞う。 */ var_t bf_trace( text_line const& line, std::vector< var_t > const& arg_list, context const* p_ctx ) { std::size_t arity = arg_list.size(); if ( arity < 1 ) { error( line, _( "too few arguments for `%1%\'" ), "TRACE" ); } else if ( arity > 2 ) { error( line, _( "too many arguments for `%1%\'" ), "TRACE" ); } var_t value( arg_list[ 0 ] ); std::string trace_str = "{ "; for ( var_t::const_iterator iter( value.begin() ), last( value.end() ); iter != last; ++iter ) { trace_str += "\"" + iter->s + "\"("; if ( iter->i ) // 値属性があれば... { trace_str += boost::lexical_cast< std::string >( *iter->i ); } trace_str += "), "; } trace_str += " }\n"; std::string filename( "stderr" ); if ( arity == 2 ) { filename = get_s( arg_list[ 1 ], p_ctx ); } if ( filename == "stdout" ) { fputs( trace_str.c_str(), stdout ); } else if ( filename == "stderr" ) { fputs( trace_str.c_str(), stderr ); } else { std::FILE* stream = std::fopen( filename.c_str(), "a" ); if ( stream != 0 ) { fputs( trace_str.c_str(), stream ); std::fclose( stream ); } } element e; return var_t( 1, e ); }
/*! * \brief 環境変数の取得 * \param[in] line 行番号 * \param[in] arg_list マクロ実引数リスト * \param[in] p_ctx マクロコンテキスト * \retval マクロ返却値 * 第1マクロ実引数で指定した環境変数の値を返す。 */ var_t bf_environ( text_line const& line, std::vector< var_t > const& arg_list, context const* p_ctx ) { element e; if ( macro_processor::check_arity( line, arg_list.size(), 1, "ENVIRON" ) ) { std::string name = get_s( arg_list[0], p_ctx ); char const* env = std::getenv( name.c_str() ); if ( env == 0 ) { return var_t(); } e.s = env; errno = 0; char* endptr; if ( std::tr1::int64_t value = std::strtol( env, &endptr, 0 ) ) { if ( *endptr == '\0' && errno == 0 ) { e.i = value; } } } return var_t( 1, e ); }
/*! * \brief 値の生成 * \param[in] line 行番号 * \param[in] arg_list マクロ実引数リスト * \param[in] p_ctx マクロコンテキスト * \retval マクロ返却値 * 第1マクロ実引数をテキスト、第2マクロ実引数を数値として、値を生成する。 */ var_t bf_value( text_line const& line, std::vector< var_t > const& arg_list, context const* p_ctx ) { element e; if ( macro_processor::check_arity( line, arg_list.size(), 2, "VALUE" ) ) { if ( !arg_list[0].empty() ) { e.s = get_s( arg_list[0], p_ctx ); } if ( !arg_list[1].empty() ) { e.i = get_i( arg_list[1], p_ctx ); } } return var_t( 1, e ); }
/*! * \brief 代替値 * \param[in] line 行番号 * \param[in] arg_list マクロ実引数リスト * \param[in] p_ctx マクロコンテキスト * \retval マクロ返却値 * 第1マクロ実引数が無効な変数の場合は第2実引数を返す。その他は第1実引数を返す。 */ var_t bf_alt( text_line const& line, std::vector< var_t > const& arg_list, context const* p_ctx ) { element e; if ( macro_processor::check_arity( line, arg_list.size(), 2, "ALT" ) ) { if ( !arg_list[0].empty() ) { return arg_list[0]; } else { return arg_list[1]; } } return var_t( 1, e ); }
/*! * \brief マクロ実引数の書式化 * \param[in] line 行番号 * \param[in] arg_list マクロ実引数リスト * \param[in] p_ctx マクロコンテキスト * \retval マクロ返却値 * 第1マクロ実引数で指定した初期化文字列によって、第2マクロ実引数以降を書式化する。 * 書式化文字列は、%nが使えないことを除き、printf関数のスーパーセットである。 * 正確な仕様は、boost::formatを参照のこと。 */ var_t bf_format( text_line const& line, std::vector< var_t > const& arg_list, context const* p_ctx ) { element e; std::size_t arity = arg_list.size(); if ( arity < 1 ) { error( line, _( "too few arguments for `%1%\'" ), "FORMAT" ); } boost::format fmt( get_s( arg_list[0], p_ctx ) ); for ( std::size_t i = 1; i < arity; i++ ) { std::pair< var_t const*, context const* > arg( &arg_list[i], p_ctx ); fmt % arg; } e.s = fmt.str(); return var_t( 1, e ); }
/*! * \brief 順序リストの指定要素の参照 * \param[in] line 行番号 * \param[in] arg_list マクロ実引数リスト * \param[in] p_ctx マクロコンテキスト * \retval マクロ返却値 * 第1マクロ実引数で指定した順序リストの、第2マクロ実引数で指定した要素を返す。 */ var_t bf_at( text_line const& line, std::vector< var_t > const& arg_list, context const* p_ctx ) { element e; if ( macro_processor::check_arity( line, arg_list.size(), 2, "CAT" ) ) { try { e = arg_list[0].at( static_cast< std::vector< var_t >::size_type >( get_i( arg_list[1], p_ctx ) ) ); } catch ( std::out_of_range& ) { // 添え字が不正 // 特に何もしない → この時点で e が空値であることを期待 } } return var_t( 1, e ); }
/*! * \brief 変数群の交換 * \param[in] line 行番号 * \param[in] arg_list マクロ実引数リスト * \param[in] p_ctx マクロコンテキスト * \retval マクロ返却値 * 第一引数で指定したプレフィックスで始まる変数群を削除する。’SWAPPREFIX’関数で交換したあと、 * 不要になった変数群はこの関数で削除しておくことが望ましい。 */ var_t bf_cleanvars( text_line const& line, std::vector< var_t > const& arg_list, context* p_ctx ) { if ( macro_processor::check_arity( line, arg_list.size(), 1, "CLEANVARS" ) ) { std::string prefix = get_s( arg_list[ 0 ], p_ctx ) + "."; // 変数の接頭辞 std::size_t n = prefix.size(); std::map< std::string, var_t > temp_map; for ( std::map< std::string, var_t >::const_iterator iter = p_ctx->var_map.begin(), last =p_ctx->var_map.end(); iter != last; ++iter ) { if ( std::strncmp( iter->first.c_str(), prefix.c_str(), n ) != 0 ) { temp_map.insert( *iter ); } } p_ctx->var_map.swap( temp_map ); } return var_t(); }
/*! * \brief 順序リストの整列 * \param[in] line 行番号 * \param[in] arg_list マクロ実引数リスト * \param[in] p_ctx マクロコンテキスト * \retval マクロ返却値 * 第1マクロ実引数として与えた順序付きリストの各要素を、第2マクロ実引数の添え字とした場合の変数を評価し、 * その評価結果に基づき昇順に整列する。 * * \example * $FOO[1] = 20$ * $FOO[2] = 10$ * $FOO[3] = 30$ * $SORT({ 1,2,3 }, "FOO")$ * → { 2,1,3 } * \endexample */ var_t bf_sort( text_line const& line, std::vector< var_t > const& arg_list, context const* p_ctx ) { var_t result; if ( macro_processor::check_arity( line, arg_list.size(), 2, "SORT" ) ) { var_t list( arg_list[0] ); std::string field( get_s( arg_list[1], p_ctx ) ); std::vector< std::pair< element, std::tr1::int64_t > > temp; for ( var_t::const_iterator iter( list.begin() ), last( list.end() ); iter != last; ++iter ) { std::tr1::int64_t order = iter->i.get(); std::string name( ( boost::format( "%s[%d]" ) % field % order ).str() ); std::map< std::string, var_t >::const_iterator m_iter( p_ctx->var_map.find( name ) ); if ( m_iter == p_ctx->var_map.end() ) { return var_t(); } if ( !m_iter->second.empty() ) { temp.push_back( std::make_pair( m_iter->second.front(), order ) ); } } std::stable_sort( temp.begin(), temp.end() ); for ( std::vector< std::pair< element, std::tr1::int64_t > >::const_iterator iter( temp.begin() ), last( temp.end() ); iter != last; ++iter ) { element e; e.i = iter->second; result.push_back( e ); } } return result; }
/*! * \brief 何もしない組み込み関数 * \param[in] line 行番号 * \param[in] arg_list マクロ実引数リスト * \param[in] p_ctx マクロコンテキスト * \retval マクロ返却値 * この組み込み関数は何も行わない。また、マクロ実引数のチェックも行わない。 * NOOP関数は常に "" を返す。 * \note 空値を返さないのは、$NOOP()$のような使い方をしたときでも不正な参照が起こらないようにするため。 */ var_t bf_noop( text_line const& line, std::vector< var_t > const& arg_list, context const* p_ctx ) { element e; return var_t( 1, e ); }