parse_cli Subroutine

private subroutine parse_cli(w, settings, fpm_cmdline, subcmd)

Parse the complete CLI and produce watcher options + typed fpm settings.

Parsing order: 1. Initialize watcher options from defaults and fpm.toml. 2. Consume leading --watch-* options and verbosity flags (-q, -v). 3. Identify the fpm subcommand (build|test|run). 4. Parse selected fpm settings used to build the model (profile, flags, compilers, build-dir, features, and run/test names).

All arguments after the subcommand are also preserved in fpm_cmdline.

Arguments

Type IntentOptional Attributes Name
type(watch_opts_t), intent(out) :: w
class(fpm_build_settings), intent(out), allocatable :: settings
character(len=:), intent(out), allocatable :: fpm_cmdline
character(len=:), intent(out), allocatable :: subcmd

Calls

proc~~parse_cli~~CallsGraph proc~parse_cli parse_cli proc~add_features_csv add_features_csv proc~parse_cli->proc~add_features_csv proc~apply_watch_flag apply_watch_flag proc~parse_cli->proc~apply_watch_flag proc~apply_watch_from_manifest apply_watch_from_manifest proc~parse_cli->proc~apply_watch_from_manifest proc~default_build_dir default_build_dir proc~parse_cli->proc~default_build_dir proc~get_arg get_arg proc~parse_cli->proc~get_arg proc~init_build_settings init_build_settings proc~parse_cli->proc~init_build_settings proc~is_supported_subcmd is_supported_subcmd proc~parse_cli->proc~is_supported_subcmd proc~is_watch_flag is_watch_flag proc~parse_cli->proc~is_watch_flag proc~join_argv join_argv proc~parse_cli->proc~join_argv proc~normalize_watch_opts normalize_watch_opts proc~parse_cli->proc~normalize_watch_opts proc~push_feature push_feature proc~parse_cli->proc~push_feature proc~set_names set_names proc~parse_cli->proc~set_names proc~set_watch_defaults set_watch_defaults proc~parse_cli->proc~set_watch_defaults proc~usage_and_stop usage_and_stop proc~parse_cli->proc~usage_and_stop proc~usage_and_stop_ok usage_and_stop_ok proc~parse_cli->proc~usage_and_stop_ok proc~add_features_csv->proc~push_feature proc~apply_watch_flag->proc~get_arg proc~apply_watch_flag->proc~normalize_watch_opts proc~apply_watch_flag->proc~push_feature proc~apply_watch_flag->proc~usage_and_stop proc~apply_watch_flag->proc~usage_and_stop_ok proc~parse_int parse_int proc~apply_watch_flag->proc~parse_int proc~parse_real parse_real proc~apply_watch_flag->proc~parse_real proc~apply_watch_from_manifest->proc~normalize_watch_opts proc~load_watch_table load_watch_table proc~apply_watch_from_manifest->proc~load_watch_table proc~toml_get_int toml_get_int proc~apply_watch_from_manifest->proc~toml_get_int proc~toml_get_list_strings toml_get_list_strings proc~apply_watch_from_manifest->proc~toml_get_list_strings proc~toml_get_logical toml_get_logical proc~apply_watch_from_manifest->proc~toml_get_logical proc~toml_get_real toml_get_real proc~apply_watch_from_manifest->proc~toml_get_real features features proc~init_build_settings->features proc~join_argv->proc~get_arg proc~needs_quotes needs_quotes proc~join_argv->proc~needs_quotes proc~quote_arg quote_arg proc~join_argv->proc~quote_arg name name proc~set_names->name colorize colorize proc~usage_and_stop->colorize proc~usage_print_only usage_print_only proc~usage_and_stop->proc~usage_print_only proc~usage_and_stop_ok->proc~usage_print_only exists exists proc~load_watch_table->exists get_value get_value proc~load_watch_table->get_value read_package_file read_package_file proc~load_watch_table->read_package_file proc~is_windows_os is_windows_os proc~quote_arg->proc~is_windows_os proc~toml_get_int->get_value get_list get_list proc~toml_get_list_strings->get_list proc~toml_get_logical->get_value proc~toml_get_real->get_value proc~usage_print_only->colorize get_os_type get_os_type proc~is_windows_os->get_os_type

Called by

proc~~parse_cli~~CalledByGraph proc~parse_cli parse_cli proc~parse_cli_config parse_cli_config proc~parse_cli_config->proc~parse_cli

