(* -*- mode: sml -*-
 * $Id: wc.smlnj,v 1.2 2001/07/09 00:25:29 doug Exp $
 * http://www.bagley.org/~doug/shootout/
 * from Stephen Weeks
 *)


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

fun incr r = r := !r + 1
   
val nl = ref 0
val nw = ref 0
val nc = ref 0
val max = 4096
val buf = Word8Array.array (max, 0w0)
val sub = Word8Array.sub

fun readblock scanfun =
   let
      val nread = Posix.IO.readArr (Posix.FileSys.stdin,
                    {buf = buf, i =  0, sz = NONE})
   in
      if nread = 0
     then ()
      else (nc := !nc + nread;
        scanfun (0, nread))
   end

val c2b = Byte.charToByte
val newline = c2b #"\n"
val space = c2b #" "
val tab = c2b #"\t"

fun scan_out_of_word (i, n) =
   if i < n
      then
     let
        val c = sub (buf, i)
     in
        if c = newline
           then (incr nl; scan_out_of_word (i + 1, n))
        else if c = space orelse c = tab
            then scan_out_of_word (i + 1, n)
         else (incr nw; scan_in_word (i + 1, n))
     end
   else readblock scan_out_of_word

and scan_in_word (i, n) =
  if i < n then
     let
    val c = sub (buf, i)
     in
    if c = newline
       then (incr nl; scan_out_of_word (i + 1, n))
    else if c = space orelse c = tab
        then scan_out_of_word (i + 1, n)
         else scan_in_word (i + 1, n)
     end
  else readblock scan_in_word

fun printl [] = print "\n" | printl(h::t) = ( print h ; printl t )
   
fun main (name, args) =
  let
    val _ =
        (scan_out_of_word (0, 0);
    printl [Int.toString (!nl), " ", Int.toString (!nw), " ", Int.toString (!nc)])
  in
    OS.Process.success
  end
end

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