Blame src/extString.ml

rpm-build 0f2925
(*
rpm-build 0f2925
 * ExtString - Additional functions for string manipulations.
rpm-build 0f2925
 * Copyright (C) 2003 Nicolas Cannasse
rpm-build 0f2925
 * 
rpm-build 0f2925
 * This library is free software; you can redistribute it and/or
rpm-build 0f2925
 * modify it under the terms of the GNU Lesser General Public
rpm-build 0f2925
 * License as published by the Free Software Foundation; either
rpm-build 0f2925
 * version 2.1 of the License, or (at your option) any later version,
rpm-build 0f2925
 * with the special exception on linking described in file LICENSE.
rpm-build 0f2925
 *
rpm-build 0f2925
 * This library is distributed in the hope that it will be useful,
rpm-build 0f2925
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
rpm-build 0f2925
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
rpm-build 0f2925
 * Lesser General Public License for more details.
rpm-build 0f2925
 *
rpm-build 0f2925
 * You should have received a copy of the GNU Lesser General Public
rpm-build 0f2925
 * License along with this library; if not, write to the Free Software
rpm-build 0f2925
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
rpm-build 0f2925
 *)
rpm-build 0f2925
rpm-build 0f2925
exception Invalid_string
rpm-build 0f2925
rpm-build 0f2925
open ExtBytes
rpm-build 0f2925
rpm-build 0f2925
module String = struct
rpm-build 0f2925
rpm-build 0f2925
include String
rpm-build 0f2925
rpm-build 0f2925
#if OCAML < 402
rpm-build 0f2925
let init len f =
rpm-build 0f2925
  let s = Bytes.create len in
rpm-build 0f2925
  for i = 0 to len - 1 do
rpm-build 0f2925
    Bytes.unsafe_set s i (f i)
rpm-build 0f2925
  done;
