[Pkg-octave-commit] [octave-io] 01/04: Imported Upstream version 2.2.0

Thomas Weber tweber at moszumanska.debian.org
Tue Apr 22 12:35:48 UTC 2014


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

tweber pushed a commit to branch master
in repository octave-io.

commit 2ce50e7730f2695329635073a11394e8c981e132
Author: Thomas Weber <tweber at debian.org>
Date:   Sun Apr 20 18:21:58 2014 +0200

    Imported Upstream version 2.2.0
---
 DESCRIPTION                         |   6 +-
 NEWS                                |  52 ++++
 PKG_ADD                             |  19 +-
 doc/READ-ODS.html                   |  67 +++--
 doc/READ-XLS.html                   |  34 ++-
 inst/calccelladdress.m              |  19 +-
 inst/chk_spreadsheet_support.m      |  67 +++--
 inst/io_ods_testscript.m            |  46 ++--
 inst/io_xls_testscript.m            |  27 +-
 inst/oct2ods.m                      |  23 +-
 inst/oct2xls.m                      |  19 +-
 inst/ods2oct.m                      |  23 +-
 inst/odsclose.m                     |   5 +-
 inst/odsfinfo.m                     |  20 +-
 inst/odsopen.m                      |  41 +--
 inst/odsread.m                      |  28 +-
 inst/odswrite.m                     |  22 +-
 inst/private/__OCT_gnm2oct__.m      |  35 ++-
 inst/private/__OCT_merge_data__.m   |  72 +++++
 inst/private/__OCT_oct2ods__.m      | 292 ++++++++++++++++++++
 inst/private/__OCT_oct2spsh__.m     |  75 ++++++
 inst/private/__OCT_oct2xlsx__.m     | 514 ++++++++++++++++++++++++++++++++++++
 inst/private/__OCT_ods2oct__.m      |   8 +-
 inst/private/__OCT_spsh_close__.m   |  55 +++-
 inst/private/__OCT_spsh_open__.m    |  57 ++--
 inst/private/__OCT_xlsx2oct__.m     |  19 +-
 inst/private/__OTK_oct2ods__.m      |   5 +-
 inst/private/__OTK_spsh_info__.m    |   9 +-
 inst/private/__OXS_spsh_open__.m    |   7 +-
 inst/private/__POI_getusedrange__.m |   5 +-
 inst/private/parse_sp_range.m       | 103 ++++----
 inst/templates/template.ods         | Bin 0 -> 6803 bytes
 inst/templates/template.xlsx        | Bin 0 -> 7367 bytes
 inst/xls2oct.m                      |   7 +-
 inst/xlsclose.m                     |  15 +-
 inst/xlsfinfo.m                     |  16 +-
 inst/xlsopen.m                      |  40 ++-
 inst/xlsread.m                      |  34 ++-
 inst/xlswrite.m                     |  23 +-
 src/Makefile                        |  10 +-
 src/__char2num__.c                  |  72 +++++
 src/__num2char__.c                  |  75 ++++++
 42 files changed, 1694 insertions(+), 372 deletions(-)

diff --git a/DESCRIPTION b/DESCRIPTION
index d63b82c..a819bf2 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -1,13 +1,13 @@
 Name: io
-Version: 2.0.2
-Date: 2014-01-09
+Version: 2.2.0
+Date: 2014-04-15
 Author: various authors
 Maintainer: Philip Nienhuis <prnienhuis at users.sf.net>
 Title: Input/Output
 Description: Input/Output in external formats.
 Categories: IO
 Problems: Default initial Java memory probably too small, increase with java.opts (see documentation). No OXS write support. UNO support experimental.
-Depends: octave (>= 3.7.2)
+Depends: octave (>= 3.8.0)
 Suggested: windows (>= 1.2.1)
 Autoload: no
 License: GPLv3+, simplified BSD
diff --git a/NEWS b/NEWS
index 18238c0..e810ef2 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,58 @@
 Summary of important user-visible changes for releases of the io package
 
 ===============================================================================
+io-2.2.0   Release Date: 2014-04-13 Release Manager: Philip Nienhuis
+===============================================================================
+
+*** New features:
+    - Experimental write support w/o Java or ActiveX, just native Octave, for
+       ODS 1.2 (LibreOffice native format) and OOXML (Excel 2007+ .xlsx)
+    - (write support for gnumeric pending)
+
+An updated overview of which interface can be used for what types of files
+(extensions):
+~ = dependent on Excel/LO/OOo version);  + = read/write;  R = only reading )
+                                 Interface
+File extension       COM POI POI/OOXML JXL OXS UNO OTK JOD OCT
+--------------------------------------------------------------
+.xls (Excel95)        R                 R       R 
+.xls (Excel97-2003)   +   +      +      +   +   +
+.xlsx                 ~          +         (+)  R           +
+.xlsb, .xlsm          ~                     ?   R
+.wk1                  +                         R
+.wks                  +                         R
+.dbf                  +                         +
+.ods                  ~                         +   +   +   +
+.sxc                                            +       +
+.fods                                           +
+.uos                                            +
+.dif                                            +
+.csv                  +                         R
+.gnumeric                                                   R
+--------------------------------------------------------------
+
+*** Docs (html) & texinfo help texts updated
+
+*** Bug fixes:
+    - (gnumeric reading): Properly handle ValueFormat tags
+                          Fix older formats w/o Value* tags
+    - Restored UNO interface option in ods2oct.m
+    - (xlswrite) when truncating an array (sheet capacity, too small a range),
+      convey truncated range rather than topleft cell
+    - PKG_ADD: Fix case-sensitivity when searching for Libre/OpenOffice loc.
+               Do not automatically load Java class libs on *nix
+    - OCT: delete tmp dirs after closing spreadsheet files
+    - POI: return complete cell range for a.o., xlsfinfo
+
+===============================================================================
+io-2.1.x   Release Date: TBA Release Manager: Philip Nienhuis
+===============================================================================
+
+(unstable version)
+For changes see 2.2.0 (above)
+
+
+===============================================================================
 io-2.0.2   Release Date: 2014-01-09 Release Manager: Philip Nienhuis
 ===============================================================================
 
diff --git a/PKG_ADD b/PKG_ADD
index bddd9fd..85061f8 100644
--- a/PKG_ADD
+++ b/PKG_ADD
@@ -10,7 +10,7 @@ if (octave_config_info ("features").JAVA)
     # (MinGW) assume jar files are in /lib/java 
     libdir = octave_config_info ("libdir");
 # elseif (ismac)
-    ## Who knows where OSX keeps e.g., Apache POI stuff? if it does at all...
+#   ## Who knows where OSX keeps e.g., Apache POI stuff? if it does at all...
   elseif (isunix)
     homedir = tilde_expand ("~");
     ## On linux spreadsheet .jars are often found somewhere in /usr/share/java
@@ -30,10 +30,10 @@ if (octave_config_info ("features").JAVA)
                "/opt", ...
                "/usr/lib"};
   while (isempty (ooopath) && ii < numel (bnam))
-    ooopath = glob ([ bnam{++ii} filesep "LibreOffice*"]);
+    ooopath = glob ([ bnam{++ii} filesep "[Ll]ibre[Oo]ffice*"]);
   endwhile
   while (isempty (ooopath) && ii < numel (bnam))
-    ooopath = glob ([ bnam{++ii} filesep "OpenOffice.org*"]);
+    ooopath = glob ([ bnam{++ii} filesep "[Oo]pen[Oo]ffice.org*"]);
   endwhile
   while (isempty (ooopath) && ii < numel (bnam))
     ooopath = glob ([ bnam{++ii} filesep "ooo*"]);
@@ -48,7 +48,7 @@ if (octave_config_info ("features").JAVA)
   try
     if (! isempty (userdir))
       if (strcmpi (userdir, "no") || strcmpi (userdir, "false") || strcmpi (userdir, "0"))
-        ## Do not load Java class libs .jar files). First clean up
+        ## Do not load Java class libs .jar files). First clean up, then return
         clear libdir spr_status userdir homedir ;
         return
       endif
@@ -60,14 +60,21 @@ if (octave_config_info ("features").JAVA)
         spr_status = chk_spreadsheet_support (userdir, 0, ooopath);
       endif
       ## Also try user's home directory
+    elseif (isunix && ...
+      ! (strcmpi (userdir, "no") || strcmpi (userdir, "false") || strcmpi (userdir, "0")))
+      ## On non-Windows systems, automatic loading of Java classes is opt-in due to
+      ## excessive search time (see bug #42044). Most of the delay is due to searching
+      ## for the Libre/OpenOffice.org jars
+      clear libdir spr_status userdir homedir ;
+      return
     else
       ## Allow some time for io package to be fully loaded
       pause (0.25);
     endif
     ## Try <HOME>/java
     spr_status = chk_spreadsheet_support ([ homedir filesep "java" ], 0, ooopath);
-    ## Only then search for system-supplied jars
-    spr_status = chk_spreadsheet_support ([ libdir filesep "java" ], 0, ooopath);
+    ## Only then search for system-supplied jars. ooopath has been searched
+    spr_status = chk_spreadsheet_support ([ libdir filesep "java" ], 0);
   catch
     warning ("(Automatic loading of spreadsheet I/O Java classlibs failed)\n");
   end_try_catch
diff --git a/doc/READ-ODS.html b/doc/READ-ODS.html
index facaf83..6f71cee 100644
--- a/doc/READ-ODS.html
+++ b/doc/READ-ODS.html
@@ -6,7 +6,7 @@
     	<meta name="AUTHOR" content="Philip Nienhuis">
     	<meta name="CREATED" content="20091229;22213000">
     	<meta name="CHANGEDBY" content="Philip Nienhuis">
-    	<meta name="CHANGED" content="20120226;18275600">
+    	<meta name="CHANGED" content="20140408;18275600">
     	<meta name="Info 1" content="">
     	<meta name="CHANGEDBY" content="Philip Nienhuis"></head>
     
@@ -15,10 +15,10 @@
 	<b>ODS support for Octave</b></font></font></u>
 </p>
 <p align="center"><font face="Arial, sans-serif"><font size="2">
-	Copyright � 2009 - 2013 Philip Nienhuis <prnienhuis at users.sf.net></font></font>
+	Copyright � 2009 - 2014 Philip Nienhuis <prnienhuis at users.sf.net></font></font>
 </p>
 	<p align="center"><font face="Arial, sans-serif"><font size="2">
-	This version December 30, 2013</font></font>
+	This version April 8, 2014</font></font>
 </p>
     <p><font face="Arial, sans-serif"><font size="2">
 	<i>(ODS = Open Document Format spreadsheet data format, used by e.g., OpenOffice.org.)</i></font></font>
@@ -64,44 +64,40 @@
 </dl>
     <p align="center"><font face="Arial, sans-serif"><font size="4"><u><b>REQUIRED
     SUPPORT SOFTWARE</b></u></font></font></p><dl>
-    <p><font face="Arial, sans-serif"><font size="2">(Apart from io package >= 1.3.5 :)</font></font></p>
+<DT><FONT FACE="Arial, sans-serif" SIZE=2><U><B>For the native Octave interface (OCT)</B></U></DT><br>
+<P>(currently <u><b>read/write</b></u> support for <b>ODS 1.2</b> (LibreOffice/OpenOffice.org Calc) and <b>OOXML</b> (Excel 2007+), <u><b>read</b></u> support for <b>Gnumeric</b>)<br>
+<b>NO</b> external support software is required!
+</FONT></P>
     	</dl>
-    	<li><p align="left">
-    	<font face="Arial, sans-serif"><font size="2">For just read support: <B>Octave > 3.7.2</B> will do just fine; for write support Octave requires Java support to be compiled in, a Java JRE > 1.6.0, and one or more of the following:</font></font></p></li>
-    	<li>
+<p align="left">
+<font face="Arial, sans-serif"><font size="2"><B>Octave >= 3.8.0</B> will do just fine but maybe a bit slow. If you want faster I/O, Java support need to be compiled in, a Java JRE > 1.6.0 must be installed, and one or more of the following is required:</font></font></p>
 		<p align="left"><font face="Arial, sans-serif"><font size="2">
-		<b>odfdom.jar</b> currently the preferred option)<br>
-    (<u>only</u> versions <b>0.7.5</b>,
+		<li><b>odfdom.jar</b> (for the <b>OTK</b> interface, currently the preferred option)<br>
+    <ul>(<u>only</u> versions <b>0.7.5</b>,
     	<b>0.8.6</b>, <b>0.8.7</b> and <b>0.8.8</b> (the latter from incubator v. 0.5, see download URL below) work OK!) & <b>xercesImpl.jar</b> (watch out here too! only version 2.9.1 (2007-sep-14) works OK with odfdom). Get them here:
 	</font></font></p>
-	</li>
-  <ul>
+
   <li>
   <p align="left"><a href="http://odftoolkit.org/projects/odfdom/pages/Home"><font face="Arial, sans-serif"><font size="2">http://odftoolkit.org/projects/odfdom/pages/Home</font></font></a></p>
-  </li><li>
-  <p align="left" lang="zxx"><font color="#000080"><font face="Arial, sans-serif"><font size="2"><a href="http://incubator.apache.org/odftoolkit/downloads.html"><font face="Arial, sans-serif"><font size="2">http://incubator.apache.org/odftoolkit/downloads.html</font></font></a> (preferred)</font></font></font></p>
+  </li><li><p align="left" lang="zxx"><font color="#000080"><font face="Arial, sans-serif"><font size="2"><a href="http://incubator.apache.org/odftoolkit/downloads.html"><font face="Arial, sans-serif"><font size="2">http://incubator.apache.org/odftoolkit/downloads.html</font></font></a> (preferred)</font></font></font></p>
   </li><li><p align="left"><a href="http://www.google.com/search?ie=UTF-8&oe=utf-8&q=xerces-2.9.1+download"><font face="Arial, sans-serif"><font size="2">Google for xerces-2.9.1 download</a></p>
+  </li></ul>
   </li>
-  </ul>
-</ul>
-    <dl><dt><p>
+  <dl><dt><p>
 	<br><font face="Arial, sans-serif"><font size="2">and/or</font></font>
 </p></dt></dl>
-    <ul>
-    	<li>
-	<p align="left"><font face="Arial, sans-serif"><font size="2"><b>jopendocument</b></font></font><font face="Arial, sans-serif"><font size="2"><version></font></font><font face="Arial, sans-serif"><font size="2"><b>.jar</b></font></font><font face="Arial, sans-serif"><font size="2">.
-    	Get it from <a href="http://www.jopendocument.org/">http://www.jopendocument.org</a></font></font></p><p align="left">
-    	<font face="Arial, sans-serif"><font size="2">(jOpenDocument 1.3 (final) is the most recent one and recommended for Octave)</font></font>
+<li><p align="left"><font face="Arial, sans-serif"><font size="2"><b>jopendocument</b></font></font><font face="Arial, sans-serif"><font size="2"><version></font></font><font face="Arial, sans-serif"><font size="2"><b>.jar</b> (for the <b>JOD</b> interface)</font></font><font face="Arial, sans-serif"><font size="2"><br>
+<ul>Get it from <a href="http://www.jopendocument.org/">http://www.jopendocument.org</a></font></font></p><p align="left">
+    	<font face="Arial, sans-serif"><font size="2">(jOpenDocument 1.3 (final) is the most recent one and recommended for Octave)</font></font></ul>
 	</p>
 	</li>
-</ul>
 <dl><dt><p>
 	<br><font face="Arial, sans-serif"><font size="2">and/or</font></font>
 </p></dt></dl>
-<ul>
 	<li>
-	<p align="left"><font face="Arial, sans-serif"><font size="2"><b>OpenOffice.org</b> (or clones like <b>LibreOffice</b>, <b>Go-Office</b>, ...)</font></font></font></font><font face="Arial, sans-serif"><font size="2">.
-	Get it from <a href="http://www.openoffice.org/">http://www.openoffice.org</a>. The relevant Java class libs are <b>unoil.jar</b>, 
+	<p align="left"><font face="Arial, sans-serif"><font size="2"><b>OpenOffice.org</b> (or clones like <b>LibreOffice</b>, <b>Go-Office</b>, ...) (for the <b>UNO</b> interface)</font></font></font></font><font face="Arial, sans-serif"><font size="2"><br>
+	
+<ul>Get it from <a href="http://www.openoffice.org/">http://www.openoffice.org</a>. The relevant Java class libs are <b>unoil.jar</b>, 
 	<b>unoloader.jar</b>, <b>jurt.jar</b>, <b>juh.jar</b> and <b>ridl.jar</b> (which are scattered around the OOo installation directory), while also the <b><OOo>/program/</b> 
 	directory needs to be in the classpath.</font></font></p>
 	<p align="left">
@@ -109,7 +105,8 @@
 	</li>
 </ul>
 	<dl><dt>
-	<p><font face="Arial, sans-serif"><font size="2">These class libs must be referenced with full pathnames in your javaclasspath.<br>
+	<p><font face="Arial, sans-serif"><font size="2">Whatever Java option, these class libs must be referenced with full pathnames in your javaclasspath.<br>
+When the io package gets loaded, a utility function (PKG_ADD) tries to automatically find the Java class libs and adds the ones it found to the javaclasspath; When the io package gets unloaded, these same class libs will be removed from the javaclasspath.<br><br>
   Except for the UNO (OOo) classes, on MinGW the jar files had best be put in /<libdir>/java where <libdir> on MinGW it is usually /lib; on Linux system supplied Java class libs usually reside in /usr/share/java. Alternatively, you can put them in your HOME directory in a subdirectory java (mind case!) - on *nix that would be ~./java, on Windows %USERPROFILE%/java (same level as My Documents). The PKG_ADD routine, that gets run each time the io package is loaded, expects the  [...]
   In addition, you can specify a subdirectory using the environment variable OCTAVE_IO_JAVALIBS.<br>
   Once a particular Java class lib has been added to the javaclasspath, it won't be searched anymore nor reloaded from the next search location. The search order is:
@@ -118,7 +115,7 @@
   <LI><HOME_DIR>/java</LI>
   <LI>/usr/share/java (*nix) or /lib/java (MinGW)</LI>
   </OL>
-  If you do not want PKG_ADD to load the Java class libs, specify a value of "no", "false" or "0" for the OCTAVE_IO_JAVALIBS envioronment variable before starting Octave.</font></font>
+  If you do not want PKG_ADD to load the Java class libs, specify a value of "no", "false" or "0" for the OCTAVE_IO_JAVALIBS environment variable before starting Octave.</font></font>
     	</p></dt><dt><p><br>
     </p></dt></dl>
     <p align="center"><font face="Arial, sans-serif"><font size="4"><u><b>USAGE</b></u></font></font></p>
@@ -372,10 +369,7 @@
 </p></dt>
 <dt><p><font face="Arial, sans-serif"><font size="2">The <b>OCT (native Octave)</b>
     	interface is also promising as it is completely under control of Octave (-Forge) developers.
-      Currently it only offers (relatively slow) read support (for ODS, OOXML and gnumeric), but an immense
-      advantage is that for reading ODS no other external software is required.<br>
-      Write support is underway but may be appearing only in 2015, depending on time
-      and resources of the io package developers.</font></font></p></dt>
+      Currently it only offers (relatively slow) read and -experimental- write support for ODS and OOXML and read support for gnumeric. An immense advantage is that no other external software is required. Write support has not extensively tested yet, however.</font></font></p></dt>
 
 </dl>
 	
@@ -478,12 +472,11 @@
     	r/w stuff, adding new interfaces should be easy and straightforward.
     	Add relevant stanzas for your new interface <b><i>INTF</i></b> in <b>odsopen</b>, <b>odsclose</b>, <b>odsfinfo</b>, <b>oct2ods</b>, <b>ods2oct</b>, <b>getusedrange</b> and add new subfunctions (for the real work) in subdir ./private; you'll need a total of six interface-dependent private functions (see the various examples for each interface in subdir ./private).</font></font></p><p><font face="Arial, sans-serif"><font size="2">Suggestions for
     	future development:</font></font></p>
-    	<ul><li><font face="Arial, sans-serif"><font size="2">Reliable and easy ODS
-    	write support (maybe when jOpenDocument is more mature)</font></font></li></ul><ul><li><p align="left">
+    	<ul><li><p align="left">
     	<font face="Arial, sans-serif"><font size="2">Speeding up (ODS is 10 X
     	slower than e.g. OOXML !!!). jOpenDocument is much faster but still
     	immature.<br>
-	<b>UNO</b> *is* MUCH faster than jOpenDocument but starting up OpenOffice.org
+	For large spreadsheets, <b>UNO</b> *is* MUCH faster than jOpenDocument but starting up OpenOffice.org
 	for the first time can take tens of seconds...<br>
   Note that UNO is still experimental. The issue is that odsclose() will simply
   kill ALL other OpenOffice.org invocations, also those that were not opened
@@ -499,7 +492,7 @@
     	<font face="Arial, sans-serif"><font size="2">Adding styles (borders,
     	cell lay-out, font, etc.)</font></font></p></li></ul>
     	<font face="Arial, sans-serif"><font size="2">Some notes on the
-    	choice for Java:</font></font>
+    	choice for Java (becoming less relevant as the OCT interface gets more mature):</font></font>
     <ol>
     	<li>
     	<font face="Arial, sans-serif"><font size="2">It saves a LOT of
@@ -508,6 +501,7 @@
     	wheel.</font></font></li><li>
     	<font face="Arial, sans-serif"><font size="2">A BIG advantage is that
     	a Java-based solution is platform-independent (�portable�).</font></font></li><li>
+    	<font face="Arial, sans-serif"><font size="2">The Java classes offer much more options than just reading and writing. Formatting, recalculation options, hiding/merging cell ranges, etc.</font></font></li><li>
     	<font face="Arial, sans-serif"><font size="2">But Java is known to be
     	not very conservative with resources, especially not when processing
     	XML-based formats.</font></font></li></ol>
@@ -553,8 +547,7 @@
     	7158)</font></font></li><li>
     	<font face="Arial, sans-serif"><font size="2">oct2ods.m (revision
     	7159)</font></font></li></ul>
