[Pkg-ocaml-maint-commits] [ocaml-csv] 01/07: Imported Upstream version 1.5

Stéphane Glondu glondu at moszumanska.debian.org
Wed Aug 3 09:41:11 UTC 2016


This is an automated email from the git hooks/post-receive script.

glondu pushed a commit to branch master
in repository ocaml-csv.

commit a33a6f0e04bd874e3efd24e029c506d67dcddcdb
Author: Stephane Glondu <steph at glondu.net>
Date:   Wed Aug 3 11:27:27 2016 +0200

    Imported Upstream version 1.5
---
 .merlin             |   3 ++
 Makefile            |   7 ++-
 _oasis              |   3 +-
 _oasis_remove_.ml   |   7 +++
 csv.install         |   6 +++
 examples/csvtool.ml | 139 ++++++++++++++++++++++++++++------------------------
 opam/descr          |   8 +++
 opam/findlib        |   1 +
 opam/opam           |  33 +++++++++++++
 src/csv.ml          |  22 ++++-----
 src/csv.mli         |  10 ++++
 11 files changed, 160 insertions(+), 79 deletions(-)

diff --git a/.merlin b/.merlin
new file mode 100644
index 0000000..11c5393
--- /dev/null
+++ b/.merlin
@@ -0,0 +1,3 @@
+S src
+S examples
+B _build/**
diff --git a/Makefile b/Makefile
index d93511a..190cb84 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@ PKGVERSION  = $(shell oasis query version)
 PKG_TARBALL = $(PKGNAME)-$(PKGVERSION).tar.gz
 
 DISTFILES   = LICENSE.txt INSTALL.txt README.md _oasis \
-  _tags Makefile setup.ml \
+  _tags Makefile setup.ml _oasis_remove_.ml csv.install \
   $(filter-out %~, $(wildcard src/*) $(wildcard examples/*) $(wildcard tests/*))
 
 WEB = shell.forge.ocamlcore.org:/home/groups/csv/htdocs
@@ -30,8 +30,11 @@ csvtool: all
 	./csvtool.native pastecol 1-3 2,1,2 \
 	  tests/testcsv9.csv tests/testcsv9.csv
 
+opam csv.install: _oasis
+	oasis2opam --local
+
 # "Force" a tag to be defined for each released tarball
-dist tar: setup.ml
+dist tar: setup.ml opam
 	@ if [ -z "$(PKGNAME)" ]; then echo "PKGNAME not defined"; exit 1; fi
 	@ if [ -z "$(PKGVERSION)" ]; then \
 		echo "PKGVERSION not defined"; exit 1; fi
diff --git a/_oasis b/_oasis
index 86f74b8..4b036d0 100644
--- a/_oasis
+++ b/_oasis
@@ -1,7 +1,7 @@
 #								-*-conf-*-
 OASISFormat: 0.4
 Name:        csv
-Version:     1.4.2
+Version:     1.5
 Synopsis:    A pure OCaml library to read and write CSV files.
 Description: This is a pure OCaml library to read and write CSV files, 
   including all extensions used by Excel — e.g. quotes, newlines, 
@@ -63,6 +63,7 @@ Test conformity
   Run: true
 
 Executable test_header
+  Build$:         flag(tests)
   Path:           tests/
   MainIs:         test_header.ml
   BuildDepends:   csv
diff --git a/_oasis_remove_.ml b/_oasis_remove_.ml
new file mode 100644
index 0000000..0d23853
--- /dev/null
+++ b/_oasis_remove_.ml
@@ -0,0 +1,7 @@
+open Printf
+
+let () =
+  let dir = Sys.argv.(1) in
+  (try Sys.chdir dir
+   with _ -> eprintf "Cannot change directory to %s\n%!" dir);
+  exit (Sys.command "ocaml setup.ml -uninstall")
diff --git a/csv.install b/csv.install
new file mode 100644
index 0000000..c6cfc2d
--- /dev/null
+++ b/csv.install
@@ -0,0 +1,6 @@
+etc: [
+  "setup.ml"
+  "setup.data"
+  "setup.log"
+  "_oasis_remove_.ml"
+]
diff --git a/examples/csvtool.ml b/examples/csvtool.ml
index d2ece8a..274ffa8 100644
--- a/examples/csvtool.ml
+++ b/examples/csvtool.ml
@@ -71,6 +71,34 @@ let take n l =
   dummy.tl
 (*------------------------------ end of extlib code *)
 
+(** Generic [iter] function reading a list of CSV files.  The function
+    [f] can raise [Exit] to mean that no further processing should be done. *)
+let csv_iter ~input_sep ~f files =
+  try
+    List.iter (fun filename ->
+        let fh = if filename = "-" then stdin else open_in filename in
+        let csv_in = Csv.of_channel ~separator:input_sep fh in
+        try (f filename csv_in : unit);
+            Csv.close_in csv_in;
+        with e -> Csv.close_in csv_in; raise e
+      ) files
+  with Exit -> ()
+
+let iter_csv_rows ~input_sep ~f files =
+  csv_iter ~input_sep files ~f:(fun _ csv_in -> Csv.iter ~f csv_in)
+
+(** Generic [fold] function on a list of CSV files. *)
+let csv_fold ~input_sep ~f ~init files =
+  List.fold_left (fun a filename ->
+      let fh = if filename = "-" then stdin else open_in filename in
+      let csv_in = Csv.of_channel ~separator:input_sep fh in
+      let a = f a csv_in in
+      Csv.close_in csv_in;
+      a
+    ) init files
+
+
+
 (* Parse column specs. *)
 type colspec = range list
 and range =
@@ -94,7 +122,7 @@ let parse_colspec ~count_zero colspec =
              Col (int_of_string col)
         )
       with
-        Failure "int_of_string" ->
+        Failure _ ->
           failwith (colspec ^ ":" ^ col ^ ": invalid column-spec")
   ) cols in
 
@@ -124,7 +152,7 @@ let cols_of_colspec colspec row =
     | [] -> []
     | Col c :: rest ->
         (try List.nth row c
-         with Failure "nth" -> "") :: loop rest
+         with Failure _ -> "") :: loop rest
     | Range (s, e) :: rest ->
         let width = e-s+1 in
         let range = take width (drop s row) in
@@ -137,73 +165,49 @@ let cols_of_colspec colspec row =
 
 (* The actual commands. *)
 let cmd_cols ~input_sep ~output_sep ~chan colspec files =
-  List.iter (
-    fun filename ->
-      let csv = Csv.load ~separator:input_sep filename in
-      let csv = List.map (cols_of_colspec colspec) csv in
-      Csv.output_all (Csv.to_channel ~separator:output_sep chan) csv
-  ) files
+  let csv_out = Csv.to_channel ~separator:output_sep chan in
+  iter_csv_rows ~input_sep files ~f:(fun row ->
+      Csv.output_record csv_out (cols_of_colspec colspec row));
+  Csv.close_out csv_out
 
 let cmd_namedcols ~input_sep ~output_sep ~chan names files =
-  List.iter (
-    fun filename ->
-      let csv = Csv.load ~separator:input_sep filename in
-      let header, data =
-        match csv with
-        | [] -> failwith "no rows in this CSV file"
-        | h :: t -> h, t in
-      (* Do the headers requested exist in the CSV file?  If not,
-       * throw an error.
-       *)
-      List.iter (
-        fun name ->
-          if not (List.mem name header) then
-            failwith ("namedcol: requested header not in CSV file: " ^ name)
-      ) names;
-      let data = Csv.associate header data in
-      let data = List.map (
-        fun row -> List.map (fun name -> List.assoc name row) names
-      ) data in
-      let data = names :: data in
-      Csv.output_all (Csv.to_channel ~separator:output_sep chan) data
-  ) files
+  let csv_out = Csv.to_channel ~separator:output_sep chan in
+  (* Output the header of the final file. *)
+  Csv.output_record csv_out names;
+  csv_iter ~input_sep files ~f:(fun fname csv_in ->
+      match (try Some(Csv.next csv_in) with End_of_file -> None) with
+      | None -> ()
+      | Some header ->
+         (* Do the headers requested exist in the CSV file?  If not,
+            throw an error.  *)
+         List.iter (fun name ->
+             if not (List.mem name header) then
+               failwith (sprintf "namedcol: requested header %S not in CSV \
+                                  file %S" name fname)
+        ) names;
+      Csv.iter csv_in ~f:(fun row ->
+          let row = Csv.combine ~header row in
+          let named = List.map (fun name -> List.assoc name row) names in
+          Csv.output_record csv_out named;
+        )
+    );
+  Csv.close_out csv_out
 
 let cmd_width ~input_sep ~chan files =
-  let width = List.fold_left (
-    fun width filename ->
-      let csv = Csv.load ~separator:input_sep filename in
-      let width = max width (Csv.columns csv) in
-      width
-  ) 0 files in
+  let width = csv_fold ~input_sep files ~init:0 ~f:(fun w csv_in ->
+                  Csv.fold_left csv_in ~init:w ~f:(fun w row ->
+                      max w (List.length row))) in
   fprintf chan "%d\n" width
 
 let cmd_height ~input_sep ~chan files =
-  let height = List.fold_left (
-    fun height filename ->
-      let csv = Csv.load ~separator:input_sep filename in
-      let height = height + Csv.lines csv in
-      height
-  ) 0 files in
+  let height = csv_fold ~input_sep files ~init:0 ~f:(fun h csv_in ->
+                   Csv.fold_left ~f:(fun h _ -> h + 1) ~init:h csv_in) in
   fprintf chan "%d\n" height
 
 let cmd_readable ~input_sep ~chan files =
   let csv = List.concat (List.map (Csv.load ~separator:input_sep) files) in
   Csv.save_out_readable chan csv
 
-let iter_csv_rows ~input_sep ~f files =
-  List.iter (fun filename ->
-             let in_chan, close =
-               match filename with
-               | "-" -> stdin, false
-               | filename -> open_in filename, true in
-             try
-               Csv.iter ~f (Csv.of_channel ~separator:input_sep in_chan);
-               if close then close_in in_chan
-             with Exit ->
-               if close then close_in in_chan
-            ) files
-
-
 let cmd_cat ~input_sep ~output_sep ~chan files =
   (* Avoid loading the whole file into memory. *)
   let chan = Csv.to_channel ~separator:output_sep chan in
@@ -306,17 +310,24 @@ let cmd_pastecol ~input_sep ~output_sep ~chan colspec1 colspec2 file1 file2 =
 
 let cmd_set_columns ~input_sep ~output_sep ~chan cols files =
   (* Avoid loading the whole file into memory. *)
+  let csv_out = Csv.to_channel ~separator:output_sep chan in
   let f row =
-    let csv = [row] in
-    let csv = Csv.set_columns ~cols csv in
-    Csv.output_all (Csv.to_channel ~separator:output_sep chan) csv
-  in
-  iter_csv_rows ~input_sep ~f files
+    match Csv.set_columns ~cols [row] with
+    | [row] -> Csv.output_record csv_out row
+    | _ -> assert false in
+  iter_csv_rows ~input_sep ~f files;
+  Csv.close_out csv_out
 
 let cmd_set_rows ~input_sep ~output_sep ~chan rows files =
-  let csv = List.concat (List.map (Csv.load ~separator:input_sep) files) in
-  let csv = Csv.set_rows ~rows csv in
-  Csv.output_all (Csv.to_channel ~separator:output_sep chan) csv
+  let rows = ref rows in
+  let csv_out = Csv.to_channel ~separator:output_sep chan in
+  iter_csv_rows ~input_sep files ~f:(fun row ->
+      if !rows <= 0 then raise Exit;
+      Csv.output_record csv_out row;
+      decr rows;
+    );
+  for _i = 1 to !rows do Csv.output_record csv_out [] done;
+  Csv.close_out csv_out
 
 let cmd_head ~input_sep ~output_sep ~chan rows files =
   (* Avoid loading the whole file into memory, or even loading
diff --git a/opam/descr b/opam/descr
new file mode 100644
index 0000000..b552980
--- /dev/null
+++ b/opam/descr
@@ -0,0 +1,8 @@
+A pure OCaml library to read and write CSV files.
+This is a pure OCaml library to read and write CSV files, including
+all extensions used by Excel — e.g. quotes, newlines, 8 bit
+characters in fields, \"0 etc. A special representation of rows of CSV
+files with a header is provided. The library comes with a handy
+command line tool called csvtool for handling CSV files from shell
+scripts.
+
diff --git a/opam/findlib b/opam/findlib
new file mode 100644
index 0000000..efa258e
--- /dev/null
+++ b/opam/findlib
@@ -0,0 +1 @@
+csv
diff --git a/opam/opam b/opam/opam
new file mode 100644
index 0000000..5141d49
--- /dev/null
+++ b/opam/opam
@@ -0,0 +1,33 @@
+opam-version: "1.2"
+name: "csv"
+version: "1.5"
+maintainer: "Christophe Troestler <Christophe.Troestler at umons.ac.be>"
+authors: [ "Richard Jones"
+           "Christophe Troestler" ]
+license: "LGPL-2.1 with OCaml linking exception"
+homepage: "https://github.com/Chris00/ocaml-csv"
+dev-repo: "https://github.com/Chris00/ocaml-csv.git"
+bug-reports: "https://github.com/Chris00/ocaml-csv/issues"
+tags: [ "database" "science"  ]
+build: [
+  ["oasis" "setup"]
+  ["ocaml" "setup.ml" "-configure" "--prefix" prefix]
+  ["ocaml" "setup.ml" "-build"]
+]
+install: ["ocaml" "setup.ml" "-install"]
+remove: [
+  ["ocaml" "%{etc}%/csv/_oasis_remove_.ml" "%{etc}%/csv"]
+]
+build-test: [
+  ["oasis" "setup"]
+  ["ocaml" "setup.ml" "-configure" "--enable-tests"]
+  ["ocaml" "setup.ml" "-build"]
+  ["ocaml" "setup.ml" "-test"]
+]
+build-doc: [ "ocaml" "setup.ml" "-doc" ]
+depends: [
+  "base-bytes"
+  "oasis" {build & >= "0.4"}
+  "ocamlbuild" {build}
+  "ocamlfind" {build & >= "1.5"}
+]
diff --git a/src/csv.ml b/src/csv.ml
index dfe70ed..5177b00 100644
--- a/src/csv.ml
+++ b/src/csv.ml
@@ -743,6 +743,9 @@ let to_buffer ?separator ?backslash_escape ?excel_tricks buf =
        method close_out () = ()
      end)
 
+let close_out oc =
+  oc.out_chan#close_out()
+
 let rec really_output oc s ofs len =
   let w = oc.out_chan#output s ofs len in
   if w < len then really_output oc s (ofs+w) (len-w)
@@ -854,7 +857,7 @@ let save ?separator ?backslash_escape ?excel_tricks fname t =
   let ch = open_out fname in
   let csv = to_channel ?separator ?backslash_escape ?excel_tricks ch in
   output_all csv t;
-  close_out ch
+  Pervasives.close_out ch
 
 (*
  * Reading rows with headers
@@ -1099,18 +1102,13 @@ let to_array csv =
 let of_array csv =
   List.map Array.to_list (Array.to_list csv)
 
+let rec combine ~header row = match header, row with
+  | [], _ -> []
+  | _, [] -> List.map (fun h -> (h, "")) header
+  | h0 :: h, x :: r -> (h0, x) :: combine ~header:h r
+
 let associate header data =
-  let nr_cols = List.length header in
-  let rec trunc = function
-    | 0, _ -> []
-    | n, [] -> "" :: trunc (n-1, [])
-    | n, (x :: xs) -> x :: trunc (n-1, xs)
-  in
-  List.map (
-    fun row ->
-      let row = trunc (nr_cols, row) in
-      List.combine header row
-  ) data
+  List.map (fun row -> combine header row) data
 
 let map ~f csv =
   List.map (fun row -> List.map (fun el -> f el) row) csv
diff --git a/src/csv.mli b/src/csv.mli
index e98b08d..dcfc609 100644
--- a/src/csv.mli
+++ b/src/csv.mli
@@ -245,6 +245,9 @@ val to_buffer : ?separator:char ->
                 Buffer.t -> out_channel
   (** Same as {!Csv.to_out_obj} but output to a buffer. *)
 
+val close_out : out_channel -> unit
+(** [close_out oc] close the channel [oc].  The underlying channel is
+    closed as well. *)
 
 val output_record : out_channel -> string list -> unit
   (** [output_record oc r] write the record [r] is CSV form to the
@@ -475,6 +478,13 @@ val associate : string list -> t -> (string * string) list list
     by the spreadsheet is not much larger.
   *)
 
+val combine : header: string list -> string list -> (string * string) list
+(** [combine ~header row] returns a row with elements [(h, x)] where
+    [h] is the header name and [x] the corresponding row entry.  If
+    the [row] has less entries than [header], they are interpreted as
+    being empty.  See {!associate} which applies this function to all
+    rows. *)
+
 val map : f:(string -> string) -> t -> t
 (** [map f csv] applies [f] to all entries of [csv] and returns the
     resulting CSV. *)

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ocaml-maint/packages/ocaml-csv.git



More information about the Pkg-ocaml-maint-commits mailing list