summaryrefslogtreecommitdiff
path: root/src/validate_value.ml
blob: 02cd15a403aa7fac3626a660ccb34ec13d8a2a94 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
type check = Regex of string | Exec of string

let validate_value buf value_constraint value =
    match value_constraint with
    | Regex s ->
        (try
           let _ = Pcre.exec ~pat:s value in true
       with Not_found -> false)
    | Exec c ->
        (* XXX: Unix.open_process_in is "shelling out", which is a bad idea on multiple levels,
                especially when the input comes directly from the user...
                We should do something about it.
         *)
        let chan = Unix.open_process_in (Printf.sprintf "%s \'%s\' 2>&1" c value) in
        let out = try CCIO.read_all chan with _ -> "" in
        let result = Unix.close_process_in chan in
        match result with
        | Unix.WEXITED 0 -> true
        | Unix.WEXITED 127 ->
          let () = Printf.printf "Could not execute validator %s" c in
          false
        | _ ->
          let () = Buffer.add_string buf out; Buffer.add_string buf "\n" in
          false

let value = ref ""

let checks = ref []

let args = [
    ("--regex", Arg.String (fun s -> checks := (Regex s) :: !checks), "Check the value against a regex");
    ("--exec", Arg.String (fun s -> checks := (Exec s) :: !checks), "Check the value against an external command");
    ("--value", Arg.String (fun s -> value := s), "Value to check");
]
let usage = Printf.sprintf "Usage: %s [OPTIONS] <number>" Sys.argv.(0)

let () = Arg.parse args (fun _ -> ()) usage

let _ =
  let buf = Buffer.create 4096 in
  let value = !value in
  let checks = !checks in
  match checks with
  | [] -> exit 0
  | _ ->
    List.iter (fun c -> if (validate_value buf c value) then exit 0 else ()) checks;
    (* If we got this far, value validation failed.
       Show the user output from the validators.
     *)
    Buffer.contents buf |> print_endline;
    exit 1