(* In this program, we'll write a simplified version of the command line
 * utility cat. When cat is invoked with no arguments, it echoes user input
 * line by line. When passed a list of filenames, cat prints the contents of
 * each file to the screen. Cat also has a bunch of command line flags to alter
 * its behaviour, but we won't implement any of those. *)

open Core.Std
open Async.Std

let readme () =
  "Concatenate FILE(s), or standard input, to standard output"

(* First, we write a function to transfer stdin to stdout. *)
let cat_stdin () =
  let stdin  = Lazy.force Reader.stdin in
  let stdout = Lazy.force Writer.stdout in
  Reader.transfer stdin (Writer.pipe stdout)

(* Next, we write a function to print the contents of a file. *)
let cat_file filename =
  let stdout = Lazy.force Writer.stdout in
  Reader.with_file filename
    ~f:(fun file -> Reader.transfer file (Writer.pipe stdout))

(* Finally, we write our main function. If the user didn't specify any
 * filenames, we echo stdin. Otherwise, we print out the contents of the
 * provided files. *)

let main filenames () : unit Deferred.t =
  match filenames with
  | [] -> cat_stdin ()
  | fs -> Deferred.List.iter fs ~f:cat_file

let () =
  Command.async
    ~summary:"concatenate files and print on the standard output"
    ~readme:readme
    Command.Spec.(
      empty
      +> anon (sequence ("FILE" %: file))
    )
    main
  |> Command.run