Coccinelle release 1.0.0-rc12
[bpt/coccinelle.git] / bundles / extlib / extlib-1.5.2 / extString.ml
1 (*
2 * ExtString - Additional functions for string manipulations.
3 * Copyright (C) 2003 Nicolas Cannasse
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version,
9 * with the special exception on linking described in file LICENSE.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *)
20
21 exception Invalid_string
22
23 module String = struct
24
25 include String
26
27 let init len f =
28 let s = create len in
29 for i = 0 to len - 1 do
30 unsafe_set s i (f i)
31 done;
32 s
33
34 let starts_with str p =
35 if length str < length p then
36 false
37 else
38 let rec loop str p i =
39 if i = length p then true else
40 if unsafe_get str i <> unsafe_get p i then false
41 else loop str p (i+1)
42 in
43 loop str p 0
44
45 let ends_with s e =
46 if length s < length e then
47 false
48 else
49 let rec loop s e i =
50 if i = length e then true else
51 if unsafe_get s (length s - length e + i) <> unsafe_get e i then false
52 else loop s e (i+1)
53 in
54 loop s e 0
55
56 let find str sub =
57 let sublen = length sub in
58 if sublen = 0 then
59 0
60 else
61 let found = ref 0 in
62 let len = length str in
63 try
64 for i = 0 to len - sublen do
65 let j = ref 0 in
66 while unsafe_get str (i + !j) = unsafe_get sub !j do
67 incr j;
68 if !j = sublen then begin found := i; raise Exit; end;
69 done;
70 done;
71 raise Invalid_string
72 with
73 Exit -> !found
74
75 let exists str sub =
76 try
77 ignore(find str sub);
78 true
79 with
80 Invalid_string -> false
81
82 let strip ?(chars=" \t\r\n") s =
83 let p = ref 0 in
84 let l = length s in
85 while !p < l && contains chars (unsafe_get s !p) do
86 incr p;
87 done;
88 let p = !p in
89 let l = ref (l - 1) in
90 while !l >= p && contains chars (unsafe_get s !l) do
91 decr l;
92 done;
93 sub s p (!l - p + 1)
94
95 let split str sep =
96 let p = find str sep in
97 let len = length sep in
98 let slen = length str in
99 sub str 0 p, sub str (p + len) (slen - p - len)
100
101 let nsplit str sep =
102 if str = "" then []
103 else if sep = "" then raise Invalid_string
104 else (
105 let rec nsplit str sep =
106 try
107 let s1 , s2 = split str sep in
108 s1 :: nsplit s2 sep
109 with
110 Invalid_string -> [str]
111 in
112 nsplit str sep
113 )
114
115 let join = concat
116
117 let slice ?(first=0) ?(last=Sys.max_string_length) s =
118 let clip _min _max x = max _min (min _max x) in
119 let i = clip 0 (length s)
120 (if (first<0) then (length s) + first else first)
121 and j = clip 0 (length s)
122 (if (last<0) then (length s) + last else last)
123 in
124 if i>=j || i=length s then
125 create 0
126 else
127 sub s i (j-i)
128
129 let lchop s =
130 if s = "" then "" else sub s 1 (length s - 1)
131
132 let rchop s =
133 if s = "" then "" else sub s 0 (length s - 1)
134
135 let of_int = string_of_int
136
137 let of_float = string_of_float
138
139 let of_char = make 1
140
141 let to_int s =
142 try
143 int_of_string s
144 with
145 _ -> raise Invalid_string
146
147 let to_float s =
148 try
149 float_of_string s
150 with
151 _ -> raise Invalid_string
152
153 let enum s =
154 let l = length s in
155 let rec make i =
156 Enum.make
157 ~next:(fun () ->
158 if !i = l then
159 raise Enum.No_more_elements
160 else
161 let p = !i in
162 incr i;
163 unsafe_get s p
164 )
165 ~count:(fun () -> l - !i)
166 ~clone:(fun () -> make (ref !i))
167 in
168 make (ref 0)
169
170 let of_enum e =
171 let l = Enum.count e in
172 let s = create l in
173 let i = ref 0 in
174 Enum.iter (fun c -> unsafe_set s !i c; incr i) e;
175 s
176
177 let map f s =
178 let len = length s in
179 let sc = create len in
180 for i = 0 to len - 1 do
181 unsafe_set sc i (f (unsafe_get s i))
182 done;
183 sc
184
185 (* fold_left and fold_right by Eric C. Cooper *)
186 let fold_left f init str =
187 let n = String.length str in
188 let rec loop i result =
189 if i = n then result
190 else loop (i + 1) (f result str.[i])
191 in
192 loop 0 init
193
194 let fold_right f str init =
195 let n = String.length str in
196 let rec loop i result =
197 if i = 0 then result
198 else
199 let i' = i - 1 in
200 loop i' (f str.[i'] result)
201 in
202 loop n init
203
204 (* explode and implode from the OCaml Expert FAQ. *)
205 let explode s =
206 let rec exp i l =
207 if i < 0 then l else exp (i - 1) (s.[i] :: l) in
208 exp (String.length s - 1) []
209
210 let implode l =
211 let res = String.create (List.length l) in
212 let rec imp i = function
213 | [] -> res
214 | c :: l -> res.[i] <- c; imp (i + 1) l in
215 imp 0 l
216
217
218 let replace_chars f s =
219 let len = String.length s in
220 let tlen = ref 0 in
221 let rec loop i acc =
222 if i = len then
223 acc
224 else
225 let s = f (unsafe_get s i) in
226 tlen := !tlen + length s;
227 loop (i+1) (s :: acc)
228 in
229 let strs = loop 0 [] in
230 let sbuf = create !tlen in
231 let pos = ref !tlen in
232 let rec loop2 = function
233 | [] -> ()
234 | s :: acc ->
235 let len = length s in
236 pos := !pos - len;
237 blit s 0 sbuf !pos len;
238 loop2 acc
239 in
240 loop2 strs;
241 sbuf
242
243 let replace ~str ~sub ~by =
244 try
245 let i = find str sub in
246 (true, (slice ~last:i str) ^ by ^
247 (slice ~first:(i+(String.length sub)) str))
248 with
249 Invalid_string -> (false, String.copy str)
250
251 end