(* -*- mode: sml -*-
 * $Id: strcat.smlnj,v 1.6 2001/07/10 04:01:48 doug Exp $
 * http://www.bagley.org/~doug/shootout/
 * from Stephen Weeks
 * Modified by Daniel Wang
 *)

structure Test : sig
    val main : (string * string list) -> OS.Process.status
end = struct

fun for (start, stop, f) =
   let
      fun loop i =
     if i > stop
        then ()
     else (f i; loop (i + 1))
   in
      loop start
   end

fun atoi s = case Int.fromString s of SOME num => num | NONE => 0
fun printl [] = print "\n" | printl(h::t) = ( print h ; printl t )

val stuff = "hello\n"

structure Buffer:
   sig
      type 'a t

      val add: 'a t * 'a array -> unit
      val length: 'a t -> int
      val new: 'a -> 'a t
   end =
   struct
      datatype 'a t = T of {dummy: 'a,
                length: int ref,
                elts: 'a array ref}

      fun add (T {dummy, elts, length}, a) =
     let
        val l = !length
        val e = !elts
        val en = Array.length e
        val an = Array.length a
        val e =
           if l + an >= en then    
         let val e' = Array.array(2 * en,dummy)
           val _ = Array.copy {src = e, si = 0,len = SOME en,
                       dst = e',di = 0}
           val _ = elts := e'
         in e'
         end
           else e
        val _ =
           Array.copy {src = a, si = 0, len = NONE,
               dst = e, di = l}
        val _ = length := l + an
     in ()
     end

      fun new (dummy: 'a) = T {dummy = dummy,
                   length = ref 0,
                   elts = ref (Array.array (32, dummy))}

      fun length (T {length, ...}) = !length
   end

fun main (name, args) =
   let
       val stuff =
       Array.tabulate (String.size stuff, fn i => String.sub (stuff, i))
       val n = atoi (hd (args @ ["1"]))
       val b = Buffer.new #"\000"
       val _ = for (1, n, fn _ => Buffer.add (b, stuff))
       val _ = printl [Int.toString (Buffer.length b)]
   in
       OS.Process.success
   end
end

val _ = SMLofNJ.exportFn("strcat", Test.main);