changeset 12461:f87e10495905 octave-forge

Preliminary gnumeric write support
author prnienhuis
date Wed, 30 Apr 2014 22:30:26 +0000
parents 6373318c2af8
children c39154770a99
files main/io/inst/private/__OCT_oct2gnm__.m main/io/inst/private/__OCT_spsh_close__.m main/io/inst/private/__OCT_spsh_open__.m
diffstat 3 files changed, 80 insertions(+), 49 deletions(-) [+]
line wrap: on
line diff
--- a/main/io/inst/private/__OCT_oct2gnm__.m	Wed Apr 30 22:29:37 2014 +0000
+++ b/main/io/inst/private/__OCT_oct2gnm__.m	Wed Apr 30 22:30:26 2014 +0000
@@ -23,7 +23,7 @@
 ## Author: Philip Nienhuis <prnienhuis at users . sf .net>
 ## Created: 2014-04-20
 
-function [xls, status] = __OCT_oct2gnm__ (arr, xls, wsh, crange, spsh_opts=0)
+function [xls, status] = __OCT_oct2gnm__ (obj, xls, wsh, crange, spsh_opts=0, obj_dims)
 
   ## A. Find out if we write to existing or new sheet
   new_sh = 0;
@@ -47,32 +47,36 @@
     endif
     wsh = idx;
   endif
-  ## Check if we made a new file from template
+
+  ## Check if we made a new file from template, add a new sheet, or add data to a sheet
   if (strcmpi (xls.sheets.sh_names{1}, " ") && numel (xls.sheets.sh_names) == 2 && new_sh)
+    ## Completely new file. Clean up and copy a few things
     xls.sheets.sh_names(1) = [];
-    new_sh = 0;
     wsh--;
+    idx_s = xls.sheets.shtidx(wsh);
+    idx_e = xls.sheets.shtidx(wsh+1) - 1;
     xls.changed = 2;
-  endif
-
-  ## B. Update sheet info in file pointer struct
-  if (new_sh)
+    lims = [obj_dims.lc, obj_dims.rc; obj_dims.tr, obj_dims.br];
+    rawarr = obj;
+  elseif (new_sh)
+    ## New sheet. Provisionally update sheet info in file pointer struct
     wsh = numel (xls.sheets.sh_names);
     idx_s = xls.sheets.shtidx(wsh) ;               ## First position after last sheet
     idx_e = idx_s - 1;
-    raw = {};
-    lims = [];
+    xls.changed = 1;
+    lims = [obj_dims.lc, obj_dims.rc; obj_dims.tr, obj_dims.br];
+    rawarr = obj;
   else
+    ## Just write new data into an existing sheet
     idx_s = xls.sheets.shtidx(wsh);
     idx_e = xls.sheets.shtidx(wsh+1) - 1;
-    ## Get all data in sheet and row/column limits
-    [raw, xls]  = __OCT_gnm2oct__ (xls, wsh, "", struct ("formulas_as_text", 1));
+    ## Get all current data in sheet and current row/column limits
+    [rawarr, xls]  = __OCT_gnm2oct__ (xls, wsh, "", struct ("formulas_as_text", 1));
     lims = xls.limits;
+    ## C. Merge old and new data. Provisionally allow empty new data to wipe old data
+    [rawarr, lims] = __OCT_merge_data__ (rawarr, lims, obj, obj_dims);
   endif
   
-  ## C. Merge old and new data. Provisionally allow empty new data to wipe old data
-  [arr, lims, onr, onc] = __OCT_merge_data__ (raw, lims, obj, obj_dims);
-  
 #==============================================================================
 
   ## D. Create a temporary file to hold the new sheet xml
@@ -84,27 +88,35 @@
   endif
 
   ## Write data to sheet
-  status  = __OCT__oct2gnm_sh__ (fid, rawarr, wsh, lims, onc, onr);
+  status  = __OCT__oct2gnm_sh__ (fid, rawarr, xls.sheets.sh_names{wsh}, lims);
 
   ## E. Merge new/updated sheet into gnumeric file
   ## Read first chunk  until sht_idx<xx>
-  fidc = fopen (xls.workbook), "r+");
-  ## Go to start of requested sheet
-# fseek (fidc, 0, 'bof');
+  fidc = fopen (xls.workbook, "r+");
 
   ## Read and concatenate just adapted/created sheet/table:table
   gnm_xml = fread (fidc, idx_s - 1, "char=>char")';
 
   ## F. Optionally update SheetName Index node
