]> Creatis software - CreaPhase.git/blob - octave_packages/io-1.0.19/xlsopen.m
Add a useful package (from Source forge) for octave
[CreaPhase.git] / octave_packages / io-1.0.19 / xlsopen.m
1 ## Copyright (C) 2009,2010,2011,2012 Philip Nienhuis <prnienhuis at users.sf.net>
2 ## 
3 ## This program is free software; you can redistribute it and/or modify
4 ## it under the terms of the GNU General Public License as published by
5 ## the Free Software Foundation; either version 2 of the License, or
6 ## (at your option) any later version.
7 ## 
8 ## This program is distributed in the hope that it will be useful,
9 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
10 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 ## GNU General Public License for more details.
12 ## 
13 ## You should have received a copy of the GNU General Public License
14 ## along with Octave; see the file COPYING.  If not, see
15 ## <http://www.gnu.org/licenses/>.
16
17 ## -*- texinfo -*-
18 ## @deftypefn {Function File} @var{xls} = xlsopen (@var{filename})
19 ## @deftypefnx {Function File} @var{xls} = xlsopen (@var{filename}, @var{readwrite})
20 ## @deftypefnx {Function File} @var{xls} = xlsopen (@var{filename}, @var{readwrite}, @var{reqintf})
21 ## Get a pointer to an Excel spreadsheet in the form of return argument
22 ## (file pointer struct) @var{xls}. After processing the spreadsheet,
23 ## the file pointer must be explicitly closed by calling xlsclose().
24 ##
25 ## Calling xlsopen without specifying a return argument is fairly useless!
26 ##
27 ## To make this function work at all, you need MS-Excel (95 - 2003), and/or
28 ## the Java package >= 1.2.8 plus Apache POI >= 3.5 and/or JExcelAPI and/or
29 ## OpenXLS and/or OpenOffice.org (or clones) installed on your computer +
30 ## proper javaclasspath set. These interfaces are referred to as COM, POI,
31 ## JXL, OXS, and UNO, resp., and are preferred in that order by default
32 ## (depending on their presence).
33 ## For OOXML support, in addition to Apache POI support you also need the
34 ## following jars in your javaclasspath: poi-ooxml-schemas-3.5.jar,
35 ## xbean.jar and dom4j-1.6.1.jar (or later versions). Later OpenOffice.org
36 ## versions (UNO) have support for OOXML as well.
37 ## Excel'95 spreadsheets can only be read by JExcelAPI and OpenOffice.org.
38 ##
39 ## @var{filename} should be a valid .xls or xlsx Excel file name (including
40 ## extension). But if you use the COM interface you can specify any extension
41 ## that your installed Excel version can read AND write; the same goes for UNO
42 ## (OpenOffice.org). Using the other Java interfaces, only .xls or .xlsx are
43 ## allowed. If @var{filename} does not contain any directory path, the file
44 ## is saved in the current directory.
45 ##
46 ## If @var{readwrite} is set to 0 (default value) or omitted, the Excel file
47 ## is opened for reading. If @var{readwrite} is set to True or 1, an Excel
48 ## file is opened (or created) for reading & writing.
49 ##
50 ## Optional input argument @var{reqintf} can be used to override the Excel
51 ## interface that otherwise is automatically selected by xlsopen. Currently
52 ## implemented interfaces (in order of preference) are 'COM' (Excel/COM),
53 ## 'POI' (Java/Apache POI), 'JXL' (Java/JExcelAPI), 'OXS' (Java/OpenXLS), or
54 ## 'UNO' (Java/OpenOffice.org - EXPERIMENTAL!).
55 ## In most situations this parameter is unneeded as xlsopen automatically
56 ## selects the most useful interface present.
57 ##
58 ## Beware: Excel invocations may be left running invisibly in case of COM
59 ## errors or forgetting to close the file pointer. Similarly for OpenOffice.org
60 ## which may even prevent Octave from being closed.
61 ##
62 ## Examples:
63 ##
64 ## @example
65 ##   xls = xlsopen ('test1.xls');
66 ##   (get a pointer for reading from spreadsheet test1.xls)
67 ##
68 ##   xls = xlsopen ('test2.xls', 1, 'POI');
69 ##   (as above, indicate test2.xls will be written to; in this case using Java
70 ##    and the Apache POI interface are requested)
71 ## @end example
72 ##
73 ## @seealso {xlsclose, xlsread, xlswrite, xls2oct, oct2xls, xlsfinfo}
74 ##
75 ## @end deftypefn
76
77 ## Author: Philip Nienhuis
78 ## Created: 2009-11-29
79 ## Updates:
80 ## 2010-01-03 Added OOXML support
81 ## 2010-01-10 Changed (java) interface preference order to COM->POI->JXL
82 ## 2010-01-16 Removed echoeing debug info in POI stanza
83 ## 2010-03-01 Removed javaclasspath check for rt.jar
84 ## 2010-03-14 Fixed check on xwrite flag lines 204+, if xlsopen fails xls ptr
85 ##            should be []
86 ## 2010-08-25 Improved help text
87 ## 2010-09-27 Improved POI help message for unrecognized .xls format to hint for BIFF5/JXL
88 ## 2010-10-20 Improved code for tracking changes to new/existing files
89 ##     ''     Lots of code cleanup, improved error checking and catching
90 ##     ''     Implemented fallback to JXL if POI can't read a file.
91 ## 2010-10-30 More fine-grained file existence/writable checks
92 ## 2010-11-01 Added <COM>.Application.DisplayAlerts=0 in COM section to avoid Excel pop-ups
93 ## 2010-11-05 Option for multiple requested interface types (cell array)
94 ##     ''     Bug fix: JXL fallback from POI for BIFF5 is only useful for reading
95 ## 2010-11-05 Slight change to reporting to screen
96 ## 2010-11-08 Tested with POI 3.7 (OK)
97 ## 2010-11-10 Texinfo header updated
98 ## 2010-12-01 Small bugfix - reset xlssupport in l. 102
99 ## 2010-12-06 Textual changes to info header 
100 ## 2011-03-26 OpenXLS support added
101 ## 2011-05-18 Experimental UNO support added, incl. creating new spreadsheets
102 ## 2011-05-22 Textual changes in header
103 ## 2011-05-29 Cleanup of comments & messages
104 ## 2011-09-03 Reset chkintf to [] if no xls support was discovered (to allow
105 ##            rediscovery of interfaces between xlsopen calls, e.g. javaclasspath changes)
106 ## 2011-09-08 Minor code cleanup
107 ## 2012-01-26 Fixed "seealso" help string
108 ## 2012-06-06 Improved interface detection logic. No more messages if same interface is
109 ##            requested & used consecutively
110 ## 2012-06-07 Fixed mixed-up lastintf assignments for POI and JXL
111 ##
112 ## Latest subfunction update: 2012-06-06
113
114 function [ xls ] = xlsopen (filename, xwrite=0, reqinterface=[])
115
116   persistent xlsinterfaces; persistent chkintf; persistent lastintf;
117   # xlsinterfaces.<intf> = [] (not yet checked), 0 (found to be unsupported) or 1 (OK)
118   if (isempty (chkintf));
119       chkintf = 1;
120       xlsinterfaces = struct ('COM', [], 'POI', [], 'JXL', [], 'OXS', [], 'UNO', []);
121   endif
122   if (isempty (lastintf))
123     lastintf = "---";
124   endif
125
126   xlssupport = 0;
127
128   if (nargout < 1)
129       usage ("XLS = xlsopen (Xlfile [, Rw] [, reqintf]). But no return argument specified!"); 
130   endif
131
132   if (~(islogical (xwrite) || isnumeric (xwrite)))
133       usage ("Numerical or logical value expected for arg # 2")
134   endif
135
136   if (~isempty (reqinterface))
137     if ~(ischar (reqinterface) || iscell (reqinterface)), usage ("Arg # 3 not recognized"); endif
138     # Turn arg3 into cell array if needed
139     if (~iscell (reqinterface)), reqinterface = {reqinterface}; endif
140     ## Check if previously used interface matches a requested interface
141     if (isempty (regexpi (reqinterface, lastintf, 'once'){1}))
142       ## New interface requested
143       xlsinterfaces.COM = 0; xlsinterfaces.POI = 0; xlsinterfaces.JXL = 0;
144       xlsinterfaces.OXS = 0; xlsinterfaces.UNO = 0;
145       for ii=1:numel (reqinterface)
146         reqintf = toupper (reqinterface {ii});
147         # Try to invoke requested interface(s) for this call. Check if it
148         # is supported anyway by emptying the corresponding var.
149         if     (strcmpi (reqintf, 'COM'))
150           xlsinterfaces.COM = [];
151         elseif (strcmpi (reqintf, 'POI'))
152           xlsinterfaces.POI = [];
153         elseif (strcmpi (reqintf, 'JXL'))
154           xlsinterfaces.JXL = [];
155         elseif (strcmpi (reqintf, 'OXS'))
156           xlsinterfaces.OXS = [];
157         elseif (strcmpi (reqintf, 'UNO'))
158           xlsinterfaces.UNO = [];
159         else 
160           usage (sprintf ("Unknown .xls interface \"%s\" requested. Only COM, POI, JXL, OXS or UNO supported\n", reqinterface{}));
161         endif
162       endfor
163       printf ("Checking requested interface(s):\n");
164       xlsinterfaces = getxlsinterfaces (xlsinterfaces);
165       # Well, is/are the requested interface(s) supported on the system?
166       # FIXME check for multiple interfaces
167       xlsintf_cnt = 0;
168       for ii=1:numel (reqinterface)
169         if (~xlsinterfaces.(toupper (reqinterface{ii})))
170           # No it aint
171           printf ("%s is not supported.\n", upper (reqinterface{ii}));
172         else
173           ++xlsintf_cnt;
174         endif
175       endfor
176       # Reset interface check indicator if no requested support found
177       if (~xlsintf_cnt)
178         chkintf = [];
179         xls = [];
180         return
181       endif
182     endif
183   endif
184
185   # Var xwrite is really used to avoid creating files when wanting to read, or
186   # not finding not-yet-existing files when wanting to write.
187
188   # Check if Excel file exists. Adapt file open mode for readwrite argument
189   if (xwrite), fmode = 'r+b'; else fmode = 'rb'; endif
190   fid = fopen (filename, fmode);
191   if (fid < 0)            # File doesn't exist...
192     if (~xwrite)        # ...which obviously is fatal for reading...
193       error ( sprintf ("File %s not found\n", filename));
194     else              # ...but for writing, we need more info:
195       fid = fopen (filename, 'rb');  # Check if it exists at all...
196       if (fid < 0)      # File didn't exist yet. Simply create it
197         printf ("Creating file %s\n", filename);
198         xwrite = 3;
199       else            # File exists, but is not writable => Error
200         fclose (fid);  # Do not forget to close the handle neatly
201         error (sprintf ("Write mode requested but file %s is not writable\n", filename))
202       endif
203     endif
204   else
205     # Close file anyway to avoid COM or Java errors
206     fclose (fid);
207   endif
208   
209   # Check for the various Excel interfaces. No problem if they've already
210   # been checked, getxlsinterfaces (far below) just returns immediately then.
211   xlsinterfaces = getxlsinterfaces (xlsinterfaces);
212
213   # Supported interfaces determined; Excel file type check moved to seperate interfaces.
214   chk1 = strcmpi (filename(end-3:end), '.xls');      # Regular (binary) BIFF 
215   chk2 = strcmpi (filename(end-4:end-1), '.xls');    # Zipped XML / OOXML
216   
217   # Initialize file ptr struct
218   xls = struct ("xtype", 'NONE', "app", [], "filename", [], "workbook", [], "changed", 0, "limits", []); 
219
220   # Keep track of which interface is selected
221   xlssupport = 0;
222
223   # Interface preference order is defined below: currently COM -> POI -> JXL -> OXS -> UNO
224   if (xlsinterfaces.COM && ~xlssupport)
225     # Excel functioning has been tested above & file exists, so we just invoke it
226     app = actxserver ("Excel.Application");
227     try      # Because Excel itself can still crash on file formats etc.
228       app.Application.DisplayAlerts = 0;
229       if (xwrite < 2)
230         # Open workbook
231         wb = app.Workbooks.Open (canonicalize_file_name (filename));
232       elseif (xwrite > 2)
233         # Create a new workbook
234         wb = app.Workbooks.Add ();
235         ### Uncommenting the below statement can be useful in multi-user environments.
236         ### Be sure to uncomment correspondig stanza in xlsclose to avoid zombie Excels
237         # wb.SaveAs (canonicalize_file_name (filename))
238       endif
239       xls.app = app;
240       xls.xtype = 'COM';
241       xls.workbook = wb;
242       xls.filename = filename;
243       xlssupport += 1;
244       lastintf = 'COM';
245     catch
246       warning ( sprintf ("ActiveX error trying to open or create file %s\n", filename));
247       app.Application.DisplayAlerts = 1;
248       app.Quit ();
249       delete (app);
250     end_try_catch
251   endif
252   
253   if (xlsinterfaces.POI && ~xlssupport)
254     if ~(chk1 || chk2)
255       error ("Unsupported file format for Apache POI.")
256     endif
257     # Get handle to workbook
258     try
259       if (xwrite > 2)
260         if (chk1)
261           wb = java_new ('org.apache.poi.hssf.usermodel.HSSFWorkbook');
262         elseif (chk2)
263           wb = java_new ('org.apache.poi.xssf.usermodel.XSSFWorkbook');
264         endif
265           xls.app = 'new_POI';
266       else
267         xlsin = java_new ('java.io.FileInputStream', filename);
268         wb = java_invoke ('org.apache.poi.ss.usermodel.WorkbookFactory', 'create', xlsin);
269         xls.app = xlsin;
270       endif
271       xls.xtype = 'POI';
272       xls.workbook = wb;
273       xls.filename = filename;
274       xlssupport += 2;
275       lastintf = 'POI';
276     catch
277       clear xlsin;
278       if (xlsinterfaces.JXL)
279         printf ('Couldn''t open file %s using POI; trying Excel''95 format with JXL...\n', filename);
280       endif
281     end_try_catch
282   endif
283       
284   if (xlsinterfaces.JXL && ~xlssupport)
285     if (~chk1)
286       error ("JXL can only read reliably from .xls files")
287     endif
288     try
289       xlsin = java_new ('java.io.File', filename);
290       if (xwrite > 2)
291         # Get handle to new xls-file
292         wb = java_invoke ('jxl.Workbook', 'createWorkbook', xlsin);
293       else
294         # Open existing file
295         wb = java_invoke ('jxl.Workbook', 'getWorkbook', xlsin);
296       endif
297       xls.xtype = 'JXL';
298       xls.app = xlsin;
299       xls.workbook = wb;
300       xls.filename = filename;
301       xlssupport += 4;
302       lastintf = 'JXL';
303     catch
304       clear xlsin;
305       if (xlsinterfaces.POI)
306         printf ('... No luck with JXL either, unsupported file format.\n', filename);
307       endif
308     end_try_catch
309   endif
310
311   if (xlsinterfaces.OXS && ~xlssupport)
312     if (~chk1)
313       error ("OXS can only read from .xls files")
314     endif
315     try
316       wb = javaObject ('com.extentech.ExtenXLS.WorkBookHandle', filename);
317       xls.xtype = 'OXS';
318       xls.app = 'void - OpenXLS';
319       xls.workbook = wb;
320       xls.filename = filename;
321       xlssupport += 8;
322       lastintf = 'OXS';
323     catch
324       printf ('Unsupported file format for OpenXLS - %s\n');
325     end_try_catch
326   endif
327
328   if (xlsinterfaces.UNO && ~xlssupport)
329     # First, the file name must be transformed into a URL
330     if (~isempty (strmatch ("file:///", filename)) || ~isempty (strmatch ("http:///", filename))...
331       || ~isempty (strmatch ("ftp:///", filename)) || ~isempty (strmatch ("www:///", filename)))
332       # Seems in proper shape for OOo (at first sight)
333     else
334       # Transform into URL form
335       fname = canonicalize_file_name (strsplit (filename, filesep){end});
336       # On Windows, change backslash file separator into forward slash
337       if (strcmp (filesep, "\\"))
338         tmp = strsplit (fname, filesep);
339         flen = numel (tmp);
340         tmp(2:2:2*flen) = tmp;
341         tmp(1:2:2*flen) = '/';
342         fname = [ tmp{:} ];
343       endif
344       filename = [ 'file://' fname ];
345     endif
346     try
347       xContext = java_invoke ("com.sun.star.comp.helper.Bootstrap", "bootstrap");
348       xMCF = xContext.getServiceManager ();
349       oDesktop = xMCF.createInstanceWithContext ("com.sun.star.frame.Desktop", xContext);
350       # Workaround for <UNOruntime>.queryInterface():
351       unotmp = java_new ('com.sun.star.uno.Type', 'com.sun.star.frame.XComponentLoader');
352       aLoader = oDesktop.queryInterface (unotmp);
353       # Some trickery as Octave Java cannot create initialized arrays
354       lProps = javaArray ('com.sun.star.beans.PropertyValue', 1);
355       lProp = java_new ('com.sun.star.beans.PropertyValue', "Hidden", 0, true, []);
356       lProps(1) = lProp;
357       if (xwrite > 2)
358         xComp = aLoader.loadComponentFromURL ("private:factory/scalc", "_blank", 0, lProps);
359       else
360         xComp = aLoader.loadComponentFromURL (filename, "_blank", 0, lProps);
361       endif
362       # Workaround for <UNOruntime>.queryInterface():
363       unotmp = java_new ('com.sun.star.uno.Type', 'com.sun.star.sheet.XSpreadsheetDocument');
364       xSpdoc = xComp.queryInterface (unotmp);
365       # save in ods struct:
366       xls.xtype = 'UNO';
367       xls.workbook = xSpdoc;        # Needed to be able to close soffice in odsclose()
368       xls.filename = filename;
369       xls.app.xComp = xComp;        # Needed to be able to close soffice in odsclose()
370       xls.app.aLoader = aLoader;      # Needed to be able to close soffice in odsclose()
371       xls.odfvsn = 'UNO';
372       xlssupport += 16;
373       lastintf = 'UNO';
374     catch
375       error ('Couldn''t open file %s using UNO', filename);
376     end_try_catch
377   endif
378
379   # if 
380   #  ---- other interfaces
381   # endif
382
383   # Rounding up. If none of the xlsinterfaces is supported we're out of luck.
384   if (~xlssupport)
385     if (isempty (reqinterface))
386       printf ("None.\n");
387       warning ("No support for Excel .xls I/O"); 
388     else
389       warning ("File type not supported by %s %s %s %s %s", reqinterface{:});
390     endif
391     xls = [];
392     # Reset found interfaces for re-testing in the next call. Add interfaces if needed.
393     chkintf = [];
394   else
395     # From here on xwrite is tracked via xls.changed in the various lower
396     # level r/w routines and it is only used to determine if an informative
397     # message is to be given when saving a newly created xls file.
398     xls.changed = xwrite;
399
400     # Until something was written to existing files we keep status "unchanged".
401     # xls.changed = 0 (existing/only read from), 1 (existing/data added), 2 (new,
402     # data added) or 3 (pristine, no data added).
403     if (xls.changed == 1), xls.changed = 0; endif
404   endif
405   
406 endfunction
407
408
409 ## Copyright (C) 2009,2010,2011,2012 Philip Nienhuis <prnienhuis at users.sf.net>
410 ## 
411 ## This program is free software; you can redistribute it and/or modify
412 ## it under the terms of the GNU General Public License as published by
413 ## the Free Software Foundation; either version 2 of the License, or
414 ## (at your option) any later version.
415 ## 
416 ## This program is distributed in the hope that it will be useful,
417 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
418 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
419 ## GNU General Public License for more details.
420 ## 
421 ## You should have received a copy of the GNU General Public License
422 ## along with Octave; see the file COPYING.  If not, see
423 ## <http://www.gnu.org/licenses/>.
424
425 ## -*- texinfo -*-
426 ## @deftypefn {Function File} @var{xlsinterfaces} = getxlsinterfaces (@var{xlsinterfaces})
427 ## Get supported Excel .xls file read/write interfaces from the system.
428 ## Each interface for which the corresponding field is set to empty
429 ## will be checked. So by manipulating the fields of input argument
430 ## @var{xlsinterfaces} it is possible to specify which
431 ## interface(s) should be checked.
432 ##
433 ## Currently implemented interfaces comprise:
434 ## - ActiveX / COM (native Excel in the background)
435 ## - Java & Apache POI
436 ## - Java & JExcelAPI
437 ## - Java & OpenXLS (only JRE >= 1.4 needed)
438 ## - Java & UNO bridge (native OpenOffice.org in background) - EXPERIMENTAL!!
439 ##
440 ## Examples:
441 ##
442 ## @example
443 ##   xlsinterfaces = getxlsinterfaces (xlsinterfaces);
444 ## @end example
445
446 ## Author: Philip Nienhuis
447 ## Created: 2009-11-29
448 ## Last updates: 
449 ## 2009-12-27 Make sure proper dimensions are checked in parsed javaclasspath
450 ## 2010-09-11 Rearranged code and clarified messages about missing classes
451 ## 2010-09-27 More code cleanup
452 ## 2010-10-20 Added check for minimum Java version (should be >= 6 / 1.6)
453 ## 2010-11-05 Slight change to reporting to screen
454 ## 2011-02-15 Adapted to javaclasspath calling style of java-1.2.8 pkg
455 ## 2011-03-26 OpenXLS support added
456 ##      ''    Bug fix: javaclasspath change wasn't picked up between calls with req.intf
457 ## 2011-05-18 Experimental UNO support added
458 ## 2011-05-29 Reduced verbosity
459 ## 2011-06-06 Fix for javaclasspath format in *nix w java-1.2.8 pkg
460 ## 2011-06-13 Fixed potentially faulty tests for java classlib presence
461 ## 2011-09-03 Fixed order of xlsinterfaces.<member> statements in Java detection try-catch
462 ##      ''    Reset tmp1 (always allow interface rediscovery) for empty xlsinterfaces arg
463 ## 2011-09-08 Minor code cleanup
464 ## 2011-09-18 Added temporary warning about UNO interface
465 ## 2012-03-01 Changed UNO warning so that it is suppressed when UNO is not yet chosen
466 ## 2012-03-07 Only check for COM if run on Windows
467 ## 2012-03-21 Print newline if COM found but no Java support
468 ##     ''     Improved logic for finding out what interfaces to check
469 ##     ''     Fixed bugs with Java interface checking (tmp1 initialization)
470 ## 2012-06-06 Improved & simplified Java check code
471
472 function [xlsinterfaces] = getxlsinterfaces (xlsinterfaces)
473
474   # tmp1 = [] (not initialized), 0 (No Java detected), or 1 (Working Java found)
475   persistent tmp1 = []; persistent jcp;  # Java class path
476   persistent uno_1st_time = 0;
477
478   if (isempty (xlsinterfaces.COM) && isempty (xlsinterfaces.POI) && isempty (xlsinterfaces.JXL)
479    && isempty (xlsinterfaces.OXS) && isempty (xlsinterfaces.UNO))
480     # Looks like first call to xlsopen. Check Java support
481     printf ("Detected XLS interfaces: ");
482     tmp1 = [];
483   elseif (isempty (xlsinterfaces.POI) || isempty (xlsinterfaces.JXL)
484        || isempty (xlsinterfaces.OXS) || isempty (xlsinterfaces.UNO))
485     # Can't be first call. Here one of the Java interfaces is requested
486     if (~tmp1)
487       # Check Java support again
488       tmp1 = [];
489     endif
490   endif
491   deflt = 0;
492
493   # Check if MS-Excel COM ActiveX server runs (only on Windows!)
494   if (isempty (xlsinterfaces.COM))
495     xlsinterfaces.COM = 0;
496     if (ispc)
497       try
498         app = actxserver ("Excel.application");
499         # If we get here, the call succeeded & COM works.
500         xlsinterfaces.COM = 1;
501         # Close Excel. Yep this is inefficient when we need only one r/w action,
502         # but it quickly pays off when we need to do more with the same file
503         # (+, MS-Excel code is in OS cache anyway after this call so no big deal)
504         app.Quit();
505         delete(app);
506         printf ("COM");
507         if (deflt), printf ("; "); else, printf ("*; "); deflt = 1; endif
508       catch
509         # COM non-existent. Only print message if COM is explicitly requested (tmp1==[])
510         if (~isempty (tmp1))
511           printf ("ActiveX not working; no Excel installed?\n"); 
512         endif
513       end_try_catch
514     endif
515   endif
516
517   if (isempty (tmp1))
518     # Check Java support. First try javaclasspath
519     try
520       jcp = javaclasspath ('-all');              # For java pkg > 1.2.7
521       if (isempty (jcp)), jcp = javaclasspath; endif  # For java pkg < 1.2.8
522       # If we get here, at least Java works. Now check for proper version (>= 1.6)
523       jver = char (java_invoke ('java.lang.System', 'getProperty', 'java.version'));
524       cjver = strsplit (jver, '.');
525       if (sscanf (cjver{2}, '%d') < 6)
526         warning ("\nJava version might be too old - you need at least Java 6 (v. 1.6.x.x)\n");
527         return
528       endif
529       # Now check for proper entries in class path. Under *nix the classpath
530       # must first be split up. In java 1.2.8+ javaclasspath is already a cell array
531       if (isunix && ~iscell (jcp)); jcp = strsplit (char (jcp), ":"); endif
532       tmp1 = 1;
533     catch
534       # No Java support found
535       tmp1 = 0;
536       if (isempty (xlsinterfaces.POI) || isempty (xlsinterfaces.JXL)...
537         || isempty (xlsinterfaces.OXS) || isempty (xlsinterfaces.UNO))
538         # Some or all Java-based interface(s) explicitly requested but no Java support
539         warning (' No Java support found (no Java JRE? no Java pkg installed AND loaded?');
540       endif
541       # Set Java interfaces to 0 anyway as there's no Java support
542       xlsinterfaces.POI = 0;
543       xlsinterfaces.JXL = 0;
544       xlsinterfaces.OXS = 0;
545       xlsinterfaces.UNO = 0;
546       printf ("\n");
547       # No more need to try any Java interface
548       return
549     end_try_catch
550   endif
551
552   # Try Java & Apache POI
553   if (isempty (xlsinterfaces.POI))
554     xlsinterfaces.POI = 0;
555     # Check basic .xls (BIFF8) support
556     jpchk1 = 0; entries1 = {"poi-3", "poi-ooxml-3"};
557     # Only under *nix we might use brute force: e.g., strfind (classname, classpath);
558     # under Windows we need the following more subtle, platform-independent approach:
559     for ii=1:length (jcp)
560       for jj=1:length (entries1)
561         if (isempty (strfind (tolower (jcp{ii}), entries1{jj}))), ++jpchk1; endif
562       endfor
563     endfor
564     if (jpchk1 > 1)
565       xlsinterfaces.POI = 1;
566       printf ("POI");
567     endif
568     # Check OOXML support
569     jpchk2 = 0; entries2 = {"xbean", "poi-ooxml-schemas", "dom4j"};
570     for ii=1:length (jcp)
571       for jj=1:length (entries2)
572         if (isempty (strfind (lower (jcp{ii}), entries2{jj}))), ++jpchk2; endif
573       endfor
574     endfor
575     if (jpchk2 > 2), printf (" (& OOXML)"); endif
576     if (xlsinterfaces.POI)
577       if (deflt), printf ("; "); else, printf ("*; "); deflt = 1; endif
578     endif
579   endif
580
581   # Try Java & JExcelAPI
582   if (isempty (xlsinterfaces.JXL))
583     xlsinterfaces.JXL = 0;
584     jpchk = 0; entries = {"jxl"};
585     for ii=1:length (jcp)
586       for jj=1:length (entries)
587         if (isempty (strfind (lower (jcp{ii}), entries{jj}))), ++jpchk; endif
588       endfor
589     endfor
590     if (jpchk > 0)
591       xlsinterfaces.JXL = 1;
592       printf ("JXL");
593       if (deflt), printf ("; "); else, printf ("*; "); deflt = 1; endif
594     endif
595   endif
596
597   # Try Java & OpenXLS
598   if (isempty (xlsinterfaces.OXS))
599     xlsinterfaces.OXS = 0;
600     jpchk = 0; entries = {"openxls"};
601     for ii=1:length (jcp)
602       for jj=1:length (entries)
603         if (isempty (strfind (lower (jcp{ii}), entries{jj}))), ++jpchk; endif
604       endfor
605     endfor
606     if (jpchk > 0)
607       xlsinterfaces.OXS = 1;
608       printf ("OXS");
609       if (deflt), printf ("; "); else, printf ("*; "); deflt = 1; endif
610     endif
611   endif
612
613   # Try Java & UNO
614   if (isempty (xlsinterfaces.UNO))
615     xlsinterfaces.UNO = 0;
616     # entries0(1) = not a jar but a directory (<00o_install_dir/program/>)
617     jpchk = 0; entries = {'program', 'unoil', 'jurt', 'juh', 'unoloader', 'ridl'};
618     for jj=1:numel (entries)
619       for ii=1:numel (jcp)
620         jcplst = strsplit (jcp{ii}, filesep);
621         jcpentry = jcplst {end};
622         if (~isempty (strfind (lower (jcpentry), lower (entries{jj})))); ++jpchk; endif
623       endfor
624     endfor
625     if (jpchk >= numel (entries))
626       xlsinterfaces.UNO = 1;
627       printf ('UNO');
628       if (deflt), printf ("; "); else, printf ("*; "); deflt = 1; uno_1st_time = min (++uno_1st_time, 2); endif
629     endif
630   endif
631
632   # ---- Other interfaces here, similar to the ones above
633
634   if (deflt), printf ("(* = active interface)\n"); endif
635
636   ## FIXME the below stanza should be dropped once UNO is stable.
637   # Echo a suitable warning about experimental status:
638   if (uno_1st_time == 1)
639     ++uno_1st_time;
640     printf ("\nPLEASE NOTE: UNO (=OpenOffice.org-behind-the-scenes) is EXPERIMENTAL\n");
641     printf ("After you've opened a spreadsheet file using the UNO interface,\n");
642     printf ("xlsclose on that file will kill ALL OpenOffice.org invocations,\n");
643     printf ("also those that were started outside and/or before Octave!\n");
644     printf ("Trying to quit Octave w/o invoking xlsclose will only hang Octave.\n\n");
645   endif
646
647 endfunction