(*
 * String utilities
 *)

(* Convert a string to uppercase *)
let uppercase s =
  let l = String.length s in
  let res = String.sub s 0 l in
    for i = 0 to l - 1 do
        match s.[i] with
         'a'..'z' as c -> res.[i] <- Char.chr (Char.code c - 32)
       | _ -> ()
    done;
  res

(* Convert a string to lowercase *)
let lowercase s =
  let l = String.length s in
  let res = String.sub s 0 l in
    for i = 0 to l - 1 do
        match s.[i] with
         'A'..'Z' as c -> res.[i] <- Char.chr (Char.code c + 32)
       | _ -> ()
    done;
  res

(* split a string according to char_sep predicate *)
let split_str char_sep str =
  let len = String.length str in
  if len = 0 then [] else
    let rec skip_sep cur =
      if cur >= len then cur
      else if char_sep str.[cur] then skip_sep (succ cur)
      else cur  in
    let rec split beg cur =
      if cur >= len then 
	if beg = cur then []
	else [String.sub str beg (len - beg)]
      else if char_sep str.[cur] 
	   then 
	     let nextw = skip_sep cur in
	      (String.sub str beg (cur - beg))
		::(split nextw nextw)
	   else split beg (succ cur) in
    let wstart = skip_sep 0 in
    split wstart wstart

(* [first_char_pos c s] 
   finds the first position of char c in s or raises Not_found 
 *)
let first_char_pos c s =
  let l = String.length s in
  let rec pos i =
    if i >= l then raise Not_found
    else if s.[i] == c then i
    else pos (succ i) in
  pos 0

(* [last_char_pos c s] 
   finds the last position of char c in s or raises Not_found 
 *)
let last_char_pos c s =
  let l = String.length s in
    let rec pos i =
      if i < 0 then raise Not_found
      else if s.[i] == c then i
      else pos (pred i) in
    pos (l - 1)

(* extract the . suffix (dot excluded) of a string *)
let get_suffix s =
  try
    let dotpos = succ (last_char_pos '.' s) in
      String.sub s dotpos (String.length s - dotpos)
  with
    Not_found -> ""

(* HEX/DEC conversions *)
let hex_to_dec c = match c with
    '0'..'9' -> Char.code c - 48
  | 'a'..'f' -> Char.code c - 87 (* 87 = Char.code 'a' - 10 *)
  | 'A'..'F' -> Char.code c - 55 (* 55 = Char.code 'A' - 10 *)
  | _ -> failwith "hex_to_dec"

let dec_to_hex i =
  if i < 10 then Char.chr (i + 48)  (* 48 = Char.code '0' *)
  else Char.chr (i + 55)            (* 55 = Char.code 'A' - 10 *)

(* Converting a hex stored string *)
let hex_to_string s =
  let len = String.length s / 2 in
  let res = String.create len in
    for i = 0 to len - 1 do
      res.[i] <- Char.chr ( 16 * (hex_to_dec s.[i+i]) + hex_to_dec s.[i+i+1])
      done;
    res

let gensym =
  let cnter = ref 0 in
  (fun n ->
    incr cnter;
    n ^ string_of_int !cnter)