-  if new_sh)
-    [shtidxnode, ss, ee] = getxmlnode (gnm_xml, "gnm:SheetNameIndex");
-    sh_node = sprintf('><gnm:SheetName gnm:Cols="1024" gnm:Rows="65536">%s</gnm:SheetName>',
-                       xls.sheets.sh_names{wsh});
-    ## Add close tag to ease up next strrep
-    sh_node = [ sh_node "</gnm:SheetNameIndex>" ];
-    shtidxnode = strrep (shtidxnode, "></gnm:SheetNameIndex>", sh_node);
-    ## Replace SheetNameIndex node
-    gnm_xml = [gnm_xml(1:ss-1) shtidxnode gnm_xml(ee+1:end) ];
+  if (new_sh)
+    if (wsh == 1)
+      ## New file,existing sheet. Find then (only) gnm:SheetName node
+      [shtnmnode, ss, ee] = getxmlnode (gnm_xml, "gnm:SheetName");
+      ipos = index (shtnmnode, "> </gnm:SheetName>");
+      shtnmnode = [ shtnmnode(1:ipos) xls.sheets.sh_names{1} shtnmnode(ipos+2:end) ];
+      ## Replace SheetName node
+      gnm_xml = [ gnm_xml(1:ss-1) shtnmnode gnm_xml(ee+1:end) ];
+    else
+      ## Existing file, append new SheetName node to end of SheetName nodes list
+      [shtidxnode, ss, ee] = getxmlnode (gnm_xml, "gnm:SheetNameIndex");
+      sh_node = sprintf('><gnm:SheetName gnm:Cols="1024" gnm:Rows="65536">%s</gnm:SheetName>',
+                         xls.sheets.sh_names{wsh});
+      ## Add close tag to ease up next strrep
+      sh_node = [ sh_node "</gnm:SheetNameIndex>" ];
+      shtidxnode = strrep (shtidxnode, "</gnm:SheetNameIndex>", sh_node);
+      ## Replace SheetNameIndex node
+      gnm_xml = [ gnm_xml(1:ss-1) shtidxnode gnm_xml(ee+1:end) ];
+    endif
   endif
 
   ## Rewind tmp sheet and read it behind gnm_xml
@@ -124,7 +136,7 @@
   fprintf (fidc, "%s", gnm_xml);
   fclose (fidc);
 
-  ## G. Update sheet pointers in ods file pointer
+  ## G. Update sheet pointers in ods/xls file pointer
   if (new_sh)
     xls.sheets.shtidx(wsh+1) = idx_s + lsheet;
     xls.changed = 2;
@@ -137,18 +149,18 @@
 endfunction
 
 
-function [ status ] = __OCT__oct2gnm_sh__ (fid, raw, wsh, lims, onc, onr)
+function [ status ] = __OCT__oct2gnm_sh__ (fid, raw, wsh, lims)
 
   ## Write out the lot to requested sheet
 
   ## 1. Sheet open tags
-  tag = 'gnm:Sheet DisplayFormulas="0" HideZero="0" HideGrid="0"';
+  tag = '<gnm:Sheet DisplayFormulas="0" HideZero="0" HideGrid="0"';
   tag = [ tag ' HideColHeader="0" HideRowHeader="0" DisplayOutlines="1"' ];
   tag = [ tag ' OutlineSymbolsBelow="1" OutlineSymbolsRight="1"' ];
   tag = [ tag ' Visibility="GNM_SHEET_VISIBILITY_VISIBLE" GridColor="0:0:0">' ];
   fprintf (fid, "%s", tag);
 
-  fprintf (fid, "<gnm:Name>Sheet%d</gnm:Name>", wsh);
+  fprintf (fid, "<gnm:Name>%s</gnm:Name>", wsh);
 
   fprintf (fid, "<gnm:MaxCol>%d</gnm:MaxCol><gnm:MaxRow>%d</gnm:MaxRow>", ...
            lims(1, 2) - 1, lims(2, 2) - 1);
@@ -163,30 +175,33 @@
     for jj=1:size (raw, 2)
       # lims(##, ##):lims(##, ##)
       ## Column # in gnumeric = 0-based
