1414
1515/* This file is ALSO:
1616 * Copyright 2001-2004 David Abrahams.
17- * Copyright 2018-2025 Rene Rivera
17+ * Copyright 2018-2026 René Ferdinand Rivera Morell
1818 * Distributed under the Boost Software License, Version 1.0.
1919 * (See accompanying file LICENSE.txt or copy at
2020 * https://www.bfgroup.xyz/b2/LICENSE.txt)
@@ -222,6 +222,18 @@ struct args_data
222222 std::string out_filename;
223223} args_data;
224224
225+ namespace b2 { namespace args {
226+ list_ref extra_args ()
227+ {
228+ list_ref result;
229+ for (auto const & a : args_data.extra_args )
230+ {
231+ result.push_back (a);
232+ }
233+ return result;
234+ }
235+ }} // namespace b2::args
236+
225237int guarded_main (int argc, char * argv[])
226238{
227239 int status = 0 ;
@@ -230,8 +242,18 @@ int guarded_main(int argc, char * argv[])
230242 module_t * environ_module;
231243 b2::system_info sys_info;
232244
245+ // On each reparse of arguments we need to reset the data we collect of
246+ // arguments.
247+ b2::args::set_reparse_callback ([]() { args_data = { }; });
248+
233249 auto & cli = b2::args::lyra_cli ().relaxed ();
234250
251+ // In specifying options we do validation at the time of parsing the option
252+ // value. We need to do it this way as we use the relaxed option parser
253+ // which will ignore options it fails on, for example by not being able to
254+ // convert the value or otherwise. Hence we do our own parse checks and
255+ // failures.
256+
235257 cli |= lyra::arg (args_data.extra_args , " request" )
236258 .help (" Targets, requirements, etc." )
237259 .choices ([](const std::string & v) {
@@ -266,40 +288,54 @@ int guarded_main(int argc, char * argv[])
266288 /* Undocumented -p3 (acts like both -p1 -p2) means separate pipe action
267289 * stdout and stderr.
268290 */
269- cli |= lyra::opt (globs.pipe_action , " x" )
291+ cli |= lyra::opt (
292+ [](const std::string & v) {
293+ if (!lyra::detail::from_string (v, globs.pipe_action )
294+ || globs.pipe_action < 0 || globs.pipe_action > 3 )
295+ {
296+ out_printf (" error: Invalid value for the '-p' option.\n " );
297+ b2::clean_exit (EXITBAD );
298+ }
299+ },
300+ " x" )
270301 .name (" -p" )
271302 .help (
272303 " x=0, pipes action stdout and stderr "
273- " merged into action output." )
274- .choices ([](int val) { return 0 <= val && val <= 3 ; });
304+ " merged into action output." );
275305
276306 cli |= lyra::opt (globs.quitquick )
277307 .name (" -q" )
278308 .help (" Quit quickly as soon as a target fails." );
279309
280310 cli |= lyra::opt (
281311 [](const std::string & v) {
282- globs.quitquick = (v == " on" || v == " yes" || v == " true" );
312+ if (v != " on" && v != " yes" && v != " true" && v != " off"
313+ && v != " no" && v != " false" )
314+ {
315+ out_printf (
316+ " error: Invalid value for the '--keep-going' option.\n " );
317+ b2::clean_exit (EXITBAD );
318+ }
319+ globs.quitquick = (v == " off" || v == " no" || v == " false" );
283320 },
284321 " x" )
285322 .name (" --keep-going" )
286323 .help (
287324 " Specify if we continue to build after failures or not "
288- " (--keep-going=no is equivalent to -q)" )
289- .choices (" on" , " yes" , " true" , " off" , " no" , " false" );
325+ " (--keep-going=no is equivalent to -q)" );
290326
291- cli |= lyra::opt (globs.jobs , " x" )
327+ cli |= lyra::opt (
328+ [](const std::string & v) {
329+ if (!lyra::detail::from_string (v, globs.jobs ) || globs.jobs < 1 )
330+ {
331+ out_printf (" error: Invalid value for the '-j' option.\n " );
332+ b2::clean_exit (EXITBAD );
333+ }
334+ },
335+ " x" )
292336 .name (" -j" )
293337 .name (" --jobs" )
294- .help (" Run up to x shell commands concurrently." )
295- .choices ([](int val) {
296- if (val < 1 )
297- {
298- err_printf (" Invalid value for the '-j' option.\n " );
299- b2::clean_exit (EXITBAD );
300- }
301- return true ;
302- });
338+ .help (" Run up to x shell commands concurrently." );
303339
304340 cli |= lyra::opt (globs.newestfirst )
305341 .name (" -g" )
@@ -410,7 +446,6 @@ int guarded_main(int argc, char * argv[])
410446 argv[2 ] = argv[0 ];
411447 arg_v = argv = (argv + 2 );
412448 globs.debug_interface = global_config::debug_interface_child;
413- args_data = {};
414449 b2::args::set_args (arg_c, arg_v);
415450 b2::args::process_args (true );
416451 }
@@ -429,7 +464,6 @@ int guarded_main(int argc, char * argv[])
429464 arg_c = argc = debug_child_data.argc ;
430465 arg_v = argv = (char **)debug_child_data.argv ;
431466 globs.debug_interface = global_config::debug_interface_child;
432- args_data = {};
433467 b2::args::set_args (arg_c, arg_v);
434468 b2::args::process_args (true );
435469 }
@@ -605,7 +639,6 @@ int guarded_main(int argc, char * argv[])
605639 }
606640
607641 // Process options.
608- args_data = {};
609642 b2::args::set_args (arg_c, arg_v);
610643 b2::args::process_args ();
611644
@@ -675,7 +708,7 @@ struct SetConsoleCodepage
675708 UINT orig_console_output_cp = 0 ;
676709};
677710
678- static const SetConsoleCodepage g_console_codepage_setter {};
711+ static const SetConsoleCodepage g_console_codepage_setter { };
679712
680713} // namespace
681714#endif
0 commit comments