From dbf73551a7f770f763d6286f5080c37cdb15f20c Mon Sep 17 00:00:00 2001 From: John Estabrook Date: Fri, 17 Jun 2022 20:30:52 -0500 Subject: numeric: T4467: add support for relative values: +/-N Add option '--relative' to check that value is of the form '+/-N' for some numeric N (e.g. +10' or '-30'), interpreted as a relative increment or decrement, rather than a signed integer/float. This may be combined with any other option, which will be applied to the value stripped of the leading modifier. Testing this extension revealed that negative values are being interpreted as options, whether quoted or not; to address that, an Arg.Rest keyword '--' is introduced, which will need to be passed along with the option in interface definitions using the above. For example: --- src/numeric.ml | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/numeric.ml b/src/numeric.ml index b296cec..ad3a066 100644 --- a/src/numeric.ml +++ b/src/numeric.ml @@ -3,13 +3,15 @@ type options = { nonnegative: bool; allow_float: bool; ranges: string list; + relative: bool; } let default_opts = { positive = false; nonnegative = false; allow_float = false; - ranges = [] + ranges = []; + relative = false } let opts = ref default_opts @@ -21,6 +23,8 @@ let args = [ ("--positive", Arg.Unit (fun () -> opts := {!opts with positive=true}), "Check if the number is positive (> 0)"); ("--range", Arg.String (fun s -> let optsv = !opts in opts := {optsv with ranges=(s :: optsv.ranges)}), "Check if the number is within a range (inclusive)"); ("--float", Arg.Unit (fun () -> opts := {!opts with allow_float=true}), "Allow floating-point numbers"); + ("--relative", Arg.Unit (fun () -> opts := {!opts with relative=true}), "Allow relative increment/decrement (+/-N)"); + ("--", Arg.Rest (fun s -> number_arg := s), "Interpret next item as an argument"); ] let usage = Printf.sprintf "Usage: %s [OPTIONS] " Sys.argv.(0) @@ -39,6 +43,20 @@ let looks_like_number value = try let _ = Pcre.exec ~pat:"^(\\-?)[0-9]+(\\.[0-9]+)?$" value in true with Not_found -> false +let is_relative value = + try let _ = Pcre.exec ~pat:"^[+-][0-9]+$" value in true + with Not_found -> false + +let number_string_from_relative value = + String.sub value 1 (String.length value - 1) + +let get_relative opts s = + if opts.relative then + if not (is_relative s) then + failwith "Value is not a relative increment/decrement" + else number_string_from_relative s + else s + let number_of_string opts s = if not (looks_like_number s) then Printf.ksprintf failwith "'%s' is not a valid number" s else let n = float_of_string_opt s in @@ -75,7 +93,8 @@ let check_ranges ranges n = let () = try let opts = !opts in - let n = number_of_string opts !number_arg in + let s = get_relative opts !number_arg in + let n = number_of_string opts s in check_nonnegative opts n; check_positive opts n; if opts.ranges <> [] then -- cgit v1.2.3