Csv.square, Csv.print_readable functions.
[ocaml-csv.git] / csv.ml
diff --git a/csv.ml b/csv.ml
index 837d215..a5207e7 100644 (file)
--- a/csv.ml
+++ b/csv.ml
@@ -1,6 +1,6 @@
 (* csv.ml - comma separated values parser
  *
- * $Id: csv.ml,v 1.3 2004-12-22 13:47:51 rich Exp $
+ * $Id: csv.ml,v 1.5 2005-02-17 15:51:47 rich Exp $
  *)
 
 (* The format of CSV files:
@@ -204,6 +204,20 @@ let trim ?(top=true) ?(left=true) ?(right=true) ?(bottom=true) csv =
 
   csv
 
+let square csv =
+  let columns = columns csv in
+  List.map (
+    fun row ->
+      let n = List.length row in
+      let row = List.rev row in
+      let rec loop acc = function
+       | 0 -> acc
+       | i -> "" :: loop acc (i-1)
+      in
+      let row = loop row (columns - n) in
+      List.rev row
+  ) csv
+
 let associate header data =
   let nr_cols = List.length header in
   let rec trunc = function
@@ -245,9 +259,51 @@ let save_out ?(separator = ',') chan csv =
               output_char chan '\n') csv
 
 let print ?separator csv =
-  save_out ?separator stdout csv
+  save_out ?separator stdout csv; flush stdout
 
 let save ?separator file csv =
   let chan = open_out file in
   save_out ?separator chan csv;
   close_out chan
+
+let save_out_readable chan csv =
+  (* Escape all the strings in the CSV file first. *)
+  let csv = List.map (List.map String.escaped) csv in
+
+  let csv = square csv in
+
+  (* Find the width of each column. *)
+  let widths =
+    match csv with
+      | [] -> []
+      | r :: _ ->
+         let n = List.length r in
+         let lengths = List.map (List.map String.length) csv in
+         let max2rows r1 r2 =
+           let rp = List.combine r1 r2 in
+           List.map (fun ((a : int), (b : int)) -> max a b) rp
+         in
+         let rec repeat x = function
+           | 0 -> []
+           | i -> x :: repeat x (i-1)
+         in
+         List.fold_left max2rows (repeat 0 n) lengths in
+
+  (* Print out each cell at the correct width. *)
+  let rec repeat f = function
+    | 0 -> ()
+    | i -> f (); repeat f (i-1)
+  in
+  List.iter (
+    fun row ->
+      let row = List.combine widths row in
+      List.iter (
+       fun (width, cell) ->
+         output_string chan cell;
+         let n = String.length cell in
+         repeat (fun () -> output_char chan ' ') (width - n + 1)
+      ) row;
+      output_char chan '\n'
+  ) csv
+
+let print_readable = save_out_readable stdout