Source Code

   subroutine parse_cli(w, settings, fpm_cmdline, subcmd)
      type(watch_opts_t), intent(out) :: w
      class(fpm_build_settings), allocatable, intent(out) :: settings
      character(len=:), allocatable, intent(out) :: fpm_cmdline
      character(len=:), allocatable, intent(out) :: subcmd

      integer :: narg, i, subcmd_pos
      character(len=:), allocatable :: a
      character(len=:), allocatable :: profile, build_dir
      character(len=:), allocatable :: compiler, c_compiler, cxx_compiler, archiver
      character(len=:), allocatable :: flag, cflag, cxxflag, ldflag
      character(len=:), allocatable :: runner
      type(string_t), allocatable :: features(:)
      type(string_t), allocatable :: names(:)
      logical :: prune, example

      call set_watch_defaults(w)
      call apply_watch_from_manifest(w)

      prune   = .true.
      example = .false.

      profile = ""
      build_dir = default_build_dir()
      compiler = ""
      c_compiler = ""
      cxx_compiler = ""
      archiver = ""
      flag = ""
      cflag = ""
      cxxflag = ""
      ldflag = ""
      runner = ""

      allocate(features(0))
      allocate(names(0))

      narg = command_argument_count()
      if (narg < 1) then
         call usage_and_stop("missing fpm subcommand (build/test/run)")
      end if

      a = get_arg(1)
      if (a == "--help" .or. a == "-h") then
         call usage_and_stop_ok()
      end if

      i = 1
      do while (i <= narg)
         a = get_arg(i)

         if (is_watch_flag(a)) then
            call apply_watch_flag(a, i, narg, w)
            i = i + 1
            cycle
         end if

         if (a == "-q") then
            w%verbosity = -1
            i = i + 1
            cycle
         end if
         if (a == "-v") then
            w%verbosity = max(w%verbosity, 1)
            i = i + 1
            cycle
         end if
         if (a == "-vv") then
            w%verbosity = max(w%verbosity, 2)
            i = i + 1
            cycle
         end if

         exit
      end do

      if (i > narg) call usage_and_stop("missing fpm subcommand (build/test/run)")

      a = get_arg(i)
      if (a == "--help" .or. a == "-h") then
         call usage_and_stop_ok()
      end if

      subcmd_pos = i
      subcmd = get_arg(subcmd_pos)

      if (.not. is_supported_subcmd(subcmd)) then
         call usage_and_stop("unsupported subcommand: " // trim(subcmd) // " (supported: build,test,run)")
      end if

      if (subcmd_pos < narg) then
         fpm_cmdline = "fpm " // trim(subcmd) // " " // join_argv(subcmd_pos+1, narg)
      else
         fpm_cmdline = "fpm " // trim(subcmd)
      end if

      i = subcmd_pos + 1
      do while (i <= narg)
         a = get_arg(i)

         if (a == "--") exit

         select case (a)
          case ("--profile")
            if (i+1 > narg) call usage_and_stop("--profile requires a value")
            profile = get_arg(i+1)
            i = i + 2
            cycle
          case ("--features")
            if (i+1 > narg) call usage_and_stop("--features requires a value")
            call add_features_csv(features, get_arg(i+1))
            i = i + 2
            cycle
          case ("--build-dir")
            if (i+1 > narg) call usage_and_stop("--build-dir requires a value")
            build_dir = get_arg(i+1)
            i = i + 2
            cycle
          case ("--compiler")
            if (i+1 > narg) call usage_and_stop("--compiler requires a value")
            compiler = get_arg(i+1)
            i = i + 2
            cycle
          case ("--c-compiler")
            if (i+1 > narg) call usage_and_stop("--c-compiler requires a value")
            c_compiler = get_arg(i+1)
            i = i + 2
            cycle
          case ("--cxx-compiler")
            if (i+1 > narg) call usage_and_stop("--cxx-compiler requires a value")
            cxx_compiler = get_arg(i+1)
            i = i + 2
            cycle
          case ("--archiver")
            if (i+1 > narg) call usage_and_stop("--archiver requires a value")
            archiver = get_arg(i+1)
            i = i + 2
            cycle
          case ("--flag")
            if (i+1 > narg) call usage_and_stop("--flag requires a value")
            flag = get_arg(i+1)
            i = i + 2
            cycle
          case ("--c-flag")
            if (i+1 > narg) call usage_and_stop("--c-flag requires a value")
            cflag = get_arg(i+1)
            i = i + 2
            cycle
          case ("--cxx-flag")
            if (i+1 > narg) call usage_and_stop("--cxx-flag requires a value")
            cxxflag = get_arg(i+1)
            i = i + 2
            cycle
          case ("--link-flag")
            if (i+1 > narg) call usage_and_stop("--link-flag requires a value")
            ldflag = get_arg(i+1)
            i = i + 2
            cycle
          case ("--runner")
            if (i+1 > narg) call usage_and_stop("--runner requires a value")
            runner = get_arg(i+1)
            i = i + 2
            cycle
          case ("--prune")
            prune = .true.
            i = i + 1
            cycle
          case ("--no-prune")
            prune = .false.
            i = i + 1
            cycle
          case ("--example")
            example = .true.
            i = i + 1
            cycle
          case default
            if (trim(subcmd) == "run" .or. trim(subcmd) == "test") then
               if (len_trim(a) > 0) then
                  if (a(1:1) /= "-") call push_feature(names, a)
               end if
            end if
            i = i + 1
            cycle
         end select
      end do

      select case (trim(subcmd))
       case ("build")
         allocate(fpm_build_settings :: settings)
         call init_build_settings(settings, build_dir, prune, profile, features, compiler, c_compiler, cxx_compiler, archiver, flag, cflag, cxxflag, ldflag)
       case ("test")
         allocate(fpm_test_settings :: settings)
         call init_build_settings(settings, build_dir, prune, profile, features, compiler, c_compiler, cxx_compiler, archiver, flag, cflag, cxxflag, ldflag)
         select type (s => settings)
          type is (fpm_test_settings)
            s%build_tests = .true.
            if (len_trim(runner) > 0) s%runner = trim(runner)
            call set_names(s, names)
         end select
       case ("run")
         allocate(fpm_run_settings :: settings)
         call init_build_settings(settings, build_dir, prune, profile, features, compiler, c_compiler, cxx_compiler, archiver, flag, cflag, cxxflag, ldflag)
         select type (s => settings)
          type is (fpm_run_settings)
            s%example = example
            if (len_trim(runner) > 0) s%runner = trim(runner)
            call set_names(s, names)
         end select
       case default
         call usage_and_stop("unsupported subcommand: " // trim(subcmd) // " (supported: build,test,run)")
      end select

      call normalize_watch_opts(w)
   end subroutine parse_cli