1 ## Copyright (C) 2009,2010,2011,2012 Philip Nienhuis <prnienhuis at users.sf.net>
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.
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.
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/>.
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().
25 ## Calling xlsopen without specifying a return argument is fairly useless!
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.
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.
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.
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.
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.
65 ## xls = xlsopen ('test1.xls');
66 ## (get a pointer for reading from spreadsheet test1.xls)
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)
73 ## @seealso {xlsclose, xlsread, xlswrite, xls2oct, oct2xls, xlsfinfo}
77 ## Author: Philip Nienhuis
78 ## Created: 2009-11-29
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
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
112 ## Latest subfunction update: 2012-06-06
114 function [ xls ] = xlsopen (filename, xwrite=0, reqinterface=[])
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));
120 xlsinterfaces = struct ('COM', [], 'POI', [], 'JXL', [], 'OXS', [], 'UNO', []);
122 if (isempty (lastintf))
129 usage ("XLS = xlsopen (Xlfile [, Rw] [, reqintf]). But no return argument specified!");
132 if (~(islogical (xwrite) || isnumeric (xwrite)))
133 usage ("Numerical or logical value expected for arg # 2")
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 = [];
160 usage (sprintf ("Unknown .xls interface \"%s\" requested. Only COM, POI, JXL, OXS or UNO supported\n", reqinterface{}));
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
168 for ii=1:numel (reqinterface)
169 if (~xlsinterfaces.(toupper (reqinterface{ii})))
171 printf ("%s is not supported.\n", upper (reqinterface{ii}));
176 # Reset interface check indicator if no requested support found
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.
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);
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))
205 # Close file anyway to avoid COM or Java errors
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);
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
217 # Initialize file ptr struct
218 xls = struct ("xtype", 'NONE', "app", [], "filename", [], "workbook", [], "changed", 0, "limits", []);
220 # Keep track of which interface is selected
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;
231 wb = app.Workbooks.Open (canonicalize_file_name (filename));
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))
242 xls.filename = filename;
246 warning ( sprintf ("ActiveX error trying to open or create file %s\n", filename));
247 app.Application.DisplayAlerts = 1;
253 if (xlsinterfaces.POI && ~xlssupport)
255 error ("Unsupported file format for Apache POI.")
257 # Get handle to workbook
261 wb = java_new ('org.apache.poi.hssf.usermodel.HSSFWorkbook');
263 wb = java_new ('org.apache.poi.xssf.usermodel.XSSFWorkbook');
267 xlsin = java_new ('java.io.FileInputStream', filename);
268 wb = java_invoke ('org.apache.poi.ss.usermodel.WorkbookFactory', 'create', xlsin);
273 xls.filename = filename;
278 if (xlsinterfaces.JXL)
279 printf ('Couldn''t open file %s using POI; trying Excel''95 format with JXL...\n', filename);
284 if (xlsinterfaces.JXL && ~xlssupport)
286 error ("JXL can only read reliably from .xls files")
289 xlsin = java_new ('java.io.File', filename);
291 # Get handle to new xls-file
292 wb = java_invoke ('jxl.Workbook', 'createWorkbook', xlsin);
295 wb = java_invoke ('jxl.Workbook', 'getWorkbook', xlsin);
300 xls.filename = filename;
305 if (xlsinterfaces.POI)
306 printf ('... No luck with JXL either, unsupported file format.\n', filename);
311 if (xlsinterfaces.OXS && ~xlssupport)
313 error ("OXS can only read from .xls files")
316 wb = javaObject ('com.extentech.ExtenXLS.WorkBookHandle', filename);
318 xls.app = 'void - OpenXLS';
320 xls.filename = filename;
324 printf ('Unsupported file format for OpenXLS - %s\n');
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)
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);
340 tmp(2:2:2*flen) = tmp;
341 tmp(1:2:2*flen) = '/';
344 filename = [ 'file://' fname ];
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, []);
358 xComp = aLoader.loadComponentFromURL ("private:factory/scalc", "_blank", 0, lProps);
360 xComp = aLoader.loadComponentFromURL (filename, "_blank", 0, lProps);
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:
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()
375 error ('Couldn''t open file %s using UNO', filename);
380 # ---- other interfaces
383 # Rounding up. If none of the xlsinterfaces is supported we're out of luck.
385 if (isempty (reqinterface))
387 warning ("No support for Excel .xls I/O");
389 warning ("File type not supported by %s %s %s %s %s", reqinterface{:});
392 # Reset found interfaces for re-testing in the next call. Add interfaces if needed.
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;
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
409 ## Copyright (C) 2009,2010,2011,2012 Philip Nienhuis <prnienhuis at users.sf.net>
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.
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.
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/>.
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.
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!!
443 ## xlsinterfaces = getxlsinterfaces (xlsinterfaces);
446 ## Author: Philip Nienhuis
447 ## Created: 2009-11-29
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
472 function [xlsinterfaces] = getxlsinterfaces (xlsinterfaces)
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;
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: ");
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
487 # Check Java support again
493 # Check if MS-Excel COM ActiveX server runs (only on Windows!)
494 if (isempty (xlsinterfaces.COM))
495 xlsinterfaces.COM = 0;
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)
507 if (deflt), printf ("; "); else, printf ("*; "); deflt = 1; endif
509 # COM non-existent. Only print message if COM is explicitly requested (tmp1==[])
511 printf ("ActiveX not working; no Excel installed?\n");
518 # Check Java support. First try javaclasspath
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");
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
534 # No Java support found
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?');
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;
547 # No more need to try any Java interface
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
565 xlsinterfaces.POI = 1;
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
575 if (jpchk2 > 2), printf (" (& OOXML)"); endif
576 if (xlsinterfaces.POI)
577 if (deflt), printf ("; "); else, printf ("*; "); deflt = 1; endif
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
591 xlsinterfaces.JXL = 1;
593 if (deflt), printf ("; "); else, printf ("*; "); deflt = 1; endif
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
607 xlsinterfaces.OXS = 1;
609 if (deflt), printf ("; "); else, printf ("*; "); deflt = 1; endif
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)
620 jcplst = strsplit (jcp{ii}, filesep);
621 jcpentry = jcplst {end};
622 if (~isempty (strfind (lower (jcpentry), lower (entries{jj})))); ++jpchk; endif
625 if (jpchk >= numel (entries))
626 xlsinterfaces.UNO = 1;
628 if (deflt), printf ("; "); else, printf ("*; "); deflt = 1; uno_1st_time = min (++uno_1st_time, 2); endif
632 # ---- Other interfaces here, similar to the ones above
634 if (deflt), printf ("(* = active interface)\n"); endif
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)
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");