package bcfg
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
A boringly simpleconfiguration format
Install
dune-project
Dependency
Authors
Maintainers
Sources
bcfg-0.1.0.tbz
sha256=7c4862dc6f1bc77bf643881aaad4d59b718c8d5e8e206a63b6a2c532692f0d56
sha512=5c31155c41d6fb84133cbc9aa947a6a3e851acb562204412dd1310407e9b99c6d7619e5a0da77cc9f16268db2583daa5ede0f5db7e43a2057d31079d9fd4a17b
doc/src/bcfg.validate/bcfg_validate.ml.html
Source file bcfg_validate.ml
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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248let error_msgf fmt = Fmt.kstr (fun msg -> Error (`Msg msg)) fmt let rchop ~len str = if len > String.length str then invalid_arg "rchop"; String.sub str 0 (String.length str - len) let rchop_if_lf str = if str = "" then "" else match str.[String.length str - 1] with '\n' -> rchop ~len:1 str | _ -> str let escape str = let buf = Buffer.create (String.length str) in let fn = function | '\x07' -> Buffer.add_string buf "\\a" | '\x08' -> Buffer.add_string buf "\\b" | '\x09' -> Buffer.add_string buf "\\t" | '\x0a' -> Buffer.add_string buf "\\n" | '\x0b' -> Buffer.add_string buf "\\v" | '\x0c' -> Buffer.add_string buf "\\f" | '\x0d' -> Buffer.add_string buf "\\r" | '\x20' .. '\x7e' as chr -> Buffer.add_char buf chr | chr -> let hex = Fmt.str "\\x%02x" (Char.code chr) in Buffer.add_string buf hex in String.iter fn str; Buffer.contents buf let read_all ic = let buf = Buffer.create 0x10000 in let chunk = Bytes.create 0x10000 in let rec go () = let n = input ic chunk 0 (Bytes.length chunk) in if n > 0 then begin Buffer.add_substring buf (Bytes.unsafe_to_string chunk) 0 n; go () end in go (); Buffer.contents buf (* Read the whole input into memory once. We need the full content both to feed the parser and to re-read the lines around a potential error; buffering it in a string avoids the previous two-pipe [tee], which deadlocked on inputs larger than a pipe buffer (the error-context pipe was only drained on error). The input is read exactly once, so this also works on non-seekable stdin. *) let read_input = function | None -> read_all stdin | Some filepath -> let ic = open_in_bin filepath in Fun.protect ~finally:(fun () -> close_in_noerr ic) (fun () -> read_all ic) let has_newline str = if str = "" then false else str.[String.length str - 1] = '\n' let max_line_number lines = let fn acc (line_number, _) = max acc line_number in List.fold_left fn 0 lines type cfg = { length_of_line_numbers : int } let cfg lines = let v = max_line_number lines in let v = Float.of_int v |> Float.log10 |> Float.to_int |> succ in { length_of_line_numbers = v } let pp_line_number ~cfg ppf line_number = let pp ppf line_number = Fmt.pf ppf "%*d" cfg.length_of_line_numbers line_number in Fmt.pf ppf "%a" Fmt.(styled `Faint pp) line_number let pp_error ppf str = let str = escape str in Fmt.pf ppf "%a" Fmt.(styled (`Fg `Red) string) str let pp_newline ppf = function | false -> () | true -> Fmt.pf ppf "%a" Fmt.(styled `Faint string) "\\n" let pp_line_with_ansi ~cfg ppf = function | line_number, Bcfg.Txtloc.Context_line line -> Fmt.pf ppf " %a %a@\n" (pp_line_number ~cfg) line_number Fmt.(styled `Faint string) (rchop_if_lf line) | line_number, Bcfg.Txtloc.Errored_line { err; around = pre, nxt } -> let with_newline = has_newline nxt in Fmt.pf ppf ">%a %s%a%s%a@\n" (pp_line_number ~cfg) line_number pre Fmt.(styled (`Fg `Red) pp_error) err (rchop_if_lf nxt) pp_newline with_newline | _, Eof { errored = true } -> Fmt.pf ppf ">%s %a@\n" (String.make cfg.length_of_line_numbers ' ') Fmt.(styled (`Fg `Red) string) "EOF" | _, Eof { errored = false } -> Fmt.pf ppf " %s %a@\n" (String.make cfg.length_of_line_numbers ' ') Fmt.(styled `Faint string) "EOF" let pp_symbol : type a. a Bcfg.Error.symbol -> a Fmt.t = fun symbol ppf v -> match symbol with | Terminal Error -> Fmt.string ppf "#error" | Terminal Eof -> Fmt.string ppf "#eof" | Terminal Newline -> Fmt.string ppf "#newline" | Terminal Word -> Fmt.pf ppf "%S" v | Terminal LBrace -> Fmt.pf ppf "{" | Terminal RBrace -> Fmt.pf ppf "}" | Non_terminal Directives -> Fmt.pf ppf "@[<1>(Directives@ @[<hov>%a@])@]" Bcfg.pp_as_ocaml_value v | Non_terminal Newlines -> Fmt.string ppf "#newlines" | Non_terminal Directive -> Fmt.pf ppf "@[<1>(Directive @[<hov>%a@])@]" Bcfg.pp_as_ocaml_value [ v ] | Non_terminal Parameters -> Fmt.pf ppf "@[<hov>%a@]" Fmt.(Dump.list (fmt "%S")) v | Non_terminal Children -> Fmt.pf ppf "@[<1>(Children@ ]@[<hov>%a@])@]" Bcfg.pp_as_ocaml_value v | Non_terminal Top -> Fmt.pf ppf "@[<1>(Top@ @[<hov>%a@]@]" Bcfg.pp_as_ocaml_value v let pp_error_message ppf (state, Bcfg.Error.Error (symbol, v)) = match (state, symbol) with | 1, Terminal Newline -> Fmt.pf ppf "> Unexpected closing curly bracked.@\n" | 4, Terminal Word -> Fmt.pf ppf "> The %a directive must end with a line break or an opening curly \ bracket.@\n" Fmt.(styled (`Fg `Yellow) (fmt "%S")) v | 5, Terminal Word -> Fmt.pf ppf "> Unexpected closing curly bracket after %a.@\n" Fmt.(styled (`Fg `Yellow) (fmt "%S")) v | 8, Terminal Newline -> Fmt.pf ppf "> A directive (potentially with parameters) must always precede a \ opening curly bracket.@\n" | 10, Terminal LBrace -> Fmt.pf ppf "> A opening curly bracket must always be followed by a line break.@\n" | 11, Non_terminal Newlines -> Fmt.pf ppf "> Missing a subdirective.@\n" | 12, Non_terminal Directives -> Fmt.pf ppf "> We are in a directive that does not end; a closing curly bracket \ should follow the subdirective %a.@\n" Fmt.(styled (`Fg `Yellow) (fmt "%S")) (List.hd v).Bcfg.name | 13, Terminal RBrace -> Fmt.pf ppf "> A closing curly bracket must always be followed by a line break.@\n" | 15, Non_terminal Directive -> Fmt.pf ppf "> We are in a directive that does not end; a closing curly bracket \ should follow the subdirective %a.@\n" Fmt.(styled (`Fg `Yellow) (fmt "%S")) v.Bcfg.name | 19, Non_terminal Directives -> Fmt.pf ppf "> The directive %a was never opened, so there is no reason to close \ it.@\n" Fmt.(styled (`Fg `Yellow) (fmt "%S")) (List.hd v).Bcfg.name | 21, Non_terminal Directive -> Fmt.pf ppf "> The directive %a was never opened, so there is no reason to close \ it.@\n" Fmt.(styled (`Fg `Yellow) (fmt "%S")) v.Bcfg.name | state, symbol -> Fmt.pf ppf "%d => @[<hov>%a@]@\n" state (pp_symbol symbol) v let pp_error_with_source ~content ppf err = let lines txtloc = Bcfg.Txtloc.lines_around_txtloc_string ~txtloc content in match err with | `Lexer_error (txtloc, `Message msg) -> let lines = lines txtloc in let cfg = cfg lines in Fmt.pf ppf "Error at %a:@\n" Bcfg.Txtloc.pp txtloc; (* NOTE(dinosaure): [msg] (from [Lexer]) does **not** contains ['\n']. *) Fmt.pf ppf "> %s@\n" msg; let fn = Fmt.pf ppf "%a" (pp_line_with_ansi ~cfg) in List.iter fn lines | `Lexer_error (txtloc, `Invalid_character chr) -> let lines = lines txtloc in let cfg = cfg lines in Fmt.pf ppf "Invalid character %S at %a:@\n" (String.make 1 chr) Bcfg.Txtloc.pp txtloc; let fn = Fmt.pf ppf "%a" (pp_line_with_ansi ~cfg) in List.iter fn lines | `Parser_error (txtloc, None) -> let lines = lines txtloc in let cfg = cfg lines in Fmt.pf ppf "Invalid syntax at %a:@\n" Bcfg.Txtloc.pp txtloc; let fn = Fmt.pf ppf "%a" (pp_line_with_ansi ~cfg) in List.iter fn lines | `Parser_error (txtloc, Some err) -> let lines = lines txtloc in let cfg = cfg lines in Fmt.pf ppf "Error at %a:@\n" Bcfg.Txtloc.pp txtloc; (* NOTE(dinosaure): [msg] already contains ['\n']. *) Fmt.pf ppf "%a" pp_error_message err; let fn = Fmt.pf ppf "%a" (pp_line_with_ansi ~cfg) in List.iter fn lines | `Rejected -> Fmt.pf ppf "Rejected@\n" let run quiet input = let content = read_input input in let lexbuf = Lexing.from_string ~with_positions:true content in match Bcfg.parser lexbuf with | Ok _ -> Ok 0 | Error err when not quiet -> Fmt.epr "%a%!" (pp_error_with_source ~content) err; Ok 1 | Error _ -> Ok 1 open Cmdliner open Bcfg_cli let input = let doc = "The configuration file to validate." in let parser str = match str with | "-" -> Ok None | filepath when Sys.file_exists filepath && is_regular_file filepath -> Ok (Some filepath) | filepath -> error_msgf "%S does not exist or is not a regular file" filepath in let pp ppf = function | None -> Fmt.string ppf "-" | Some filepath -> Fmt.string ppf filepath in let input = Arg.conv (parser, pp) in let open Arg in value & pos 0 input None & info [] ~doc ~docv:"FILE" let term = let open Term in const run $ setup_logs $ input |> term_result ~usage:false let cmd = let doc = "$(tname) validates a configuration file." in let man = [] in let info = Cmd.info "validate" ~doc ~man in Cmd.v info term
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>