OSDN Git Service

マルチプロジェクト型にレポジトリを変更するために移動した
[toppersasp4lpc/asp.git] / asp / cfg / cfg / cfg.cpp
1 /*
2  *  TOPPERS Software
3  *      Toyohashi Open Platform for Embedded Real-Time Systems
4  *
5  *  Copyright (C) 2007-2009 by TAKAGI Nobuhisa
6  * 
7  *  上記著作権者は,以下の(1)〜(4)の条件を満たす場合に限り,本ソフトウェ
8  *  ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
9  *  変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
10  *  (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
11  *      権表示,この利用条件および下記の無保証規定が,そのままの形でソー
12  *      スコード中に含まれていること.
13  *  (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
14  *      用できる形で再配布する場合には,再配布に伴うドキュメント(利用
15  *      者マニュアルなど)に,上記の著作権表示,この利用条件および下記
16  *      の無保証規定を掲載すること.
17  *  (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
18  *      用できない形で再配布する場合には,次のいずれかの条件を満たすこ
19  *      と.
20  *    (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
21  *        作権表示,この利用条件および下記の無保証規定を掲載すること.
22  *    (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
23  *        報告すること.
24  *  (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
25  *      害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
26  *      また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
27  *      由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
28  *      免責すること.
29  * 
30  *  本ソフトウェアは,無保証で提供されているものである.上記著作権者お
31  *  よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
32  *  に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
33  *  アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
34  *  の責任を負わない.
35  * 
36  */
37 #include "cfg.hpp"
38 #include <boost/program_options.hpp>
39 #include <boost/spirit/include/classic.hpp>
40
41 namespace
42 {
43
44   //! 連続したスラッシュ / を単一のスラッシュに置換する
45   std::string slashes_to_single_slash( std::string const& str )
46   {
47     std::string result( str );
48     std::string::size_type pos = 0; 
49     while ( ( pos = result.find( "//", pos ) ) != std::string::npos )
50     {
51       result.erase( pos, 1 );
52     }
53     return result;
54   }
55
56   //! 起動オプションの解析
57   int parse_program_options( int argc, char* argv[] )
58   {
59     namespace po = boost::program_options;
60     int pass = 0;
61
62     // 一般オプション
63     po::options_description generic( _( "Generic options" ) );
64     generic.add_options()
65       ( "help", _( "display this information" ) )    
66       ( "version,v", _( "display cfg version number" ) )
67       ;
68
69     // 設定オプション
70     po::options_description config( _( "Configuration" ) );
71     config.add_options()
72       ( "kernel,k", po::value< std::string >()->default_value( std::string( "asp" ) ), _( "kernel type (default: asp)" ) )
73       ( "pass,p", po::value< int >( &pass )->default_value( 0 ), _( "run for pass #`arg\'" ) )
74       ( "include-path,I", po::value< std::vector< std::string > >(), _( "include path" ) )
75       ( "template-file,T", po::value< std::string >(), _( "template file" ) )
76       ( "input-charset", po::value< std::string >()->default_value( std::string( "ascii" ) ), _( "character set of input file (default: ascii)" ) )
77       ( "api-table", po::value< std::vector< std::string > >(), _( "specify static API table" ) )
78       ( "cfg1-def-table", po::value< std::vector< std::string > >(), _( "specify cfg1 definition table" ) )
79       ( "cfg1_out", po::value< std::string >()->default_value( std::string( "cfg1_out" ) ), _( "specify file name instead of `cfg1_out.srec\' (default: cfg1_out)" ) )
80       ( "rom-image,r", po::value< std::string >(), _( "ROM image (S-record)" ) )
81       ( "symbol-table,s", po::value< std::string >(), _( "Symbol table (`nm' style)" ) )
82       ( "cfg-directory,d", po::value< std::string >(), _( "cfg directory" ) )
83       ( "msgcat-directory,m", po::value< std::vector< std::string > >(), _( "msgcat(*.po) directory" ) )
84       ( "destination-directory,n", po::value< std::string >()->default_value( "." ), _( "destination directory" ) )
85       ( "id-output-file", po::value< std::string >()->default_value( std::string() ), _( "output file for id assignment" ) )
86       ( "id-input-file", po::value< std::string >()->default_value( std::string() ), _( "input file for id assignment" ) )
87       ( "alignof-fp", po::value< std::size_t >()->default_value( 1 ), _( "alignment of pointer to function" ) )
88       ( "external-id", _( "output ID numbers as external `const\' object" ) )
89       ( "print-dependencies,M", po::value< std::string >(), _( "output dependencies of source file (for `make\')" ) )
90       ( "with-software-components", _( "with software components" ) )
91       ;
92
93     // 非表示オプション
94     po::options_description hidden( _( "Hidden options" ) );
95     hidden.add_options()
96       ( "input-file,s", po::value< std::string >(), _( "input file" ) )
97       ;
98     
99     po::options_description cmdline_options;
100     cmdline_options.add( generic ).add( config ).add( hidden );
101
102     po::options_description visible( _( "Allowed options" ) );
103     visible.add( generic ).add( config );
104     
105     po::positional_options_description p;
106     p.add( "input-file", -1 );
107     
108     po::variables_map vm;
109     try
110     {
111       store( po::command_line_parser( argc, argv ).
112             options( cmdline_options ).positional( p ).run(), vm );
113       notify( vm );
114     }
115     catch ( boost::program_options::error& )
116     {
117       toppers::fatal( _( "illegal options" ) );
118     }
119
120     // グローバル変数の設定
121     if ( vm.count( "print-dependencies" ) )
122     {
123       toppers::global( "print-dependencies" ) = vm[ "print-dependencies" ].as< std::string >();
124       pass = 1; // 依存関係の出力が必要な場合、強制的にパス1に変更
125     }
126
127     toppers::global( "pass" ) = pass;
128     if ( vm.count( "kernel" ) )
129     {
130       std::string kernel = toppers::tolower( vm[ "kernel" ].as< std::string >() );
131       toppers::global( "kernel" ) = kernel;
132       bool has_class = false;
133       bool has_domain = false;
134
135       if ( kernel == "fmp" || kernel == "fmp+hrp2" || kernel == "hrp2+fmp" )
136       {
137         has_class = true;
138       }
139       if ( kernel == "hrp2" || kernel == "fmp+hrp2" || kernel == "hrp2+fmp" )
140       {
141         has_domain = true;
142       }
143
144       toppers::global( "max-pass" ) = ( has_domain ? 4 : 3 );
145       toppers::global( "has-class" ) = has_class;
146       toppers::global( "has-domain" ) = has_domain;
147     }
148     if ( vm.count( "include-path" ) )
149     {
150       std::vector< std::string > v( vm[ "include-path" ].as< std::vector< std::string > >() );
151       std::transform( v.begin(), v.end(), v.begin(), &slashes_to_single_slash );
152       toppers::global( "include-path" ) = v;
153     }
154     if ( vm.count( "template-file" ) )
155     {
156       toppers::global( "template-file" )
157         = slashes_to_single_slash( vm[ "template-file" ].as< std::string >() );
158     }
159     if ( vm.count( "input-file" ) )
160     {
161       toppers::global( "input-file" )
162         = slashes_to_single_slash( vm[ "input-file" ].as< std::string >() );
163     }
164     if ( vm.count( "input-charset" ) )
165     {
166       std::string input_charset( toppers::tolower( vm[ "input-charset" ].as< std::string >() ) );
167       toppers::global( "input-charset" ) = input_charset;
168
169       toppers::codeset_t codeset = toppers::ascii;
170       if ( ( input_charset == "cp932" )
171         || ( input_charset == "shift_jis" )
172         || ( input_charset == "sjis" ) )
173       {
174         codeset = toppers::shift_jis;
175       }
176       else if ( ( input_charset == "eucjp" )
177         || ( input_charset == "euc-jp" )
178         || ( input_charset == "euc" ) )
179       {
180         codeset = toppers::euc_jp;
181       }
182       else if ( ( input_charset == "utf-8" )
183         || ( input_charset == "utf8" ) )
184       {
185         codeset = toppers::utf8;
186       }
187       toppers::global( "codeset" ) = codeset;
188     }
189     if ( vm.count( "api-table" ) )
190     {
191       std::vector< std::string > v( vm[ "api-table" ].as< std::vector< std::string > >() );
192       std::transform( v.begin(), v.end(), v.begin(), &slashes_to_single_slash );
193       toppers::global( "api-table" ) = v;
194     }
195     if ( vm.count( "cfg1-def-table" ) )
196     {
197       std::vector< std::string > v( vm[ "cfg1-def-table" ].as< std::vector< std::string > >() );
198       std::transform( v.begin(), v.end(), v.begin(), &slashes_to_single_slash );
199       toppers::global( "cfg1-def-table" ) = v;
200     }
201     if ( vm.count( "cfg1_out" ) )
202     {
203       toppers::global( "cfg1_out" ) = vm[ "cfg1_out" ].as< std::string >();
204     }
205     else
206     {
207       toppers::global( "cfg1_out" ) = std::string( "cfg1_out" );
208     }
209     if ( vm.count( "cfg-directory" ) )
210     {
211       std::string cfg_directory( vm[ "cfg-directory" ].as< std::string >() );
212       toppers::global( "cfg-directory" ) = slashes_to_single_slash( cfg_directory );
213       toppers::load_msgcat( cfg_directory );
214     }
215     if ( vm.count( "msgcat-directory" ) )
216     {
217       std::vector< std::string > msgcat_dirs( vm[ "msgcat-directory" ].as< std::vector< std::string > >() );
218       std::transform( msgcat_dirs.begin(), msgcat_dirs.end(), msgcat_dirs.begin(), &slashes_to_single_slash );
219       std::for_each( msgcat_dirs.begin(), msgcat_dirs.end(), &toppers::load_msgcat );
220     }
221     if ( true ) // include-path を空にしてはならない
222     {
223       std::vector< std::string > include_path;
224       boost::any t( toppers::global( "include-path" ) );
225       if ( !t.empty() )
226       {
227         include_path = boost::any_cast< std::vector< std::string > >( t );
228       }
229       include_path.push_back( toppers::get_global< std::string >( "cfg-directory" ) );
230       toppers::global( "include-path" ) = include_path;
231     }
232     if ( vm.count( "output-directory" ) )
233     {
234       toppers::global( "output-directory" ) = slashes_to_single_slash( vm[ "output-directory" ].as< std::string >() );
235     }
236     if ( vm.count( "rom-image" ) )
237     {
238       toppers::global( "rom-image" ) = slashes_to_single_slash( vm[ "rom-image" ].as< std::string >() );
239     }
240     if ( vm.count( "symbol-table" ) )
241     {
242       toppers::global( "symbol-table" ) = slashes_to_single_slash( vm[ "symbol-table" ].as< std::string >() );
243     }
244     else
245     {
246       toppers::global( "symbol-table" ) = toppers::get_global< std::string >( "kernel" ) + ".syms";
247     }
248     if ( vm.count( "id-output-file" ) )
249     {
250       toppers::global( "id-output-file" ) = slashes_to_single_slash( vm[ "id-output-file" ].as< std::string >() );
251     }
252     if ( vm.count( "id-input-file" ) )
253     {
254       toppers::global( "id-input-file" ) = slashes_to_single_slash( vm[ "id-input-file" ].as< std::string >() );
255     }
256     if ( vm.count( "alignof-fp" ) )
257     {
258       toppers::global( "alignof-fp" ) = vm[ "alignof-fp" ].as< std::size_t >();
259     }
260     toppers::global( "external-id" ) = vm.count( "external-id" ) ? true : false;
261     toppers::global( "with-software-components" ) = vm.count( "with-software-components" ) ? true : false;
262
263     toppers::global( "version" ) = std::string( CFG_VERSION );
264
265     if ( vm.count( "version" ) )
266     {
267       std::cout << "TOPPERS Kernel Configurator version " << CFG_VERSION << std::endl;
268       toppers::global( "pass0" ) = true;
269     }
270     if ( vm.count( "help" ) )
271     {
272       toppers::global( "help" ) = boost::lexical_cast< std::string >( visible );
273       std::cout << visible << std::endl;
274       toppers::global( "pass0" ) = true;
275     }
276     return pass;
277   }
278
279 }
280
281 //! コンフィギュレータのメイン処理
282 int cfg_main( int argc, char* argv[] )
283 {
284   using namespace toppers;
285
286   std::string const cfg_path( argv[0] );
287   std::string const cfg_name( "cfg" );
288   std::string::const_iterator iter = std::find_end( cfg_path.begin(), cfg_path.end(), cfg_name.begin(), cfg_name.end() );
289   // 環境変数のサーチまでは行わない
290   std::string cfg_dir( cfg_path.begin(), iter );
291   if ( *cfg_dir.rbegin() == '/' || *cfg_dir.rbegin() == '\\' )
292   {
293     cfg_dir.resize( cfg_dir.size() - 1 );
294   }
295   toppers::global( "cfg-directory" ) = cfg_dir;
296   toppers::global( "argv0" ) = std::string( argv[ 0 ] );  // プログラム名
297   toppers::global( "timestamp" ) = cfg_timestamp();       // タイムスタンプ
298
299   int pass = parse_program_options( argc, argv );
300   bool ( * pfn_cfg[] )() = { &cfg0_main, &cfg1_main, &cfg2_main, &cfg3_main, &cfg4_main };
301   int max_pass = toppers::get_global< int >( "max-pass" );
302
303   if ( pass < 0 || max_pass < pass )
304   {
305     fatal( _( "illegal cfg pass #%d" ), pass );
306   }
307
308   if ( !( *pfn_cfg[ pass ] )() )
309   {
310     return EXIT_FAILURE;
311   }
312   return EXIT_SUCCESS;
313 }
314
315 int main( int arg, char* argv[] )
316 {
317   int status;
318   try
319   {
320     toppers::set_program_name( "cfg" );
321     status = cfg_main( arg, argv );
322     if ( status != EXIT_SUCCESS && toppers::get_error_count() == 0 )
323     {
324       std::fprintf( stderr, "cfg: %s\n", _( "unknown error" ) );
325     }
326     if ( toppers::get_error_count() > 0 )
327     {
328       status = EXIT_FAILURE;
329     }
330   }
331   catch ( toppers::normal_exit& )
332   {
333     status = EXIT_SUCCESS;
334   }
335   catch ( std::exception& e )
336   {
337     std::fprintf( stderr, "cfg: %s\n", e.what() );
338     status = EXIT_FAILURE;
339   }
340   catch ( ... )
341   {
342     std::fprintf( stderr, "cfg: %s\n", _( "internal error" ) );
343     status = EXIT_FAILURE;
344   }
345   return status;
346 }