-      irow = lims(1, 2) - 2 + ii;
-      if (islogical (raw{ii, jj}))
+      icol = lims(2, 1) - 2 + jj;
+      if (isempty (raw{ii, jj}))
+        ## Do nothing
+
+      elseif (islogical (raw{ii, jj}))
         ## BOOLEAN. Convert to acceptable format for gnumeric
-        val = FALSE;
+        val = "FALSE";
         if (raw{ii, jj})
-          val = TRUE;
+          val = "TRUE";
         endif
-        fprintf (fid, '<gnm:Cell Row="%d" Col="%d" ValueType="20"></gnm:Cell>', ...
+        fprintf (fid, '<gnm:Cell Row="%d" Col="%d" ValueType="20">%s</gnm:Cell>', ...
                  irow, icol, val)
 
       elseif (isnumeric (raw{ii, jj}))
-        ## Any numric value; gnumeric only has FLOAT type
+        ## Any numeric value; gnumeric only has FLOAT type
         fprintf (fid, '<gnm:Cell Row="%d" Col="%d" ValueType="40">%f</gnm:Cell>', ...
                  irow, icol, raw{ii, jj});
 
       elseif (ischar (raw{ii, jj}))
         ## STRING
-        fprintf (fid, '<gnm:Cell Row="%d" Col="%d" ValueType="20">%s</gnm:Cell>', ...
+        fprintf (fid, '<gnm:Cell Row="%d" Col="%d" ValueType="60">%s</gnm:Cell>', ...
                  irow, icol, raw{ii, jj});
 
       else
         ## Do nothing, just skip
 
-      endswitch
+      endif
     endfor
   endfor
 
--- a/main/io/inst/private/__OCT_spsh_close__.m	Wed Apr 30 22:29:37 2014 +0000
+++ b/main/io/inst/private/__OCT_spsh_close__.m	Wed Apr 30 22:30:26 2014 +0000
@@ -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
@@ -33,7 +33,8 @@
 ## 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
+##     ''     cd out of tmp dir before removing it
+## 2014-04-30 Gnumeric write support
 
 function [xls] = __OCT_spsh_close__ (xls)
 
@@ -56,14 +57,27 @@
         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);
+        printf ("odsclose: could not zip ods contents in %s to %s\n", ...
+                xls.workbook, filename);
       end_try_catch;
     endif
 
   elseif (strcmpi (xls.filename(end-8:end), ".gnumeric"))
-    ## gnumeric files are gzipped
-    ## Delete temporary file
-    unlink (xls.workbook);
+    ## gnumeric files are gzipped
+    try
+      status = system (sprintf ("gzip -c -S=gnumeric %s > %s", ...
+               xls.workbook, filename));
+      if (! status)
+        ## Delete temporary file
+        unlink (xls.workbook);
+      endif
+    catch
+      status = 1;
+    end_try_catch
+    if (status)
+      printf ("odsclose: could not gzip gnumeric contents in %s to %s\n", ...
+              xls.workbook, filename);
+    endif
 
   endif
 
@@ -74,6 +88,5 @@
     confirm_recursive_rmdir (0, "local");
     rmdir (xls.workbook, "s");
   endif
-
 
 endfunction
--- a/main/io/inst/private/__OCT_spsh_open__.m	Wed Apr 30 22:29:37 2014 +0000
+++ b/main/io/inst/private/__OCT_spsh_open__.m	Wed Apr 30 22:30:26 2014 +0000
@@ -44,7 +44,8 @@
 ## 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)
+## 2014-03-18 Reinstate SheetId (was used somewhere after all)
+## 2014-04-30 Close file handle for gnumeric files
 
 function [ xls, xlssupport, lastintf] = __OCT_spsh_open__ (xls, xwrite, filename, xlssupport, ftype)
 
@@ -61,7 +62,7 @@
     elseif (ftype == 5)
       ext = ".gnumeric";
     endif
-    ## New file, get it from template
+    ## New file, get it from template. Use odsopen.m to find it
     templ = strrep (which ("odsopen"), "odsopen.m", ["templates" filesep "template" ext]);
   else
     templ = filename;
@@ -71,7 +72,9 @@
     ## Gnumeric xml files are gzipped
     system (sprintf ("gzip -d -c -S=gnumeric %s > %s", templ, tmpdir));
     fid = fopen (tmpdir, 'r');
-    xml = fread (fid, "char=>char").';
+    xml = fread (fid, "char=>char").';
+    ## Close file handle, don't delete file
+    fclose (fid);
   else
     ## xlsx and ods are zipped
     try