-    	<p><font face="Arial, sans-serif"><font size="2">Enjoy!</font></font></p><p align="center"><font face="Arial, sans-serif"><font size="2">Philip
-    	Nienhuis, December 30, 2013</font></font></p><dl><dd><p align="center">
+    	<p><font face="Arial, sans-serif"><font size="2">Enjoy!</font></font></p><p align="center"><font face="Arial, sans-serif"><font size="2">Philip Nienhuis, April 8, 2014</font></font></p><dl><dd><p align="center">
     	<br>
     </p></dd></dl>
     </body></html>
\ No newline at end of file
diff --git a/doc/READ-XLS.html b/doc/READ-XLS.html
index d7a41e3..7278d40 100644
--- a/doc/READ-XLS.html
+++ b/doc/READ-XLS.html
@@ -4,16 +4,16 @@
 <META NAME="Generator" CONTENT="Microsoft Word 97">
 <META NAME="CREATED" CONTENT="20091211;17230700">
 <META NAME="CHANGEDBY" CONTENT="Philip Nienhuis">
-<META NAME="CHANGED" CONTENT="20120226;18083900">
+<META NAME="CHANGED" CONTENT="20140408;18083900">
 </HEAD>
 <BODY LINK="#0000ff" VLINK="#800080">
 
 <P><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN"></P>
-<FONT FACE="Arial, sans-serif" SIZE=2><FONT FACE="Arial, sans-serif" SIZE=2><P ALIGN="CENTER">README for Excel spreadsheet file r/w access scripts for octave (> 3.7.2)<BR>
+<FONT FACE="Arial, sans-serif" SIZE=2><FONT FACE="Arial, sans-serif" SIZE=2><P ALIGN="CENTER">README for Excel spreadsheet file r/w access scripts for octave (> 3.8.x)<BR>
 <BR>
-Copyright (C) 2009 - 2013 Philip Nienhuis <prnienhuis at users.sf.net><BR>
+Copyright (C) 2009 - 2014 Philip Nienhuis <prnienhuis at users.sf.net><BR>
 <BR>
-This version December 30, 2012</P>
+This version April 8, 2014</P>
 </FONT></FONT><B><U><FONT FACE="Arial, sans-serif" SIZE=4><FONT FACE="Arial, sans-serif" SIZE=4><P ALIGN="CENTER">EXCEL .XLS SUPPORT FILES</P>
 </B></U></FONT></FONT><FONT FACE="Arial, sans-serif" SIZE=2><FONT FACE="Arial, sans-serif" SIZE=2><DL>
 <DT><BR>
@@ -54,8 +54,14 @@ This file.</FONT></FONT> </DT><BR>
 <P ALIGN="CENTER"><BR>
 </FONT></FONT><B><U><FONT FACE="Arial, sans-serif" SIZE=4><FONT FACE="Arial, sans-serif" SIZE=4>REQUIRED SUPPORT SOFTWARE</P>
 </B></U></FONT></FONT><FONT FACE="Arial, sans-serif" SIZE=2><FONT FACE="Arial, sans-serif" SIZE=2><DL>
-<DT><BR>
-<U><B>For the Excel/COM interface:</B></U></DT>
+<BR>
+
+<DT><FONT FACE="Arial, sans-serif" SIZE=2><U><B>For the native Octave interface (OCT)</B></U></DT><br>
+<P>(currently read/write support for OOXML (Excel 2007+) and ODS 1.2 (LibreOffice/OpenOffice.org Calc), read support for Gnumeric)<br>
+<b>NO</b> external support software is required!
+</FONT></P>
+
+<DT><U><B>For the Excel/COM interface:</B></U></DT>
 </DL>
 
 <UL>
@@ -115,7 +121,9 @@ This file.</FONT></FONT> </DT><BR>
 </UL>
 
 <FONT FACE="Arial, sans-serif" SIZE=2><FONT FACE="Arial, sans-serif" SIZE=2><DL>
-<DT>These class libs must be referenced with full pathnames in your javaclasspath.<br>On MinGW they had best be put in /<libdir>/java (where <libdir> on MinGW is usually /lib); on Linux system supplied Java class libs usually reside in /usr/share/java. Alternatively, you can put them in your HOME directory in a subdirectory java (mind case!) - on *nix that would be ~./java, on Windows %USERPROFILE%/java (same level as My Documents). The PKG_ADD routine, that gets run each tim [...]
+<DT>These class libs must be referenced with full pathnames in your javaclasspath.<br>
+When the io package gets loaded, a utility function (PKG_ADD) tries to automatically find the Java class libs and adds the ones it found to the javaclasspath; When the io package gets unloaded, these same class libs will be removed from the javaclasspath.<br><br>
+On MinGW the required Java class libs had best be put in /<libdir>/java (where <libdir> on MinGW is usually /lib); on Linux system supplied Java class libs usually reside in /usr/share/java. Alternatively, you can put them in your HOME directory in a subdirectory java (mind case!) - on *nix that would be ~./java, on Windows %USERPROFILE%/java (same level as My Documents). The PKG_ADD routine, that gets run each time the io package is loaded, expects the class libs there; if t [...]
   In addition, you can specify a subdirectory using the environment variable OCTAVE_IO_JAVALIBS.<br>
   Once a particular Java class lib has been added to the javaclasspath, it won't be searched anymore nor reloaded from the next search location. The search order is:
   <OL>
@@ -123,14 +131,11 @@ This file.</FONT></FONT> </DT><BR>
   <LI><HOME_DIR>/java</LI>
   <LI>/usr/share/java (*nix) or /lib/java (MinGW)</LI>
   </OL>
-  If you do not want PKG_ADD to load the Java class libs, specify a value of "no", "false" or "0" for the OCTAVE_IO_JAVALIBS envioronment variable before starting Octave.</DT></DL>
+  If you do not want PKG_ADD to load the Java class libs, specify a value of "no", "false" or "0" for the OCTAVE_IO_JAVALIBS environment variable before starting Octave.</DT></DL>
 <DL><DT>UNO specific  (invoking OpenOffice.org (or clones) behind the scenes):<BR>
 NOTE: EXPERIMENTAL!!  A working OpenOffice.org installation. The utility function chk_spreadsheet_support can be used to add the needed entries to the javaclasspath.<BR></DT>
 </DL>
 
-<P><FONT FACE="Arial, sans-serif" SIZE=2><U><B>For the native Octave interface</B></U> <br>
-(currently only read support for OOXML, ODS 1.2 and Gnumeric), no external support software is required.</FONT></P>
-
 <P ALIGN="CENTER"><BR>
 </FONT></FONT><B><U><FONT FACE="Arial, sans-serif" SIZE=4><FONT FACE="Arial, sans-serif" SIZE=4>USAGE</P>
 </B></U></FONT></FONT><FONT FACE="Arial, sans-serif" SIZE=2><FONT FACE="Arial, sans-serif" SIZE=2><DL>
@@ -240,20 +245,21 @@ Another -obvious- limitation is that COM Excel access only works on Windows syst
 <b>Apache POI</b> (Java-based and platform-independent too) is based on the OpenOffice.org I/O Excel r/w routines. It is a more versatile than JExcelAPI, while it doesn't support BIFF5 it does support BIFF8 (Excel 97 � 2003) and OOXML (Excel 2007).</DT>
 <DT>It is slower than native JXL let alone Excel & COM but it features active formula evaluation, although at the moment (end of 2013, v. 3.9) still not *all* Excel functions have been implemented (a daunting task for the POI devs, as it is hard to keep up with MS here). I've made the relevant subfunction (xls2jpoi2oct) fall back to cached formula results (and yield a suitable warning) for non-implemented Excel functions while reading Excel files. <BR>
 <BR>
