diff --git a/data/cookbook/parse-command-line-arguments/00-stdlib.ml b/data/cookbook/parse-command-line-arguments/00-stdlib.ml new file mode 100644 index 0000000000..a2abed7b36 --- /dev/null +++ b/data/cookbook/parse-command-line-arguments/00-stdlib.ml @@ -0,0 +1,62 @@ +--- +packages: [] +--- +(* `Sys.argv` is the command-line arguments as an array of strings + ([standard library documentation](https://ocaml.org/manual/5.3/api/Sys.html#VALargv)). + Here we print each argument with its corresponding index in the array. *) +let simplest_parser () = + Sys.argv + |> Array.to_list + |> List.iteri (Printf.printf "argument %d: %s\n") + +(* `Arg` is a module for parsing command-line arguments, and it is part of + OCaml's standard library + ([documentation](https://ocaml.org/manual/5.3/api/Arg.html)). + In this function we define the structure of the command-line arguments we + expect, the argument types types and their documentation. This is basically + the same function defined in the module's documentation. *) +let arg_module_parser () = + let usage_msg = + "mycmd [--verbose] [] ... -o " + and verbose = ref false + and input_files = ref [] + and output_file = ref "" in +(* This function is called once for each anonymous argument. *) + let anonymous_args_f filename = + input_files := filename :: !input_files +(* The spec list defines argument keywords, "setter" functions to handle the + values, and their corresponding documentation. *) + and spec_list = + [("--verbose", Arg.Set verbose, "Output debug information"); + ("-o", Arg.Set_string output_file, "Set output file name")] + in + Arg.parse spec_list anonymous_args_f usage_msg; + Printf.printf "verbose: %b\n" !verbose; + Printf.printf "input files: %s\n" + (!input_files |> String.concat ", "); + Printf.printf "output file: %s\n" !output_file + +(* Given a command-line like `mycmd --verbose file1 -o /tmp/out`, we should + expect the following output: + + ``` + === Simplest parser === + argument 0: mycmd + argument 1: --verbose + argument 2: file1 + argument 3: -o + argument 4: /tmp/out + + === Arg.parse === + verbose: true + input files: file1 + output file: /tmp/out + ``` *) +let () = + print_endline "=== Simplest parser ==="; + simplest_parser (); + + Printf.printf "\n%!"; + + print_endline "=== Arg.parse ==="; + arg_module_parser () diff --git a/data/cookbook/parse-command-line-arguments/01-cmdliner.ml b/data/cookbook/parse-command-line-arguments/01-cmdliner.ml new file mode 100644 index 0000000000..f2c1f45706 --- /dev/null +++ b/data/cookbook/parse-command-line-arguments/01-cmdliner.ml @@ -0,0 +1,78 @@ +--- +packages: +- name: cmdliner + tested_version: "1.3.0" + used_libraries: + - cmdliner +--- +(* In this example, we define a parser for a command-line like this: + + ``` + mycmd --verbose input_file -o output_file + ``` + + `--verbose` and `-o` are optional, and the command should accept multiple + input files. + + We can find more examples on + [this page](https://erratique.ch/software/cmdliner/doc/examples.html). + *) +let cmdliner_parser () = +(* `Cmdliner` is a library that allows the declarative definition of + command-line interfaces + ([documentation page](https://erratique.ch/software/cmdliner/doc/index.html)). + *) + let open Cmdliner in +(* First we declare the expected arguments of our command-line, and how + `Cmdliner` should parse them. *) + let verbose = + let doc = "Output debug information" in +(* `&` is a right associative composition operator + ([documentation](https://erratique.ch/software/cmdliner/doc/Cmdliner/Arg/index.html#val-(&))). + *) + Arg.(value & flag & info ["v" ; "verbose"] ~doc) + and input_files = + let doc = "Input file(s)" in + Arg.(non_empty & pos_all file [] + & info [] ~docv:"INPUT" ~doc) + and output_file = + let doc = "Output file" + and docv = "OUTPUT" in + Arg.(value & opt (some string) None + & info ["o"] ~docv ~doc) +(* `mycmd` is the function that the program will apply to the parsed + arguments. *) + and mycmd verbose input_files output_file = + Printf.printf "verbose: %b\n" verbose; + Printf.printf "input files: %s\n" + (input_files |> String.concat ", "); + Printf.printf "output file: %s\n" + (Option.value ~default:"" output_file) + in +(* Declaration of the complete command, including its man-like + documentation. *) + let cmd = + let doc = "An example command" + and man = [ + `S Manpage.s_description; + `P "A command that can take multiple files + and outputs a file (optional)." + ] + in + Cmd.v (Cmd.info "mycmd" ~doc ~man) + Term.(const mycmd $ verbose $ input_files $ output_file) + in + Cmd.eval cmd + + +(* Given a command-line like + `mycmd --verbose -o somefile ./dune-project ./cmd_cookbook.opam`, we should + expect the following output: + + ``` + verbose: true + input files: ./dune-project, ./cmd_cookbook.opam + output file: somefile + ``` *) +let () = + exit @@ cmdliner_parser ()