package b0
Software construction and deployment kit
Install
dune-project
Dependency
Authors
Maintainers
Sources
b0-0.0.6.tbz
sha512=e9aa779e66c08fc763019f16d4706f465d16c05d6400b58fbd0313317ef33ddea51952e2b058db28e65f7ddb7012f328c8bf02d8f1da17bb543348541a2587f0
doc/src/b0.std/b0__cmd.ml.html
Source file b0__cmd.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
(*--------------------------------------------------------------------------- Copyright (c) 2025 The more programmers. All rights reserved. SPDX-License-Identifier: ISC ---------------------------------------------------------------------------*) type t = | A of string | Unstamp of t | Rseq of t list (* Sequence is reversed; only empty at toplevel *) let empty = Rseq [] let rec is_empty = function Rseq [] -> true | _ -> false let arg a = A a let append l0 l1 = match l0, l1 with | Rseq [], l1 -> l1 | l0, Rseq [] -> l0 | Rseq ls, l -> Rseq (l :: ls) | l1, l2 -> Rseq ([l2; l1]) let unstamp = function | Rseq [] -> empty | l -> Unstamp l let ( % ) l a = append l (arg a) let ( %% ) = append (* Derived combinators *) let if' cond l = if cond then l else empty let if_some o = match o with Some cmd -> cmd | None -> empty let path p = A (B0__fpath.to_string p) let int i = A (string_of_int i) let float f = A (string_of_float f) let list ?slip l = match slip with | None -> Rseq (List.rev_map arg l) | Some slip -> Rseq (List.fold_left (fun acc v -> A v :: A slip :: acc) [] l) let of_list ?slip conv l = match slip with | None -> Rseq (List.rev_map (fun a -> A (conv a)) l) | Some slip -> let add acc v = A (conv v) :: A slip :: acc in Rseq (List.fold_left add [] l) let paths ?slip ps = of_list ?slip B0__fpath.to_string ps (* Converting *) let to_list l = let rec loop acc = function | A a -> a :: acc | Rseq ls -> List.fold_left loop acc ls | Unstamp l -> loop acc l in loop [] l let to_list_and_stamp l = let rec loop unstamped acc sg = function | A a -> (a :: acc), (if unstamped then sg else a :: sg) | Rseq ls -> let rec sub unstamped acc sg = function | [] -> acc, sg | l :: ls -> let acc, sg = loop unstamped acc sg l in sub unstamped acc sg ls in sub unstamped acc sg ls | Unstamp l -> loop true acc sg l in loop false [] [] l let to_stamp l = let rec loop acc = function | A a -> (a :: acc) | Rseq ls -> List.fold_left loop acc ls | Unstamp l -> acc in loop [] l let of_string s = (* Parsing is loosely based on http://pubs.opengroup.org/onlinepubs/009695399/utilities/\ xcu_chap02.html#tag_02_03 XXX Rewrite, this was quickly ported from bos code based on Astring.String.sub *) try let err_unclosed kind _ = B0__fmt.failwith "unclosed %s quote delimited string" kind in let skip_white s = B0__string.drop_first_while B0__char.Ascii.is_white s in let tok_sep c = c = '\'' || c = '\"' || B0__char.Ascii.is_white c in let tok_char c = not (tok_sep c) in let not_squote c = c <> '\'' in let tail s = (* Yikes *) B0__string.subrange ~first:1 s in let parse_squoted s = let tok, rem = B0__string.cut_first_while not_squote (tail s) in if not (String.equal rem "") then tok, tail rem else err_unclosed "single" s in let parse_dquoted acc s = let is_data = function '\\' | '"' -> false | _ -> true in let rec loop acc s = let data, rem = B0__string.cut_first_while is_data s in match B0__string.head rem with | Some '"' -> (data :: acc), (tail rem) | Some '\\' -> let rem = tail rem in begin match B0__string.head rem with | Some ('"' | '\\' | '$' | '`' as c) -> let acc = (B0__string.of_char c) :: data :: acc in loop acc (tail rem) | Some ('\n') -> loop (data :: acc) (tail rem) | Some c -> let acc = (data ^ (B0__fmt.str "\\%c" c)) :: acc in loop acc (tail rem) | None -> err_unclosed "double" s end | None -> err_unclosed "double" s | Some _ -> assert false in loop acc (tail s) in let parse_token s = let ret acc s = String.concat "" (List.rev acc), s in let rec loop acc s = match B0__string.head s with | None -> ret acc s | Some c when B0__char.Ascii.is_white c -> ret acc s | Some '\'' -> let tok, rem = parse_squoted s in loop (tok :: acc) rem | Some '\"' -> let acc, rem = parse_dquoted acc s in loop acc rem | Some c -> let sat = tok_char in let tok, rem = B0__string.cut_first_while sat s in loop (tok :: acc) rem in loop [] s in let rec loop acc s = match String.equal s "" with | false -> let token, s = parse_token s in loop (A token :: acc) (skip_white s) | true -> match acc with | [a] -> a | acc -> Rseq acc in Ok (loop [] (skip_white s)) with Failure err -> B0__fmt.error "command line %a: %s" B0__fmt.OCaml.string s err let to_string l = String.concat " " (List.map Filename.quote @@ to_list l) let pp ppf l = B0__fmt.pf ppf "@[%a@]" B0__fmt.(list ~sep:sp string) (to_list l) let pp_dump ppf l = let pp_arg ppf a = B0__fmt.string ppf (Filename.quote a) in B0__fmt.pf ppf "@[<h>%a@]" B0__fmt.(list ~sep:sp pp_arg) (to_list l) let pp_shell = let pp_arg ppf a = B0__fmt.string ppf (Filename.quote a) in let pp_cmd ppf l = let is_opt s = String.length s > 1 && s.[0] = '-' in match (to_list l) with | [] -> () | s :: ss -> let rec loop ~last_is_opt ppf = function | [] -> () | s :: ss -> let is_opt = is_opt s in (if last_is_opt && not is_opt then B0__fmt.char ppf ' ' else B0__fmt.sp ppf ()); pp_arg ppf s; loop ~last_is_opt:is_opt ppf ss in pp_arg ppf s; loop ~last_is_opt:(is_opt s) ppf ss in B0__fmt.suffix_lines ~suffix:" \\" pp_cmd let rec fold ~arg ~unstamp ~append ~empty = function | A a -> arg a | Unstamp c -> unstamp (fold ~arg ~unstamp ~append ~empty c) | Rseq l -> let append acc v = append (fold ~arg ~unstamp ~append ~empty v) acc in List.fold_left append empty l let rec iter_enc ~arg ~unstamp ~append ~empty e = function | A a -> arg e a | Unstamp c -> unstamp e; iter_enc ~arg ~unstamp ~append ~empty e c | Rseq l -> let append e v = append e; iter_enc ~arg ~unstamp ~append ~empty e v; e in ignore (List.fold_left append e l); empty e (* Tools *) type tool = B0__fpath.t let tool = arg let rec find_tool = function | A a -> Result.to_option (B0__fpath.of_string a) | Unstamp l -> find_tool l | Rseq ls -> let rec loop = function | [l] -> find_tool l | l :: ls -> loop ls | [] -> None in loop ls let get_tool l = match find_tool l with | Some t -> Ok t | None when is_empty l -> Error "The command is empty" | None -> B0__fmt.error "%s: Not a tool" (to_string l) let rec set_tool tool = function | Rseq [] -> path tool | l -> let rec loop = function | A a -> A (B0__fpath.to_string tool) | Unstamp l -> Unstamp (loop l) | Rseq ls -> match List.rev ls with | arg :: args -> Rseq (List.rev @@ (loop arg) :: args) | [] -> assert false in loop l type tool_search = t -> (t, string) result (* Predicates *) let rec is_singleton = function | A a -> true | Unstamp l -> is_singleton l | Rseq _ -> false
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>