dist: Add extra files to tarball.
[goals.git] / src / utils.ml
1 (* Goalfile utilities
2  * Copyright (C) 2019 Richard W.M. Jones
3  * Copyright (C) 2019 Red Hat Inc.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  *)
19
20 open Printf
21
22 external nprocs : unit -> int = "nprocs"
23
24 let failwithf fs = ksprintf failwith fs
25
26 let (//) = Filename.concat
27 let is_directory d = try Sys.is_directory d with Sys_error _ -> false
28
29 let unique = let i = ref 0 in fun () -> incr i; !i
30
31 (* From OCaml 4.08 sources.  We can remove this when we can
32  * depend on min OCaml 4.08.
33  *)
34 let filter_map f =
35   let rec aux accu = function
36     | [] -> List.rev accu
37     | x :: l ->
38         match f x with
39         | None -> aux accu l
40         | Some v -> aux (v :: accu) l
41   in
42   aux []
43
44
45 (* From libguestfs sources. *)
46 let rec string_find s sub =
47   let len = String.length s in
48   let sublen = String.length sub in
49   let rec loop i =
50     if i <= len-sublen then (
51       let rec loop2 j =
52         if j < sublen then (
53           if s.[i+j] = sub.[j] then loop2 (j+1)
54           else -1
55         ) else
56           i (* found *)
57       in
58       let r = loop2 0 in
59       if r = -1 then loop (i+1) else r
60     ) else
61       -1 (* not found *)
62   in
63   loop 0
64
65 let rec split sep str =
66   let len = String.length sep in
67   let seplen = String.length str in
68   let i = string_find str sep in
69   if i = -1 then str, ""
70   else (
71     String.sub str 0 i, String.sub str (i + len) (seplen - i - len)
72   )
73
74 and nsplit ?(max = 0) sep str =
75   if max < 0 then
76     invalid_arg "String.nsplit: max parameter should not be negative";
77
78   (* If we reached the limit, OR if the pattern does not match the string
79    * at all, return the rest of the string as a single element list.
80    *)
81   if max = 1 || string_find str sep = -1 then
82     [str]
83   else (
84     let s1, s2 = split sep str in
85     let max = if max = 0 then 0 else max - 1 in
86     s1 :: nsplit ~max sep s2
87   )
88
89 let isspace c =
90   c = ' '
91   (* || c = '\f' *) || c = '\n' || c = '\r' || c = '\t' (* || c = '\v' *)
92
93 let triml ?(test = isspace) str =
94   let i = ref 0 in
95   let n = ref (String.length str) in
96   while !n > 0 && test str.[!i]; do
97     decr n;
98     incr i
99   done;
100   if !i = 0 then str
101   else String.sub str !i !n
102
103 let trimr ?(test = isspace) str =
104   let n = ref (String.length str) in
105   while !n > 0 && test str.[!n-1]; do
106     decr n
107   done;
108   if !n = String.length str then str
109   else String.sub str 0 !n
110
111 let trim ?(test = isspace) str =
112   trimr ~test (triml ~test str)
113
114 let absolute_path path =
115   if not (Filename.is_relative path) then path else Sys.getcwd () // path