-<b>OpenXLS</b> (an open source version of Extentech's commercial Java-xls product) is still a bit experimental. It seems to work faster than JExcelAPI, but it has other issues - i.e., processing of OOXML files is still unreliable.<BR>
+<b>OpenXLS</b> (an open source version of Extentech's commercial Java-xls product) is still a bit experimental. It seems to work faster than JExcelAPI, but it has other issues - i.e., processing of OOXML files is still unreliable. In addition OpenXLS scatters Extentech.tmp files here and there. For .xls (BIFF8) it works OK.<BR>
 <BR>
 <b>UNO</b> (invoking OpenOffice.org (OOo) or LibreOffice (LO) or clones behind the scenes, a la ActiveX) is experimental. It works FAST (i.e., once OOo itself is loaded and initialized which can take some time) and can process much larger spreadsheets than the other Java-based interfaces because the data are not entered in the JVM but in OOo's memory.<BR>
 A big stumbling block is that odsclose() on a UNO xls struct will kill ALL OpenOffice.org invocations, also those that were not related to Octave! This is due to UNO-Java limitations.<BR>
 The underlying issue is that when Octave starts an OpenOffice.org invocation, OpenOffice.org must be closed for Octave to be able to exit; otherwise Octave will wait for OOo to shut down before it can terminate itself. So Octave must kill OOo to be able to terminate.<br>
 A way out hasn't been found yet.<br><br>
 All in all, of the three Java options I'd prefer Apache POI rather than OpenXLS or JexcelAPI. But the latter is indispensable for BIFF5 formats. Once UNO is stable it is to be preferred as it can read ALL file formats supported by OOo (viz. wk1, ods, xlsx, sxc, ...). If you need to process really large spreadsheets, UNO is by far the fastest option (behind COM on Windows systems), but for smaller spreadsheets you'll find that the other interfaces are more efficient.<DT><br>
-<DT>The OCT interface (native Octave calls) is by far the fastest for OOXML, the only Octave option for gnumeric, but for ODS it is still slower than COM/ActiveX or UNO. OCT write support is under construction and already working but not yet very mature.</DT>
+<DT>The <b>OCT</b> interface (native Octave calls) is by far the fastest for OOXML, the only Octave option for gnumeric, but for ODS it is still slower than COM/ActiveX or UNO. Experimental OCT write support is available for OOXML and ODS 1.2 but not extensively tested yet.</DT>
 <DT><br>Some notes on the choice for Java:</DT>
 </DL>
 <OL>
 
 <LI>It saves a LOT of development time to use ready-baked Java classes rather than developing your own routines and thus effectively reinvent the wheel.</LI>
 <LI>A BIG advantage is that a Java-based solution is platform-independent ("portable").</LI>
+<LI>The Java classes offer much more options than just reading and writing. Formatting, recalculation options, hiding/merging cell ranges, etc.</LI>
 <LI>But Java is known to be not very conservative with resources, especially not when processing XML-based formats.</LI></OL>
 
 <DL>
@@ -343,6 +349,6 @@ Some other options for development (who?):</DT>
 
 <P>Enjoy!</FONT></FONT> </P>
 <FONT FACE="Arial, sans-serif" SIZE=2><FONT FACE="Arial, sans-serif" SIZE=2><DL>
-<DD ALIGN="CENTER">Philip Nienhuis, December 30, 2013</DD>
+<DD ALIGN="CENTER">Philip Nienhuis, April 8, 2014</DD>
 </DL></FONT></FONT></BODY>
 </HTML>
diff --git a/inst/calccelladdress.m b/inst/calccelladdress.m
index 9d18c36..68fe75e 100644
--- a/inst/calccelladdress.m
+++ b/inst/calccelladdress.m
@@ -1,4 +1,4 @@
-## Copyright (C) 2009,2010,2011 Philip Nienhuis <pr.nienhuis at users.sf.net>
+## Copyright (C) 2009,2010,2011,2012,2013,2014 Philip Nienhuis
 ##
 ## This program is free software; you can redistribute it and/or modify it under
 ## the terms of the GNU General Public License as published by the Free Software
@@ -30,7 +30,8 @@
 ## 2011-04-30 Simplified column name computation
 ## 2011-12-17 Bugfix for wrong column address if column equals multiple of 26
 ## 2011-12-18 Added tests for multiple-of-26 cases
-## 2012-10-24 Style fixes
+## 2012-10-24 Style fixes
+## 2014-04-13 Use by __num2char__ for colstr->col conversion
 
 function [ celladdress ] = calccelladdress (row, column)
 
@@ -43,14 +44,14 @@ function [ celladdress ] = calccelladdress (row, column)
     error ('Specified row out of range (1..1048576)'); 
   endif
 
-	str = '';
-	while (column > 0.01)
-		rmd = floor ((column - 1) / 26);
-		str = [ char(column - rmd * 26 + 'A' - 1) str ];
-		column = rmd;
-	endwhile
+%	str = '';
+%	while (column > 0.01)
+%		rmd = floor ((column - 1) / 26);
+%		str = [ char(column - rmd * 26 + 'A' - 1) str ];
+%		column = rmd;
+%	endwhile
 
-	celladdress = sprintf ("%s%d", str, row);
+	celladdress = sprintf ("%s%d", __num2char__ (column), row);
 
 endfunction
 
diff --git a/inst/chk_spreadsheet_support.m b/inst/chk_spreadsheet_support.m
index 7ad6b7a..31fbf85 100644
--- a/inst/chk_spreadsheet_support.m
+++ b/inst/chk_spreadsheet_support.m
@@ -91,25 +91,25 @@
 ## @end table
 ##
 ## Output:
-## @var{retval} = 0: only spreadsheet read support for OOXML,
-## ODS 1.2 and gnumeric present through OCT interface, or
+## @var{retval} = 0: only spreadsheet support for OOXML & ODS 1.2
+## and read support for gnumeric present through OCT interface, or
 ## @var{retval} <> 0: At least one read/write spreadsheet I/O
-## interface found.
+## interface found based on external software.
 ## RETVAL will be set to the sum of values for found interfaces:
 ## @example
 ##     0 = OCT (Native Octave)
-##         (only read support for .xlsx, .ods and .gnumeric)
-##    ---------- XLS (Excel) interfaces: ----------
+##         (read/write support for .xlsx and .ods, read support for .gnumeric)
+##   ----------- XLS (Excel) interfaces: ----------
 ##     1 = COM (ActiveX / Excel) (any file format supported by MS-Excel)
 ##     2 = POI (Java / Apache POI) (Excel 97-2003 = BIFF8)
 ##     4 = POI+OOXML (Java / Apache POI) (Excel 2007-2010 = OOXML)
 ##     8 = JXL (Java / JExcelAPI) (Excel 95-read and Excel-97-2003-r/w)
 ##    16 = OXS (Java / OpenXLS) (Excel 97-2003)
-##    --- ODS (OpenOffice.org Calc) interfaces ----
+##   ---- ODS (OpenOffice.org Calc) interfaces ----
 ##    32 = OTK (Java/ ODF Toolkit) (ODS 1.2)
 ##    64 = JOD (Java / jOpenDocument) (.sxc (old OOo)-read, ODS 1.2)
-##    ----------------- XLS & ODS: ----------------
-##     0 = OOXML / ODS / gumeric read support (built-in)
+##   ------------------ XLS & ODS: ----------------
+##     0 = OOXML / ODS read/write-, gnumeric read support (built-in)
 ##   128 = UNO (Java/UNO bridge - OpenOffice.org) (any format supported by OOo)
 ## @end example
 ##
@@ -167,6 +167,10 @@
 ## 2014-01-07 Style fixes; "forward slash expected" message conditional on dbug
 ## 2014-01-08 Keep track of loaded jars; allow unloading them; return them as output arg
 ##     ''     Return checked interfaces; update texinfo header
+## 2014-01-17 Tame messages about COM/ActiveX if dbug = 0
+## 2014-04-06 Skip unojarpath search for UNO entries 4 and up; code style fixes
+## 2014-04-14 Updated texinfo header & OCT r/w support messages
+## 2014-04-15 More updates to texinfo header
 
 function  [ retval, sinterfaces, loaded_jars ]  = chk_spreadsheet_support (path_to_jars, dbug, path_to_ooo)
 
@@ -241,11 +245,11 @@ function  [ retval, sinterfaces, loaded_jars ]  = chk_spreadsheet_support (path_
       winpkgind = find (cellfun (@(x) strcmp(x.name, "windows"), pkglist), 1, "first");
       if (! isempty (winpkgind))
         winpkg = pkglist{winpkgind};
-        if (winpkg.loaded)
-          printf ("MS-Excel couldn't be started (maybe because of 64-bit MS-Office?)\n");
+        if (winpkg.loaded && dbug)
+          printf ("MS-Excel couldn't be started although OF windows is loaded...\n");
         endif
-      else
-        printf ("(windows package is required for COM/ActiveX support)\n");
+      elseif (dbug)
+        printf ("(OF windows package is required for COM/ActiveX support)\n");
       endif
       printf ("\n");
     end_try_catch
@@ -269,7 +273,7 @@ function  [ retval, sinterfaces, loaded_jars ]  = chk_spreadsheet_support (path_
     if (jtst)
       printf ("Apparently no Java JRE installed.\n");
       if (! retval)
-        printf ("Only read support for ODS 1.2 (.ods), OOXML (.xlsx) and .gnumeric present\n");
+        printf ("Only ODS 1.2 (.ods) & OOXML (.xlsx) r/w support & .gnumeric read support present\n");
       endif
       return;
     else
@@ -302,14 +306,14 @@ function  [ retval, sinterfaces, loaded_jars ]  = chk_spreadsheet_support (path_
         if (! octave_config_info.features.JAVA)
           if (dbug)
             printf ("none.\n");
-            printf ("     (Octave was built without core Java support)\n");
+            printf ("     (Octave was built without Java support)\n");
           endif
         endif
       elseif (isfield (octave_config_info, "UGLY_DEFS"))
         if (isempty (regexp (octave_config_info.UGLY_DEFS, "HAVE_JAVE=1", "match")))
           if (dbug)
             printf ("none.\n");
-            printf ("     (Octave was built without enabled core Java support)\n");
+            printf ("     (Octave was built without Java support)\n");
           endif
         endif
       endif
@@ -349,7 +353,7 @@ function  [ retval, sinterfaces, loaded_jars ]  = chk_spreadsheet_support (path_
     if (dbug)
       printf ("No Java support found.\n");
       if (! retval)
-        printf ("Only read support for ODS 1.2 (.ods), OOXML (.xlsx) and .gnumeric\n");
+        printf ("Only ODS 1.2 (.ods) & OOXML (.xlsx) r/w support & .gnumeric read support present\n");
       endif
     endif
     return
@@ -530,7 +534,7 @@ function  [ retval, sinterfaces, loaded_jars ]  = chk_spreadsheet_support (path_
       return;
     endif
     if (dbug && ! isempty (strfind (path_to_ooo, '\')))
-      printf ("\n(Hmmm... forward slashes are preferred over backward slashes in path)\n");
+      printf ("\n(forward slashes are preferred over backward slashes in path)\n");
     endif
     ## Add missing jars to javaclasspath. First combine all entries
     targt = sum (missing0);
@@ -601,14 +605,17 @@ function  [ retval, sinterfaces, loaded_jars ]  = chk_spreadsheet_support (path_
           unojarpath = tmp;
           file = dir ([ unojarpath filesep entries0{2} "*" ]);
         else
-          ## Rest of jars in ./ure/share/java or ./ure/java
-          unojardir = get_dir_ (uredir, "share");
-          if (isempty (unojardir))
-            tmp = uredir;
-          else
-            tmp = unojardir;
+          ## Rest of jars in ./ure/share/java or ./ure/java
+          if (ii == 3)
+            ## Find unojarpath; the rest of the entries should live here too
+            unojardir = get_dir_ (uredir, "share");
+            if (isempty (unojardir))
+              tmp = uredir;
+            else
+              tmp = unojardir;
+            endif
+            unojarpath = get_dir_ (tmp, "java");
           endif
-          unojarpath = get_dir_ (tmp, "java");
           file = dir ([unojarpath filesep entries0{ii} "*"]);
         endif
         ## Path found, now try to add jar
@@ -638,8 +645,10 @@ function  [ retval, sinterfaces, loaded_jars ]  = chk_spreadsheet_support (path_
           end_try_catch
         endif
       endif
-    endfor
-    if (! targt)
+    endfor
+    ## Check if all entries have been found
+    if (! targt)
+      ## Yep
       retval = retval + 128;
       sinterfaces = [sinterfaces, "UNO"];
     endif
@@ -666,7 +675,7 @@ function  [ retval, sinterfaces, loaded_jars ]  = chk_spreadsheet_support (path_
 
   if (! jars_complete && nargin > 0 && ! isempty (path_to_jars))
     ## Add missing jars to javaclasspath. Assume they're all in the same place
-    ## FIXME: add checks for prope odfdom && OpenXLS jar versions
+    ## FIXME: add checks for proper odfdom && OpenXLS jar versions
     if (dbug)
       printf ("Trying to add missing java class libs to javaclasspath...\n");
     endif
@@ -743,7 +752,9 @@ function [ ret_dir ] = get_dir_ (base_dir, req_dir)
     ii = 1;
     while (! ret_dir_list(idx(ii)).isdir)
       ii = ii + 1;
-      if (ii > numel (idx)); return; endif
+      if (ii > numel (idx))
+        return; 
+      endif
     endwhile
     ## If we get here, a dir with proper name has been found. Construct path
     ret_dir = [ base_dir filesep  ret_dir_list(idx(ii)).name ];
diff --git a/inst/io_ods_testscript.m b/inst/io_ods_testscript.m
index f487c6a..5f203ba 100644
--- a/inst/io_ods_testscript.m
+++ b/inst/io_ods_testscript.m
@@ -48,18 +48,15 @@
 ## 2013-12-18 Add option to write and read with different interfaces (needed for OCT)
 ##     ''     Catch more erroneous read-back results
 ## 2013-12-31 More extensive texinfo help text
-##     ''     Provide default test file name
+##     ''     Provide default test file name
+## 2014-01-23 Adapted to write support for OCT
+## 2014-01-24 Fiddle with delays to allow OS to zip/unzip files to/from disk
 
 function io_ods_testscript (intf, fname="io-test.ods", intf2='')
 
   printf ("\nTesting .ods interface %s using file %s...\n", upper (intf), fname);
   
   isuno = false; dly = 0.25;
-  if (strcmpi (intf, 'oct'))
-    if (isempty (intf2))
-      intf2 = 'otk';
-    endif
-  endif
   if (isempty (intf2))
     intf2 = intf;
   else
@@ -77,26 +74,31 @@ function io_ods_testscript (intf, fname="io-test.ods", intf2='')
   
   ## 2. Insert empty sheet
   printf ("\n 2. Insert first empty sheet.\n");
-  odswrite (fname, {''}, 'EmptySheet', 'b4', intf2); if (isuno); sleep (dly); endif
-  
+  odswrite (fname, {''}, 'EmptySheet', 'b4', intf2); 
+  sleep (dly);
+
   ## 3. Add data to test sheet
   printf ("\n 3. Add data to test sheet.\n");
   odswrite (fname, arr1, 'Testsheet', 'c2:d3', intf2); if (isuno); sleep (dly); endif
-  odswrite (fname, arr2, 'Testsheet', 'd4:z20', intf2); if (isuno); sleep (dly); endif
+  odswrite (fname, arr2, 'Testsheet', 'd4:z20', intf2);
+  sleep (dly);
   
   ## 4. Insert another sheet
   printf ("\n 4. Add another sheet with just one number in A1.\n");
-  odswrite (fname, [1], 'JustOne', 'A1', intf2); if (isuno); sleep (dly); endif
+  odswrite (fname, [1], 'JustOne', 'A1', intf2);
+  sleep (dly);
   
   ## 5. Get sheet info & find sheet with data and data range
   printf ("\n 5. Explore sheet info.\n");
-  [~, shts] = odsfinfo (fname, intf); if (isuno); sleep (dly); endif
+  [~, shts] = odsfinfo (fname, intf);
   shnr = strmatch ('Testsheet', shts(:, 1));                      # Note case!
-  crange = shts{shnr, 2};
+  crange = shts{shnr, 2};
+  sleep (dly);
 
   ## 6. Read data back
   printf ("\n 6. Read data back.\n");
-  [num, txt, raw, lims] = odsread (fname, shnr, crange, intf); if (isuno); sleep (dly); endif
+  [num, txt, raw, lims] = odsread (fname, shnr, crange, intf);
+  sleep (dly);
   
   ## First check: has anything been read at all?
   if (isempty (raw))
@@ -121,7 +123,8 @@ function io_ods_testscript (intf, fname="io-test.ods", intf2='')
     assert (isnumeric (num(3,3)), true);
     printf ("matches.\n");
   catch
-    printf ("Hmmm.... error, see 'num'\n");
+    printf ("Hmmm.... error, see 'num'\n");
+    num
   end_try_catch
   try
     printf ("    ...Cellstr array... ");
@@ -129,7 +132,8 @@ function io_ods_testscript (intf, fname="io-test.ods", intf2='')
     assert (txt{2, 2}, 'r2c2');
     printf ("matches.\n");
   catch
-    printf ("Hmmm.... error, see 'txt'\n"); 
+    printf ("Hmmm.... error, see 'txt'\n"); 
+    txt
   end_try_catch
   try
     printf ("    ...Boolean... "); 
@@ -139,16 +143,18 @@ function io_ods_testscript (intf, fname="io-test.ods", intf2='')
     if (isnumeric (raw{5, 2}))
       printf ("recovered as numeric '1' rather than logical TRUE\n");
     else
-      printf ("Hmmm.... error, see 'raw'\n");
+      printf ("Hmmm.... error, see 'raw'\n");
+      raw
     endif
   end_try_catch
+  sleep (dly);
 
   ## Check if formulas_as_text works:
   printf ("\n 8. Repeat reading, now return formulas as text\n");
   opts.formulas_as_text = 1;
-  ods = odsopen (fname, 0, intf); if (isuno); sleep (dly); endif
-  raw = ods2oct (ods, shnr, crange, opts); if (isuno); sleep (dly); endif
-  ods = odsclose (ods); if (isuno); sleep (dly); endif
+  ods = odsopen (fname, 0, intf);
+  raw = ods2oct (ods, shnr, crange, opts);
+  ods = odsclose (ods);
   clear ods;
   
   ## 9. Here come the tests, part 2. Fails on COM
@@ -172,7 +178,7 @@ function io_ods_testscript (intf, fname="io-test.ods", intf2='')
   ## 10. Clean up
   printf ("\n10. Cleaning up.....");
   delete (fname);
-  clear arr1 arr2 ods num txt raw lims opts shnr shts crange;
+  clear arr1 arr2 ods num txt raw lims opts shnr shts crange dly;
   printf (" OK\n");
   
   endfunction
diff --git a/inst/io_xls_testscript.m b/inst/io_xls_testscript.m
index 0a821fc..e7cc871 100644
--- a/inst/io_xls_testscript.m
+++ b/inst/io_xls_testscript.m
@@ -1,4 +1,4 @@
-## Copyright (C) 2012,2013 Philip Nienhuis
+## Copyright (C) 2012,2013,2014 Philip Nienhuis
 ##
 ## This program is free software; you can redistribute it and/or modify it under
 ## the terms of the GNU General Public License as published by the Free Software
@@ -60,20 +60,21 @@ function io_xls_testscript (intf, fname="io-test.xls", intf2=[])
 
   isuno = false;
   dly = 0.25;
-  if (strcmpi (intf, 'oct'))
-  ## FIXME commented out/replaced until UNO & OXS OOXML write support is fixed
-##  if (isempty (intf2))
-    if (isempty (intf2) || ! strcmpi (intf2, "com"))
-      intf2 = 'poi';
-    endif
-    printf ("OCT interface has no write support enabled - writing is done with %s.\n", intf2);
-  endif
+%  if (strcmpi (intf, 'oct'))
+%  ## FIXME commented out/replaced until UNO & OXS OOXML write support is fixed
+%##  if (isempty (intf2))
+%    if (isempty (intf2) || ! strcmpi (intf2, "com"))
+%      intf2 = 'poi';
+%    endif
+%    printf ("OCT interface has no write support enabled - writing is done with %s.\n", intf2);
+%  endif
   ## If no intf2 is supplied, write with intf1
   if (isempty (intf2))
     intf2 = intf;
   endif
   ## Allow the OS some delay to accomodate for file operations (zipping etc.)
-  if (strcmpi (intf, "uno") || strcmpi (intf2, "uno"));
+  if (strcmpi (intf, "uno") || strcmpi (intf2, "uno") ||
+      strcmpi (intf, "oct") || strcmpi (intf2, "oct"));
     isuno = true;
   endif
 
@@ -99,6 +100,10 @@ function io_xls_testscript (intf, fname="io-test.xls", intf2=[])
   xlswrite (fname, arr2, 'Testsheet', 'd4:z20', intf2);
   if (isuno)
     sleep (dly);
+    if (strcmpi (intf, "oct") || strcmpi (intf2, "oct"))
+      ## Some more delay to give zip a breath
+      sleep (dly); sleep (dly);
+    endif
   endif
   
   ## 4. Insert another sheet
@@ -123,7 +128,7 @@ function io_xls_testscript (intf, fname="io-test.xls", intf2=[])
   if (strcmpi (crange, "A1:A1"))
     crange = ''
   endif
-  
+
   ## 6. Read data back
   printf ("\n 6. Read data back.\n");
   [num, txt, raw, lims] = xlsread (fname, shnr, crange, intf);
diff --git a/inst/oct2ods.m b/inst/oct2ods.m
index df38be8..6690bb2 100644
--- a/inst/oct2ods.m
+++ b/inst/oct2ods.m
@@ -1,4 +1,4 @@
-## Copyright (C) 2009,2010,2011,2012,2013 Philip Nienhuis
+## Copyright (C) 2009,2010,2011,2012,2013,2014 Philip Nienhuis
 ##
 ## This program is free software; you can redistribute it and/or modify it under
 ## the terms of the GNU General Public License as published by the Free Software
@@ -120,7 +120,8 @@
 ## 2012-10-12 Moved all interface-specific subfubcs into ./private
 ## 2012-10-24 Style fixes
 ## 2012-12-18 Improved error/warning messages
-## 2013-12-18 Copyright string updates, style fixes
+## 2013-12-18 Copyright string updates, style fixes
+## 2014-03-18 Add back in UNO interface (changed into by OCT - blush)
 ##
 ## Latest subfunc update: 2012-10-12
 
@@ -140,7 +141,7 @@ function [ ods, rstatus ] = oct2ods (c_arr, ods, wsh=1, crange="", spsh_opts=[])
   elseif (ischar(c_arr))
     c_arr = {c_arr};
     printf ("(oct2ods: input character array converted to 1x1 cell)\n");
-  elseif (~iscell (c_arr))
+  elseif (! iscell (c_arr))
     error ("oct2ods: input array neither cell nor numeric array");
   endif
   if (ndims (c_arr) > 2)
@@ -200,11 +201,15 @@ function [ ods, rstatus ] = oct2ods (c_arr, ods, wsh=1, crange="", spsh_opts=[])
   elseif (strcmp (ods.xtype, "JOD"))
     ## Write ods file tru Java & jOpenDocument. API still leaves lots to be wished...
     [ ods, rstatus ] = __JOD_oct2spsh__ (c_arr, ods, wsh, crange);
+
+  elseif (strcmp (ods.xtype, "UNO"))
+    ## Write ods file tru UNO
+    [ ods, rstatus ] = __UNO_oct2spsh__ (c_arr, ods, wsh, crange, spsh_opts);
 
-  elseif (strcmp (ods.xtype, "UNO"))
-    ## Write ods file tru Java & UNO bridge (OpenOffice.org & clones)
-    [ ods, rstatus ] = __UNO_oct2spsh__ (c_arr, ods, wsh, crange, spsh_opts);
-
+  elseif (strcmp (ods.xtype, "OCT"))
+    ## Write ods or gnumeric file tru native Octave
+    [ ods, rstatus ] = __OCT_oct2spsh__ (c_arr, ods, wsh, crange, spsh_opts);
+
   ##elseif 
     ##---- < Other interfaces here >
 
@@ -213,6 +218,8 @@ function [ ods, rstatus ] = oct2ods (c_arr, ods, wsh=1, crange="", spsh_opts=[])
                     ods.xtype));
   endif
 
-  if (rstatus), ods.limits = []; endif
+  if (rstatus)
+    ods.limits = [];
+  endif
 
 endfunction
diff --git a/inst/oct2xls.m b/inst/oct2xls.m
index 882145d..da85824 100644
--- a/inst/oct2xls.m
+++ b/inst/oct2xls.m
@@ -1,4 +1,4 @@
-## Copyright (C) 2009,2010,2011,2012 Philip Nienhuis <prnienhuis at users.sf.net>
+## Copyright (C) 2009,2010,2011,2012,2013,2014 Philip Nienhuis
 ##
 ## This program is free software; you can redistribute it and/or modify it under
 ## the terms of the GNU General Public License as published by the Free Software
@@ -86,11 +86,11 @@
 ##
 ## @end deftypefn
 
-## Author: Philip Nienhuis
+## Author: Philip Nienhuis <prnienhuis at users sf net>
 ## Created: 2009-12-01
 ## Updates: 
-## 2010-01-03 (OOXML support)
-## 2010-03-14 Updated help text section on java memory usage
+## 2010-01-03 (OOXML support / POI)
+## 2010-03-14 Updated help text section on Java memory usage
 ## 2010-07-27 Added formula writing support (based on patch by Benjamin Lindner)
 ## 2010-08-01 Added check on input array size vs. spreadsheet capacity
 ##     ''     Changed argument topleft into range (now compatible with ML); the
@@ -115,9 +115,8 @@
 ## 2012-10-12 Moved all interface-specific subfubcs into ./private
 ## 2012-10-24 Style fixes
 ## 2012-12-18 Improved error/warning messages
-## 2012-12-29 Style fixes
-##
-## Latest subfunc update: 2012-10-12
+## 2012-12-29 Style fixes
+## 2014-01-29 Allow OCT write support for OOXML & ODS & gnumeric
 
 function [ xls, rstatus ] = oct2xls (obj, xls, wsh=1, crange="", spsh_opts=[])
 
@@ -194,12 +193,14 @@ function [ xls, rstatus ] = oct2xls (obj, xls, wsh=1, crange="", spsh_opts=[])
     ## Invoke Java and JExcelAPI
     [xls, rstatus] = __JXL_oct2spsh__ (obj, xls, wsh, crange, spsh_opts);
   elseif (strcmpi (xls.xtype, "OXS"))
-    ## Invoke Java and OpenXLS     ##### Not complete, saving file doesn't work yet!
-    ## printf ("Sorry, writing with OpenXLS not reliable => not supported yet\n");
+    ## Invoke Java and OpenXLS
     [xls, rstatus] = __OXS_oct2spsh__ (obj, xls, wsh, crange, spsh_opts);
   elseif (strcmpi (xls.xtype, "UNO"))
     ## Invoke Java and UNO bridge (OpenOffice.org)
     [xls, rstatus] = __UNO_oct2spsh__ (obj, xls, wsh, crange, spsh_opts);
+  elseif (strcmpi (xls.xtype, "OCT"))
+    ## Invoke native Octave code (only ods/xlsx/gnumeric)
+    [xls, rstatus] = __OCT_oct2spsh__ (obj, xls, wsh, crange, spsh_opts);
 ##elseif (strcmpi (xls.xtype, "<whatever>"))
     ##<Other Excel interfaces>
   else
diff --git a/inst/ods2oct.m b/inst/ods2oct.m
index 1f21df1..cd22d75 100644
--- a/inst/ods2oct.m
+++ b/inst/ods2oct.m
@@ -1,4 +1,4 @@
-## Copyright (C) 2009,2010,2011,2012,2013 Philip Nienhuis
+## Copyright (C) 2009,2010,2011,2012,2013,2014 Philip Nienhuis
 ##
 ## This program is free software; you can redistribute it and/or modify it under
 ## the terms of the GNU General Public License as published by the Free Software
@@ -20,7 +20,8 @@
 ## @deftypefnx {Function File} [ @var{rawarr}, @var{ods}, @var{rstatus} ] = ods2oct (@var{ods}, @var{wsh}, @var{range}, @var{options})
 ##
 ## Read data contained within cell range @var{range} from worksheet @var{wsh}
-## in an OpenOffice_org Calc spreadsheet file pointed to in struct @var{ods}.
+## in an OpenOffice_org Calc or Gnumeric spreadsheet file pointed to
+## in struct @var{ods}.
 ##
 ## @var{ods} is supposed to have been created earlier by odsopen in the
 ## same octave session.
@@ -30,7 +31,7 @@
 ## Note that in case of a numerical @var{wsh} this number refers to the
 ## position in the worksheet stack, counted from the left in a Calc
 ## window. The default is numerical 1, i.e. the leftmost worksheet
-## in the ODS file.
+## in the ODS or gnumeric file.
 ##
 ## @var{range} is expected to be a regular spreadsheet range format,
 ## or "" (empty string, indicating all data in a worksheet).
@@ -45,7 +46,7 @@
 ## @item "formulas_as_text"
 ## If set to TRUE or 1, spreadsheet formulas (if at all present)
 ## are read as formula strings rather than the evaluated formula
-## result values. This only works for the OTK and UNO interfaces.
+## result values. This only works for the OTK, UNO and OCT interfaces.
 ## The default value is 0 (FALSE).
 ##
 ## @item 'strip_array'
@@ -74,14 +75,14 @@
 ## requested data have been read successfully, 0 otherwise.
 ##
 ## Erroneous data and empty cells turn up empty in @var{rawarr}.
-## Date/time values in OpenOffice.org are returned as numerical values
-## with base 1-1-0000 (same as octave). But beware that Excel spreadsheets
-## rewritten by OpenOffice.org into .ods format may have numerical date
-## cells with base 01-01-1900 (same as MS-Excel).
+## Date/time values in OpenOffice.org or Gnumeric are returned as numerical
+## values with base 1-1-0000 (same as octave). But beware that Excel
+## spreadsheets rewritten by OpenOffice.org into .ods format may have
+## numerical date cells with epoch (base) 01-01-1900 (same as MS-Excel).
 ##
 ## When reading from merged cells, all array elements NOT corresponding 
-## to the leftmost or upper OpenOffice.org cell will be treated as if the
-## "corresponding" cells are empty.
+## to the leftmost or upper OpenOffice.org Calc or Gnumeric cell will be
+## treated as if the "corresponding" cells are empty.
 ##
 ## Examples:
 ##
@@ -130,6 +131,8 @@
 ## 2013-10-02 Some adaptations for gnumeric
 ## 2013-12-01 Style fixes
 ## 2013-12-27 More style fixes
+## 2014-04-13 Copyright string updated
+## 2014-04-15 More updates to texinfo header
 ##
 ## Latest subfunc update: 2012-10-12
 
diff --git a/inst/odsclose.m b/inst/odsclose.m
index a47344a..38b76b9 100644
--- a/inst/odsclose.m
+++ b/inst/odsclose.m
@@ -1,4 +1,4 @@
-## Copyright (C) 2009,2010,2011,2012,2013 Philip Nienhuis
+## Copyright (C) 2009,2010,2011,2012,2013,2014 Philip Nienhuis
 ##
 ## This program is free software; you can redistribute it and/or modify it under
 ## the terms of the GNU General Public License as published by the Free Software
@@ -73,7 +73,8 @@
 ## 2013-09-09 Native Octave interface ("OCT") for reading
 ##      ''    Warning message for empty file ptr structs
 ## 2013-10-02 Texinfo header adapted
-## 2013-12-01 Style fixes
+## 2013-12-01 Style fixes
+## 2014-04-13 Updated copyright strings
 
 function [ ods ] = odsclose (ods, varargs)
 
diff --git a/inst/odsfinfo.m b/inst/odsfinfo.m
index daa5f3c..2b93636 100644
--- a/inst/odsfinfo.m
+++ b/inst/odsfinfo.m
@@ -1,4 +1,4 @@
-## Copyright (C) 2009,2010,2011,2012,2013 Philip Nienhuis
+## Copyright (C) 2009,2010,2011,2012,2013,2014 Philip Nienhuis
 ##
 ## This program is free software; you can redistribute it and/or modify it under
 ## the terms of the GNU General Public License as published by the Free Software
@@ -16,16 +16,16 @@
 ## -*- texinfo -*-
 ## @deftypefn {Function File} [@var{filetype}] = odsfinfo (@var{filename} [, @var{reqintf}])
 ## @deftypefnx {Function File} [@var{filetype}, @var{sh_names}] = odsfinfo (@var{filename} [, @var{reqintf}])
-## Query an OpenOffice_org spreadsheet file @var{filename} (with ods
-## suffix) for some info about its contents.
+## Query an OpenOffice_org or Gnumeric spreadsheet file @var{filename}
+## (with ods or gnumeric suffix) for some info about its contents.
 ##
-## If @var{filename} is a recognizable OpenOffice.org spreadsheet file,
-## @var{filetype} returns the string "OpenOffice.org Calc spreadsheet",
-## or @'' (empty string) otherwise.
+## If @var{filename} is a recognizable OpenOffice.org or Gnumeric spreadsheet
+## file, @var{filetype} returns the string "OpenOffice.org Calc spreadsheet"
+## (or "Gnumeric spreadsheet"), or @'' (empty string) otherwise.
 ## 
-## If @var{filename} is a recognizable OpenOffice.org Calc spreadsheet
-## file, optional argument @var{sh_names} contains a list (cell array)
-## of sheet names contained in @var{filename}, in the order (from left
+## If @var{filename} is a recognizable OpenOffice.org Calc or Gnumeric
+## spreadsheet file, optional argument @var{sh_names} contains a list (cell
+## array) of sheet names contained in @var{filename}, in the order (from left
 ## to right) in which they occur in the sheet stack.
 ##
 ## If you omit return arguments @var{filetype} and @var{sh_names} altogether,
@@ -38,7 +38,7 @@
 ## used data ranges.
 ##
 ## By specifying a value of 'jod', 'otk', 'uno' or 'oct' for @var{reqintf} the
-## automatic selection of the java interface is bypassed and the specified
+## automatic selection of the Java interface is bypassed and the specified
 ## interface will be used (if at all present).
 ##
 ## Examples:
diff --git a/inst/odsopen.m b/inst/odsopen.m
index 430e1b6..4d12473 100644
--- a/inst/odsopen.m
+++ b/inst/odsopen.m
@@ -24,9 +24,9 @@
 ## Calling odsopen without specifying a return argument is fairly useless!
 ##
 ## Octave links to external software for read/write support of spreadsheets;
-## these links are "interfaces". For just reading ODS 1.2 and Gnumeric XML
-## no external SW is required, yet this "interface" is called 'OCT'.
-## To make this function work at all for write support, you need a Java JRE
+## these links are "interfaces". For I/O from/to ODS 1.2 and reading Gnumeric
+## XML, in principle no external SW is required, this "interface" is called
+## 'OCT'. For more flexibility and better performance, you need a Java JRE
 ## or JDK plus one or more of (ODFtoolkit (version 0.7.5 or 0.8.6 - 0.8.8) &
 ## xercesImpl v.2.9.1), jOpenDocument, or OpenOffice.org (or clones) installed
 ## on your computer + proper javaclasspath set. These interfaces are referred
@@ -35,25 +35,25 @@
 ## The relevant Java class libs for spreadsheet I/O had best be added to the
 ## javaclasspath by utility function chk_spreadsheet_support().
 ##
-## @var{filename} must be a valid .ods OpenOffice.org file name including
-## .ods suffix. If @var{filename} does not contain any directory path,
-## the file is saved in the current directory.
-## For UNO bridge, filenames need to be in the form "file:///<path_to_file>/filename";
+## @var{filename} must be a valid .ods OpenOffice.org Calc, or Gnumeric, file
+## name including .ods or .gnumeric suffix. If @var{filename} does not contain
+## any directory path, the file is saved in the current directory. For UNO
+## bridge, filenames need to be in the form "file:///<path_to_file>/filename";
 ## a URL will also work. If a plain file name is given (absolute or relative),
-## odsopen() will transform it into proper form.
+## odsopen() will try to transform it into proper form.
 ##
 ## @var{readwrite} must be set to true or numerical 1 if writing to spreadsheet
 ## is desired immediately after calling odsopen(). It merely serves proper
 ## handling of file errors (e.g., "file not found" or "new file created").
 ##
 ## Optional input argument @var{reqintf} can be used to override the ODS
-## interface automatically selected by odsopen. Currently implemented interfaces
-## are 'OTK' (Java/ODF Toolkit), 'JOD' (Java/jOpenDocument), 'UNO'
-## (Java/OpenOffice.org UNO bridge), and 'OCT' (native Octave, only reading).
-## In most situations this parameter is unneeded as odsopen automatically
-## selects the most useful interface present ("default interface").
-## Depending on file type, odsopen.m can invoke other detected interfaces than
-## the default one.
+## interface automatically selected by odsopen. Currently implemented
+## interfaces are 'OTK' (Java/ODF Toolkit), 'JOD' (Java/jOpenDocument), 'UNO'
+## (Java/OpenOffice.org UNO bridge), and 'OCT' (native Octave, for Gnumeric
+## only reading). In most situations this parameter is unneeded as odsopen
+## automatically selects the most useful interface present ("default
+## interface"). Depending on file type, odsopen.m can invoke other detected
+## interfaces than the default one.
 ##
 ## Beware:
 ## The UNO interface is still experimental. While in itself reliable, it may
@@ -135,6 +135,9 @@
 ## 2013-12-27 Use one variable for processed file types
 ## 2014-01-01 Add warning that UNO will write ODS f. unsupported file extensions
 ##     ''     Copyright string update
+## 2014-01-23 OCT ods write support for .ods
+## 2014-04-14 Update texinfo header
+## 2014-04-15 More updates to texinfo header
 
 function [ ods ] = odsopen (filename, rw=0, reqinterface=[])
 
@@ -207,10 +210,12 @@ function [ ods ] = odsopen (filename, rw=0, reqinterface=[])
   ## Var rw is really used to avoid creating files when wanting to read, or
   ## not finding not-yet-existing files when wanting to write a new one.
   ## Be sure it's either 0 or 1 initially
-  if (rw)
-    if (odsintf_cnt == 1 && odsinterfaces.OCT)
+  if (rw)
+    [~, ~, ext] = fileparts (filename);
+    ## .ods write support is supported
+    if (odsintf_cnt == 1 && odsinterfaces.OCT && ! strcmpi (ext, ".ods"))
       ## Check if OCT is only interface and writing is requested
-      error ("OCT interface doesn't support writing files");
+      error ("OCT interface doesn't support writing gnumeric files (yet)");
     endif
     rw = 1;
   endif
diff --git a/inst/odsread.m b/inst/odsread.m
index 999ab9c..bf5d464 100644
--- a/inst/odsread.m
+++ b/inst/odsread.m
@@ -1,4 +1,4 @@
-## Copyright (C) 2009,2010,2011,2012,2013 Philip Nienhuis
+## Copyright (C) 2009,2010,2011,2012,2013,2014 Philip Nienhuis
 ##
 ## This program is free software; you can redistribute it and/or modify it under
 ## the terms of the GNU General Public License as published by the Free Software
@@ -23,13 +23,14 @@
 ## in OpenOffice_org Calc spreadsheet file @var{filename}. Reading
 ## Gnumeric xml files is also supported.
 ##
-## A native Octave interface (OCT) is available for reading data.
-## For ODS the supported Java-based interfaces offer more flexibility
-## and better speed, plus write support. For these you need a Java JRE or JDK
+## A native Octave interface (OCT) is available, but presently still
+## experimental. For ODS only the supported Java-based interfaces offer
+## more flexibility and better speed. For those you need a Java JRE or JDK
 ## and one or both of jopendocument-<version>.jar or preferrably: (odfdom.jar
 ## (versions 0.7.5 or 0.8.6-0.8.8) & xercesImpl.jar v. 2.9.1) in your
 ## javaclasspath. There is also experimental support invoking
-## OpenOffice.org/LibreOffice or clones through a Java/UNO bridge.
+## OpenOffice.org/LibreOffice or clones through a Java/UNO bridge.
+## The OCT interface also offers .gnumeric read support.
 ##
 ## Return argument @var{numarr} contains the numeric data, optional
 ## return arguments @var{txtarr} and @var{rawarr} contain text strings
@@ -41,8 +42,8 @@
 ## the filename extension (.ods).
 ##
 ## @var{wsh} is either numerical or text, in the latter case it is 
-## case-sensitive and it should conform to OpenOffice.org Calc sheet
-## name requirements.
+## case-sensitive and it should conform to OpenOffice.org Calc or
+## Gnumeric sheet name requirements.
 ## Note that in case of a numerical @var{wsh} this number refers to the
 ## position in the worksheet stack, counted from the left in a Calc
 ## window. The default is numerical 1, i.e. the leftmost worksheet
@@ -64,9 +65,9 @@
 ## The optional last argument @var{reqintf} can be used to override 
 ## the automatic selection by odsread of one interface out of the
 ## supported ones: Java/ODFtoolkit ('OTK'), Java/jOpenDocument 
-## ('JOD'), Java/UNO bridge ('UNO'), or native Octave (OCT; only for
-## reading). Octave selects one of these, preferrably in the order above,
-## based on presence of support software and the file at hand.
+## ('JOD'), Java/UNO bridge ('UNO'), or native Octave (OCT). Octave
+## selects one of these, preferrably in the order above, based on
+## presence of support software and the file at hand.
 ##
 ## Erroneous data and empty cells are set to NaN in @var{numarr} and
 ## turn up empty in @var{txtarr} and @var{rawarr}. Date/time values
@@ -77,7 +78,8 @@
 ## .ods format by OpenOffice.org Calc may have different date base
 ## values.
 ## As there's no gnumeric formula evaluator and gnumeric doesn't store
-## cached formula results, formulas are returned as text strings.
+## cached formula results, formulas are returned as text strings when
+## reading from Gnumeric files.
 ##
 ## @var{numarr} and @var{txtarr} are trimmed from empty outer rows
 ## and columns, so any returned array may turn out to be smaller than
@@ -137,7 +139,9 @@
 ##     ''     Texinfo header adapted
 ## 2013-11-04 Better error message about unsupported file types
 ##     ''     Add .sxc to supported file types
-## 2013-12-01 Updated texinfo header
+## 2013-12-01 Updated texinfo header
+## 2014-04-13 Updated copyright strings and texinfo header
+## 2014-04-15 More updates to texinfo header
 
 function [ numarr, txtarr, rawarr, lim ] = odsread (filename, wsh=1, datrange=[], reqintf=[])
 
diff --git a/inst/odswrite.m b/inst/odswrite.m
index d932e35..fa9bbc6 100644
--- a/inst/odswrite.m
+++ b/inst/odswrite.m
@@ -1,4 +1,4 @@
-## Copyright (C) 2009,2010,2011,2012,2013 Philip Nienhuis <pr.nienhuis at users.sf.net>
+## Copyright (C) 2009,2010,2011,2012,2013,2014 Philip Nienhuis
 ##
 ## This program is free software; you can redistribute it and/or modify it under
 ## the terms of the GNU General Public License as published by the Free Software
@@ -59,15 +59,16 @@
 ## The optional last argument @var{reqintf} can be used to override 
 ## the automatic selection by odswrite of one interface out of the
 ## supported ones: Java/ODFtooolkit ('OTK'), Java/jOpenDocument ('JOD'),
-## or Java/OpenOffice.org ('UNO').
+## Java/OpenOffice.org ('UNO'), or native Octave ('OCT').
 ##
 ## odswrite is a mere wrapper for various scripts which find out what
-## ODS interface to use (ODF toolkit or jOpenDocument) plus code to mimic
-## the other brand's syntax. For each call to odswrite such an interface
-## must be started and possibly an ODS file loaded. When writing to multiple
-## ranges and/or worksheets in the same ODS file, a speed bonus can be
-## obtained by invoking those scripts (odsopen / octods / .... / odsclose)
-## directly.
+## ODS interface to use (ODF toolkit, jOpenDocument, Open/LibreOffice or
+## native Octave) plus code to mimic the other brand's xlswrite syntax
+## (and quirks).
+## For each call to odswrite such an interface must be started and
+## possibly an ODS file loaded. When writing to multiple ranges and/or
+## worksheets in the same ODS file, a speed bonus can be obtained by
+## invoking those scripts (odsopen / octods / .... / odsclose) directly.
 ##
 ## Example:
 ##
@@ -82,7 +83,7 @@
 ##
 ## @end deftypefn
 
-## Author: Philip Nienhuis
+## Author: Philip Nienhuis <pr.nienhuis at users.sf.net>
 ## Created: 2009-12-14
 ## Updates:
 ## 2010-01-14 Finalized write support tru ODS toolkit
@@ -97,7 +98,8 @@
 ## 2012-06-08 Tabs replaced by double space
 ## 2012-10-24 Style fixes
 ## 2013-12-18 Copyright string updates, style fixes
-## 2014-01-01 Drop file extension check
+## 2014-01-01 Drop file extension check
+## 2014-04-13 Updated copyright strings & texinfo header
 
 function [ rstatus ] = odswrite (filename, data, wsh=1, crange="", reqintf=[])
 
diff --git a/inst/private/__OCT_gnm2oct__.m b/inst/private/__OCT_gnm2oct__.m
index a521014..c5a90ae 100644
--- a/inst/private/__OCT_gnm2oct__.m
+++ b/inst/private/__OCT_gnm2oct__.m
@@ -29,7 +29,9 @@
 ## 2013-11-03 Fix processing chunks
 ##     ''     Get ValueType using getxmlattv, not regexp
 ##     ''     Process Boolean type
-## 2013-11-15 Replace slow xml node parsing by regexp a la Markus Bergholz
+## 2013-11-15 Replace slow xml node parsing by regexp a la Markus Bergholz
+## 2014-02-20 Add ValueFormat tag to regexp pattern
+## 2014-04-13 Fix regexp patterns
 
 function [ rawarr, xls, rstatus] = __OCT_gnm2oct__ (xls, wsh, cellrange='', spsh_opts)
 
@@ -98,12 +100,31 @@ function [ rawarr, xls, rstatus] = __OCT_gnm2oct__ (xls, wsh, cellrange='', spsh
   ## Get cell nodes
   cells = getxmlnode (xml, "gnm:Cells");
 
-  ## Pattern gets all required tokens in one fell swoop
-  pattrn = '<gnm:Cell Row="(\d*?)" Col="(\d*?)" (?:ValueType="(\d*?)"|ExprID="(\d*?)")>(.*?)</gnm:Cell>';
-  allvals = cell2mat (regexp (cells, pattrn, "tokens"));
-
-  ## Reshape into 4 x ... cell array
-  allvals = reshape (allvals, 4,  numel (allvals) / 4);
+  ## Pattern gets most required tokens in one fell swoop
+  pattrn = '<gnm:Cell Row="(\d*?)" Col="(\d*?)"(?: (?:ValueType|ExprID)="(\d*?)")(?: ValueFormat="\w+")?>(.*?)</gnm:Cell>';
+  allvals = cell2mat (regexp (cells, pattrn, "tokens"));
+
+  if (! isempty (allvals))
+    ## Reshape into 4 x ... cell array
+    allvals = reshape (allvals, 4,  numel (allvals) / 4);
+  else
+    allvals= cell(4, 0);
+  endif
+
+  ## For those cells w/o ValueType | ExprId tags
+  pattrn = '<gnm:Cell Row="(\d*?)" Col="(\d*?)">(.*?)</gnm:Cell>';
+  smevals = cell2mat (regexp (cells, pattrn, "tokens"));
+  ## Reshape these into 3 X ... cell array, expand to 4 X ...
+  if (! isempty (smevals))
+    smevals = reshape (smevals, 3,  numel (smevals) / 3);
+    smevals(4, :) = smevals(3, :);
+    smevals(3, :) = 0;
+  else
+    smevals= cell(4, 0);
+  endif
+
+  ## Try to concatenate both
+  allvals = [ allvals smevals ];
 
   ## Convert 0-based rw/column indices to 1-based numeric
   allvals(1:2, :) = num2cell (str2double (allvals(1:2, :)) + 1);
diff --git a/inst/private/__OCT_merge_data__.m b/inst/private/__OCT_merge_data__.m
new file mode 100644
index 0000000..c3bd514
--- /dev/null
+++ b/inst/private/__OCT_merge_data__.m
@@ -0,0 +1,72 @@
+## Copyright (C) 2014 Philip Nienhuis
+## 
+## This program is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+## 
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+## 
+## You should have received a copy of the GNU General Public License
+## along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*- 
+## @deftypefn {Function File} {@var{retval} =} __OCT_merge_data__ (@var{input1}, @var{input2})
+## Internal function meant for merging existing sheet data and new data
+##
+## @end deftypefn
+
+## Author: Philip Nienhuis <prnienhuis at users sf net>
+## Created: 2014-01-29
+
+function [rawarr, lims, onr, onc] = __OCT_merge_data__ (rawarr, lims, obj, obj_dims)
+
+  ## C . If required, adapt current data array size to disjoint new data
+  if (! isempty (rawarr))
+    ## Merge new & current data. Assess where to augment/overwrite current data
+    [onr, onc] = size (rawarr);
+    if (obj_dims.tr < lims(2, 1))
+      ## New data requested above current data. Add rows above current data
+      rawarr = [ cell(lims(2, 1) - obj_dims.tr, onc) ; rawarr];
+      lims(2, 1) = obj_dims.tr;
+    endif
+    if (obj_dims.br > lims(2, 2))
+      ## New data requested below current data. Add rows below current data
+      rawarr = [rawarr ; cell(obj_dims.br - lims(2, 2), onc)];
+      lims (2, 2) = obj_dims.br;
+    endif
+    ## Update number of rawarr rows
+    onr = size (rawarr, 1);
+    if (obj_dims.lc < lims(1, 1))
+      ## New data requested to left of curremnt data; prepend columns
+      rawarr = [cell(onr, lims(1, 1) - obj_dims.lc), rawarr];
+      lims(1, 1) = obj_dims.lc;
+    endif
+    if (obj_dims.rc > lims(1, 2))
+      ## New data to right of current data; append columns
+      rawarr = [rawarr, cell(onr, obj_dims.rc - lims(1, 2))];
+      lims(1, 2) = obj_dims.rc;
+    endif
+    ## Update number of columns
+    onc = size (rawarr, 2);
+
+    ## Copy new data into place
+    objtr = obj_dims.tr - lims(2, 1) + 1;
+    objbr = obj_dims.br - lims(2, 1) + 1;
+    objlc = obj_dims.lc - lims(1, 1) + 1;
+    objrc = obj_dims.rc - lims(1, 1) + 1;
+    rawarr(objtr:objbr, objlc:objrc) = obj; 
+
+  else
+    ## New sheet
+    lims = [obj_dims.lc, obj_dims.rc; obj_dims.tr, obj_dims.br];
+    onc = obj_dims.nc;
+    onr = obj_dims.nr;
+    rawarr = obj;
+  endif
+
+
+endfunction
diff --git a/inst/private/__OCT_oct2ods__.m b/inst/private/__OCT_oct2ods__.m
new file mode 100644
index 0000000..5661c3a
--- /dev/null
+++ b/inst/private/__OCT_oct2ods__.m
@@ -0,0 +1,292 @@
+## Copyright (C) 2014 Philip Nienhuis
+## 
+## This program is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+## 
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+## 
+## You should have received a copy of the GNU General Public License
+## along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*- 
+## @deftypefn {Function File} {@var{ods}, @var{status} =} __OCT_oct2ods__ (@var{obj}, @var{ods}, @var{wsh}, @var{crange}, @var{spsh_opts})
+## Internal function for writing to ODS sheet
+##
+## @seealso{}
+## @end deftypefn
+
+## Author: Philip Nienhuis <prnienhuis at users.sf.net>
+## Created: 2014-01-18
+## Updates:
+## 2014-01-23 Fix writing repeated empty cells
+##     ''     Added writing deafult style names in document
+## 2014-01-24 Integrated empty left columns with empty left vals in rawarr
+##     ''     Same for empty upper rows & empty upper data rows
+##     ''     Fix temp file name
+## 2014-01-29 Move stuff common for all file types to caller or merge function
+
+function [ ods, status ] = __OCT_oct2ods__ (obj, ods, wsh, crange, spsh_opts=0, obj_dims)
+
+  ## Find out if we write to existing or new sheet
+  new_sh = 0;
+  if (isnumeric (wsh))
+    if (wsh < 1)
+      error ("ods2oct: sheet number (%d) should be > 0", wsh);
+    elseif (wsh > numel (ods.sheets.sh_names))
+      ## New sheet
+      ods.sheets.sh_names(wsh) = sprintf ("Sheet%d", wsh);
+      new_sh = 1; 
+      wsh = numel (ods.sheets.sh_names) + 1;
+    endif
+  elseif (ischar (wsh))
+    idx = strmatch (wsh, ods.sheets.sh_names);
+    if (isempty (idx))
+      ## New sheet
+      ods.sheets.sh_names(end+1) = wsh;
+      new_sh = 1;
+      idx = numel (ods.sheets.sh_names);
+    endif
+    wsh = idx;
+  endif
+  ## Check if we made a new file from template
+  if (strcmpi (ods.sheets.sh_names{1}, " ") && numel (ods.sheets.sh_names) == 2 && new_sh)
+    ods.sheets.sh_names(1) = [];
+    new_sh = 0;
+    wsh--;
+    ods.changed = 2;
+  endif
+
+  if (new_sh)
+    wsh = numel (ods.sheets.sh_names);
+    idx_s = ods.sheets.shtidx(wsh) ;               ## First position after last sheet
+    idx_e = idx_s - 1;
+    rawarr = {};
+    lims = [];
+  else
+    idx_s = ods.sheets.shtidx(wsh);
+    idx_e = ods.sheets.shtidx(wsh+1) - 1;
+    ## Get all data in sheet and row/column limits
+    [rawarr, ods]  = __OCT_ods2oct__ (ods, wsh, "", struct ("formulas_as_text", 1));
+    lims = ods.limits;
+  endif
+  
+  ## Merge old and new data. Provisionally allow empty new data to wipe old data
+  [rawarr, lims, onr, onc] = __OCT_merge_data__ (rawarr, lims, obj, obj_dims);
+
+  ## D. Get default table/row/column styles
+  ##    Open file content.xml
+  fids = fopen (sprintf ("%s/content.xml", ods.workbook), "r");
+  ## Get first part, til first sheet
+  contnt = fread (fids, ods.sheets.shtidx(1)-1, "char=>char").';
+  fclose (fids);
+  ## Get default styles stuff
+  contnt = getxmlnode (contnt, "office:automatic-styles");
+  is = 1; 
+  stylenode = " ";                                ## Any non-empty value
+  ## Usual default style names
+  styles = struct ("tbl", "ta1", "row", "ro1", "col", "co1");
+  ## Get actual default styles
+  while (! isempty (stylenode))
+    [stylenode, ~, is] = getxmlnode (contnt, "style:style", is, 1);
+    stylefam = getxmlattv (stylenode, "style:family");
+    if     (strcmpi (stylefam, "table-column"))
+      style.col = stylefam;
+    elseif (strcmpi (stylefam, "table"))
+      styles.tbl = stylefam;
+    elseif (strcmpi (stylefam, "table-row"))
+      styles.row = stylefam;
+    endif
+  endwhile
+
+  ## E. Create a temporary file to hold the new sheet xml
+  ## Open sheet file (new or old)
+  tmpfil = tmpnam;
+  fid = fopen (tmpfil, "w+");
+  if (fid < 0)
+    error ("oct2ods: unable to write to file %s", tmpfil);
+  endif
+
+  ## Write data to sheet (actually table:table section in content.xml)
+  status  = __OCT__oct2ods_sh__ (fid, rawarr, wsh, lims, onc, onr, ...
+            ods.sheets.sh_names{wsh}, styles);
+
+  ## F. Merge new/updated sheet into content.xml
+  ## Read first chunk of content.xml until sht_idx<xx>
+  fidc = fopen (sprintf ("%s/content.xml", ods.workbook), "r+");
+  ## Go to start of requested sheet
+  fseek (fidc, 0, 'bof');
+
+  ## Read and concatenate just adapted/created sheet/table:table
+  content_xml = fread (fidc, idx_s - 1, "char=>char").';
+  ## Rewind sheet and read it behind content_xml
+  fseek (fid, 0, "bof");
+  sheet = fread (fid, Inf, "char=>char").';
+  lsheet = length (sheet);
+  ## Close & delete sheet file
+  fclose (fid);
+  delete (tmpfil);
+  content_xml = [ content_xml  sheet] ;
+
+  ## Read rest of content.xml, optionally delete overwritten sheet/table:table
+  fseek (fidc, idx_e, 'bof');
+  content_xml = [ content_xml  fread(fidc, Inf, "char=>char").' ];
+  ## Write updated content.xml back to disk.
+  fseek (fidc, 0, 'bof');
+  fprintf (fidc, "%s", content_xml);
+  fclose (fidc);
+
+  ## F. Update sheet pointers in ods file pointer
+  if (new_sh)
+    ods.sheets.shtidx(wsh+1) = idx_s + lsheet;
+    ods.changed = 2;
+  else
+    offset = lsheet - (idx_e - idx_s) - 1;
+    ods.sheets.shtidx(wsh+1 : end) += offset;
+  endif
+  ods.changed = max (ods.changed, 1);
+
+  ## FIXME: Perhaps we'd need to update the metadata in meta.xml
+
+endfunction
+
+
+## ===========================================================================
+function [ status ] = __OCT__oct2ods_sh__ (fid, rawarr, wsh, lims, onc, onr, tname, styles)
+
+  ## Write out the lot to requested sheet
+
+  ## 1. Sheet open tag
+  fprintf (fid, '<table:table table:name="%s" table:style-name="%s">', tname, styles.tbl);
+
+  ## 2. Default column styles. If required add columns repeated tag
+  if (lims(1, 2) > 1)
+    tncr = sprintf (' table:number-columns-repeated="%d"', lims(1, 2));
+  else
+    tncr = "";
+  endif
+  fprintf (fid, '<table:table-column table-style-name="%s"%s table:default-cell-style-name="Default" />', ...
+          styles.col, tncr);
+
+  ## 3. Spreadsheet rows
+  ii = 1;
+  while (ii <= onr)
+    ## 3.1 Check for empty rows
+    if (ii == 1)
+      tnrr = lims(2, 1) - 1;
+    else
+      tnrr = 0;
+    endif
+    ## Check for consecutive empty rows
+    while (ii <= onr && all (cellfun ("isempty", rawarr(ii, :))))
+      ++tnrr;
+      ++ii;
+    endwhile
+    if (tnrr > 1)
+      tnrrt = sprintf (' table:number-rows-repeated="%d"', tnrr);
+    else
+      tnrrt = "";
+    endif
+    if (tnrr)
+      ## Write empty row, optionally with row repeat tag
+      if (lims (1, 2) > 1)
+        ## Add number of empty columns repeat tag
+        tcell = sprintf ('<table:table-cell table:number-columns-repeated="%d" />', ...
+                        lims(1, 2));
+      endif
+      fprintf (fid, '<table:table-row%s>%s</table:table-row>', tnrrt, tcell);
+    endif
+    if (ii <= onr)
+      ## Write table row opening tag
+      fprintf (fid, '<table:table-row table:style-name="%s">', styles.row);
+
+      ## 3.2 Value cells
+      jj = 1;
+      while (jj <= onc)
+        ## 3.2.1 Check if empty. Include empty columns left of rawarr
+        if (jj == 1)
+          tncr = lims(1, 1) - 1;
+        else
+          tncr = 0;
+        endif
+        ## Check consecutive empty cells & adapt ncr attr, write empty cells
+        while (jj <= onc && isempty (rawarr{ii, jj}))
+          ++tncr;
+          ++jj;
+        endwhile
+        if (tncr > 1)
+          fprintf (fid, '<table:table-cell table:number-columns-repeated="%d" />', tncr);
+        elseif (tncr == 1)
+          fprintf (fid, '<table:table-cell />');
+        endif
+        ## Process non-empty data cells
+        if (jj <= onc)
+          ## 3.2.2 Non-empty cell. Determine value type. Set formula attr = empty
+          of = "";
+          switch class (rawarr{ii, jj})
+            case {"double", "single"}
+              ovt = ' office:value-type="float"';
+              val = sprintf ("%.4f", rawarr{ii, jj});
+              txt = sprintf ('<text:p>%s</text:p>', val);
+              ## Convert to attribute
+              val = sprintf (' office:value="%.10f"', rawarr{ii, jj});
+            case {"int64", "int32", "int16", "int8", "uint64", "uint32", "uint16", "uint8"}
+              ovt = ' office:value-type="integer"';
+              val = strtrim (sprintf ("%d15", rawarr{ii, jj}));
+              txt = sprintf ('<text:p>%s</text:p>', val);
+              ## Convert to attribute
+              val = sprintf (' office:value="%s"', val);
+            case "logical"
+              ovt = ' office:value-type="boolean"';
+              val = "false";
+              if (rawarr{ii, jj})
+                val = "true";
+              endif
+              txt = sprintf ('<text:p>%s</text:p>', upper (val));
+              ## Convert to attribute
+              val = sprintf (' office:boolean-value="%s"', val);
+            case "char"
+              if (rawarr{ii, jj}(1) == "=")
+                ## We guess a formula. Prepare formula attribute
+                ovt = "";
+                txt = "";
+                val = "";
+                of = sprintf (' table:formula="of:%s"', rawarr{ii, jj});
+                ## FIXME We'd need to parse cell types in formula = may be formulas as well
+                ## We cannot know, or parse, the resulting cell type, omit type info & text
+              else
+                ## Plain text
+                ovt = ' office:value-type="string"';
+                val = rawarr{ii, jj};
+                txt = sprintf ('<text:p>%s</text:p>', val);
+                ## Convert to attribute
+                val = sprintf (' office:string-value="%s"', val);
+              endif
+            otherwise
+              ## Unknown, illegal or otherwise unrecognized value
+              ovt = "";
+              val = "";
+              txt = "";
+          endswitch
+          # write out table-cell w office-value-type / office:value
+          fprintf (fid, '<table:table-cell%s%s%s>%s</table:table-cell>',
+                   of, ovt, val, txt);
+        endif
+        ++jj;
+      endwhile
+      ## Write table row closing tag
+      fprintf (fid, '</table:table-row>');
+    endif
+    ++ii;
+  endwhile
+
+  ## 4. Closing tag
+  fprintf (fid, '</table:table>');
+
+  status = 1;
+
+endfunction
diff --git a/inst/private/__OCT_oct2spsh__.m b/inst/private/__OCT_oct2spsh__.m
new file mode 100644
index 0000000..5930d33
--- /dev/null
+++ b/inst/private/__OCT_oct2spsh__.m
@@ -0,0 +1,75 @@
+## Copyright (C) 2014 Philip Nienhuis
+## 
+## This program is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+## 
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+## 
+## You should have received a copy of the GNU General Public License
+## along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*- 
+## @deftypefn {Function File} {@var{retval} =} __OCT_oct2spsh__ (@var{input1}, @var{input2})
+##
+## @seealso{}
+## @end deftypefn
+
+## Author: Philip Nienhuis <prnienhuiS at users dot sf dot net>
+## Created: 2014-01-24
+
+function [ ods, rstatus ] = __OCT_oct2spsh__ (obj, ods, wsh, crange, spsh_opts)
+
+  ## Analyze data and requested range. Get size of data to write
+  [nnr, nnc ] = size (obj);
+
+  ## Parse requested cell range
+  [~, nr, nc, tr, lc] = parse_sp_range (crange);
+
+  ## First check row size
+  if (nnr > nr)
+    ## Truncate obj
+    obj = obj(1:nr, :);
+  elseif (nnr < nr)
+    ## Truncate requested range
+    nr = nnr;
+  endif
+  ## Next, column size
+  if (nnc > nc)
+    ## Truncate obj
+    obj = obj(:, 1:nc);
+  elseif (nnc < nc)
+    ## Truncate requested range
+    nc = nnc;
+  endif
+
+  obj_dims.tr = tr;
+  obj_dims.br = tr + nr - 1;
+  obj_dims.nr = nr;
+  obj_dims.lc = lc;
+  obj_dims.rc = lc + nc - 1;
+  obj_dims.nc = nc;
+
+  ## Invoke file type-dependent functions
+  if (strcmpi (ods.app, "ods"))
+    ## Write to .ods
+    [ ods, rstatus ] = __OCT_oct2ods__  (obj, ods, wsh, crange, spsh_opts, obj_dims);
+
+  elseif (strcmpi (ods.app, "xlsx"))
+    ## Write to .xlsx
+    [ ods, rstatus ] = __OCT_oct2xlsx__ (obj, ods, wsh, crange, spsh_opts, obj_dims);
+
+  elseif (strcmpi (ods.app, "gnumeric"))
+    ## Write to .gnumeric
+    [ ods, rstatus ] = __OCT_oct2gnm__  (obj, ods, wsh, crange, spsh_opts, obj_dims);
+
+  else
+    error ("writing to file type %s not supported by OCT", xls.app);
+
+  endif
+
+endfunction
diff --git a/inst/private/__OCT_oct2xlsx__.m b/inst/private/__OCT_oct2xlsx__.m
new file mode 100644
index 0000000..1a7c0cd
--- /dev/null
+++ b/inst/private/__OCT_oct2xlsx__.m
@@ -0,0 +1,514 @@
+## Copyright (C) 2013,2014 Markus Bergholz
+## Parts Copyright (C) 2014 Philip Nienhuis
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 3 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, see <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## xlsxwrite function pure written in octave - no dependencies are needed.
+## tested with MS Excel 2010, Gnumeric, LibreOffice 4.x
+##
+## usage:
+##	__OCT_oct2xlsx__(filename, matrix, wsh, range, spsh_opts)
+##
+##	matrix: have to be a 2D cell array. NaN will be an empty cell in Excel.
+##
+##	wsh: can be a 1, 2 or 3 for indexing the worksheet. >3 is not supported yet!
+##	wsh: can be string for naming the worksheet. the string has a limit length of 31!
+##	wsh can be a cell for defining worksheet index and name at the same time. e.g. {2,'Made by Octave'}
+##	xlswrite('default.xlsx',m) % default written to Table 1, named "Table1"
+##	xlswrite('filename.xlsx',m,3) % written to Table 3, named "Table3"
+##	xlswrite('another.xlsx',k,'string named') % written to Table 1, named "string named"
+##	xlswrite('impressive.xlsx',data,{'my data',2}) % written to Table 2, named "my data"
+##	xlswrite('impressive.xlsx',datay,{3, 'my other data'}) % written to Table 3, named "my other data"
+##	xlswrite('next.xlsx',data,{'my data',2},'B2') % values will start at B2 (temporary broken!)
+##
+##	octave:85> m=rand(100,100);
+##	octave:86> tic, xlsxwrite('test20.xlsx',m); toc
+##	Elapsed time is 3.1919641494751 seconds.
+##
+##	octave:97> m=rand(1234,702);
+##	octave:98> tic, xlsxwrite('interesting.xlsx',m); toc
+##	Elapsed time is 253.35110616684 seconds.
+## @end deftypefn
+
+## Author: Markus Bergholz <markuman at gmail.com>
+## Amended by Philip Nienhuis <prnienhuis at users.sf.net>
+## ToDo
+## - use english language as default (atm it's all german. "Tabelle1" instead of "Table1").
+## - fix write to defined range (rows still starts a row 1)
+## - write more than 3 worksheets
+## - date and boolean type
+## - write cell (numeric and string mixed)
+## - open/add/edit/manipulate an existing xlsx file
+## - improve mex file
+
+## ChangeLog
+## 2014/01/24		- include to io package
+##			        - add write to defined range/position (offset). Works for colums, not for rows!
+## 2014/01/20		- remove 702 column limit
+##           		- write mex file to bypass the bottleneck (still exists because mex file calls a script file! now ~230sec for 1000x1000 matrix. before ~410sec)
+## 2014/01/17		- include __OCT_cc__ instead of __number_to_alphabetic
+##           		- fix/improve zip behavior
+## 2013/11/23		- prepare xlswrite for handling existing files
+##           		- take care for excel limitations (maybe tbc)
+## 2013/11/17		- user can write to another worksheet. limited to index 1, 2 or 3 atm
+##           		- user can name the worksheets by string. automatically written to sheetid 1.
+##           		- user can define name+index at the same time {2,'wsh name'} e.g.
+## 2013/11/16		- relationshiptypes validation fix
+## Version 0.1
+## 2013/11/08		- Initial Release
+
+function [xls, rstatus] = __OCT_oct2xlsx__ (arrdat, xls, wsh=1, crange="", spsh_opts, obj_dims)
+
+  ## Analyze worksheet parameter & determine if new sheet is required
+  new_sh = 0;
+  if (ischar (wsh))
+    if (31 < length (wsh))
+      error ("Worksheet name longer than 31 characters is not supported by Excel");
+    endif
+    wsh_number = strmatch (wsh, xls.sheets.sh_names);
+    if (isempty (wsh_number))
+      ## Worksheet not in stack. We'll create a new one
+      new_sh = 1;
+      wsh_number = numel (xls.sheets.sh_names) + 1;
+      if (xls.changed == 3)
+        wsh_number--;
+      endif
+      xls.sheets.sh_names(end+1) = wsh;
+    endif
+    wsh_string = wsh;
+
+  elseif (isnumeric (wsh))
+    if (wsh > numel (xls.sheets.sh_names))
+      ## New worksheet
+      new_sh = 1;
+      ## Default sheet name
+      wsh_string = sprintf ("Sheet%d", wsh);
+      ## It may already exist...
+      while (! isempty (strmatch (wsh_string, xls.sheets.sh_names)) && length (wsh_string <= 31))
+        wsh_string = strrep (wsh_string, "Sheet", "Sheet_");
+      endwhile
+      if (length (string) > 31)
+        error ("oct2xls: cannot add worksheet with a unique name");
+      endif
+      ## The sheet index number can't leave a gap in the stack, so:
+      wsh_number = numel (xls.sheets.sh_names) + 1;
+      xls.sheets.sh_names(end+1) = wsh_string;
+    else
+      wsh_number = wsh;
+    endif
+  endif
+
+  if (spsh_opts.formulas_as_text == 0)
+    ## Provisionally only read/write strings, not formulas
+    ## FIXME actually a formula evaluator is required to process formulas
+    spsh_opts.formulas_as_text = 1;
+  endif
+
+  if (new_sh)
+    rawarr = {};
+    lims = [];
+  else
+    ## Get all data in sheet and row/column limits
+    [rawarr, xls]  = __OCT_xlsx2oct__ (xls, wsh, "", spsh_opts);
+    lims = xls.limits;
+  endif
+  
+  ## Merge old and new data. Provisionally allow empty new data to wipe old data
+  [rawarr, lims, onr, onc] = __OCT_merge_data__ (rawarr, lims, arrdat, obj_dims, spsh_opts);
+
+## FIXME - contains stuff that won't work with existing sheets
+##         (though I like the idea PRN)
+%## something cool, that matlab doesn't support
+%# xlswrite('myfile.xlsx',arrdat,{'1','Sheetname'})
+%if (iscell (wsh))
+%  # check size
+%  if (1 ~= rows (wsh) || 2 ~= columns (wsh))
+%    error ("Too many input arguments for wsh");
+%  endif
+%  # check first argument
+%  if (1 == ischar (wsh{1,1}))
+%    if (31 < length (wsh{1,1}))
+%      error ("Worksheet name longer than 31 characters is not supported by Excel");
+%    endif
+%    wsh_string=wsh{1,1};
+%  elseif (isnumeric (wsh{1,1}))
+%    if (1 ~= ismember (wsh{1,1} ,1:3))
+%      error ("wsh index must be 1, 2 or 3");
+%    endif
+%    wsh_number = wsh{1,1};
+%  else
+%    error ("wsh should contain one numeric value (for indexing) and one string (for naming)");
+%  endif
+%  
+%  # check second argument
+%  if (ischar (wsh{1,2}))
+%    if (31 < length(wsh{1,2}))
+%      error ("Worksheet name longer than 31 characters is not supported by Excel");
+%    endif 
+%    wsh_string = wsh{1,2};
+%  elseif (isnumeric (wsh{1,2}))
+%    if (! ismember (wsh{1,2} ,1:3))
+%      error ("wsh index must be 1, 2 or 3");
+%    endif
+%    wsh_number = wsh{1,2};
+%  else
+%    error ("wsh should contain one numeric value (for indexing) and one string (for naming)");
+%  endif
+%endif
+
+## What needs to be done:
+## - Find out worksheet number (easy, wsh_number)
+## - Write data to <temp>/xl/worksheets/sheet<wsh_number>.xml
+##   * For each string, check (persistent var) if sharedStrings.xml exists
+##     > If not, create it.
+##   * For each string check if it is in <temp>/sharedStrings.xml
+##     > if YES, put pointer in new worksheet
+##     > if NO, add node in sharedStrings.xml and pointer in new worksheet
+## - If needed (new file) update <temp>/workbook.xml w. sheet name & sheetId higher than any existing sheetId
+## - Update workbook_rels.xml
+
+  ## Write data to worksheet file
+  [xls, status]  = __OCT_oct2xlsx_sh__ (xls, wsh_number, rawarr, lims, onc, onr, spsh_opts);
+
+  ## Update worksheet bookkeeping
+  if (new_sh)                          ## !!!!! FIXME To be tested !!!!!!
+    ## Read xl/_rels/workbook.xml.rels
+    rid = fopen ([xls.workbook filesep "xl" filesep "_rels" filesep "workbook.xml.rels"], "r+");
+    rxml = fread (rid, Inf, "char=>char").';
+    fclose (rid);
+    ## Add worksheet entry. First find unique rId
+    rId = str2double (cell2mat (regexp (rxml, 'Id="rId(\d+)"', "tokens")));
+    ## Assess rId (needed in [Content_Types].xml, below)
+    nwrId = sort (rId)(end) + 1;
+
+    ## <workbook.xml>
+    wid = fopen ([xls.workbook filesep "xl" filesep "workbook.xml"], "r+");
+    wxml = fread (wid, Inf, "char=>char").';
+    fclose (wid);
+    [sheets, is, ie] = getxmlnode (wxml, "sheets");
+    sheetids = str2double (cell2mat (regexp (sheets, ' sheetId="(\d+?)"', "tokens")));
+    if (xls.changed == 3)
+      ## No new sheet, just update Sheet1 name
+      shnum = 1;
+      sheets = strrep (sheets, 'name="Sheet1"', ['name="' wsh_string '"']);
+    else
+      shnum = max(sheetids)+1;
+      wshtag = sprintf ('<sheet name="%s" sheetId="%d" r:id="rId%d" />', ...
+                        wsh_string, shnum, nwrId);
+      sheets = strrep (sheets, "/></sheets>", ["/>" wshtag "</sheets>"]);
+    endif
+    ## Re(/over-)write workbook.xml; start at sheets node
+    wid = fopen ([xls.workbook filesep "xl" filesep "workbook.xml"], "w+");
+    fprintf (wid, "%s", wxml(1:is-1));
+    fprintf (wid, "%s", sheets);
+    fprintf (wid, "%s", wxml(ie+1:end));
+    fclose (wid);
+
+    ## Write xl/_rels/workbook.xml.rels. Only needed for existing files/new sheets
+    if (xls.changed != 3)
+      ## workbook.xml.rels
+      entry = sprintf ('<Relationship Id="rId%d" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet%d.xml"/>', nwrId, shnum);
+      rxml = strrep (rxml, "/></Relationships>", ["/>" entry "</Relationships>"]);
+      rid = fopen ([xls.workbook filesep "xl" filesep "_rels" filesep "workbook.xml.rels"], "w");
+      fprintf (rid, "%s", rxml);
+      fclose (rid);
+      ## [Content_Types].xml. Insert worksheet #n entry
+      tid = fopen ([xls.workbook filesep "[Content_Types].xml"], "r+");
+      txml = fread (tid, Inf, "char=>char").';
+      fclose (tid);
+      partname = ['<Override PartName="/xl/worksheets/sheet%d.xml" ' ...
+                  'ContentType="application/vnd.openxmlformats-' ...
+                  'officedocument.spreadsheetml.worksheet+xml"/>' ];
+      partname = sprintf (partname, nwrId);
+      srchstr = 'worksheet+xml"/>';
+      ipos = strfind (txml, srchstr)(end) + length (srchstr);
+      tid = fopen ([xls.workbook filesep "[Content_Types].xml"], "w");
+      fprintf (tid, "%s", txml(1:ipos-1));
+      fprintf (tid, partname);
+      fprintf (tid, txml(ipos:end));
+      fclose (tid);
+    endif
+
+    ## <docProps/app.xml>
+    aid = fopen ([xls.workbook filesep "docProps" filesep "app.xml"], "r+");
+    axml = fread (wid, Inf, "char=>char").';
+    fclose (aid);
+    wshnode = sprintf ('<vt:lpstr>%s</vt:lpstr>', wsh_string);
+    if (xls.changed == 3)
+      [vt, is, ie] = getxmlnode (axml, "TitlesOfParts");
+      ## Just replace Sheet1 entry by new name
+      vt = strrep (vt, '>Sheet1<', ['>' wsh_string '<']);
+    else
+      ## 1. Update HeadingPairs node
+      [vt1, is, ie] = getxmlnode (axml, "HeadingPairs");
+      ## Bump number of entries
+      nshts = str2double (getxmlnode (vt1, "vt:i4", [], 1)) + 1;
+      vt1 = regexprep (vt1, '<vt:i4>(\d+)</vt:i4>', ["<vt:i4>" sprintf("%d", nshts) "</vt:i4>"]);
+      ## 2. Update TitlesOfParts node
+      [vt2, ~, ie] = getxmlnode (axml, "TitlesOfParts", ie);
+      ## Bump number of entries
+      nshts = str2double (getxmlattv (vt2, "size")) + 1;
+      vt2 = regexprep (vt2, 'size="(\d+)"', ['size="' sprintf("%d", nshts) '"']);
+      ## Add new worksheet entry
+      vt2 = strrep (vt2, "</vt:lpstr></vt:vector>", ["</vt:lpstr>" wshnode "</vt:vector>"]);
+      vt = [vt1 vt2];
+    endif
+    ## Re(/over-)write workbook.xml; start at sheets node
+    aid = fopen ([xls.workbook filesep "docProps" filesep "app.xml"], "w+");
+    fprintf (wid, "%s", axml(1:is-1));
+    fprintf (wid, "%s", vt);
+    fprintf (wid, "%s", axml(ie+1:end));
+    fclose (wid);
+  endif
+
+  ## If needed update sharedStrings entries xml descriptor files
+  if (status > 1)
+    ##  workbook_rels.xml
+    rid = fopen ([xls.workbook filesep "xl" filesep "_rels" filesep "workbook.xml.rels"], "r+");
+    rxml = fread (rid, Inf, "char=>char").';
+    fclose (rid);
+    if (isempty (strmatch ("sharedStrings", rxml)))
+      ## Add sharedStrings.xml entry. First find unique rId
+      rId = str2double (cell2mat (regexp (rxml, 'Id="rId(\d+)"', "tokens")));
+      nwrId = sort (rId)(end) + 1;
+      entry = sprintf ('<Relationship Id="rId%d" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings" Target="sharedStrings.xml"/>', nwrId);
+      rxml = strrep (rxml, "/></Relationships>", ["/>" entry "</Relationships>"]);
+      rid = fopen ([xls.workbook filesep "xl" filesep "_rels" filesep "workbook.xml.rels"], "w");
+      fprintf (rid, "%s", rxml);
+      fclose (rid);
+    endif
+
+    ## [Content_Types].xml
+    tid = fopen ([xls.workbook filesep "[Content_Types].xml"], "r+");
+    txml = fread (tid, Inf, "char=>char").';
+    fclose (tid);
+    if (isempty (strmatch ("sharedStrings", txml)))
+      ## Add sharedStrings.xml entry after styles.xml node. First find that one
+      [~, ~, ipos] = regexp (txml, '(?:styles\+xml)(?:.+)(><Over)', 'once');
+      ipos = ipos(1);
+      txml = [txml(1:ipos) '<Override PartName="/xl/sharedStrings.xml" '  ...
+                           'ContentType="application/vnd.openxmlformats-' ...
+                           'officedocument.spreadsheetml.sharedStrings+xml" />' ...
+                           txml(ipos+1:end)];
+      tid = fopen ([xls.workbook filesep "[Content_Types].xml"], "w");
+      fprintf (tid, "%s", txml);
+      fclose (tid);
+    endif
+    
+  endif
+
+  ## - /docProps/core.xml (user/modifier info & date/time)
+  cid = fopen ([xls.workbook filesep "docProps" filesep "core.xml"], "r+");
+  cxml = fread (cid, Inf, "char=>char").';
+  fclose (cid);
+  cxml = regexprep (cxml, 'dBy>(\w+)</cp:lastM', 'dBy>GNU Octave</cp:lastM');
+  modtime = datevec (now);
+  modtime = sprintf ("%4d-%2d-%2dT%2d:%2d:%2dZ", modtime(1), modtime(2), modtime(3), ...
+                                                 modtime(4), modtime(5), modtime(6));
+  modtime = strrep (modtime, " ", "0");
+  [modf, ia, ib] = getxmlnode (cxml, "dcterms:created", [], 1);
+  cxml(ia:ib) = strrep (cxml(ia:ib), modf, modtime);
+  [modf, ia, ib] = getxmlnode (cxml, "dcterms:modified", [], 1);
+  cxml(ia:ib) = strrep (cxml(ia:ib), modf, modtime);
+  cid = fopen ([xls.workbook filesep "docProps" filesep "core.xml"], "w+");
+  fprintf (cid, "%s", cxml);
+  fclose (cid);
+
+  ## Update status
+  xls.changed = max (xls.changed-1, 1);
+  rstatus = 1;
+
+endfunction
+
+
+function [ xls, rstatus ] = __OCT_oct2xlsx_sh__ (xls, wsh_number, arrdat, lims, onc, onr, spsh_opts)
+
+  ## Open sheet file (new or old), will be overwritten
+  fid = fopen ([xls.workbook filesep "xl" filesep "worksheets" filesep ...
+                sprintf("sheet%d.xml", wsh_number)], "r+");
+  if (fid < 0)
+    ## Apparently a new sheet. Fill in default xml contents
+    xml = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>';
+    xml = [ xml "\n" ];
+    xml = [ xml '<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" ' ];
+    xml = [ xml 'xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" '];
+    xml = [ xml 'xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" '];
+    xml = [ xml 'mc:Ignorable="x14ac" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac">'];
+    xml = [ xml '<dimension ref="A1"/><sheetViews><sheetView workbookViewId="0"/></sheetViews>'];
+    xml = [ xml '<sheetFormatPr baseColWidth="10" defaultRowHeight="15" x14ac:dyDescent="0.25"/>'];
+    xml = [ xml '<sheetData/>'];
+    xml = [ xml '<pageMargins left="0.7" right="0.7" top="0.8" bottom="0.8" header="0.3" footer="0.3"/>'];
+    xml = [ xml '</worksheet>' ];
+  else
+    ## Read complete contents
+    xml = fread (fid, Inf, "char=>char").';
+    fclose (fid);
+  endif
+
+  ## Update "dimension" (=range) node
+  [dimnode, is1, ie1] = getxmlnode (xml, "dimension");
+  ## Compute new limits
+  rng = sprintf ("%s:%s", calccelladdress (lims(2, 1), lims(1, 1)), ...
+                          calccelladdress (lims(2, 2), lims(1, 2)));
+
+  ## Open sheet file (new or old) in reset mode, write first part of worksheet
+  fid = fopen ([xls.workbook filesep "xl" filesep "worksheets" filesep ...
+                sprintf("sheet%d.xml", wsh_number)], "w+");
+  fprintf (fid, "%s", xml(1:is1-1));
+  ## Write updated dimension node
+  fprintf (fid, '<dimension ref="%s" />', rng);
+
+  ## Get Sheetdata node
+  [shtdata, is2, ie2] = getxmlnode (xml, "sheetData");
+  ## Write second block of xml until start of sheetData
+  fprintf (fid, "%s", [xml(ie1+1:is2-1) "<sheetData>"]);
+
+  ## Explore data types in arrdat
+  typearr = spsh_prstype (arrdat, onr, onc, [1:5], spsh_opts);
+
+  if (all (typearr(:) == 1))        ## Numeric
+#   write arrdat to sheet%%WSH%%.xml
+#  __OOXML_turbowrite__(sprintf("%s/xl/worksheets/sheet%d.xml",tmpdir,wsh_number), arrdat);
+    for r=1:rows (arrdat)
+      fprintf (fid, '<row r="%d" spans="%d:%d" x14ac:dyDescent="0.25">', ...
+               r+lims(2, 1)-1, ...
+               lims(1, 1), lims(1, 2));
+      for c = 1:columns (arrdat)
+        if (0 == isnan (arrdat{r, c}))
+          fprintf (fid, sprintf ('<c r="%s%d"><v>%f</v></c>', ... 
+                   __OCT_cc__ (c+lims(1, 1)-1), r+lims(2, 1)-1, arrdat{r, c}));
+        endif
+      endfor
+      fprintf (fid, '</row>');
+    endfor
+
+  else
+    ## Heterogeneous array. Write cell nodes depending on content
+    strings = {};
+    str_cnt = uniq_str_cnt = 0;
+    ## Check if there are any strings
+    if (any (typearr(:) == 3))
+      ## Yep. Read sharedStrings.xml
+      try
+        sid = fopen (sprintf ("%s/xl/sharedStrings.xml", xls.workbook), "r+");
+        if (sid > 0)
+          ## File exists => there are already some strings in the sheet
+          shstr = fread (sid, "char=>char").';
+          fclose (sid);
+          ## Extract string values. May be much more than present in current sheet
+          strings = cell2mat (regexp (shstr, '<si><t(?:>(.*?)</t>|(.+?)/>)</si>', "tokens"));
+          ## Watch out for a rare corner case: just one empty string... (avoid [])
+          if (isempty (strings))
+            strings = {""};
+          endif
+          uniq_str_cnt = str2double (getxmlattv (shstr, "uniqueCount"));
+          ##uniq_str_cnt = numel (unique (strings));
+          ## Make shstr a mueric value
+          shstr = 1;
+        else
+          ## File didn't exist yet
+          shstr = 0;
+        endif
+      catch
+        ## No sharedStrings.xml; implies no "fixed" strings (computed strings can still be there)
+        strings = {};
+        str_cnt = uniq_str_cnt = 0;
+      end_try_catch
+    endif
+    ## Process data row by row
+    for ii=1:rows (arrdat)
+      ## Row node opening tag
+      fprintf (fid, '<row r="%d" spans="%d:%d">', ii+lims(2, 1)-1, lims(1, 1), lims(1, 2));
+      for jj=1:columns (arrdat)
+        ## Init required attributes. Note leading space
+        addr = sprintf (' r="%s"', calccelladdress (ii+lims(2, 1)-1, jj+lims(1, 1)-1));
+        ## Init optional atttributes
+        stag = ttag = form = "";     ## t: e = error, b = boolean, s/str = string
+        switch typearr(ii, jj)
+          case 1                    ## Numeric
+            ## t tag ("type") is omitted for numeric data
+            val = ["<v>" strtrim(sprintf ("%25.10f", arrdat{ii, jj})) "</v>"];
+          case 2                    ## Boolean
+            ttag = ' t="b"';
+            if (arrdat{ii, jj})
+              val = ["<v>1</v>"];
+            else
+              val = ["<v>0</v>"];
+            endif
+          case 3                    ## String
+            ttag = ' t="s"';
+            ## FIXME s value provisionally set to 0
+%%          stag = ' s="0"';
+            sptr = strmatch (arrdat{ii, jj}, strings, "exact");
+            if (isempty (sptr))
+              ## Add new string
+              strings = [strings arrdat{ii, jj}];
+              ++uniq_str_cnt;
+              ## New pointer into sharedStrings (0-based)
+              sptr = uniq_str_cnt;
+            endif
+            ## Val must be pointer (0-based) into sharedStrings.xml
+            val = sprintf ("<v>%d</v>", sptr - 1);
+            ++str_cnt;
+          case 4                    ## Formula
+            form = sprintf ("<f>%s</f>", arrdat{ii, jj}(2:end));
+            #val = "<v>?</v>";
+            val = " ";
+          otherwise                 ## (includes "case 5"
+            ## Empty value. Clear address
+            addr = '';
+        endswitch
+        ## Append node to file, include tags
+        if (! isempty (addr))
+          fprintf (fid, '<c%s%s%s>', addr, stag, ttag);
+          if (! isempty (val))
+            fprintf (fid, "%s%s", form, val);
+          endif
+          fprintf (fid, "</c>");
+        endif
+      endfor
+      fprintf (fid, '</row>');
+    endfor
+  endif
+
+  ## Closing tag
+  fprintf (fid, "</sheetData>");
+  ## Append rest of original xml to file and close it
+  fprintf (fid, "%s", xml(ie2+1:end));
+  fclose (fid);
+
+  ## Rewrite sharedStrings.xml, if required
+  if (any (typearr(:) == 3))
+    ## (Re-)write xl/sharedStrings.xml
+    sid = fopen (sprintf ("%s/xl/sharedStrings.xml", xls.workbook), "w+");
+    fprintf (sid, '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n');
+    fprintf (sid, '<sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="%d" uniqueCount="%d">', ...
+             str_cnt, uniq_str_cnt);
+    for ii=1:uniq_str_cnt
+      fprintf (sid, "<si><t>%s</t></si>", strings{ii});
+    endfor
+    fprintf (sid, "</sst>");
+    fclose (sid);
+    ## Check if new sharedStrings file entires are required
+    if (isnumeric (shstr) && (! shstr))
+      rstatus = 2;
+      return;
+    endif
+  endif
+
+  ## Return
+  rstatus = 1;
+
+endfunction
diff --git a/inst/private/__OCT_ods2oct__.m b/inst/private/__OCT_ods2oct__.m
index 1850187..da47f02 100644
--- a/inst/private/__OCT_ods2oct__.m
+++ b/inst/private/__OCT_ods2oct__.m
@@ -1,4 +1,4 @@
-## Copyright (C) 2013 Philip Nienhuis
+## Copyright (C) 2013,2014 Philip Nienhuis
 ## 
 ## This program is free software; you can redistribute it and/or modify
 ## it under the terms of the GNU General Public License as published by
@@ -40,6 +40,8 @@
 ## 2013-11-13 Fix table-row counter bug
 ##     ''     Pretty text output
 ## 2013-12-19 Work around OTK bug (doesn't write office:value-type for formula cells)
+## 2014-01-22 Copyright string update
+## 2014-01-23 Pretty formula output
 
 function [ rawarr, ods, rstatus] = __OCT_ods2oct__ (ods, wsh, cellrange='', spsh_opts)
 
@@ -82,7 +84,8 @@ function [ rawarr, ods, rstatus] = __OCT_ods2oct__ (ods, wsh, cellrange='', spsh
     if (firstrow == 0 && lastrow == 0)
       ## Empty sheet
       rawarr = {};
-      printf ("Worksheet '%s' contains no data\n", ods.sheets.sh_names{wsh});
+      ## printf ("Worksheet '%s' contains no data\n", ods.sheets.sh_names{wsh});
+      lims = [];
       rstatus = 1;
       return;
     else
@@ -194,6 +197,7 @@ function [ rawarr, ods, rstatus] = __OCT_ods2oct__ (ods, wsh, cellrange='', spsh
               ## Put proper translation into rawarr
               switch ctype
                 case "cformula"
+                  form = strrep (form, "of:", "");
                   form = strrep (form, """, '"');
                   form = strrep (form, "<", "<");
                   form = strrep (form, ">", ">");
diff --git a/inst/private/__OCT_spsh_close__.m b/inst/private/__OCT_spsh_close__.m
index 4c6fde3..cc44621 100644
--- a/inst/private/__OCT_spsh_close__.m
+++ b/inst/private/__OCT_spsh_close__.m
@@ -21,28 +21,59 @@
 ##
 ## @end deftypefn
 
-## Author: Philip Nenhuis <prnienhuis at users.sf.net>
+## Author: Philip Nenhuis <prnienhuis at users.sf.net>
 ## Created: 2013-09-09
 ## Updates:
 ## 2013-09-23 Added in commented-out stanza for OOXML (.xlsx)
-## 2013-10-20 OOXLM support
+## 2013-10-20 OOXML support
+## 2014-01-19 Write support for ODS
+## 2014-01-20 Catch zip errors; zip to proper (original) file name
+## 2014-01-22 Zip quietly; zip into current dir, not temp dir
+## 2014-01-24 Call confirm_recursive_subdir locally
+## 2014-01-28 Zip both .ods & xlsx, gzip .gnumeric
+##     ''     Reorganize code a bit
+## 2014-04-06 Fix filename arg in error msg
+##     ''     cd out of tmp dir before removing it
 
 function [xls] = __OCT_spsh_close__ (xls)
 
-  ## Below order is vital - shortest extension first as you can have file 'a.<ext>'
-  ## that'll crash if we have 't.ods' but first try the 'gnumeric' extension
-  if (strcmpi (xls.filename(end-3:end), ".ods"))
-    ## Delete tmp file
-    rmdir (xls.workbook, "s");
+  ## Check extension and full path to file
+  [pth, fname, ext] = fileparts (xls.filename);
+  opwd = pwd;
+  if (isempty (pth))
+    filename = [ opwd filesep xls.filename ];
+  else
+    filename = xls.filename;
+  endif
+
+  ## .ods and.xlsx are both zipped
+  if (strcmpi (ext, ".ods") || strcmpi (ext, ".xlsx"))
+    if (xls.changed && xls.changed < 3)
+      ## Go to temp dir where ods file has been unzipped
+      cd (xls.workbook);
+      ## Zip tmp directory into .ods or .xlsx and copy it over original file
+      try
+        system (sprintf ("zip -q -r %s *.* .", filename));
+        xls.changed = 0;
+      catch
+        printf ("odsclose: could not zip ods contents in %s to %s\n", xls.workbook, filename);
+      end_try_catch;
+    endif
 
-  elseif (strcmpi (xls.filename(end-4:end-1), ".xls"))
-    ## For OOXML remove temp dir here
-    rmdir (xls.workbook, "s");
-
-  elseif (strcmpi (xls.filename(end-8:end), ".gnumeric"))
+  elseif (strcmpi (xls.filename(end-8:end), ".gnumeric"))
+    ## gnumeric files are gzipped
     ## Delete temporary file
     unlink (xls.workbook);
 
   endif
+
+  ## Delete tmp file and return to work dir
+  cd (opwd);
+  if (! xls.changed)
+    ## Below is needed for a silent delete of our tmpdir
+    confirm_recursive_rmdir (0, "local");
+    rmdir (xls.workbook, "s");
+  endif
+
 
 endfunction
diff --git a/inst/private/__OCT_spsh_open__.m b/inst/private/__OCT_spsh_open__.m
index 880980e..5022d56 100644
--- a/inst/private/__OCT_spsh_open__.m
+++ b/inst/private/__OCT_spsh_open__.m
@@ -1,4 +1,4 @@
-## Copyright (C) 2013 Philip Nienhuis
+## Copyright (C) 2013,2014 Philip Nienhuis
 ## Copyright (C) 2013 Markus Bergholz (.xlsx & archive unzip stuff)
 ## 
 ## This program is free software; you can redistribute it and/or modify
@@ -37,7 +37,14 @@
 ## 2013-12-14 Fix sheet names parsing regexpr # 2 (attrib order can change =>
 ##            that's why an XML parser is superior over regular expressions)
 ## 2013-12-27 Use one variable for processed file type
-##     ''     Shuffled code around to file type order
+##     ''     Shuffled code around to file type order
+## 2014-01-22 Open new files from template directory in io script directory
+## 2014-01-23 Move confirm_recursive_rmdir to __OCT_spsh_close__.m
+## 2014-01-29 Support for xlsx and gnumeric
+## 2014-02-08 Fix wrong function name in error msg (couldn't be unzipped)
+## 2014-03-17 Simplify sheet names discovery
+##     ''     Ignore SheetId (nowhere used)
+## 2014-03-18 Reinstate SheetId (was used somewhere after all)
 
 function [ xls, xlssupport, lastintf] = __OCT_spsh_open__ (xls, xwrite, filename, xlssupport, ftype)
 
@@ -45,22 +52,35 @@ function [ xls, xlssupport, lastintf] = __OCT_spsh_open__ (xls, xwrite, filename
   ## create current work folder
   tmpdir = tmpnam;
 
+  ## Get template if a new file is created
+  if (xwrite == 3)
+    if (ftype == 2)
+      ext = ".xlsx";
+    elseif (ftype == 3)
+      ext = ".ods";
+    elseif (ftype == 5)
+      ext = ".gnumeric";
+    endif
+    ## New file, get it from template
+    templ = strrep (which ("odsopen"), "odsopen.m", ["templates" filesep "template" ext]);
+  else
+    templ = filename;
+  endif
+
   if (ftype == 5)
     ## Gnumeric xml files are gzipped
-    system (sprintf ("gzip -d -c -S=gnumeric %s > %s", filename, tmpdir));
+    system (sprintf ("gzip -d -c -S=gnumeric %s > %s", templ, tmpdir));
     fid = fopen (tmpdir, 'r');
     xml = fread (fid, "char=>char").';
   else
-    ## xlsx and ods are zipped
-    ## Below is needed for a silent delete of our tmpdir
-    confirm_recursive_rmdir (0);
+    ## xlsx and ods are zipped
     try
-      unpack (filename, tmpdir, "unzip");
+      unpack (templ, tmpdir, "unzip");
     catch
       printf ("file %s couldn't be unpacked. Is it the proper file format?\n", filename);
       xls = [];
       return
-    end_try_catch
+    end_try_catch
   endif  
 
   ## Set up file pointer struct
@@ -73,7 +93,7 @@ function [ xls, xlssupport, lastintf] = __OCT_spsh_open__ (xls, xwrite, filename
     fid = fopen (sprintf ('%s/xl/workbook.xml', tmpdir));
     if (fid < 0)
       ## File open error
-      warning ("xls2oct: file %s couldn't be unzipped", filename);
+      warning ("xls2open: file %s couldn't be unzipped", filename);
       xls = [];
       return
     else
@@ -90,13 +110,15 @@ function [ xls, xlssupport, lastintf] = __OCT_spsh_open__ (xls, xwrite, filename
       fclose (fid);
 
       ## Get sheet names and indices
-      xls.sheets.sh_names = cell2mat (regexp (xml, '<sheet name="(.*?)"(?: r:id="\w+")? sheetId="\d+"', "tokens"));
-      xls.sheets.rid = str2double (cell2mat (regexp (xml, '<sheet name=".*?" sheetId="(\d+)"', "tokens")));
+      sheets = getxmlnode (xml, "sheets", [], 1);
+      xls.sheets.sh_names = cell2mat (regexp (sheets, '<sheet name="(.*?)"', "tokens"));
+      xls.sheets.rid = str2double (cell2mat (regexp (sheets, ' r:id="rId(\d+)"', "tokens")));
+      xls.sheets.sheetid = str2double (cell2mat (regexp (sheets, ' sheetId="(\d+)"', "tokens")));
 
     endif
 
   elseif (ftype == 3)
-    ## ============== ODS. Read the actual data part in content.xml ============
+    ## ============== ODS. Read the actual data part in content.xml ============
     fid = fopen (sprintf ("%s/content.xml", tmpdir), "r");
     if (fid < 0)
       ## File open error
@@ -108,9 +130,14 @@ function [ xls, xlssupport, lastintf] = __OCT_spsh_open__ (xls, xwrite, filename
       fclose (fid);
 
       ## To speed things up later on, get sheet names and starting indices
-      shtidx = strfind (xml, "<table:table table:name=");
-      shtidx = [ shtidx length(xml) ];
-      nsheets = numel (shtidx) - 1;
+      shtidx = strfind (xml, "<table:table table:name=");
+      nsheets = numel (shtidx);
+      ## Find end (+1) of very last sheet, marked by either one of below tags
+      sht_end = strfind (xml, "<table:named-expressions");
+      if (isempty (sht_end))
+        sht_end = strfind (xml, "</office:spreadsheet>");
+      endif
+      shtidx = [ shtidx sht_end ];
       ## Get sheet names
       sh_names = cell (1, nsheets);
       for ii=1:nsheets
diff --git a/inst/private/__OCT_xlsx2oct__.m b/inst/private/__OCT_xlsx2oct__.m
index 462e152..b615fdb 100644
--- a/inst/private/__OCT_xlsx2oct__.m
+++ b/inst/private/__OCT_xlsx2oct__.m
@@ -1,5 +1,5 @@
-## Copyright (C) 2013 Markus Bergholz
-## Parts Copyright (C) 2013 Philip Nienhuis
+## Copyright (C) 2013,2014 Markus Bergholz
+## Parts Copyright (C) 2013,2014 Philip Nienhuis
 ## 
 ## This program is free software; you can redistribute it and/or modify
 ## it under the terms of the GNU General Public License as published by
@@ -47,7 +47,8 @@
 ## 2013-12-14 (PRN) Adapt regexpr for values (include "n" as value type)
 ##     ''     Fix regexpr for strings ( <v>\d? => <v>\d+ )
 ##     ''     Add isfinite() check before attempt to process fixed strings
-## 2013-12-19 (MB) Replace call to __col_str_to_number with __OCT_cc__
+## 2013-12-19 (MB) Replace call to __col_str_to_number with __OCT_cc__
+## 2014-03-18 (PRN) Fix regexp for reading strings from sharedStrings.xml
 
 function [ raw, xls, rstatus ] = __OCT_xlsx2oct__ (xls, wsh, crange='', spsh_opts)
 
@@ -69,7 +70,7 @@ function [ raw, xls, rstatus ] = __OCT_xlsx2oct__ (xls, wsh, crange='', spsh_opt
       if (isempty (id))
         error ("xls2oct: cannot find sheet '%s' in file %s", wsh, xls.filename);
       else
-        wsh = xls.sheets.rid(id);
+        wsh = xls.sheets.sheetid(id);
       endif
     # endif
   elseif (wsh > numel (xls.sheets.sh_names))
@@ -92,7 +93,9 @@ function [ raw, xls, rstatus ] = __OCT_xlsx2oct__ (xls, wsh, crange='', spsh_opt
     catch
       ## No sharedStrings.xml; implies no "fixed" strings (computed strings can still be there)
       strings = "";
-    end_try_catch
+    end_try_catch
+  else
+    error ("Couldn't open worksheet xml file sheet%d.xml\n", wsh);
   endif
   rstatus = 0;
 
@@ -160,7 +163,9 @@ function [ raw, xls, rstatus ] = __OCT_xlsx2oct__ (xls, wsh, crange='', spsh_opt
       endif
     endif
     ## Turn strings into numbers
-    val = num2cell (str2double (val)); 
+    if (! isempty (val))
+      val = num2cell (str2double (val));
+    endif
 
     ## 2. String / text formulas (cached results are in this sheet; fixed strings in <sharedStrings.xml>)
     ## Formulas
@@ -223,7 +228,7 @@ function [ raw, xls, rstatus ] = __OCT_xlsx2oct__ (xls, wsh, crange='', spsh_opt
     ## 3. Strings
     if (! isempty (strings))
       ## Extract string values. May be much more than present in current sheet
-      ctext = cell2mat (regexp (strings, '<si><t(?:>(.+?)</t>|(.*)/>)</si>', "tokens"));
+      ctext = cell2mat (regexp (strings, '<si><t(?:>(.*?)</t>|(.*)/>)</si>', "tokens"));
       ## Pointers into sharedStrings.xml. "Hard" (fixed) strings have 't="s"' attribute
       ## For reasons known only to M$ those pointers are zero-based, so:
       vals = str2double (cell2mat (regexp (rawdata, '<c r="\w+"(?: s="\d")? t="s"><v>(\d+)</v>', "tokens"))) + 1;
diff --git a/inst/private/__OTK_oct2ods__.m b/inst/private/__OTK_oct2ods__.m
index c9a1905..348263e 100644
--- a/inst/private/__OTK_oct2ods__.m
+++ b/inst/private/__OTK_oct2ods__.m
@@ -1,4 +1,4 @@
-## Copyright (C) 2010,2011,2012,2013 Philip Nienhuis
+## Copyright (C) 2010,2011,2012,2013,2014 Philip Nienhuis
 ##
 ## This program is free software; you can redistribute it and/or modify it under
 ## the terms of the GNU General Public License as published by the Free Software
@@ -47,6 +47,7 @@
 ## 2012-10-24 Style fixes
 ## 2013-01-20 Adapted to ML-compatible Java calls
 ## 2013-12-01 Style fixes, copyright string updates
+## 2014-01-29 Style fixes, copyright string updates
 
 function [ ods, rstatus ] = __OTK_oct2ods__ (c_arr, ods, wsh, crange, spsh_opts)
 
@@ -114,7 +115,7 @@ function [ ods, rstatus ] = __OTK_oct2ods__ (c_arr, ods, wsh, crange, spsh_opts)
     c_arr = c_arr(1:nrows, 1:ncols);
   endif
   
-## Parse data array, setup typarr and throw out NaNs  to speed up writing;
+  ## Parse data array, setup typarr and throw out NaNs  to speed up writing;
   typearr = spsh_prstype (c_arr, nrows, ncols, ctype, spsh_opts, 0);
   if (! spsh_opts.formulas_as_text)
     ## Find formulas (designated by a string starting with "=" and ending in ")")
diff --git a/inst/private/__OTK_spsh_info__.m b/inst/private/__OTK_spsh_info__.m
index 4eaaf84..8a56396 100644
--- a/inst/private/__OTK_spsh_info__.m
+++ b/inst/private/__OTK_spsh_info__.m
@@ -1,4 +1,4 @@
-## Copyright (C) 2012,2013 Philip Nienhuis
+## Copyright (C) 2012,2013,2014 Philip Nienhuis
 ## 
 ## This program is free software; you can redistribute it and/or modify
 ## it under the terms of the GNU General Public License as published by
@@ -21,7 +21,8 @@
 ## Updates:
 ## 2012-10-12 Moved into ./private
 ## 2012-10-24 Style fixes
-## 2013-12-01 Copyright string updates
+## 2013-12-01 Copyright string updates
+## 2014-01-23 Copyright update, return "Empty" for range of empty sheets
 
 function [sh_names] = __OTK_spsh_info__ (ods)
 
@@ -46,7 +47,9 @@ function [sh_names] = __OTK_spsh_info__ (ods)
     [ tr, lr, lc, rc ] = getusedrange (ods, ii);
     if (tr)
       sh_names(ii, 2) = sprintf ("%s:%s", calccelladdress (tr, lc),... 
-                        calccelladdress (lr, rc));
+                        calccelladdress (lr, rc));
+    else
+      sh_names(ii, 2) = "Empty";
     endif
   endfor
 
diff --git a/inst/private/__OXS_spsh_open__.m b/inst/private/__OXS_spsh_open__.m
index 34e08f2..0317d35 100644
--- a/inst/private/__OXS_spsh_open__.m
+++ b/inst/private/__OXS_spsh_open__.m
@@ -1,4 +1,4 @@
-## Copyright (C) 2012,2013 Philip Nienhuis
+## Copyright (C) 2012,2013,2014 Philip Nienhuis
 ## 
 ## This program is free software; you can redistribute it and/or modify
 ## it under the terms of the GNU General Public License as published by
@@ -23,12 +23,13 @@
 ## 2013-12-06 Updated copyright string; style fixes
 ## 2013-12-28 Fix creating new files
 ##      ''    Implemented OOXML support for OpenXLS v.10
-## 2012-12-29 Fixed file open support, no more lingering file locks 
+## 2012-12-29 Fixed file open support, no more lingering file locks
+## 2014-04-14 Updated texinfo header and adapted message (no OOXML support)
 
 function [ xls, xlssupport, lastintf ] = __OXS_spsh_open__ (xls, xwrite, filename, xlssupport, ftype)
 
     if (ftype != 1 && ftype != 2)
-      error ("OXS can only read from .xls (Excel'97-2003) or .xlsx (Excel 2007+) files")
+      error ("The OXS interface only supports .xls (Excel'97-2003) files")
     endif
     try
       if (xwrite > 2)
diff --git a/inst/private/__POI_getusedrange__.m b/inst/private/__POI_getusedrange__.m
index ff008f8..eb68084 100644
--- a/inst/private/__POI_getusedrange__.m
+++ b/inst/private/__POI_getusedrange__.m
@@ -21,7 +21,8 @@
 ## 2012-10-12 Renamed & moved into ./private
 ## 2012-10-24 Style fixes
 ## 2013-09-23 Check getFirstCellNum method return value for empty rows
-## 2013-12-06 Style fixes
+## 2013-12-06 Style fixes
+## 2014-04-06 Fix getFirstCellNum return value when checking rightmost cells
 
 function [ trow, brow, lcol, rcol ] = __POI_getusedrange__ (xls, ii)
 
@@ -41,7 +42,7 @@ function [ trow, brow, lcol, rcol ] = __POI_getusedrange__ (xls, ii)
     if (! isempty (irow))
       scol = irow.getFirstCellNum;
       ## If getFirstCellNum < 0, row is empty
-      if (scol >= 1)
+      if (scol >= 0)
         lcol = min (lcol, scol);
         ecol = irow.getLastCellNum - 1;
         rcol = max (rcol, ecol);
diff --git a/inst/private/parse_sp_range.m b/inst/private/parse_sp_range.m
index 8f942f3..f24191b 100644
--- a/inst/private/parse_sp_range.m
+++ b/inst/private/parse_sp_range.m
@@ -20,52 +20,55 @@
 ## Author: Philip Nienhuis <pr.nienhuis at users.sf.net>
 ## Created: 2009-06-20
 ## Latest update 2010-01-13
-## 2013-12-06 Updated copyright strings; style fixes
+## 2013-12-06 Updated copyright strings; style fixes
+## 2014-04-13 Invoke binary __char2num__ for col->colnr conversion
 
 function [topleft, nrows, ncols, toprow, lcol] = parse_sp_range (range_org)
 
-  range = deblank (upper (range_org));
+  crange = strrep (deblank (upper (range_org)), " ", "");
   range_error = 0; 
   nrows = 0; 
   ncols = 0;
 
   # Basic checks
-  if (index (range, ':') == 0)
-    if (isempty (range))
+  if (index (crange, ':') == 0)
+    if (isempty (crange))
       range_error = 0;
       leftcol = 'A';
       rightcol = 'A';
     else
       # Only upperleft cell given, just complete range to 1x1
       # (needed for some routines)
-      range = [range ":" range];
+      crange = [crange ":" crange];
     endif
   endif
 
   # Split up both sides of the range
-  [topleft, lowerright] = strtok (range, ':');
+  [topleft, lowerright] = strtok (crange, ':');
 
   # Get toprow and clean up left column
   [st, en] = regexp (topleft, '\d+');
-  toprow = str2double (topleft(st:en));
-  leftcol = deblank (topleft(1:st-1));
-  [st, en1] = regexp (leftcol, '\s+');
-  if (isempty (en1)) 
-    en1 = 0 ; 
-  endif
-  [st, en2] = regexp (leftcol,'\D+');
-  leftcol = leftcol(en1+1:en2);
+  toprow = str2double (topleft(st:en));
+  lcol = __char2num__ (topleft(1:st-1));
+%  leftcol = deblank (topleft(1:st-1));
+%  [st, en1] = regexp (leftcol, '\s+');
+%  if (isempty (en1)) 
+%    en1 = 0 ; 
+%  endif
+%  [st, en2] = regexp (leftcol,'\D+');
+%  leftcol = leftcol(en1+1:en2);
 
   # Get bottom row and clean up right column
   [st, en] = regexp (lowerright, '\d+');
-  bottomrow = str2double (lowerright(st:en));
-  rightcol = deblank (lowerright(2:st-1));
-  [st, en1] = regexp (rightcol, '\s+');
-  if (isempty (en1)) 
-    en1 = 0; 
-  endif
-  [st, en2] = regexp (rightcol, '\D+');
-  rightcol = rightcol(en1+1:en2);
+  bottomrow = str2double (lowerright(st:en));
+  rcol = __char2num__ (lowerright (2:st-1));
+%  rightcol = deblank (lowerright(2:st-1));
+%  [st, en1] = regexp (rightcol, '\s+');
+%  if (isempty (en1)) 
+%    en1 = 0; 
+%  endif
+%  [st, en2] = regexp (rightcol, '\D+');
+%  rightcol = rightcol(en1+1:en2);
 
   # Check nr. of rows
   nrows = bottomrow - toprow + 1; 
@@ -74,19 +77,19 @@ function [topleft, nrows, ncols, toprow, lcol] = parse_sp_range (range_org)
   endif
 
   if (range_error == 0) 
-    # Get left column nr.
-    [st, en] = regexp (leftcol, '\D+');
-    lcol = (leftcol(st:st) - 'A' + 1);
-    while (++st <= en)
-      lcol = lcol * 26 + (leftcol(st:st) - 'A' + 1);
-    endwhile
-
-    # Get right column nr.
-    [st, en] = regexp (rightcol, '\D+');
-    rcol = (rightcol(st:st) - 'A' + 1);
-    while (++st <= en)
-      rcol = rcol * 26 + (rightcol(st:st) - 'A' + 1);
-    endwhile
+%    # Get left column nr.
+%    [st, en] = regexp (leftcol, '\D+');
+%    lcol = (leftcol(st:st) - 'A' + 1);
+%    while (++st <= en)
+%      lcol = lcol * 26 + (leftcol(st:st) - 'A' + 1);
+%    endwhile
+%
+%    # Get right column nr.
+%    [st, en] = regexp (rightcol, '\D+');
+%    rcol = (rightcol(st:st) - 'A' + 1);
+%    while (++st <= en)
+%      rcol = rcol * 26 + (rightcol(st:st) - 'A' + 1);
+%    endwhile
 
     # Check
     ncols = rcol - lcol + 1;
@@ -105,18 +108,18 @@ endfunction
 
 ## FIXME -- reinstate these tests one there if a way is found to test private
 ##          functions directly
-##%!test
-##%! [a b c d e] = parse_sp_range ('A1:B2');
-##%! assert ([a b c d e], ['A1', 2, 2, 1, 1]);
-
-##%!test
-##%! [a b c d e] = parse_sp_range ('A1:AB200');
-##%! assert ([a b c d e], ['A1', 200, 28, 1, 1]);
-
-##%!test
-##%! [a b c d e] = parse_sp_range ('cd230:iY65536');
-##%! assert ([a b c d e], ['CD230', 65307, 178, 230, 82]);
-
-##%!test
-##%! [a b c d e] = parse_sp_range ('BvV12798 : xFd1054786');
-##%! assert ([b c d e], [1041989, 14439, 12798, 1946]);
+#%!test
+#%! [a b c d e] = parse_sp_range ('A1:B2');
+#%! assert ([a b c d e], ['A1', 2, 2, 1, 1]);
+#%
+#%!test
+#%! [a b c d e] = parse_sp_range ('A1:AB200');
+#%! assert ([a b c d e], ['A1', 200, 28, 1, 1]);
+#%
+#%!test
+#%! [a b c d e] = parse_sp_range ('cd230:iY65536');
+#%! assert ([a b c d e], ['CD230', 65307, 178, 230, 82]);
+#%
+#%!test
+#%! [a b c d e] = parse_sp_range ('BvV12798 : xFd1054786');
+#%! assert ([b c d e], [1041989, 14439, 12798, 1946]);
diff --git a/inst/templates/template.ods b/inst/templates/template.ods
new file mode 100644
index 0000000..d4bf994
Binary files /dev/null and b/inst/templates/template.ods differ
diff --git a/inst/templates/template.xlsx b/inst/templates/template.xlsx
new file mode 100644
index 0000000..6ca6fa9
Binary files /dev/null and b/inst/templates/template.xlsx differ
diff --git a/inst/xls2oct.m b/inst/xls2oct.m
index 31d41e3..bde591a 100644
--- a/inst/xls2oct.m
+++ b/inst/xls2oct.m
@@ -1,4 +1,4 @@
-## Copyright (C) 2009,2010,2011,2012,2013 Philip Nienhuis <prnienhuis at users.sf.net>
+## Copyright (C) 2009,2010,2011,2012,2013,2014 Philip Nienhuis
 ##
 ## This program is free software; you can redistribute it and/or modify it under
 ## the terms of the GNU General Public License as published by the Free Software
@@ -112,7 +112,7 @@
 ##
 ## @end deftypefn
 
-## Author: Philip Nienhuis
+## Author: Philip Nienhuis <prnienhuis at users.sf.net>
 ## Created: 2010-10-16
 ## Updates: 
 ## 2009-01-03 (added OOXML support & cleaned up code. Excel 
@@ -141,6 +141,7 @@
 ## 2013-10-02 Delete ODS section
 ## 2013-11-02 Added rstatus return arg for __OCT_xlsx2oct__.m
 ## 2013-11-08 Added spsh_opts arg for __OCT_xls2oct__.m
+## 2014-02-08 Style fixes
 ##
 ## Latest subfunc update: 2012-10-12
 
@@ -150,7 +151,7 @@ function [ rawarr, xls, rstatus ] = xls2oct (xls, wsh=1, datrange="", spsh_opts=
   if (~isstruct (xls))
     error ("File ptr struct expected for arg @ 1"); 
   endif
-  test1 = ~isfield (xls, "xtype");
+  test1 = ! isfield (xls, "xtype");
   test1 = test1 || ~isfield (xls, "workbook");
   test1 = test1 || isempty (xls.workbook);
   test1 = test1 || isempty (xls.app);
diff --git a/inst/xlsclose.m b/inst/xlsclose.m
index 60b397d..fb45425 100644
--- a/inst/xlsclose.m
+++ b/inst/xlsclose.m
@@ -1,4 +1,4 @@
-## Copyright (C) 2009,2010,2011,2012,2013 Philip Nienhuis <prnienhuis at users.sf.net>
+## Copyright (C) 2009,2010,2011,2012,2013,2014 Philip Nienhuis
 ##
 ## This program is free software; you can redistribute it and/or modify it under
 ## the terms of the GNU General Public License as published by the Free Software
@@ -37,10 +37,10 @@
 ## an other file than opened with xlsopen(); unfortunately this doesn't work
 ## with JXL (JExcelAPI) interface.
 ##
-## You need MS-Excel (95 - 2010), and/or the Java package => 1.2.8 plus Apache
-## POI > 3.5 and/or JExcelAPI and/or OpenXLS and/or OpenOffice.org or clones
-## installed on your computer + proper javaclasspath set, to make this
-## function work at all.
+## For other file formats than OOXML and ODS, you need MS-Excel (95 - 2010),
+## and/or the Java package => 1.2.8 plus Apache POI > 3.5 and/or JExcelAPI
+## and/or OpenXLS and/or OpenOffice.org or clones installed on your computer
+## + proper javaclasspath set, to make this function work at all.
 ##
 ## @var{xls} must be a valid pointer struct made by xlsopen() in the same
 ## octave session.
@@ -56,7 +56,7 @@
 ##
 ## @end deftypefn
 
-## Author: Philip Nienhuis
+## Author: Philip Nienhuis <prnienhuis at users.sf.net>
 ## Created: 2009-11-29
 ## Updates: 
 ## 2010-01-03 (checked OOXML support)
@@ -81,7 +81,8 @@
 ## 2013-09-30 OCT interface added
 ## 2013-10-01 Warn for empty struct input
 ## 2013-12-29 Style fixes
-## 2014-01-01 Style fixes
+## 2014-01-01 Style fixes
+## 2014-04-13 Updated copyright strings
 
 function [ xls ] = xlsclose (xls, varargs)
 
diff --git a/inst/xlsfinfo.m b/inst/xlsfinfo.m
index c703262..12c3569 100644
--- a/inst/xlsfinfo.m
+++ b/inst/xlsfinfo.m
@@ -1,4 +1,4 @@
-## Copyright (C) 2009,2010,2011,2012,2013 Philip Nienhuis <pr.nienhuis at users.sf.net>
+## Copyright (C) 2009,2010,2011,2012,2013,2014 Philip Nienhuis
 ##
 ## This program is free software; you can redistribute it and/or modify it under
 ## the terms of the GNU General Public License as published by the Free Software
@@ -48,9 +48,11 @@
 ## info and/or different treatment of empty but formatted cells, each
 ## interfaces may give different results).
 ##
-## For use on OOXML spreadsheets one needs full POI and/or UNO support (see
-## xlsopen) and 'poi' or 'uno' needs to be specified for @var{reqintf}. For
-## Excel 95 file use 'jxl' or 'uno'.
+## For OOXML spreadsheets no external SW is required but full POI and/or
+## UNO support (see xlsopen) may work better or faster; to use those specify
+## 'poi' or 'uno' for @var{reqintf}. For Excel 95 files use 'com' (windows
+## only), 'jxl' or 'uno'. Gnumeric files can be explored with the built-in
+## OCT interface (no need to specify @var{reqintf} then).
 ##
 ## Examples:
 ##
@@ -69,7 +71,7 @@
 ##
 ## @end deftypefn
 
-## Author: Philip Nienhuis <prnienhuis at users.sourceforge.net>
+## Author: Philip Nienhuis <prnienhuis at users.sourceforge.net>
 ## Created: 2009-10-27
 ## Updates:
 ## 2009-01-01 Echo sheet names to screen, request interface type)
@@ -90,7 +92,9 @@
 ## 2012-10-24 Style fixes
 ## 2013-10-01 OCT interface added for gnumeric
 ## 2013-12-01 Style fixes & support for more file types than just Excel
-## 2013-12-29 Style fixes
+## 2013-12-29 Style fixes
+## 2014-04-15 Updates to texinfo header
+
 
 function [ filetype, sh_names, fformat ] = xlsfinfo (filename, reqintf=[])
 
diff --git a/inst/xlsopen.m b/inst/xlsopen.m
index c232000..18b90b1 100644
--- a/inst/xlsopen.m
+++ b/inst/xlsopen.m
@@ -1,4 +1,4 @@
-## Copyright (C) 2009,2010,2011,2012,2013 Philip Nienhuis
+## Copyright (C) 2009,2010,2011,2012,2013,2014 Philip Nienhuis
 ## 
 ## This program is free software; you can redistribute it and/or modify
 ## it under the terms of the GNU General Public License as published by
@@ -25,22 +25,20 @@
 ## Calling xlsopen without specifying a return argument is fairly useless!
 ##
 ## xlsopen works with interfaces, which are links to external software.
-## For reading from OOXML (Excel 2007 and up), ODS 1.2 and Gnumeric no
-## additional software is required when the OCT interface is used. For all
-## other spreadsheet formats and for writing to spreadsheet files, you need
-## MS-Excel (95 - 2013), or a Java JRE plus Apache POI >= 3.5 and/or JExcelAPI
+## For I/O from OOXML (Excel 2007 and up), ODS 1.2 and Gnumeric, no
+## additional software is required when the OCT interface is used (see below).
+## For all other spreadsheet formats, you need one or more of MS-Excel
+## (95 - 2013), or a Java JRE plus Apache POI >= 3.5 and/or JExcelAPI
 ## and/or OpenXLS and/or OpenOffice.org (or clones) installed on your computer
 ## + proper javaclasspath set. These interfaces are referred to as COM, POI,
 ## JXL, OXS, and UNO, resp., and are preferred in that order by default
-## (depending on their presence). The OCT interface has the lowest priority.
-## For OOXML read/write support, in addition to Apache POI support you also
-## need the following jars in your javaclasspath: poi-ooxml-schemas-3.5.jar,
-## xbean.jar and dom4j-1.6.1.jar (or later versions). Later OpenOffice.org
-## versions (UNO interface) have support for OOXML as well.
-## Excel'95 spreadsheets can only be read by JExcelAPI and OpenOffice.org.
-## For just reading OOXML (.xlsx or .xlsm), no Java or add-on packages are 
-## required; but currently you loose a bit of the flexibility of the other
-## interfaces.
+## (depending on their presence). Currently the OCT interface has the lowest
+## priority as it is still experimental.
+## For OOXML read/write support in principle no additional SW is needed.
+## However, the COM, POI and UNO interfaces may provide better OOXML write
+## performance and/or more flexibility.
+## Excel'95 spreadsheets (BIFF5) can only be read using the COM (Excel-ActiveX),
+## JXL (JExcelAPI), and UNO (Open-/LibreOffice) interfaces.
 ##
 ## @var{filename} should be a valid .xls or xlsx Excel file name (including
 ## extension). But if you use the COM interface you can specify any extension
@@ -49,9 +47,9 @@
 ## allowed. If @var{filename} does not contain any directory path, the file
 ## is saved in the current directory.
 ##
-## If @var{readwrite} is set to 0 (default value) or omitted, the Excel file
-## is opened for reading. If @var{readwrite} is set to True or 1, an Excel
-## file is opened (or created) for reading & writing.
+## If @var{readwrite} is set to 0 (default value) or omitted, the spreadsheet
+## file is opened for reading. If @var{readwrite} is set to true or 1, a
+## spreadsheet file is opened (or created) for reading & writing.
 ##
 ## Optional input argument @var{reqintf} can be used to override the Excel
 ## interface that otherwise is automatically selected by xlsopen. Currently
@@ -139,7 +137,9 @@
 ## 2013-12-28 Allow OOXML support for OpenXLS
 ## 2014-01-01 Add .csv to supported file extensions
 ##     ''     Add warning that UNO will write ODS f. unsupported file extensions
-##     ''     Copyright string update
+##     ''     Copyright string update
+## 2014-02-02 Allow write support for OCT interface
+## 2014-04-13 Updated texinfo header
 
 function [ xls ] = xlsopen (filename, xwrite=0, reqinterface=[])
 
@@ -260,10 +260,6 @@ function [ xls ] = xlsopen (filename, xwrite=0, reqinterface=[])
     if (ftype == 5)
       error ("There's only read support for gnumeric files");
     endif
-    ## Catch attempts to write xlsx if only OCT interface is supported
-    if (xlsintf_cnt == 1 && xlsinterfaces.OCT)
-      error ("Only the OCT interface is present | requested, but that has only read support");
-    endif
     fmode = 'r+b';
     if (! has_suffix)
       ## Add .xls suffix to filename (all Excel versions can write this)
diff --git a/inst/xlsread.m b/inst/xlsread.m
index 6fd9045..0d61e94 100644
--- a/inst/xlsread.m
+++ b/inst/xlsread.m
@@ -1,4 +1,4 @@
-## Copyright (C) 2009,2010,2011,2012,2013 by Philip Nienhuis <prnienhuis at users.sf.net>
+## Copyright (C) 2009,2010,2011,2012,2013,2014 by Philip Nienhuis
 ##
 ## This program is free software; you can redistribute it and/or modify it under
 ## the terms of the GNU General Public License as published by the Free Software
@@ -33,7 +33,8 @@
 ## assumed to be in the current directory. The filename extension
 ## (.xls or .xlsx) must be included in the file name; when using the
 ## COM interface all file formats can be read that are supported by the
-## locally installed MS-Excel version (e.g., wk1, csv, dbf, etc.).
+## locally installed MS-Excel version (e.g., wk1, csv, dbf, etc.).
+## The same holds for UNO (OpenOffice.orgor LibreOffice).
 ##
 ## @var{range} is expected to be a regular spreadsheet range format,
 ## or "" (empty string, indicating all data in a worksheet).
@@ -67,25 +68,28 @@
 ## The optional last argument @var{reqintf} can be used to override 
 ## the automatic interface selection by xlsread out of the supported
 ## ones: COM/Excel, Java/Apache POI, Java/JExcelAPI, Java/OpenXLS, 
-## Java/UNO (OpenOffice.org), or native Octave (only reading .xlsx)
-## (in that -built in- order of preference).
-## For reading from OOXML files a value of 'com', 'poi', 'uno', or 'oct'
-## must be specified for @var{reqintf} (see help for xlsopen); for
+## Java/UNO (OpenOffice.org), or native Octave (in that -built in-
+## order of preference).
+## For I/O to/from OOXML files a value of 'com', 'poi', 'uno', or 'oct'
+## must be specified for @var{reqintf} (see help for xlsopen). For
 ## Excel'95 files use 'com', or if Excel is not installed use 'jxl',
-## 'basic' or 'uno' (POI can't read Excel 95 but will try to fall back
-## to JXL). As @var{reqintf} can also be a cell array of strings, one
-## can select or exclude one or more interfaces.
+## 'basic' or 'uno'. POI can't read Excel'95 but will try to fall back
+## to JXL. As @var{reqintf} can also be a cell array of strings, one
+## can select or exclude one or more interfaces.
+## In addition the OCT interface offers .gnumeric read support.
 ##
 ## Erroneous data and empty cells are set to NaN in @var{numarr} and
 ## turn up empty in @var{txtarr} and @var{rawarr}. Date/time values in
 ## Excel are returned as numerical values in @var{numarr}. Note that
 ## Excel and Octave have different date base values (1/1/1900 & 
-## 1/1/0000, resp.). Spreadsheet date values lying before 1/1/1900 are
-## returned as strings, formatted as they appear in the spreadsheet.
+## 1/1/0000, resp.). When using the COM interface, spreadsheet date
+## values lying before 1/1/1900 are returned as strings, formatted as
+## they appear in the spreadsheet.
 ## @var{numarr} and @var{txtarr} are trimmed from empty outer rows
 ## and columns. Be aware that Excel does the same for @var{rawarr}, 
 ## so any returned array may turn out to be smaller than requested in
-## @var{range}.
+## @var{range}. Use the fourth return argument @var{LIMS} for info on the
+## cell ranges your date came from.
 ##
 ## When reading from merged cells, all array elements NOT corresponding 
 ## to the leftmost or upper Excel cell will be treated as if the
@@ -127,7 +131,7 @@
 ##
 ## @end deftypefn
 
-## Author: Philip Nienhuis
+## Author: Philip Nienhuis <prnienhuis at users.sf.net>
 ## Created: 2009-10-16
 ## Updates: 
 ## 2009-12-29 bug fixes
@@ -151,7 +155,9 @@
 ## 2013-09-27 Proper spelling of input arg
 ## 2013-09-30 Header adapted to native OCT interface f xlsx
 ## 2013-12-20 Style fixes
-## 2013-12-27 In case of .csv fall back to csvread for lazy Matlab users
+## 2013-12-27 In case of .csv fall back to csvread for lazy Matlab users
+## 2014-04-13 Updated copyright strings & texinfo header
+## 2014-04-15 More updates to texinfo header
 
 function [ numarr, txtarr, rawarr, lims ] = xlsread (fn, wsh, datrange, reqintf=[])
 
diff --git a/inst/xlswrite.m b/inst/xlswrite.m
index 6e017b0..bc0764b 100644
--- a/inst/xlswrite.m
+++ b/inst/xlswrite.m
@@ -1,4 +1,4 @@
-## Copyright (C) 2009,2010,2011,2012,2013 Philip Nienhuis
+## Copyright (C) 2009,2010,2011,2012,2013,2014 Philip Nienhuis
 ##
 ## This program is free software; you can redistribute it and/or modify it under
 ## the terms of the GNU General Public License as published by the Free Software
@@ -40,7 +40,7 @@
 ## @var{wsh} can be a number or string (max. 31 chars).
 ## In case of a not yet existing Excel file, the first worksheet will be
 ## used & named according to @var{wsh} - the extra worksheets that Excel
-## normally creates by default are deleted.
+## usually creates by default are deleted (COM) or simply not created.
 ## In case of existing files, some checks are made for existing worksheet
 ## names or numbers, or whether @var{wsh} refers to an existing sheet with
 ## a type other than worksheet (e.g., chart).
@@ -65,9 +65,11 @@
 ## The optional last argument @var{reqintf} can be used to override 
 ## the automatic selection by xlswrite of one interface out of the
 ## supported ones: 'com' (ActiveX/Excel), 'poi' (Java/Apache POI), 'jxl'
-## (Java/JExcelAPI), or 'uno' (Java/OpenOffice.org). 'oxs' (Java/OpenXLS)
-## is implemented but disabled for writing as it is too buggy. For
-## writing to OOXML files (.xlsx) a value of 'com', 'poi' or 'uno' must
+## (Java/JExcelAPI), 'uno' (Java/OpenOffice.org), or 'OCT' (native Octave
+## w/o any external support software). 'oxs' (Java/OpenXLS) has been
+## implemented but disabled for writing OOXML as it is too buggy; for
+## BIFF8 (Excel '97 .xls) it works reliably. For writing to OOXML files
+## (.xlsx) a value of 'com', 'poi', 'uno', or 'oct' must
 ## be specified for @var{reqintf}. The value of @var{reqintf} is
 ## case-insensitive. Multiple interfaces can be selected if entered as
 ## a cell array of strings.
@@ -112,7 +114,9 @@
 ## 2012-04-17 Fix checks on xls or xls? suffix (due to Vermylen)
 ## 2012-04-21 Improve xls/xlsx suffix check
 ## 2013-12-07 Updated copyright string
-##     ''     Check on empty file ptr struct after calling xlsopen
+##     ''     Check on empty file ptr struct after calling xlsopen
+## 2014-03-18 Convey full crange to oct2xls, not just topleft
+## 2014-04-13 Update texinfo header
 
 function [ rstatus ] = xlswrite (filename, arr, arg3, arg4, arg5)
 
@@ -166,7 +170,10 @@ function [ rstatus ] = xlswrite (filename, arr, arg3, arg4, arg5)
     nr = min (nrows, nr);
     nc = min (ncols, nc);
     warning ("xlswrite - array truncated to %d by %d to fit in range %s", ...
-             nrows, ncols, crange);
+             nrows, ncols, crange);
+    ## Adapt crange
+    crange = [ calccelladdress(trow, lcol) ":" ...
+               calccelladdress(trow+nrows-1, lcol+ncols-1) ];
   endif
 
   unwind_protect          ## Needed to be sure Excel can be closed i.c.o. errors
@@ -175,7 +182,7 @@ function [ rstatus ] = xlswrite (filename, arr, arg3, arg4, arg5)
     if (! isempty (xls))
       xls_ok = 1;
 
-      [xls, rstatus] = oct2xls (arr(1:nr, 1:nc), xls, wsh, topleft);
+      [xls, rstatus] = oct2xls (arr(1:nr, 1:nc), xls, wsh, crange);
     endif
 
   unwind_protect_cleanup
diff --git a/src/Makefile b/src/Makefile
index 6ea267d..3ffb5b0 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,4 +1,4 @@
-all: csvexplode.oct csv2cell.oct csvconcat.oct cell2csv.oct xmlread.oct
+all: csvexplode.oct csv2cell.oct csvconcat.oct cell2csv.oct xmlread.oct __num2char__.mex __char2num__.mex
 
 ## Compiling these function does produces warnings but seems there is no one
 ## to fix them so we do not enable Wall. Just for reference, here they are
@@ -38,8 +38,14 @@ xmlread.o: xmlread.cc xmltree_read.h xmltree.h
 xmlread.oct: xmlread.o xmltree_read.o xmltree.o
 	$(MKOCTFILE) $^
 
+__num2char__.mex: __num2char__.c
+	$(MKOCTFILE) --mex $^
+
+__char2num__.mex: __char2num__.c
+	$(MKOCTFILE) --mex $^
+  
 %.oct: %.cc
 	$(MKOCTFILE) $<
 
 clean:
-	rm -f *.o octave-core core *.oct *~
+	rm -f *.o octave-core core *.oct *.mex *~
diff --git a/src/__char2num__.c b/src/__char2num__.c
new file mode 100644
index 0000000..8062c9f
--- /dev/null
+++ b/src/__char2num__.c
@@ -0,0 +1,72 @@
+// Copyright (C) 2014 Markus Bergholz <markuman at gmail.com>
+//
+// This program is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation; either version 3 of the License, or (at your option) any later
+// version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+// details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, see <http://www.gnu.org/licenses/>.
+
+#include "mex.h"
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <ctype.h>
+
+int column_index_from_string(const char *s)
+{
+  int ret=0;
+  for (; *s; s++)
+    {
+      if (!isupper(*s))
+        return -1;
+      ret = ret*26 + *s-'A' +1;
+      if (ret<0) //overflow
+        return -1;
+    }
+  return ret;
+}
+
+void mexFunction( int nlhs, mxArray *plhs[],
+                  int nrhs, const mxArray *prhs[])
+{
+  if(nrhs!=1)
+    {
+      mexErrMsgIdAndTxt("IO:arrayProduct:nrhs", "Only one input allowed.");
+    }
+  else if ( !mxIsChar(prhs[0]))
+    {
+      mexErrMsgIdAndTxt("IO:arrayProduct:nrhs", "Input must be a string.");
+    }
+  else
+    {
+      char *str;
+      str = (char *) mxCalloc(mxGetN(prhs[0])+1, sizeof(char));
+      mxGetString(prhs[0], str, mxGetN(prhs[0])+1);
+      if (strlen(str)>3)
+        {
+          mexErrMsgIdAndTxt("IO:arrayProduct:nrhs", "Input string is too long.");
+        }
+      else
+        {
+          int i = column_index_from_string(str);
+          if (i<0)
+            mexErrMsgIdAndTxt("IO:arrayProduct:nrhs", "Illegal characters.");
+          else
+            {
+              plhs[0] = mxCreateNumericMatrix(1, 1, mxDOUBLE_CLASS, mxREAL);
+              double *index;
+              index = mxGetPr(plhs[0]);
+              index[0] = i;
+            }
+        }
+    }
+}
diff --git a/src/__num2char__.c b/src/__num2char__.c
new file mode 100644
index 0000000..0d81e1d
--- /dev/null
+++ b/src/__num2char__.c
@@ -0,0 +1,75 @@
+// Copyright (C) 2014 Markus Bergholz <markuman at gmail.com>
+//
+// This program is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation; either version 3 of the License, or (at your option) any later
+// version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+// details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, see <http://www.gnu.org/licenses/>.
+
+#include "mex.h"
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+
+
+#define ALPHABET "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+
+static int map[256];
+
+void init_map(void)
+{
+    unsigned i;
+    for (i = 0; ALPHABET[i]; i++) {
+        map[(unsigned char)ALPHABET[i]] = i + 1;
+    }
+}
+
+char *column_index_to_string(int c, char *s)
+{
+    int i, x;
+    if (c < 1 || c > 18278) {
+        return NULL;
+    }
+
+    for (i = 0; (c) && i < 3; i++) {
+        c -= 1;
+        x = c % 26;
+        s[2 - i] = ALPHABET[x];
+        c /= 26;
+    }
+    memmove(s, s + 3 - i , i);
+    s[i] = '\0';
+    return s;
+}
+
+void mexFunction( int nlhs, mxArray *plhs[],
+                  int nrhs, const mxArray *prhs[])
+{
+
+
+    if(nrhs!=1) {
+	mexErrMsgIdAndTxt("IO:arrayProduct:nrhs", "One INPUT argument, no more nor less!");
+    } else if ( !mxIsDouble(prhs[0]) ||  mxIsComplex(prhs[0])) {
+	mexErrMsgIdAndTxt("IO:arrayProduct:nrhs", "INPUT argument has to be double and no complex number!");
+    } else {
+
+      double *raw;
+      int *index;
+      raw = mxGetPr (prhs[0]);
+      index[0]=raw[0];
+
+      char str[4];
+      plhs[0]=mxCreateString(column_index_to_string(index[0], str));
+
+   }
+
+}

-- 
Alioth's /home/groups/pkg-octave/bin/git-commit-notice on /srv/git.debian.org/git/pkg-octave/octave-io.git



More information about the Pkg-octave-commit mailing list