diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) Andrea Rossato
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the author nor the names of his contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
diff --git a/README b/README
new file mode 100644
--- /dev/null
+++ b/README
@@ -0,0 +1,201 @@
+% Haskell Bindings to Bibutils, the Bibliography Conversion Utilities
+% Andrea Rossato
+
+About
+-----
+
+[hs-bibutils] is library with Haskell bindings to Chris Putnam's
+[bibutils], a library that interconverts between various bibliography
+formats using a common MODS-format XML intermediate.
+
+[hs-bibutils] can be used with [citeproc-hs] and [pandoc] to read and
+use various bibliographic database formats for processing and
+automatically formatting citations andreferences according to a [CSL]
+style.
+
+[citeproc-hs] adds to [pandoc], the famous [Haskell] text processing
+tool, a Bibtex like citation and bibliographic formatting and
+generation facility.
+
+[CSL] is an XML language for specifying citation and bibliographic
+formatting, similar in principle to BibTeX `.bst` files or the binary
+style files in commercial products like Endnote or Reference Manager.
+
+Download
+--------
+
+[hs-bibutils] can be downloaded from [Hackage]:
+
+<http://hackage.haskell.org/cgi-bin/hackage-scripts/package/hs-bibutils>
+
+To get the darcs source run:
+
+        darcs get http://code.haskell.org/hs-bibutils/
+
+Installation
+------------
+
+[hs-bibutils] requires [bibutils] version 4.0 or higher. Moreover, it
+requires the [bibutils] library to be installed on your system as a
+share object. This is necessary if you want to use the library with
+GHCi or [andoc].
+
+At the present time, though, [bibutils] default compilation and
+installation scripts only build a static library to be used for
+building the various [bibutils]' binaries, the only ones being
+installed.
+
+In other words you need to either patch or download a patched version
+of [bibutils] in order to build and install the library as a share
+object.[^1]
+
+### Obtaining a patched version of bibutils
+
+You can download a patched version of [bibutils] here:
+
+<http://code.haskell.org/hs-bibutils/bibutils-4.1-ar.tar.gz>
+
+To install it run:
+
+        tar xvfz bibutils-4.1-ar.tar.gz
+        cd bibutils-4.1-ar
+        ./configure
+        make
+
+And now install it with, as root:
+
+        make installlib
+
+### Patching bibutils
+
+You can patch [bibutils] by yourself.
+
+Download version 4.1 from here:
+
+<http://www.scripps.edu/~cdputnam/software/bibutils/bibutils_4.1_src.tgz>
+
+and apply the patch that comes with the [hs-bibutils] source code,
+`bibutils.patch`.
+
+        tar xvfz bibutils-4.1.tar.gz
+        cd bibutils-4.1
+        patch -p0 < bibutils.patch
+
+Now you can configure and build:
+
+        ./configure
+        make
+
+And now as root:
+
+        make installlib
+
+### Installing hs-bibutils
+
+Now you need install [hs-bibutils]. After unpacking the source code
+run:
+
+        runhaskell Setup.lhs configure --extra-include-dirs=/path/to/bibutils_4.1/lib
+
+Change `/path/to/bibutils_4.1/lib` to point to the `lib` sub-directory
+of the [bibutils] source code.
+
+`--extra-include-dirs=/path/to/bibutils_4.1/lib` will tell the
+compiler where to find the library header files needed to compile the
+bindings.
+
+Now you can build and install:
+
+        runhaskell Setup.lhs build
+        runhaskell Setup.lhs install
+
+This last step requires `root` privileges.
+
+If you don't have `root` privileges you can install [hs-bibutils]
+locally with these commands:
+
+        runhaskell Setup.lhs configure --extra-include-dirs=/path/to/bibutils_4.1/lib --user --prefix=$HOME
+        runhaskell Setup.lhs build
+        runhaskell Setup.lhs install --user
+
+Documentation
+-------------
+
+The [Haddock] generated documentation is available here:
+
+<http://code.haskell.org/hs-bibutils/docs/>
+
+The original API documentation is available here:
+
+<http://www.scripps.edu/~cdputnam/software/bibutils/library_specs.html>
+
+Bug Reports
+-----------
+
+To submit bug reports you can use the [citeproc-hs] bug tracking
+system available at the following address:
+
+<http://code.google.com/p/citeproc-hs/issues>
+
+Credits
+-------
+
+Thanks to [Chris Putnam] for his help.
+
+Author
+------
+
+Andrea Rossato
+
+`andrea.rossato at unitn.it`
+
+Links to Related Projects
+----------------
+
+Bibutils
+:    <http://www.scripps.edu/~cdputnam/software/bibutils/>
+
+Pandoc
+:    <http://johnmacfarlane.net/pandoc/>
+
+Citeproc-hs:
+:    <http://code.haskell.org/citeproc-hs/>
+
+CSL
+:    <http://xbiblio.sourceforge.net/csl/>
+
+Legal
+-----
+
+This software is released under a BSD-style license. See LICENSE for
+more details.
+
+Be aware, however, that bibutils itself is licensed under the GPL. If
+you wish to use the hs-bibutils bindings, your project will need to be
+GPL compatible.
+
+This is an early, "alpha" release. It carries no warranties of any kind.
+
+Copyright &copy; 2008 Andrea Rossato
+
+[^1]: The library must be a shared object and must be installed in
+order to build [pandoc] because [pandoc] uses the Template Haskell
+extension to produce some source code at compilation time. This
+extension requires running the GHCi interpreter which can only deal
+with shared objects. If the library is a static object
+(`libbibutils.a`) the compilation of [pandoc] or the use of the
+library with GHCi will fail.
+
+[hs-bibutils]: http://code.haskell.org/hs-bibutils
+[bibutils]: http://www.scripps.edu/~cdputnam/software/bibutils/
+[Hackage]: http://hackage.haskell.org/cgi-bin/hackage-scripts/package/hs-bibutils
+[citeproc-hs]: http://code.haskell.org/citeproc-hs
+[CSL]: http://xbiblio.sourceforge.net/csl/
+[pandoc]: http://johnmacfarlane.net/pandoc/
+[Zotero]: http://www.zotero.org
+[MODS]: http://www.loc.gov/mods/
+[Bruce D'Arcus]: http://community.muohio.edu/blogs/darcusb/
+[John MacFarlane]: http://johnmacfarlane.net/
+[Chris Putnam]: http://www.scripps.edu/~cdputnam/
+[Haskell]:  http://www.haskell.org/
+[Haddock]:  http://www.haskell.org/haddock/
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,3 @@
+#!/usr/bin/env runhaskell
+> import Distribution.Simple
+> main = defaultMain
diff --git a/bibutils.patch b/bibutils.patch
new file mode 100644
--- /dev/null
+++ b/bibutils.patch
@@ -0,0 +1,214 @@
+diff -ur ../bibutils_4.1/Makefile_start ./Makefile_start
+--- ../bibutils_4.1/Makefile_start	2008-12-21 19:31:06.000000000 +0100
++++ ./Makefile_start	2008-12-26 11:26:01.000000000 +0100
+@@ -1,7 +1,13 @@
+ POSTFIX=REPLACE_POSTFIX
+ CC = REPLACE_CC
+ RANLIB=REPLACE_RANLIB
+-INSTALLDIR=REPLACE_INSTALLDIR
++PREFIX=REPLACE_PREFIX
++LIBDIR=${PREFIX}/lib
++SHCC=REPLACE_SHCC
++SHLD=REPLACE_SHLD
++INSTALL = /usr/bin/ginstall -c
++SHLIB = lib/libbibutils.so
++STLIB = lib/libbibutils.a
+ 
+ VERSION=4.1
+ DATE=12/21/08
+@@ -10,7 +16,7 @@
+ 	xml2ads xml2bib xml2end xml2isi xml2ris xml2wordbib modsclean
+ 
+ all : FORCE
+-	cd lib; make -k $(CC) -k $(RANLIB); cd ..
++	cd lib; make -k $(SHCC) -k $(SHLD) -k $(RANLIB); cd ..
+ 	cd bin; make -k $(CC) -k VERSION="$(VERSION)" -k DATE="$(DATE)"; cd ..
+ 
+ clean: FORCE
+@@ -30,9 +36,13 @@
+ 
+ install: all FORCE
+ 	sed 's/VERSION/${VERSION}/g' packageconfig_start > lib/bibutils.pc
+-#	@for p in ${PROGRAMS}; \
+-#		do ( cp bin/$$p ${INSTALLDIR}/$$p ); \
+-#	done
++	@for p in ${PROGRAMS}; \
++		do ( cp bin/$$p ${INSTALLDIR}/$$p ); \
++	done
++
++installlib:
++	${INSTALL} ${SHLIB} ${DESTDIR}${LIBDIR}
++	${INSTALL} ${STLIB} ${DESTDIR}${LIBDIR}
+ 
+ package: all FORCE
+ 	csh -f maketgz.csh ${VERSION} ${POSTFIX}
+diff -ur ../bibutils_4.1/configure ./configure
+--- ../bibutils_4.1/configure	2008-12-20 00:48:40.000000000 +0100
++++ ./configure	2008-12-26 11:18:16.000000000 +0100
+@@ -3,15 +3,15 @@
+ set INPUT_FILE = Makefile_start
+ set OUTPUT_FILE = Makefile
+ 
+-set INSTALLDIR = /usr/local/bin
++set PREFIX = /usr/local
+ 
+ if ( ${#argv} > 0 ) then
+-	if ( $1 == "--install-dir" ) then
++	if ( $1 == "--prefix" ) then
+ 		if ( ${#argv} < 2 ) then
+-			echo "--install-dir requires a directory"
++			echo "--prefix requires a directory"
+ 			exit
+ 		else
+-			set INSTALLDIR = $2
++			set PREFIX = $2
+ 		endif
+ 	else
+ 		echo "Unidentified argument $1"
+@@ -76,81 +76,105 @@
+ #POSTFIX=REPLACE_POSTFIX
+ #CC = REPLACE_CC
+ #RANLIB=REPLACE_RANLIB
+-#INSTALLDIR=REPLACE_INSTALLDIR
++#PREFIX=REPLACE_PREFIX
+ 
+ if ( $type == "Linux_x86" ) then
+ 	cat $INPUT_FILE | \
+ 	sed 's/REPLACE_CC/CC="cc -Wall"/' | \
++	sed 's/REPLACE_SHCC/CC="cc -Wall -fPIC"/' | \
++	sed 's/REPLACE_SHLD/SHLD="gcc -shared -I."/' | \
+ 	sed 's/REPLACE_RANLIB/RANLIB="ranlib"/' | \
+-	sed "s|REPLACE_INSTALLDIR|${INSTALLDIR}|" | \
++	sed "s|REPLACE_PREFIX|${PREFIX}|" | \
+ 	sed 's/REPLACE_POSTFIX/_i386/' > $OUTPUT_FILE
+ else if ( $type == "Linux_x86_64" ) then
+ 	cat $INPUT_FILE | \
+ 	sed 's/REPLACE_CC/CC="cc -Wall"/' | \
++	sed 's/REPLACE_SHCC/CC="cc -Wall -fPIC"/' | \
++	sed 's/REPLACE_SHLD/SHLD="gcc -shared -I."/' | \
+ 	sed 's/REPLACE_RANLIB/RANLIB="ranlib"/' | \
+-	sed "s|REPLACE_INSTALLDIR|${INSTALLDIR}|" | \
++	sed "s|REPLACE_PREFIX|${PREFIX}|" | \
+ 	sed 's/REPLACE_POSTFIX/_i386/' > $OUTPUT_FILE
+ else if ( $type == "Linux_Unknown" ) then
+ 	cat $INPUT_FILE | \
+ 	sed 's/REPLACE_CC/CC="cc -Wall"/' | \
++	sed 's/REPLACE_SHCC/CC="cc -Wall -fPIC"/' | \
++	sed 's/REPLACE_SHLD/SHLD="gcc -shared -I."/' | \
+ 	sed 's/REPLACE_RANLIB/RANLIB="ranlib"/' | \
+-	sed "s|REPLACE_INSTALLDIR|${INSTALLDIR}|" | \
++	sed "s|REPLACE_PREFIX|${PREFIX}|" | \
+ 	sed 's/REPLACE_POSTFIX//' > $OUTPUT_FILE
+ else if ( $type == "MacOSX_ppc" && $universal_binary == "TRUE" ) then
+ 	cat $INPUT_FILE | \
+ 	sed 's/REPLACE_CC/CC="cc -arch i386 -arch ppc -Wall"/' | \
++	sed 's/REPLACE_SHCC/CC="cc -arch i386 -arch ppc -Wall"/' | \
++	sed 's/REPLACE_SHLD/SHLD="cc -bundle -flat_namespace -undefined suppress"/' | \
+ 	sed 's/REPLACE_RANLIB/RANLIB="ranlib -s"/' | \
+-	sed "s|REPLACE_INSTALLDIR|${INSTALLDIR}|" | \
++	sed "s|REPLACE_PREFIX|${PREFIX}|" | \
+ 	sed 's/REPLACE_POSTFIX/_osx_universal/' > $OUTPUT_FILE
+ else if ( $type == "MacOSX_intel" && $universal_binary == "TRUE" ) then
+ 	cat $INPUT_FILE | \
+ 	sed 's/REPLACE_CC/CC="cc -arch i386 -arch ppc -Wall"/' | \
++	sed 's/REPLACE_SHCC/CC="cc -arch i386 -arch ppc -Wall"/' | \
++	sed 's/REPLACE_SHLD/SHLD="cc -bundle -flat_namespace -undefined suppress"/' | \
+ 	sed 's/REPLACE_RANLIB/RANLIB="ranlib -s"/' | \
+-	sed "s|REPLACE_INSTALLDIR|${INSTALLDIR}|" | \
++	sed "s|REPLACE_PREFIX|${PREFIX}|" | \
+ 	sed 's/REPLACE_POSTFIX/_osx_universal/' > $OUTPUT_FILE
+ else if ( $type == "MacOSX_ppc" || $type == "MacOSX_intel" || \
+ 	$type == "MacOSX_unknown" ) then
+ 	cat $INPUT_FILE | \
+ 	sed 's/REPLACE_CC/CC="cc -Wall"/' | \
++	sed 's/REPLACE_SHCC/CC="cc -arch i386 -arch ppc -Wall"/' | \
++	sed 's/REPLACE_SHLD/SHLD="cc -bundle -flat_namespace -undefined suppress"/' | \
+ 	sed 's/REPLACE_RANLIB/RANLIB="ranlib -s"/' | \
+-	sed "s|REPLACE_INSTALLDIR|${INSTALLDIR}|" | \
++	sed "s|REPLACE_PREFIX|${PREFIX}|" | \
+ 	sed 's/REPLACE_POSTFIX/_osx/' > $OUTPUT_FILE
+ else if ( $type == "SunOS5" ) then
+ 	cat $INPUT_FILE | \
+ 	sed 's|REPLACE_CC|CC="gcc"|' | \
++	sed 's/REPLACE_SHCC/CC="gcc -Wall -fPIC"/' | \
++	sed 's/REPLACE_SHLD/SHLD="gcc -shared -I."/' | \
+ 	sed 's/REPLACE_RANLIB/RANLIB="echo Skipping ranlib"/' | \
+-	sed "s|REPLACE_INSTALLDIR|${INSTALLDIR}|" | \
++	sed "s|REPLACE_PREFIX|${PREFIX}|" | \
+ 	sed 's/REPLACE_POSTFIX/_sunos5/' > $OUTPUT_FILE
+ else if ( $type == "IRIX" ) then
+ 	cat $INPUT_FILE | \
+ 	sed 's|REPLACE_CC|CC="/tsri/gnu/sgi4DIRIX6/bin/gcc"|' | \
++	sed 's/REPLACE_SHCC/CC="/tsri/gnu/sgi4DIRIX6/bin/gcc -Wall -fPIC"/' | \
++	sed 's/REPLACE_SHLD/SHLD="/tsri/gnu/sgi4DIRIX6/bin/gcc -shared -I."/' | \
+ 	sed 's/REPLACE_RANLIB/RANLIB="echo Skipping ranlib"/' | \
+-	sed "s|REPLACE_INSTALLDIR|${INSTALLDIR}|" | \
++	sed "s|REPLACE_PREFIX|${PREFIX}|" | \
+ 	sed 's/REPLACE_POSTFIX/_irix/' > $OUTPUT_FILE
+ else if ( $type == "NetBSD" ) then
+ 	cat $INPUT_FILE | \
+ 	sed 's/REPLACE_CC/CC="cc -Wall"/' | \
++	sed 's/REPLACE_SHCC/CC="cc -Wall -fPIC"/' | \
++	sed 's/REPLACE_SHLD/SHLD="gcc -shared -I."/' | \
+ 	sed 's/REPLACE_RANLIB/RANLIB="ranlib"/' | \
+-	sed "s|REPLACE_INSTALLDIR|${INSTALLDIR}|" | \
++	sed "s|REPLACE_PREFIX|${PREFIX}|" | \
+ 	sed 's/REPLACE_POSTFIX/_netbsd/' > $OUTPUT_FILE
+ else if ( $type == "FreeBSD" ) then
+ 	cat $INPUT_FILE | \
+ 	sed 's/REPLACE_CC/CC="cc -Wall"/' | \
++	sed 's/REPLACE_SHCC/CC="cc -Wall -fPIC"/' | \
++	sed 's/REPLACE_SHLD/SHLD="gcc -shared -I."/' | \
+ 	sed 's/REPLACE_RANLIB/RANLIB="ranlib"/' | \
+-	sed "s|REPLACE_INSTALLDIR|${INSTALLDIR}|" | \
++	sed "s|REPLACE_PREFIX|${PREFIX}|" | \
+ 	sed 's/REPLACE_POSTFIX/_freebsd/' > $OUTPUT_FILE
+ else if ( $type == "Cygwin" ) then
+ 	cat $INPUT_FILE | \
+ 	sed 's/REPLACE_CC/"CC=cc"/' | \
++	sed 's/REPLACE_SHCC/CC="cc -fPIC"/' | \
++	sed 's/REPLACE_SHLD/SHLD="gcc -shared -I."/' | \
+ 	sed 's/REPLACE_RANLIB/RANLIB="echo Skipping ranlib"/' | \
+-	sed "s|REPLACE_INSTALLDIR|${INSTALLDIR}|" | \
++	sed "s|REPLACE_PREFIX|${PREFIX}|" | \
+ 	sed 's/REPLACE_POSTFIX/_cygwin/' > $OUTPUT_FILE
+ else
+ 	# Unknown operating system
+ 	cat $INPUT_FILE | \
+ 	sed 's/REPLACE_CC/"CC=cc"/' | \
++	sed 's/REPLACE_SHCC/CC="cc -fPIC"/' | \
++	sed 's/REPLACE_SHLD/SHLD="gcc -shared -I."/' | \
+ 	sed 's/REPLACE_RANLIB/RANLIB="echo Skipping ranlib"/' | \
+-	sed "s|REPLACE_INSTALLDIR|${INSTALLDIR}|" | \
++	sed "s|REPLACE_PREFIX|${PREFIX}|" | \
+ 	sed 's/REPLACE_POSTFIX//' > $OUTPUT_FILE
+ endif
+ 
+@@ -164,13 +188,14 @@
+ echo "    e-mail cdputnam@ucsd.edu with the system type and output of"
+ echo "    the command: uname -a"
+ echo
+-echo "Set installation directory to $INSTALLDIR."
+-echo "    To modify install directory type: configure --install-dir DIR"
++echo "Set installation directory to $PREFIX."
++echo "    To modify install directory type: configure --prefix DIR"
+ echo "    where DIR is the desired directory."
+ echo
+ if ( $OUTPUT_FILE == "Makefile" ) then
+   echo "To compile,                  type: make"
+   echo "To install,                  type: make install"
++  echo "To install the library,      type: make installlib"
+   echo "To make tgz package,         type: make package"
+   echo "To make deb package,         type: make deb"
+   echo
+diff -ur ../bibutils_4.1/lib/Makefile ./lib/Makefile
+--- ../bibutils_4.1/lib/Makefile	2008-12-21 00:17:31.000000000 +0100
++++ ./lib/Makefile	2008-12-26 11:19:48.000000000 +0100
+@@ -24,6 +24,7 @@
+ all:  libbibutils.a
+ 
+ libbibutils.a: $(BIBUTILS_OBJS)
++	${SHLD} -o libbibutils.so $(BIBUTILS_OBJS)
+ 	ar -cr libbibutils.a $(BIBUTILS_OBJS)
+ 	$(RANLIB) libbibutils.a
+ 
diff --git a/cbits/stub.c b/cbits/stub.c
new file mode 100644
--- /dev/null
+++ b/cbits/stub.c
@@ -0,0 +1,11 @@
+#include <stdio.h>
+
+FILE *c_stdout()
+{
+    return stdout;
+}
+
+FILE *c_stdin()
+{
+    return stdin;
+}
diff --git a/hs-bibutils.cabal b/hs-bibutils.cabal
new file mode 100644
--- /dev/null
+++ b/hs-bibutils.cabal
@@ -0,0 +1,48 @@
+name:               hs-bibutils
+version:            0.1
+homepage:           http://code.haskell.org/hs-bibutils
+
+synopsis:           Haskell bindings to bibutils, the bibliography
+                    conversion utilities.
+
+description:        Haskell bindings to Chris Putnam's bibutils, a
+                    library that interconverts between various
+                    bibliography formats using a common MODS-format
+                    XML intermediate.
+		    .
+                    hs-bibutils is available under a BSD3 license. See
+                    the LICENSE file for details.
+                    .
+                    Be aware, however, that bibutils itself is
+		    licensed under the GPL. If you wish to use the
+		    hs-bibutils bindings, your project will need to be
+		    GPL compatible.
+                    .
+                    For more details about bibutils, please check:
+		    <http://www.scripps.edu/~cdputnam/software/bibutils/>.
+                    .
+                    The original API documentation is available here:
+                    <http://www.scripps.edu/~cdputnam/software/bibutils/library_specs.html>.
+
+category:           Text
+license:            BSD3
+license-file:       LICENSE
+author:             Andrea Rossato
+maintainer:         andrea.rossato@unitn.it
+cabal-version:      >= 1.4
+build-type:         Simple
+
+library
+    exposed-modules:  Text.Bibutils
+    other-modules:
+    ghc-options:      -funbox-strict-fields -Wall
+    ghc-prof-options: -prof -auto-all
+    hs-source-dirs:   src
+    extra-libraries:  bibutils
+    extensions:       ForeignFunctionInterface
+    c-sources:        cbits/stub.c
+
+    if impl(ghc >= 6.10)
+       build-depends: base >= 4, syb
+    else
+       build-depends: base >= 3 && < 4
diff --git a/src/Text/Bibutils.hsc b/src/Text/Bibutils.hsc
new file mode 100644
--- /dev/null
+++ b/src/Text/Bibutils.hsc
@@ -0,0 +1,434 @@
+{-# CFILES cbits/stub.c #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Text..Bibutils
+-- Copyright   :  (C) 2008 Andrea Rossato
+-- License     :  BSD3
+--
+-- Maintainer  :  andrea.rossato@unitn.it
+-- Stability   :  provisional
+-- Portability :  portable
+--
+-- Here is a simple program using hs-bibutils to conver a MODS
+-- collection into a bibtex file, sending the output to stdout:
+--
+-- > import Text.Bibutils
+-- >
+-- > main :: IO ()
+-- > main = do
+-- >   bibl  <- bibl_init
+-- >   param <- bibl_initparams mods_in bibtex_out "mods2bibtex"
+-- >   setFormatOpts param [bibout_brackets, bibout_uppercase]
+-- >   setBOM        param
+-- >   setVerbose    param
+-- >   bibl_read     param bibl "/path/to/bibtex.bib"
+-- >   bibl_write    param bibl "-"
+-- >   bibl_free       bibl
+-- >   bibl_freeparams param
+--
+-----------------------------------------------------------------------------
+
+module Text.Bibutils
+    ( -- * Basic Functions
+      Bibl
+    , Param (..)
+    , bibl_init
+    , bibl_initparams
+    , bibl_read
+    , bibl_write
+    , bibl_free
+    , bibl_freeparams
+    , bibl_reporterr
+
+    -- * Auxiliary Functions
+    , numberOfRefs
+    , status
+    -- ** Functions for Setting Parameters
+    , setParam
+    , setFormatOpts
+    , setCharsetIn
+    , setCharsetOut
+    , setBOM
+    , unsetBOM
+    , setLatexOut
+    , unsetLatexOut
+    , setXmlOut
+    , unsetXmlOut
+    , setAddcount
+    , unsetAddcount
+    , setSinglerefperfile
+    , unsetSinglerefperfile
+    , setVerbose
+    , unsetVerbose
+
+    -- * Input Formats
+    , BiblioIn
+    , mods_in
+    , bibtex_in
+    , ris_in
+    , endnote_in
+    , copac_in
+    , isi_in
+    , medline_in
+    , biblatex_in
+    , endnotexml_in
+
+    -- * Output Formats
+    , BiblioOut
+    , mods_out
+    , bibtex_out
+    , ris_out
+    , endnote_out
+    , isi_out
+    , word2007_out
+    , adsab_out
+
+    -- * Options for Specific Output Formats
+    , FormatOpt
+    , bibout_finalcomma
+    , bibout_singledash
+    , bibout_whitespace
+    , bibout_brackets
+    , bibout_uppercase
+    , bibout_strictkey
+    , modsout_dropkey
+    , wordout_dropkey
+
+    -- * Charsets
+    , Charset
+    , bibl_charset_unknown
+    , bibl_charset_unicode
+    , bibl_charset_gb18030
+    , bibl_charset_default
+
+    -- * Return Status
+    , Status
+    , bibl_ok
+    , bibl_err_badinput
+    , bibl_err_memerr
+    , bibl_err_cantopen
+
+    ) where
+
+import Control.Monad
+import Foreign.C
+import Foreign
+import System.IO
+
+-- | A type for storing the C struct with the bibliography data.
+-- Mostly opaque to the Haskell side. See 'numberOfRefs' to retrieve
+-- the number of references stored in the struct.
+newtype Bibl = Bibl { nrefs :: CLong }
+
+instance Storable Bibl where
+    sizeOf    _     = #{size      bibl}
+    alignment _     = #{alignment bibl}
+    peek p          = #{peek      bibl, nrefs } p >>= return . Bibl
+    poke p (Bibl n) = #{poke      bibl, nrefs } p n
+
+-- | Initialize the 'Bibl' C struct. Usually the first function being
+-- called.
+bibl_init :: IO (ForeignPtr Bibl)
+bibl_init
+    = alloca $ \p -> do
+        c_bibl_init    p
+        newForeignPtr_ p
+
+-- | Free the 'Bibl' C struct.
+bibl_free :: ForeignPtr Bibl -> IO ()
+bibl_free bibl = withForeignPtr bibl c_bibl_free
+
+-- | Retrieve the number of references from a 'Bibl' C struct.
+numberOfRefs :: ForeignPtr Bibl -> IO Int
+numberOfRefs b
+    = withForeignPtr b $ \cb -> peek cb >>= return . fromIntegral . nrefs
+
+-- | A type for storing the Param C struct. It should be accessed with
+-- the functions provided, such as 'setCharsetIn', etc.
+data Param
+    = Param
+      { redaformat       :: CInt
+      , writeformat      :: CInt
+      , charsetin        :: CInt
+      , charsetin_src    :: CUChar
+      , latexin          :: CUChar
+      , utf8in           :: CUChar
+      , xmlin            :: CUChar
+      , charsetout       :: CInt
+      , charsetout_src   :: CUChar
+      , latexout         :: CUChar
+      , utf8out          :: CUChar
+      , utf8bom          :: CUChar
+      , xmlout           :: CUChar
+      , format_opts      :: CInt
+      , addcount         :: CInt
+      , output_raw       :: CUChar
+      , verbose          :: CUChar
+      , singlerefperfile :: CUChar
+      } deriving ( Show )
+
+instance Storable Param where
+    sizeOf    _ = #{size param}
+    alignment _ = #{alignment param}
+    peek p      =  Param
+                  `fmap` #{peek param, readformat       } p
+                  `ap`   #{peek param, writeformat      } p
+                  `ap`   #{peek param, charsetin        } p
+                  `ap`   #{peek param, charsetin_src    } p
+                  `ap`   #{peek param, latexin          } p
+                  `ap`   #{peek param, utf8in           } p
+                  `ap`   #{peek param, xmlin            } p
+                  `ap`   #{peek param, charsetout       } p
+                  `ap`   #{peek param, charsetout_src   } p
+                  `ap`   #{peek param, latexout         } p
+                  `ap`   #{peek param, utf8out          } p
+                  `ap`   #{peek param, utf8bom          } p
+                  `ap`   #{peek param, xmlout           } p
+                  `ap`   #{peek param, format_opts      } p
+                  `ap`   #{peek param, addcount         } p
+                  `ap`   #{peek param, output_raw       } p
+                  `ap`   #{peek param, verbose          } p
+                  `ap`   #{peek param, singlerefperfile } p
+    poke p (Param rf wf ci csi li ui xi co cso lo uo ub xo fo a raw v s) = do
+                         #{poke param, readformat       } p rf
+                         #{poke param, writeformat      } p wf
+                         #{poke param, charsetin        } p ci
+                         #{poke param, charsetin_src    } p csi
+                         #{poke param, latexin          } p li
+                         #{poke param, utf8in           } p ui
+                         #{poke param, xmlin            } p xi
+                         #{poke param, charsetout       } p co
+                         #{poke param, charsetout_src   } p cso
+                         #{poke param, latexout         } p lo
+                         #{poke param, utf8out          } p uo
+                         #{poke param, utf8bom          } p ub
+                         #{poke param, xmlout           } p xo
+                         #{poke param, format_opts      } p fo
+                         #{poke param, addcount         } p a
+                         #{poke param, output_raw       } p raw
+                         #{poke param, verbose          } p v
+                         #{poke param, singlerefperfile } p s
+
+-- | Initialize the 'Param' C struct, given the input bibliographic
+-- format, the output bibliographic format, and the program name to
+-- be used for displaying debugging information.
+bibl_initparams :: BiblioIn -> BiblioOut -> String -> IO (ForeignPtr Param)
+bibl_initparams i o s
+    = alloca $ \p -> withCString s $ \cs  -> do
+        c_bibl_initparams p (unBiblioIn i) (unBiblioOut o) cs
+        newForeignPtr_ p
+
+-- | Free the 'Param' C struct.
+bibl_freeparams :: ForeignPtr Param -> IO ()
+bibl_freeparams param = withForeignPtr param c_bibl_freeparams
+
+-- | Set fields of the 'Param' C struct directly.
+setParam :: ForeignPtr Param -> (Param -> Param) -> IO ()
+setParam p f = withForeignPtr p $ \cp -> peek cp >>= poke cp . f
+
+-- | Set the input charset. Default is Latin-1 (ISO8859-1). See
+-- 'Charset'.
+setCharsetIn ::  ForeignPtr Param -> Charset -> IO ()
+setCharsetIn p c
+    = setParam p $ \param -> param { charsetin = charset c }
+
+-- | Set the output charset.
+setCharsetOut ::  ForeignPtr Param -> Charset -> IO ()
+setCharsetOut p c
+    = setParam p $ \param -> param { charsetout = charset c }
+
+-- | Set output format specific options. See 'FormatOpt'.
+setFormatOpts ::  ForeignPtr Param -> [FormatOpt] -> IO ()
+setFormatOpts p os
+    = setParam p $ \param -> param { format_opts = unFormatOpt $ combineFormatOpts os }
+
+-- | Write utf8 byte-order-mark.
+setBOM ::  ForeignPtr Param -> IO ()
+setBOM p
+    = setParam p $ \param -> param { utf8bom = 1 }
+
+unsetBOM ::  ForeignPtr Param -> IO ()
+unsetBOM p
+    = setParam p $ \param -> param { utf8bom = 0 }
+
+-- | Write Latex codes.
+setLatexOut ::  ForeignPtr Param -> IO ()
+setLatexOut p
+    = setParam p $ \param -> param { latexout = 1 }
+
+unsetLatexOut ::  ForeignPtr Param -> IO ()
+unsetLatexOut p
+    = setParam p $ \param -> param { latexout = 0 }
+
+-- | Write characters in XML entities.
+setXmlOut ::  ForeignPtr Param -> IO ()
+setXmlOut p
+    = setParam p $ \param -> param { xmlout = 1 }
+
+unsetXmlOut ::  ForeignPtr Param -> IO ()
+unsetXmlOut p
+    = setParam p $ \param -> param { xmlout = 0 }
+
+-- | Add reference count to reference id.
+setAddcount ::  ForeignPtr Param -> IO ()
+setAddcount p
+    = setParam p $ \param -> param { addcount = 1 }
+
+unsetAddcount ::  ForeignPtr Param -> IO ()
+unsetAddcount p
+    = setParam p $ \param -> param { addcount = 0 }
+
+-- | Output a single reference for each file.
+setSinglerefperfile ::  ForeignPtr Param -> IO ()
+setSinglerefperfile p
+    = setParam p $ \param -> param { singlerefperfile = 1 }
+
+unsetSinglerefperfile ::  ForeignPtr Param -> IO ()
+unsetSinglerefperfile p
+    = setParam p $ \param -> param { singlerefperfile = 0 }
+
+-- | Verbose output.
+setVerbose ::  ForeignPtr Param -> IO ()
+setVerbose p
+    = setParam p $ \param -> param { verbose = 1 }
+
+-- | Suppress verbose output.
+unsetVerbose ::  ForeignPtr Param -> IO ()
+unsetVerbose p
+    = setParam p $ \param -> param { verbose = 0 }
+
+-- | Given a 'Param' C structure, a 'Bibl' C structure, the path to
+-- the input file (@\"-\"@ for the standard input), read the file,
+-- storing the data in the 'Bibl' struct, and report a 'Status'.
+bibl_read :: ForeignPtr Param -> ForeignPtr Bibl -> FilePath -> IO Status
+bibl_read param bibl path
+    = withForeignPtr param $ \cparam ->
+      withForeignPtr bibl  $ \cbibl  ->
+      withCString    path  $ \cpath  ->
+      withCString    "r"   $ \cmode  -> do
+        cfile <- if path == "-"
+                 then return c_stdin
+                 else throwErrnoIfNull "fopen: " (fopen cpath cmode)
+        cint  <- c_bibl_read cbibl cfile cpath cparam
+        when (path /= "-") $ fclose cfile >> return ()
+        return $ Status cint
+
+-- | Given a 'Param' C structure, a 'Bibl' C structure, the path to an
+-- output file (@\"-\"@ for the standard output), write the file
+-- returning a 'Status'.
+bibl_write :: ForeignPtr Param -> ForeignPtr Bibl -> FilePath -> IO Status
+bibl_write param bibl path
+    = withForeignPtr param $ \cparam ->
+      withForeignPtr bibl  $ \cbibl  ->
+      withCString    "w"   $ \cmode  -> do
+        cfile <- if path == "-"
+                 then return c_stdout
+                 else withCString path $ throwErrnoIfNull "fopen: " . flip fopen cmode
+        cint <- c_bibl_write cbibl cfile cparam
+        when (path /= "-") $ fclose cfile >> return ()
+        return $ Status cint
+
+bibl_reporterr :: Status -> IO ()
+bibl_reporterr (Status n) = c_bibl_reporterr n
+
+newtype BiblioIn  = BiblioIn  { unBiblioIn  :: CInt }
+    deriving ( Eq )
+
+#{enum BiblioIn, BiblioIn
+ , mods_in       = BIBL_MODSIN
+ , bibtex_in     = BIBL_BIBTEXIN
+ , ris_in        = BIBL_RISIN
+ , endnote_in    = BIBL_ENDNOTEIN
+ , copac_in      = BIBL_COPACIN
+ , isi_in        = BIBL_ISIIN
+ , medline_in    = BIBL_MEDLINEIN
+ , endnotexml_in = BIBL_ENDNOTEXMLIN
+ , biblatex_in   = BIBL_BIBLATEXIN
+ }
+
+newtype BiblioOut = BiblioOut { unBiblioOut :: CInt }
+    deriving ( Eq )
+
+#{enum BiblioOut, BiblioOut
+ , mods_out     = BIBL_MODSOUT
+ , bibtex_out   = BIBL_BIBTEXOUT
+ , ris_out      = BIBL_RISOUT
+ , endnote_out  = BIBL_ENDNOTEOUT
+ , isi_out      = BIBL_ISIOUT
+ , word2007_out = BIBL_WORD2007OUT
+ , adsab_out    = BIBL_ADSABSOUT
+ }
+
+newtype FormatOpt = FormatOpt { unFormatOpt :: CInt }
+
+#include "bibtexout.h"
+#include "modsout.h"
+#include "wordout.h"
+
+#{enum FormatOpt, FormatOpt
+ , bibout_finalcomma = BIBOUT_FINALCOMMA
+ , bibout_singledash = BIBOUT_SINGLEDASH
+ , bibout_whitespace = BIBOUT_WHITESPACE
+ , bibout_brackets   = BIBOUT_BRACKETS
+ , bibout_uppercase  = BIBOUT_UPPERCASE
+ , bibout_strictkey  = BIBOUT_STRICTKEY
+ , modsout_dropkey   = MODSOUT_DROPKEY
+ , wordout_dropkey   = WORDOUT_DROPKEY
+ }
+
+newtype Status = Status { status :: CInt }
+    deriving ( Eq, Show )
+
+#{enum Status, Status
+ , bibl_ok           = BIBL_OK
+ , bibl_err_badinput = BIBL_ERR_BADINPUT
+ , bibl_err_memerr   = BIBL_ERR_MEMERR
+ , bibl_err_cantopen = BIBL_ERR_CANTOPEN
+ }
+
+newtype Charset = Charset { charset :: CInt } deriving ( Eq )
+
+#{enum Charset, Charset
+, bibl_charset_unknown = BIBL_CHARSET_UNKNOWN
+, bibl_charset_unicode = BIBL_CHARSET_UNICODE
+, bibl_charset_gb18030 = BIBL_CHARSET_GB18030
+, bibl_charset_default = BIBL_CHARSET_DEFAULT
+ }
+
+-- Combine a list of options into a single option, using bitwise (.|.)
+combineFormatOpts :: [FormatOpt] -> FormatOpt
+combineFormatOpts = FormatOpt . foldr ((.|.) . unFormatOpt) 0
+
+#include "bibutils.h"
+#include "bibl.h"
+#let alignment t = "%lu", (unsigned long)offsetof(struct {char x__; t (y__); }, y__)
+
+foreign import ccall unsafe "bibl_init"
+    c_bibl_init :: Ptr Bibl -> IO ()
+
+foreign import ccall unsafe "bibl_free"
+    c_bibl_free :: Ptr Bibl -> IO ()
+
+foreign import ccall unsafe "bibl_initparams"
+    c_bibl_initparams :: Ptr Param -> CInt -> CInt -> CString -> IO ()
+
+foreign import ccall unsafe "bibl_freeparams"
+    c_bibl_freeparams :: Ptr Param -> IO ()
+
+foreign import ccall unsafe "bibl_read"
+    c_bibl_read :: Ptr Bibl -> Ptr CFile -> CString -> Ptr Param -> IO CInt
+
+foreign import ccall unsafe "bibl_write"
+    c_bibl_write :: Ptr Bibl -> Ptr CFile -> Ptr Param -> IO CInt
+
+foreign import ccall unsafe "bibl_reporterr"
+    c_bibl_reporterr :: CInt -> IO ()
+
+foreign import ccall unsafe "fopen"
+    fopen :: CString -> CString -> IO (Ptr CFile)
+
+foreign import ccall unsafe "fclose"
+    fclose :: Ptr CFile -> IO CInt
+
+foreign import ccall unsafe "c_stdin"  c_stdin  :: Ptr CFile
+foreign import ccall unsafe "c_stdout" c_stdout :: Ptr CFile
