(* -*- mode: sml -*-
 * $Id: reversefile.smlnj,v 1.4 2001/07/09 00:25:28 doug Exp $
 * http://www.bagley.org/~doug/shootout/
 * from Tom 7
 *)

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

val bufsize = 4096
val rdbufsize = 4096

val stdout = Posix.FileSys.wordToFD 0w1
val stdin = Posix.FileSys.wordToFD 0w0

datatype block = END
               | MORE of int ref * Word8Array.array * block

val buff = Unsafe.Word8Array.create rdbufsize

fun out END = ()
  | out (MORE (ir as ref i, a, next)) =
  let in
    Posix.IO.writeArr (stdout, {buf=a, i=i, sz=NONE});
    out next
  end

fun rd (start, len, count, b) =
  if (start + len) >= count then 
    (* done with this block. 
       Copy from start to the end of the array into
       buff, then return the starting index into buff. *)
    let in
      Word8Array.copy {di=0,
                       dst=buff,
                       src=buff,
                       len=SOME len,
                       si=start};
      (b, len)
    end
  else
    if Unsafe.Word8Array.sub(buff, start + len) = 0w10 then
      
      case b of MORE(ir as ref i, a, _) =>
        if i > len then
            let in
              
              Word8Array.copy {di=i-len - 1,
                               dst=a,
                               len=SOME(len + 1),
                               si=start,
                               src=buff};
              ir := i - (len + 1);
              
              rd(start + len + 1, 0, count, b)
            end
          else 
            let
              
              val na = Unsafe.Word8Array.create bufsize
              val l = (len + 1) - i
            in
              
              Word8Array.copy {di=0,
                               dst=a,
                               len=SOME i,
                               si=(start + len + 1) - i,
                               src=buff};
              
              
              Word8Array.copy {di=bufsize - l,
                               dst=na,
                               len=SOME l,
                               si=start,
                               src=buff};
              ir := 0;
              rd(start + len + 1, 0, count, MORE(ref (bufsize - l), na, b))
            end
    else rd (start, len + 1, count, b)
    
fun loop (b, s) =
  let 
    val count = Posix.IO.readArr (stdin, 
                                  {buf=buff, i=s, sz=SOME (rdbufsize-s)})
    val (bb, bs) = rd (0, s, count + s, b)
  in
    case count of
      0 => out bb
    | _ => loop (bb, bs)
  end

fun main(name, args) =
    ( loop (MORE(ref bufsize, Unsafe.Word8Array.create bufsize, END), 0);
      OS.Process.success);

end

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