rpm-build 0f2925
        (* 's' doesn't escape and will never be mutated again *)
rpm-build 0f2925
  Bytes.unsafe_to_string s
rpm-build 0f2925
#endif
rpm-build 0f2925
rpm-build 0f2925
let starts_with str p =
rpm-build 0f2925
  if length str < length p then 
rpm-build 0f2925
    false
rpm-build 0f2925
  else
rpm-build 0f2925
    let rec loop str p i =
rpm-build 0f2925
      if i = length p then true else
rpm-build 0f2925
      if unsafe_get str i <> unsafe_get p i then false
rpm-build 0f2925
      else loop str p (i+1)
rpm-build 0f2925
    in
rpm-build 0f2925
    loop str p 0
rpm-build 0f2925
rpm-build 0f2925
let ends_with s e =
rpm-build 0f2925
  if length s < length e then
rpm-build 0f2925
    false
rpm-build 0f2925
  else
rpm-build 0f2925
    let rec loop s e i =
rpm-build 0f2925
      if i = length e then true else
rpm-build 0f2925
      if unsafe_get s (length s - length e + i) <> unsafe_get e i then false
rpm-build 0f2925
      else loop s e (i+1)
rpm-build 0f2925
    in
rpm-build 0f2925
    loop s e 0
rpm-build 0f2925
rpm-build 0f2925
let find_from str pos sub =
rpm-build 0f2925
  let sublen = length sub in
rpm-build 0f2925
  if sublen = 0 then
rpm-build 0f2925
    0
rpm-build 0f2925
  else
rpm-build 0f2925
    let found = ref 0 in
rpm-build 0f2925
    let len = length str in
rpm-build 0f2925
    try
rpm-build 0f2925
      for i = pos to len - sublen do
rpm-build 0f2925
        let j = ref 0 in
rpm-build 0f2925
        while unsafe_get str (i + !j) = unsafe_get sub !j do
rpm-build 0f2925
          incr j;
rpm-build 0f2925
          if !j = sublen then begin found := i; raise Exit; end;
rpm-build 0f2925
        done;
rpm-build 0f2925
      done;
rpm-build 0f2925
      raise Invalid_string
rpm-build 0f2925
    with
rpm-build 0f2925
      Exit -> !found
rpm-build 0f2925
rpm-build 0f2925
let find str sub = find_from str 0 sub
rpm-build 0f2925
rpm-build 0f2925
let exists str sub =
rpm-build 0f2925
  try
rpm-build 0f2925
    ignore(find str sub);
rpm-build 0f2925
    true
rpm-build 0f2925
  with
rpm-build 0f2925
    Invalid_string -> false
rpm-build 0f2925
rpm-build 0f2925
let strip ?(chars=" \t\r\n") s =
rpm-build 0f2925
  let p = ref 0 in
rpm-build 0f2925
  let l = length s in
rpm-build 0f2925
  while !p < l && contains chars (unsafe_get s !p) do
rpm-build 0f2925
    incr p;
rpm-build 0f2925
  done;
rpm-build 0f2925
  let p = !p in
rpm-build 0f2925
  let l = ref (l - 1) in
rpm-build 0f2925
  while !l >= p && contains chars (unsafe_get s !l) do
rpm-build 0f2925
    decr l;
rpm-build 0f2925
  done;
rpm-build 0f2925
  sub s p (!l - p + 1)
rpm-build 0f2925
rpm-build 0f2925
#if OCAML < 400
rpm-build 0f2925
let trim s = strip ~chars:" \t\r\n\012" s
rpm-build 0f2925
#endif
rpm-build 0f2925
rpm-build 0f2925
let split str sep =
rpm-build 0f2925
  let p = find str sep in
rpm-build 0f2925
  let len = length sep in
rpm-build 0f2925
  let slen = length str in
rpm-build 0f2925
  sub str 0 p, sub str (p + len) (slen - p - len)
rpm-build 0f2925
rpm-build 0f2925
let nsplit str sep =
rpm-build 0f2925
  if str = "" then []
rpm-build 0f2925
  else if sep = "" then raise Invalid_string
rpm-build 0f2925
  else
rpm-build 0f2925
    let rec loop acc pos =
rpm-build 0f2925
      if pos > String.length str then
rpm-build 0f2925
        List.rev acc
rpm-build 0f2925
      else
rpm-build 0f2925
        let i = try find_from str pos sep with Invalid_string -> String.length str in
rpm-build 0f2925
        loop (String.sub str pos (i - pos) :: acc) (i + String.length sep)
rpm-build 0f2925
    in
rpm-build 0f2925
    loop [] 0
rpm-build 0f2925
rpm-build 0f2925
let join = concat
rpm-build 0f2925
rpm-build 0f2925
let slice =
rpm-build 0f2925
  let clip max x = if x > max then max else if x < 0 then 0 else x in
rpm-build 0f2925
  fun ?(first=0) ?(last=Sys.max_string_length) s ->
rpm-build 0f2925
    let len = String.length s in
rpm-build 0f2925
    let i = if first = 0 then 0 else clip len (if first < 0 then len + first else first) in
rpm-build 0f2925
    let j = if last = Sys.max_string_length then len else clip len (if last < 0 then len + last else last) in
rpm-build 0f2925
    if i>=j || i=len then
rpm-build 0f2925
      make 0 ' '
rpm-build 0f2925
    else
rpm-build 0f2925
      sub s i (j-i)
rpm-build 0f2925
rpm-build 0f2925
let lchop s =
rpm-build 0f2925
  if s = "" then "" else sub s 1 (length s - 1)
rpm-build 0f2925
rpm-build 0f2925
let rchop s =
rpm-build 0f2925
  if s = "" then "" else sub s 0 (length s - 1)
rpm-build 0f2925
rpm-build 0f2925
let of_int = string_of_int
rpm-build 0f2925
rpm-build 0f2925
let of_float = string_of_float
rpm-build 0f2925
rpm-build 0f2925
let of_char = make 1
rpm-build 0f2925
rpm-build 0f2925
let to_int s =
rpm-build 0f2925
  try
rpm-build 0f2925
    int_of_string s
rpm-build 0f2925
  with
rpm-build 0f2925
    _ -> raise Invalid_string
rpm-build 0f2925
rpm-build 0f2925
let to_float s =
rpm-build 0f2925
  try
rpm-build 0f2925
    float_of_string s
rpm-build 0f2925
  with
rpm-build 0f2925
    _ -> raise Invalid_string
rpm-build 0f2925
rpm-build 0f2925
let enum s =
rpm-build 0f2925
  let l = length s in
rpm-build 0f2925
  let rec make i =
rpm-build 0f2925
    Enum.make 
rpm-build 0f2925
    ~next:(fun () ->
rpm-build 0f2925
      if !i = l then
rpm-build 0f2925
        raise Enum.No_more_elements
rpm-build 0f2925
      else
rpm-build 0f2925
        let p = !i in
rpm-build 0f2925
        incr i;
rpm-build 0f2925
        unsafe_get s p
rpm-build 0f2925
      )
rpm-build 0f2925
    ~count:(fun () -> l - !i)
rpm-build 0f2925
    ~clone:(fun () -> make (ref !i))
rpm-build 0f2925
  in
rpm-build 0f2925
  make (ref 0)
rpm-build 0f2925
rpm-build 0f2925
let of_enum e =
rpm-build 0f2925
  let l = Enum.count e in
rpm-build 0f2925
  let s = Bytes.create l in
rpm-build 0f2925
  let i = ref 0 in
rpm-build 0f2925
  Enum.iter (fun c -> Bytes.unsafe_set s !i c; incr i) e;
rpm-build 0f2925
        (* 's' doesn't escape and will never be mutated again *)
rpm-build 0f2925
  Bytes.unsafe_to_string s
rpm-build 0f2925
rpm-build 0f2925
#if OCAML < 400
rpm-build 0f2925
let map f s =
rpm-build 0f2925
  let len = length s in
rpm-build 0f2925
  let sc = Bytes.create len in
rpm-build 0f2925
  for i = 0 to len - 1 do
rpm-build 0f2925
    Bytes.unsafe_set sc i (f (unsafe_get s i))
rpm-build 0f2925
  done;
rpm-build 0f2925
        (* 'sc' doesn't escape and will never be mutated again *)
rpm-build 0f2925
  Bytes.unsafe_to_string sc
rpm-build 0f2925
#endif
rpm-build 0f2925
rpm-build 0f2925
#if OCAML < 402
rpm-build 0f2925
let mapi f s =
rpm-build 0f2925
  let len = length s in
rpm-build 0f2925
  let sc = Bytes.create len in
rpm-build 0f2925
  for i = 0 to len - 1 do
rpm-build 0f2925
    Bytes.unsafe_set sc i (f i (unsafe_get s i))
rpm-build 0f2925
  done;
rpm-build 0f2925
        (* 'sc' doesn't escape and will never be mutated again *)
rpm-build 0f2925
  Bytes.unsafe_to_string sc
rpm-build 0f2925
#endif
rpm-build 0f2925
rpm-build 0f2925
#if OCAML < 400
rpm-build 0f2925
let iteri f s =
rpm-build 0f2925
  for i = 0 to length s - 1 do
rpm-build 0f2925
    let () = f i (unsafe_get s i) in ()
rpm-build 0f2925
  done
rpm-build 0f2925
#endif
rpm-build 0f2925
rpm-build 0f2925
(* fold_left and fold_right by Eric C. Cooper *)
rpm-build 0f2925
let fold_left f init str =
rpm-build 0f2925
  let n = String.length str in
rpm-build 0f2925
  let rec loop i result =
rpm-build 0f2925
    if i = n then result
rpm-build 0f2925
    else loop (i + 1) (f result str.[i])
rpm-build 0f2925
  in
rpm-build 0f2925
  loop 0 init
rpm-build 0f2925
rpm-build 0f2925
let fold_right f str init =
rpm-build 0f2925
  let n = String.length str in
rpm-build 0f2925
  let rec loop i result =
rpm-build 0f2925
    if i = 0 then result
rpm-build 0f2925
    else
rpm-build 0f2925
      let i' = i - 1 in
rpm-build 0f2925
      loop i' (f str.[i'] result)
rpm-build 0f2925
  in
rpm-build 0f2925
  loop n init
rpm-build 0f2925
rpm-build 0f2925
(* explode and implode from the OCaml Expert FAQ. *)
rpm-build 0f2925
let explode s =
rpm-build 0f2925
  let rec exp i l =
rpm-build 0f2925
    if i < 0 then l else exp (i - 1) (s.[i] :: l) in
rpm-build 0f2925
  exp (String.length s - 1) []
rpm-build 0f2925
rpm-build 0f2925
let implode l =
rpm-build 0f2925
  let res = Bytes.create (List.length l) in
rpm-build 0f2925
  let rec imp i = function
rpm-build 0f2925
  | [] -> res
rpm-build 0f2925
  | c :: l -> Bytes.set res i c; imp (i + 1) l in
rpm-build 0f2925
  let s = imp 0 l in
rpm-build 0f2925
  (* 's' doesn't escape and will never be mutated again *)
rpm-build 0f2925
  Bytes.unsafe_to_string s
rpm-build 0f2925
rpm-build 0f2925
let replace_chars f s =
rpm-build 0f2925
  let len = String.length s in
rpm-build 0f2925
  let tlen = ref 0 in
rpm-build 0f2925
  let rec loop i acc =
rpm-build 0f2925
    if i = len then
rpm-build 0f2925
      acc
rpm-build 0f2925
    else 
rpm-build 0f2925
      let s = f (unsafe_get s i) in
rpm-build 0f2925
      tlen := !tlen + length s;
rpm-build 0f2925
      loop (i+1) (s :: acc)
rpm-build 0f2925
  in
rpm-build 0f2925
  let strs = loop 0 [] in
rpm-build 0f2925
  let sbuf = Bytes.create !tlen in
rpm-build 0f2925
  let pos = ref !tlen in
rpm-build 0f2925
  let rec loop2 = function
rpm-build 0f2925
    | [] -> ()
rpm-build 0f2925
    | s :: acc ->
rpm-build 0f2925
      let len = length s in
rpm-build 0f2925
      pos := !pos - len;
rpm-build 0f2925
      blit s 0 sbuf !pos len;
rpm-build 0f2925
      loop2 acc
rpm-build 0f2925
  in
rpm-build 0f2925
  loop2 strs;
rpm-build 0f2925
        (* 'sbuf' doesn't escape and will never be mutated again *)
rpm-build 0f2925
  Bytes.unsafe_to_string sbuf
rpm-build 0f2925
rpm-build 0f2925
let replace ~str ~sub ~by =
rpm-build 0f2925
  try
rpm-build 0f2925
    let i = find str sub in
rpm-build 0f2925
    (true, (slice ~last:i str) ^ by ^ 
rpm-build 0f2925
                   (slice ~first:(i+(String.length sub)) str))
rpm-build 0f2925
        with
rpm-build 0f2925
    Invalid_string -> (false, String.sub str 0 (String.length str))
rpm-build 0f2925
rpm-build 0f2925
#if OCAML < 403
rpm-build 0f2925
let uppercase_ascii = uppercase
rpm-build 0f2925
let lowercase_ascii = lowercase
rpm-build 0f2925
let capitalize_ascii = capitalize
rpm-build 0f2925
let uncapitalize_ascii = uncapitalize
rpm-build 0f2925
rpm-build 0f2925
let equal = (=)
rpm-build 0f2925
#endif
rpm-build 0f2925
rpm-build 0f2925
#if OCAML < 404
rpm-build 0f2925
let split_on_char sep s =
rpm-build 0f2925
  let r = ref [] in
rpm-build 0f2925
  let j = ref (length s) in
rpm-build 0f2925
  for i = length s - 1 downto 0 do
rpm-build 0f2925
    if unsafe_get s i = sep then begin
rpm-build 0f2925
      r := sub s (i + 1) (!j - i - 1) :: !r;
rpm-build 0f2925
      j := i
rpm-build 0f2925
    end
rpm-build 0f2925
  done;
rpm-build 0f2925
  sub s 0 !j :: !r
rpm-build 0f2925
#endif
rpm-build 0f2925
rpm-build 0f2925
#if OCAML < 405
rpm-build 0f2925
rpm-build 0f2925
let rec index_rec_opt s lim i c =
rpm-build 0f2925
  if i >= lim then None else
rpm-build 0f2925
  if unsafe_get s i = c then Some i else index_rec_opt s lim (i + 1) c
rpm-build 0f2925
rpm-build 0f2925
let index_opt s c = index_rec_opt s (length s) 0 c
rpm-build 0f2925
rpm-build 0f2925
let index_from_opt s i c =
rpm-build 0f2925
  let l = length s in
rpm-build 0f2925
  if i < 0 || i > l then invalid_arg "ExtString.index_from_opt" else
rpm-build 0f2925
  index_rec_opt s l i c
rpm-build 0f2925
rpm-build 0f2925
let rec rindex_rec_opt s i c =
rpm-build 0f2925
  if i < 0 then None else
rpm-build 0f2925
  if unsafe_get s i = c then Some i else rindex_rec_opt s (i - 1) c
rpm-build 0f2925
rpm-build 0f2925
let rindex_opt s c = rindex_rec_opt s (length s - 1) c
rpm-build 0f2925
rpm-build 0f2925
let rindex_from_opt s i c =
rpm-build 0f2925
  if i < -1 || i >= length s then
rpm-build 0f2925
    invalid_arg "ExtString.rindex_from_opt"
rpm-build 0f2925
  else
rpm-build 0f2925
    rindex_rec_opt s i c
rpm-build 0f2925
rpm-build 0f2925
#endif
rpm-build 0f2925
rpm-build 0f2925
end