io/0000755000076400010400000000000012263601446012477 5ustar PhilipAdministratorsio/COPYING0000644000076400010400000010451312217071420013526 0ustar PhilipAdministrators GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . io/DESCRIPTION0000644000076400010400000000074012263333160014201 0ustar PhilipAdministratorsName: io Version: 2.0.2 Date: 2014-01-09 Author: various authors Maintainer: Philip Nienhuis 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) Suggested: windows (>= 1.2.1) Autoload: no License: GPLv3+, simplified BSD Url: http://octave.sf.net io/doc/0000755000076400010400000000000012263601446013244 5ustar PhilipAdministratorsio/doc/READ-ODS.html0000644000076400010400000011573212262364326015303 0ustar PhilipAdministrators

ODS support for Octave

Copyright © 2009 - 2013 Philip Nienhuis <prnienhuis at users.sf.net>

This version December 30, 2013

(ODS = Open Document Format spreadsheet data format, used by e.g., OpenOffice.org.)

Files content

odsread.m
No-hassle read script for reading from an ODS file and parsing the numeric and text data into separate arrays.

odswrite.m
No-hassle write script for writing to an ODS file.

odsopen.m 
Get a file pointer to an ODS spreadsheet file.

ods2oct.m
Read raw data from an ODS spreadsheet file using the file pointer handed by odsopen.

oct2ods.m
Write data to an ODS spreadsheet file using the file pointer handed by odsopen.

odsclose.m
Close file handle made by odsopen and -if data have been transfered to a spreadsheet- save data.

odsfinfo.m
Explore sheet names and optionally estimated data size of ods files with unknown content.

calccelladdress.m
Utility function, can be used to compute a spreadsheet-type cell adress from 1-based row and column numbers.

parsecell.m
(contained in Excel xlsread scripts, but works also for ods support) parse raw data (cell array) into separate numeric array and text (cell) array.)

chk_spreadsheet_support.m
Internal function for (1) checking, (2) setting up, (3) debugging spreadsheet support. While not specifically meant for direct invocation from the Octave prompt (it is more useful during initialization of Octave itself) it can be very helpful when hunting down issues with spreadsheet support in Octave.

test_spsh.m, io_ods_testscript.m
Undocumented scripts for testing basic operation of ODS spreadsheet functions. Meant for testers and developers, but I don't mind if mere mortal users give it a try as well ;-)


REQUIRED SUPPORT SOFTWARE

(Apart from io package >= 1.3.5 :)

  • For just read support: Octave > 3.7.2 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:

  • odfdom.jar currently the preferred option)
    (only versions 0.7.5, 0.8.6, 0.8.7 and 0.8.8 (the latter from incubator v. 0.5, see download URL below) work OK!) & xercesImpl.jar (watch out here too! only version 2.9.1 (2007-sep-14) works OK with odfdom). Get them here:


  • and/or

    • jopendocument<version>.jar. Get it from http://www.jopendocument.org

      (jOpenDocument 1.3 (final) is the most recent one and recommended for Octave)


    and/or

    • OpenOffice.org (or clones like LibreOffice, Go-Office, ...). Get it from http://www.openoffice.org. The relevant Java class libs are unoil.jar, unoloader.jar, jurt.jar, juh.jar and ridl.jar (which are scattered around the OOo installation directory), while also the <OOo>/program/ directory needs to be in the classpath.

    These class libs must be referenced with full pathnames in your javaclasspath.
    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 class libs there; if they are elsewhere, add them in ./share/octave/<version>/m/startup/octaverc using appropriate javaaddpath statements or a chk_spreadsheet_support() call.
    In addition, you can specify a subdirectory using the environment variable OCTAVE_IO_JAVALIBS.
    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:

    1. Specified by the environment variable OCTAVE_IO_JAVALIBS
    2. <HOME_DIR>/java
    3. /usr/share/java (*nix) or /lib/java (MinGW)
    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.


    USAGE

    (see “help ods<function_filename>” in octave terminal.)

    odsread is a sort of analog to xlsread and works more or less the same. odsread is a mere wrapper for the functions odsopen, ods2oct, and odsclose that do file access and the actual reading, plus parsecell for post-processing.

    odswrite works similar to xlswrite. It too is a wrapper for scripts which do the actual work and invoke other scripts, a.o. oct2ods.

    odsfinfo can be used to explore odsfiles with unknown content for sheet names and to get an impression of the data content sizes.

    When you need data from just one sheet, odsread is for you. But when you need data from multiple sheets in the same spreadsheet file, or if you want to process spreadsheet data by limited-size chunks at a time, odsopen / ods2oct [/parsecell] / … / odsclose sequences provides for much more speed and flexibility as the spreadsheet needs to be read just once rather than repeatedly for each call to odsread.

    Same reasoning goes for odswrite.

    Also, if you use odsopen / …../, you can process multiple spreadsheets simultaneously – just use odsopen repeatedly to get multiple spreadsheet file pointers.

    Moreover, after adding data to an existing spreadsheet file, you can fiddle with the filename in the ods file pointer struct to save the data into another, possibly new spreadsheet file.

    If you use odsopen / ods2oct / … / oct2ods / …. / odsclose, DO NOT FORGET to invoke odsclose in the end. The file pointers can contain an enormous amount of data and may needlessly keep precious memory allocated. In case of the UNO interface, the hidden OpenOffice.org invocation (soffice.bin) can even block proper closing of Octave.


    SPREADSHEET FORMULA SUPPORT

    When using the OTK, UNO, and/or OCT interface you can:
    • (When reading, ods2oct) either read spreadsheet formula results, or the literal formula text strings;
    • (When writing, oct2ods) either enter formulas in the worksheet as formulas, or enter them as literal text strings.
    In short, you can enter spreadsheet formulas and in a later stage read them back, change them and re-enter them in the worksheet. The behaviour is controlled by an option structure options (as last argument to oct2ods.m and ods2oct.m) which for now has only one (logical) field:
    • options.formulas_as_text = 0 (the default) implies enter formulas as formulas and read back formula results
    • options.formulas_as_text =1 (or any positive integer) means enter formulas as text strings and read them back as text strings.
    Be aware that there's no formula evaluator in ODS java, not even a formula validator. So if you create formulas in your spreadsheet using oct2ods or odswrite, do not expect meaningful results when reading those files later on unless you open them in OpenOffice.org Calc and write them back to disk.
    You can write all kind of junk as a formula into a spreadsheet cell. There's not much validity checking built into odfdom.jar. I didn't bother to try OpenOffice.org Calc to read such faulty spreadsheets, so I don't know what will happen with spreadsheets containing invalid formulas. But using the above options, you can at least repair them using octave....
    The only exception is if you select the UNO interface, as that invokes OpenOffice.org behind the scenes, and OOo obviously has a validator and evaluator built-in.

    GOTCHAS

    I know of one big gotcha: i.e. reading dates (& time). A less obvious one is Java memory pool allocation size.

    Date and time in ODS

    Octave (as does Matlab) stores dates as a number representing the number of days since January 1, 0 (and as an aside ignores a.o. Pope Gregorius' intervention in 1582 when 10 days were simply skipped).

    OpenOffice.org stores dates as text strings like “yyyy-mm-dd”.

    MS-Excel stores dates as a number representing the number of days since January 1, 1900 (and as an aside, erroneously assumes 1900 to be a leap year).

    Now, converting OpenOffice.org date cell values (actually, character strings flagged by “date” attributes) into Octave looks pretty straightforward. But when the ODS spreadsheet was originally an Excel spreadsheet converted by OpenOffice.org, the date cells can either be OOo date values (i.e.,strings) OR old numerical values from the Excel spreadsheet.

    So: you should carefully check what happens to date cells.

    As octave has no ”date” or “time” data type, octave date values (usually numerical data) are simply transferred as “floats” to ODS spreadsheets. You'll have to convert the values into dates yourself from within OpenOffice.org.

    While adding data and time values has been implemented in the write scripts, the wait is for clever solutions to distinguish dates from floats in octave cell arrays.

    Java memory pool allocation size

    The Java virtual machine (JVM) initializes one big chunk of your computer's RAM in which all Java classes and methods etc. are to be loaded: the Java memory pool. It does this because Java has a very sophisticated “garbage collection” system. At least on Windows, the initial size is 2MB and the maximum size is 64MB. On Linux this allocated size is much bigger. This part of memory is where the Java-based ODS octave routines (and the Java-based ods routines) live and keep their variables etc.

    For transferring large pieces of information to and from spreadsheets you might hit the limits of this pool. E.g. to be able to handle I/O of an array of around 50,000 cells I needed a memory pool size of 512 MB.

    The memory size can be increased by inserting a file called “java.opts” (without quotes) in the directory ./share/octave/packages/java-<version> (where the script file javaclasspath.m is located), containing just the following lines:

    -Xms16m
    -Xmx512m

    (where 16 = initial size, 512 = maximum size (in this example), m stands for Megabyte. This number is system-dependent).

    After processing a large chunk of spreadsheet information you might notice that octave's memory footprint does not shrink so it looks like Java's memory pool does not shrink back; but rest assured, the memory footprint is the allocated (reserved) memory size, not the actual used size. After the JVM has done its garbage collection, only the so-called “working set” of the memory allocation is really in use and that is a trimmed-down part of the memory allocation pool. On Windows systems it often suffices to minimize the octave terminal for a few seconds to get a more reasonable memory footprint.

    Reading cells containing errors

    Spreadsheet cells containing erroneous stuff are transferred to Octave as NaNs. But not all errors can be catched. Cells showing #Value# in OpenOffice.org Calc often contain invalid formulas but may have a 0 (null) value stored in the value fields. It is impossible to catch this as there is no run-time formula evaluator (yet) in ODF Toolkit nor jOpenDocument (like there is in Apache POI for Excel).

    Smaller gotcha's (only with jOpenDocument 1.2b2, fixed in 1.2b3+ and 1.2 final):

    • While reading, empty cells are sometimes not skipped but interpreted with numerical value 0 (zero).

    • A valid range MUST be specified, I haven't found a way to discover the actual occupied rows and columns (jOpenDocument can give the physical ones (= capacity) but that doesn't help).

    NOT fixed in version 1.2 final nor 1.3b1:

    • jOpenDocument doesn't set the so-called <office:value-type='string'> attribute in cells containing text; as a consequence ODF Toolkit will treat them as empty cells. Ooo will read them OK.


    MATLAB COMPATIBILITY

    Depending on the MS-Excel version on the same computer, Matlab may read/write ODS files using xlsread/xlswrite. Note that decent ODS 1.2 support only started with Excel 2013.
    odsread is fairly function-compatible to xlsread, however.

    Same goes for odswrite, odsfinfo and xlsfinfo – however odsfinfo has better functionality IMO.


    COMPARISON OF INTERFACES

    The ODFtoolkit is the one that gives the best (but slow) results at present. However, parsing xml trees into rectangular arrays is not quite straightforward and the other way round is a real nightmare; odftoolkit up til 0.7.5. did little to hide the gory details for the developers.

    While reading ODS is still OK, writing implies checking whether cells already exist explicitly (in table:table-cells) or implicitly (in number-columns-repeated or number-rows-repeated nodes) or not at all yet in which case you'll need to add various types of parent nodes. Inserting new cells (“nodes”) or deleting nodes implies rebuilding possibly large parts of the tree in memory - nothing for the faint-of-heart. Only with ODFToolkit (odfdom) 0.8.6 and 0.8.7 things have been simplified for developers.

    The jOpenDocument interface is more promising, as it does shield the xml tree details and presents developers something which looks like a spreadsheet model.
    However, unfortunately the developers decided to shield essential methods by making them 'protected' (e.g. the vital getCellType). JopenDocument does support writing. But OTOH many obvious methods are still lacking and formula support is absent.
    And last (but not least) the jOpenDocument developers state that their development is primarily driven by requests from customers who pay for support. I do sympathize with this business model but for octave needs this may hamper progress for a while.
    In addition, jOpenDocument 1.2 and 1.3b1 still have bugs here and there. For one, it doesn't write appropriate OfficeValueType attributes to the cells, so there's no way to reliably read and distinguish boolean, string and integer values.

    The (still experimental) UNO interface, based on a Java/UNO bridge linking a hidden OpenOffice.org invocation to Octave, is the most promising:

    • Admittedly OOo needs some tens of seconds to start for the first time, but once OOo is in the operating system's disk cache, it operates much faster than ODF or JOD;
    • It has built-in formula validator and evaluator;
    • It has a much more reliable data parser;
    • It can read much more spreadsheet formats than just ODS; .sxc (older OOo and StarOffice), but also .xls, .xlsx (Excel), .wk1 (Lotus 123), dbf, etc.
    • It consumes only a fraction of the JVM heap memory that the other Java ODS spreadsheet solutions need because OOo reads the spreadsheet in its own memory chunk in RAM. The other solutions read, expand, parse and manipulate all data in the JVM. In addition, OOo's code is outside the JVM (and Octave) while the ODF Toolkit and jOpenDocument classes also reside in the JVM.
    However, UNO is not stable yet (see below)..

    The OCT (native Octave) 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.
    Write support is underway but may be appearing only in 2015, depending on time and resources of the io package developers.

    TROUBLESHOOTING

    Some hints for troubleshooting ODS support are given here.
    Since April 2011 the function chk_spreadsheet_support() has been included in the io package. Calling it with arguments ('', 3) (empty string and debug level 3) will echo a lot of diagnostics to the screen. Large parts of the steps outlined below have been automated in this script.
    Problems with UNO are too complicated to treat them here; most of the troubleshooting has been implemented in chk_spreadsheet_support.m, only some general guidelines are given below.

    1. Check if Java works. Do a pkg list and see

      a. If there's a Java package mentioned (then it's installed). If not, install it.

      b. If there's an asterisk on the java package line (then the package is loaded). If not, do a pkg rebuild-auto java

    1. Check Java memory settings. Try javamem

      a. If it works, check if it reports sufficiently large max memory (had better be 200 MiB, the bigger the better)

      b. If it doesn't work, do:

        rt = java_invoke ('java.lang.Runtime', 'getRuntime')

        rt.gc

        rt.maxMemory ().doubleValue () / 1024 / 1024

        The last command will show MaxMemory in MiB.

      c. In case you have insufficient memory, see in “GOTCHAS”, “Java memory pool allocation size”, how to increase java's memory pre-reservation.

    2. Check if all classes (.jarfiles) are in class path. Do a 'jcp = javaclasspath (-all)'  (under unix/linux, do 'jcp = javaclasspath; strsplit (jcp,”:”)' (w/o quotes). See above under “REQUIRED SUPPORT SOFTWARE” what classes should be mentioned.

      If classes (.jar files) are missing, download and put them somewhere and add them to the javaclass path with their fully qualified pathname (in quotes) using javaaddpath().

    Once all classes are present and in the javaclasspath, the ods interfaces should just work. The only remaining showstoppers are insufficient write privileges for the working directory, a wrecked up octave or some other problems outside octave.

    1. Try opening an ods file:

      ods1 = odsopen ('test.ods', 1, 'otk'). If this works and ods1 is a struct with various fields containing objects, ODF toolkit interface (OTK) works. Do an ods1 = odsclose (ods1) to close the file.

      ods2 = odsopen ('test.ods', 1, 'jod'). If this works and ods2 is a struct with various fields containing objects, jOpenDocument interface (JOD) works as well. Do ods2 = odsclose (ods2) to close the file.

    2. For the UNO interface, at least version 1.2.8 of the Java package is needed plus the following Java class libs (jars) and directory:
      * unoil.jar (usually found in subdirectory Basis<version>/program/classes/ or the like of the OpenOffice.org (<OOo>) installation directory;
      * juh.jar, jurt.jar, unoloader.jar and ridl.jar, usually found in the subdirectory URE/share/java/ (or the like) of OOo's installation directory;
      * The subdirectory program/ (where soffice[.exe] (or ooffice) resides).
      The exact case (URE or ure, Basis or basis), name ("Basis3.2" or just "basis") and subdirectory tree (URE/java or URE/share/java) varies across OOo versions and -clones, so chk_spreadsheet_support.m can have a hard time finding all needed classes. In particularly bad cases, when chk_spreadsheet_support cannot find them, you might need to add one or more of these these classes manually to the javaclasspath.


    DEVELOPMENT

    As with the Excel r/w stuff, adding new interfaces should be easy and straightforward. Add relevant stanzas for your new interface INTF in odsopen, odsclose, odsfinfo, oct2ods, ods2oct, getusedrange 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).

    Suggestions for future development:

    • Reliable and easy ODS write support (maybe when jOpenDocument is more mature)
    • Speeding up (ODS is 10 X slower than e.g. OOXML !!!). jOpenDocument is much faster but still immature.
      UNO *is* MUCH faster than jOpenDocument but starting up OpenOffice.org for the first time can take tens of seconds...
      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 through Octave! This is related to UNO-Java limitations.
      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.
      A way out hasn't been found yet.

    • Passing function handle” a la Matlab's xlsread

    • Adding styles (borders, cell lay-out, font, etc.)

    Some notes on the choice for Java:
    1. 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.
    2. A BIG advantage is that a Java-based solution is platform-independent (“portable”).
    3. But Java is known to be not very conservative with resources, especially not when processing XML-based formats.
    So Java is a compromise between portability and rapid development time versus capacity (and speed).
    But IMO data sets larger than 5.105 cells should not be kept in spreadsheets anyway. Use real databases for such data sets.

    ODFDOM versions

    I have tried various odfdom versions. As to 0.8 & 0.8.5, while the API has been simplified enormously (finally one can address cells by spreadsheet address rather than find out yourself by parsing the table-column/-row/-cell structure), many irrecoverable bugs have been introduced :-((
    In addition processing ODS files became significantly slower (up to 7 times!).

    End of August 2010 there's implemented support for odfdom-0.8.6.jar – that version is at last sufficiently reliable to use. The few remaining bugs and limitations could easily be worked around by diving in the older TableTable API. Later on (early 2011) version 0.8.7 has been tested too - this needed a few adjustments. Early 2012 odfdom-0.8.8 (from odfdom-0.5-incubator) was accepted. Aug. 2013 odfdom-0.8.9 (odfdom-0.6-incubator) was tested but alas, it doesn't work; clearly the odfdom API (currently at main version 0) is not stable yet.
    So at the moment (August 2012 = last I looked) only odfdom versions 0.7.5, 0.8.6, 0.8.7 and 0.8.8(-incubator) are supported.

    If you want to experiment with odfdom 0.8 & 0.8.5, you can try:
    • odsopen.m (revision 7157)
    • ods2oct.m (revision 7158)
    • oct2ods.m (revision 7159)

    Enjoy!

    Philip Nienhuis, December 30, 2013


    io/doc/READ-XLS.html0000644000076400010400000010670112262364344015320 0ustar PhilipAdministrators

    README for Excel spreadsheet file r/w access scripts for octave (> 3.7.2)

    Copyright (C) 2009 - 2013 Philip Nienhuis <prnienhuis at users.sf.net>

    This version December 30, 2012

    EXCEL .XLS SUPPORT FILES


    doc/README-XLS.html
    This file.

    xlsread.m
    All-in-one function for reading data from one specific worksheet in an Excel spreadsheet file. This script has Matlab-compatible functionality.

    xlswrite.m
    All-in-one function for writing data to one specific worksheet in an Excel spreadsheet file. This script has Matlab-compatible functionality.

    xlsfinfo.m
    All-in-one function for exploring basic properties of an Excel spreadsheet file. This script has Matlab-compatible functionality.

    xlsopen.m
    Function for "opening" (= providing a handle to) an Excel spreadsheet file ("workbook"). This function sorts out which interface to use for .xls access (i.e.,COM; Java & Apache POI; JexcelAPI; OpenXLS; etc.), but it's choice can be overridden.

    xls2oct.m
    Function for reading data from a specific worksheet pointed to in a struct created by xlsopen.m. xls2oct can be called multiple times consecutively using the same pointer struct, each time allowing to read data from different ranges and/or worksheets. Data are returned in the form of a 2D heterogeneous cell array that can be parsed by parsecell.m. xls2oct is a mere wrapper for interface-dependent scripts that do the actual low-level reading.

    oct2xls.m
    Function for writing data to a specific worksheet pointed to in a struct created by xlsopen.m. octxls can be called multiple times consecutively using the same pointer struct, each time allowing to write data to different ranges and/or worksheets. oct2xls is a mere wrapper for interface-dependent scripts that do the actual low-level writing.

    xlsclose.m
    Function for closing (the handle to) an Excel workbook. When data have been written to the workbook oct2xls will write the workbook to disk. Otherwise, the file pointer is simply closed and possibly used interfaces for Excel access (COM/ActiveX/Excel.exe) will be shut down properly.

    parsecell.m
    Function for separating the data in raw arrays returned by xls2oct, into numerical/logical and text (cell) arrays.

    chk_spreadsheet_support.m
    Internal function for (1) checking, (2) setting up, (3) debugging spreadsheet support. While not specifically meant for direct invocation from the Octave prompt (it is more useful during initialization of Octave itself) it can be very helpful when hunting down issues with spreadsheet support in Octave.
    calccelladdress.m,
    Support function called by the script functions; calculates spreadsheet type row/column address based on 1-based row/column numbers.

    test_spsh.m, io_xls_testscript.m
    Undocumented scripts for testing basic features of the spreadsheet scripts. Meant for testers and developers, but I don't mind ordinary users to give it a try.


    REQUIRED SUPPORT SOFTWARE


    For the Excel/COM interface:
    • A windows computer with Excel installed
    • Octave-forge Windows-1.2.1

    For the Java / Apache POI / JExcelAPI / OpenXLS / LibreOffice | OpenOffice.org interfaces (general):

    • Octave 3.7.2 or later with Java support compiled in
    • Java JRE or JDK > 1.6.0 (hasn't been tested with earlier versions)
    Apache POI specific:

    and here:

    • for OOXML support with Apache POI:

    poi-ooxml-schemas-<version>.jar, + either xbean.jar or xmlbeans.jar, + dom4j-1.6.1.jar in javaclasspath.

    Get them here:

    http://poi.apache.org/download.html ("xmlbeans" and poi-ooxml-schemas)

    http://sourceforge.net/projects/dom4j/files (dom4j-<version>)

    JExcelAPI specific:
    OpenXLS specific:
    These class libs must be referenced with full pathnames in your javaclasspath.
    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 time the io package is loaded, expects the class libs there; if they are elsewhere, add them in ./share/octave/<version>/m/startup/octaverc using appropriate javaaddpath statements or a chk_spreadsheet_support() call.
    In addition, you can specify a subdirectory using the environment variable OCTAVE_IO_JAVALIBS.
    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:
    1. Specified by the environment variable OCTAVE_IO_JAVALIBS
    2. <HOME_DIR>/java
    3. /usr/share/java (*nix) or /lib/java (MinGW)
    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.
    UNO specific (invoking OpenOffice.org (or clones) behind the scenes):
    NOTE: EXPERIMENTAL!! A working OpenOffice.org installation. The utility function chk_spreadsheet_support can be used to add the needed entries to the javaclasspath.

    For the native Octave interface
    (currently only read support for OOXML, ODS 1.2 and Gnumeric), no external support software is required.


    USAGE


    xlsread and xlswrite are mere wrappers for xlsopen-xls2oct-xlsclose-parsecell and xlsopen-oct2xls-xlsclose sequences, resp. They exist for the sake of Matlab compatibility.

    xlsfinfo can be used for finding out what worksheet names exist in the file. For OOXML files you either need MS-Excel 2007 for Windows (or later version) installed, and/or the input parameter REQINTF should be specified with a value of 'poi', 'oxs' or 'uno' (case-insensitive) and -obviously- either the complete POI interface must have been installed, and/or OpenXLS, and/or LibreOffice/OpenOffice.org.

    Invoking xlsopen/..../xlsclose directly provides for much more flexibility, speed, and robustness than xlsread / xlswrite. Indeed, using the same file handle (pointer struct) you can mix reading & writing before writing the workbook out to disk using xlsclose.
    And: xlsopen / xlsclose hide the gory interface details from the user.
    Currently only .xls files (BIFF8) can be read/written; using JExcelAPI BIFF5 can be read as well. For OOXML files either Excel 2007 for Windows (or higher) and/or the complete Apache POI interface, and/or OpenXLS v 10, or LibreOffice must be installed (and probably the REQINTF parameter specified with a value of 'poi', 'oxs', or 'uno').

    When using xlsopen....xlsclose be sure to keep track of the file handle struct.

    A possible scenario:

    xlh = xlsopen (<excel_filename> , [rw], [<requested interface>])
    # Set rw to 1 if you want to write to a workbook immediately.
    # In that case the check for file existence is skipped and
    # -if needed- a new workbook created.
    # If you really want an other interface than auto-selected
    # by xlsopen you can request that. But xlsopen still checks
    # proper support for your choice.


    # Read some data
    [ rawarr1, xlh ] = xls2oct (xlh, <SomeWorksheet>, <Range>)
    # Be sure to specify xlh as output argument as xls2oct keeps
    # track of changes and the need to write the workbook to disk
    # in the xlhstruct. And the origin range is conveyed through
    # the xlh pointer struct.


    # Separate data into numeric and text data
    [ numarr1, txtarr1, lim1 ] = parsecell (rawarr1)

    # Get more data from another worksheet in the same workbook
    [ rawarr2, xlh ] = xls2oct (xlh, <SomeOtherWorksheet>, <Range>)
    [ numarr2, txtarr2, lim2 ] = parsecell (rawarr2)

    # <... Analysis and preparation of new data in cell array Newdata....>

    # Add new data to spreadsheet
    xlh = oct2xls (Newdata, xlh, <AnotherWorksheet>, <Range>)

    # Close the workbook and write it to disk; then clear the handle
    xlh = xlsclose (xlh)
    clear xlh
    When not using the COM interface, specify a value of 'POI' for parameter REQINTF when accessing OOXML files in xlsread, xlswrite, xlsopen, xlsfinfo (and be sure the complete Apache POI interface is installed). If you haven't got ActiveX installed (i.e., not having MS-Excel under Windows) specifying 'POI' may not be needed as in such cases Apache POI is the next default interface.
    When using JExcelAPI (JXL), after writing into a worksheet you MUST save the file – adding data to the same or another worksheet is no more possible after the first call to oct2xls(). This is a limitation of JExcelAPI.

    SPREADSHEET FORMULA SUPPORT


    When using the COM, POI, JXL, OXS, UNO and OCT interfaces you can:
    • (When reading, xls2oct) either read evaluated spreadsheet formula results, or the literal formula text strings;
    • (When writing, oct2xls) either enter text strings in the form of spreadsheet formulas in the worksheet as formulas, or enter them as literal text strings.

    In short, you can enter spreadsheet formulas and in a later stage read them back, change them and re-enter them in the worksheet. 

    The behaviour is controlled by an option structure options which for now has only one (logical) field:
    options.formulas_as_text = 0 (the default) implies enter formulas as formulas and read back formula results
    options.formulas_as_text =1 (or any positive integer) means enter formulas as text strings and read them back as text strings.
    Be aware that there's no formula evaluator in JExcelAPI (JXL). So if you create formulas in your spreadsheet using oct2xls or xlswrite with 'JXL', do not expect meaningful results when reading those files later on unless you open them in Excel and write them back to disk.
    While both Apache POI and JExcelAPI feature a formula validator, not all spreadsheet functions present in Excel have been implemented (yet).
    Worse, older Excel versions feature less functions than newer versions. So be wary as this may make for interesting confusion.

    MATLAB COMPATIBILITY


    xlsread, xlswrite and xlsfinfo are for the most part Matlab-compatible. Some small differences are mentioned below. When using the Java interfaces octave supplies some formula manipulation support.

    xlsread
    Matlab's xlsread supports invoking extra functions while reading ("passing function handle"); octave not. But this can be simulated outside xlsread.

    Matlab's xlsread flags some spreadsheet errors, octave-forge just returns blank cells.

    Octave's xlsread (and for that matter, xlsfinfo as well) returns info about the actual (rather than the requested) cell range where the data came from. Personally I find it very useful to know from what part of a worksheet the data originate so I've put quite some effort in it :-)
    Matlab can't, due to Excel automatically trimming returned arrays from empty outer columns and rows. Octave is more clever but the Visual Basic call used for determining the actually used range has some limitations: (1) it relies on cached range values and thus may be out-of-date, and (2) it counts empty formatted cells too. When using ActiveX/COM, if octave's xlsfinfo.m returns wrong data ranges it is most often an overestimation.
    Matlab's xlsread ignores all non-numeric data values outside the smallest rectangle encompassing all numerical values. Octave's xlsread doesn't. This means that Matlab ignores all row/column headers, not very user-friendly IMO.

    When using the Java interface, reading and writing xls-files by octave's xlsread is platform-independent. On systems w/o installed Excel, Matlab can only read Excel 95 formatted .xls files (written using ML xlswrite's 'Basic" option) – and then differently than under Windows.....
    Matlab's xlsread returns strings for cells containing date values. This makes for endless if-then-elseif-else-end constructs to catch all expected date formates. Octave returns numerical data (where 0 = 1/1/1900 – you can easily transfer them into proper octave date values yourself using e.g. datestr(), see bottom of this document for more info).

    xlswrite
    Octave's xlswrite works on systems w/o Excel support, Matlab's doesn't (properly).
    When specifying a sheet number larger than the number of existing sheets in an .xls file, Matlab's xlswrite adds empty sheets until the new sheet number is created; Octave's xlswrite only adds one sheet called "Sheet<number>" where <number> is the specified sheet number.
    Even better (IMO) while M's xlswrite always creates Sheet1/Sheet2/Sheet3 when creating a new spreadsheet, octave's xlswrite only creates the requested worksheet. (Did you know that you can instruct Excel to create spreadsheets with just one, or any number of, worksheets? Look in Tools | Options, General tab.)
    Oh and octave doesn't touch the "active sheet" - but that's not automatically an advantage.
    If the specified write range is larger than the actual data array, Matlab's xlswrite adds #N/A cells to fill up the lowermost rows and rightmost columns; octave-forge's xlswrite doesn't.

    xlsfinfo
    When invoking Excel/COM interface, Octave's xlsfinfo also echoes the type of sheet (worksheet, chart), not just the sheet names. Using Java I haven't found similar functionality (yet).
    Octave's xlsfinfo also shows (and returns) the range of the smallest rectangle encompassing all occupied data ranges in each sheet.

    COMPARISON OF INTERFACES & USAGE

    Using Excel itself (through COM / ActiveX on Windows systems) is probably the most robust and versatile and especially FAST option (though for OOXML the OCT interface is probably faster). There's one gotcha: in case of some type of COM errors Excel will keep running invisibly; you can only end it through Task Manager.
    A tiny problem is that one cannot find out easily through COM what file types are supported; xls, wks, wk1, xlsx, etc.
    Another -obvious- limitation is that COM Excel access only works on Windows systems where Excel is installed.

    JExcelAPI (Java-based and therefore platform-independent) is proven technology but switching between reading and writing is quite involved and memory-hungry when processing large spreadsheets. As the docs state, JExcelAPI is optimized for reading and it does do that well - but still slower than Excel/COM. The fact that upon a switch from reading to writing the existing spreadsheet is overwritten in place by a blank one and that you can only get the contents back wen writing out all of the changes is worrying - and any change after the first write() is lost as a next write() doesn't seem to work, worse yet, you may completely loose the spreadsheet in question. The first is by JExcelAPI design, the second is probably a bug (in octave-forge/Java or JExcelAPI ? I don't know). Adding data to existing spreadsheets does work, but IMO undue user confidence is needed.
    JExcelAPI supports BIFF5 (only reading) and BIFF8 (Excel 95 and Excel 97-2003, respectively). Upon overwriting, BIFF5 spreadsheets are converted silently to BIFF8.
    JexcelAPI, unlike ApachePOI, doesn't evaluate functions while reading but instead relies on cached results (i.e. results computed by Excel itself). Depending on Excel settings ("Automatic calculation" ON or OFF) this may or may not yield incorrect (or expected) results.

    Apache POI (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).
    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.

    OpenXLS (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.

    UNO (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.
    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.
    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.
    A way out hasn't been found yet.

    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.

    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.

    Some notes on the choice for Java:
    1. 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.
    2. A BIG advantage is that a Java-based solution is platform-independent ("portable").
    3. But Java is known to be not very conservative with resources, especially not when processing XML-based formats.
    So Java is a compromise between portability and rapid development time versus capacity (and speed).
    But IMO data sets larger than 5.105 cells should not be kept in spreadsheets anyway. Better use real databases for such data sets.

    A NOTE ON JAVA MEMORY USAGE

    Java memory pool allocation size

    The Java virtual machine (JVM), when initialized by octave, reserves one big chunk of your computer's RAM in which all java classes and methods etc. are to be loaded: the java memory pool. It does this because java has a very sophisticated "garbage collection" system. At least on Windows, the initial size is 2MB and the maximum size is 16 MB. On Linux this allocated size might differ (e.g., my Mandriva box with openJDK has a 512 MB default max setting). This part of memory is where the Java-based XLS/ODS octave routines live and keep their variables etc.
    For transferring large pieces of information to and from spreadsheets you might hit the limits of this pool. E.g. to be able to handle I/O of an array of around 500,000 cells I needed a memory pool size of 512 MB.
    The memory size can be increased by inserting a file called "java.opts" (without quotes) in the directory ./share/octave//java (where the script file javaclasspath.m is located; try "which javaclasspath" in an Octave terminal to get the proper location), containing just the following lines:
    -Xms16m
    -Xmx512m
    (where 16 = initial size, 512 = maximum size (in this example), m stands for Megabyte. This maximum is system-dependent. E.g., I have a 1 GB setting).
    For further details consult the Octave manual, "Java Interface", "FAQ", "How can I handle memory limitations?"


    After processing a large chunk of spreadsheet information you might notice that octave's memory footprint does not shrink so it looks like Java's memory pool does not shrink back; but rest assured, the memory footprint is the allocated (reserved) memory size, not the actual used size. After the JVM has done its garbage collection, only the so-called "working set" of the memory allocation is really in use and that is a trimmed-down part of the memory allocation pool. On Windows systems it often suffices to minimize the octave terminal for a few seconds to get a more reasonable memory footprint.

    TROUBLESHOOTING

    Some hints for troubleshooting Excel support are contained in this thread:
    http://sourceforge.net/mailarchive/forum.php?thread_name=4C61B649.9090802%40hccnet.nl&forum_name=octave-dev
    dated August 10, 2010.
    A more structured approach is below.

    Since April 2011 a special purpose setup file has been included in the io package (chk_spreadsheet_support.m). Large parts of the approach below (starting at Step 2) have been automated in this script. When running it with the second input argument (debug level) set to 3 a lot of useful diagnostic output will be printed to screen.
    1. Check if COM / ActiveXworks (only under Windows OS). Do a pkg list and see
    2. a. If there's a windows package mentioned (then it's installed). If not, install it.

      b. If there's an asterisk on the windows package line (then the package is loaded). If not, do a pkg load windows

    3. Check if the ActiveX server works. Do:
    4. exl = actxserver ('Excel.Application') ## Note the period between "Excel" and "Application"

      If a COM object is returned, ActiveX / COM / Excel works. Do: exl.Quit(); delete (exl) to shut down the (hidden) Excel invocation.

      If you get an error message, your last resort is re-installing the windows package, or trying the Java-based interfaces.

    5. Check if java works. Do a pkg list and see

    a. If there's a java package mentioned (then it's installed). If not, install it.

    b. If there's an asterisk on the java package line (then the package is loaded). If not, do a pkg rebuild -auto java

    1. Check Java memory settings. Try javamem
    2. a. If it works, check if it reports sufficiently large max memory (had better be 200 MiB, the bigger the better)

      b. If it doesn't work, do:

      rt = java_invoke ('java.lang.Runtime', 'getRuntime')
      rt.gc
      rt.maxMemory ().doubleValue () / 1024 / 1024

      The last command will show MaxMemory in MiB.

      c. In case you have insufficient memory, see in "GOTCHAS", "Java memory pool allocation size", how to increase java's memory pre-reservation.

    3. Check if all classes (.jarfiles) are in class path. Do a 'javaclasspath' (under unix/linux, do 'tmp = javaclasspath; strsplit (tmp,":")' (w/o quotes). See above under "REQUIRED SUPPORT SOFTWARE" what classes should be mentioned.

    If classes (.jar files) are missing, download and put them somewhere and add them to the javaclass path with their fully qualified pathname (in quotes) using javaaddpath().

    Once all classes are present and in the javaclasspath, the xls interfaces should just work. The only remaining showstoppers are insufficient write privileges for the working directory, a wrecked up octave or some other problem outside octave.

    1. Try opening an xls file:

    xls1 = xlsopen ('test.xls', 1, 'poi'). If this works and xls1 is a struct with various fields containing objects, the Apache POI interface (POI) works. Do an xls1 = xlsclose (xls1) to close the file.

    xls2 = xlsopen ('test.xls', 1, 'jxl'). If this works and xls2 is a struct with various fields containing objects, the JExcelAPI interface (JXL) works as well. Don't forget to do xls2 = xlsclose (xls2) to close the file.

    DEVELOPMENT

    xlsopen/xlsclose and friends have been written so that adding other interfaces (Perl? native octave? ...?) should be very easily accomplished. xlsopen.m merely needs two stanzas, xlsfinfo.m, xls2oct.m, oct2xls.m and getusedrange.m each need an additional elseif stanza, and xlsclose.m needs a small stanza for closing the pointer struct and writing to disk.
    The real work lies in creating the relevant __<INTF>_spsh_open__.m & __<INTF>_spsh_close__.m, __<INTF>_spsh2oct__.m & __<INTF>_oct2spsh__.m, __<INTF>_spsh_info__.m, and __<INTF>_getusedrange__.m subfunction scripts in ./private subdir, but that shouldn't be really hard, depending on the interface support libraries' quality and documentation. The function scripts in the ./private subdir provide for ample examples.
    Separating the file access functions and the actual reading/writing from/to the workbook in memory has made developer's life (I mean: my time developing this stuff) much easier.

    Some other options for development (who?):
    • Speeding up, especially Java worksheet/cell access. For cracks, not me.
    • Automatic conversion of Excel date/time values into octave ones and vice versa (adding or subtracting 636960). But then again Excel's dates are 01-01-1900 based (octave's 0-0-0000) and buggy (Excel thinks 1900 is a leap year), and I sometimes have to use dates from before 1900. Maybe as an option?
    • Creating Excel graphs (a significant enterprise to write from scratch).
    • Support for "passing function handle" in xlsread.

    Enjoy!

    Philip Nienhuis, December 30, 2013
    io/INDEX0000644000076400010400000000132212261113650013260 0ustar PhilipAdministratorsio >> Input from and output to external formats File I/O append_save fexist rfsearch Miscellaneous conversion functions object2json pch2mat read_namelist write_namelist CSV file functions cell2csv csv2cell csvconcat csvexplode XML I/O xmlread xmlwrite getxmlattv getxmlnode Spreadsheet I/O user functions for MS-Excel oct2xls xls2oct xlsclose xlsfinfo xlsopen xlsread xlswrite Spreadsheet I/O user functions for OpenOffice.org Calc oct2ods ods2oct odsclose odsfinfo odsopen odsread odswrite Spreadsheet utility functions calccelladdress chk_spreadsheet_support parsecell Spreadsheet function test scripts io_ods_testscript io_xls_testscript test_spsh io/inst/0000755000076400010400000000000012263601446013454 5ustar PhilipAdministratorsio/inst/append_save.m0000644000076400010400000001005712217071420016112 0ustar PhilipAdministrators## Copyright (C) 2003 Tomer Altman ## ## 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 . ## append_save M-file function ## ## Objective: be able to add variables to existing save files. Works for ## all the types of save files that "save" supports. ## ## Input: ## 1) A string which specifies the existing save file. ## 2) The options you need to pass to the 'save' function to save to the ## file type that you want. ## 3) A 1x2 cell, with the first element being a string representation ## of the variable/symbol that you're trying to add, followed by the ## actual variable/symbol itself. ## 4) Any number of additional 1x2 cells, following the same format as ## the 3rd argument specified immediately before this one. ## ## Output: ## Currently, none. But there might be some debugging / error-code ## messages in the future. ## ## Example: ## octave> B = ones(2,2); ## octave> append_save( "test.txt", "-binary", {"B", B } ) function [ return_value ] = append_save ( filename, option, var_val_cell, varargin ) ## Input checking: if ( nargin < 3 ) error("append_save: needs three arguments."); elseif ( !ischar(filename) ) error("append_save: filename must be a string."); elseif ( !ischar(option) ) error("append_save: option must be a string." ); elseif ( !iscell(var_val_cell) ) error("append_save: variable-value pairs must be cells.") elseif ( nargin > 3 ) for i=1:(nargin-3) current_cell = varargin(i); if ( !iscell(current_cell) ) error("append_save: variable-value pairs must be cells."); elseif ( ( columns( current_cell ) != 2 ) || ( rows( current_cell ) != 1 ) ) error("append_save: variable-value pairs must be 1x2 cells.") elseif ( !ischar(current_cell{1} ) ) error("append_save: variable in pair must be a string." ) endif endfor endif ## First step: load into the environment what is already stuffed in ## the target file. Then, add their name to the list for "save". env1 = who; eval([ "load -force ", ... option, " ", ... filename ] ); env2 = who; num_orig_vars = rows(env1); # Not really 'current' env... num_current_vars = rows(env2); num_new_vars = num_current_vars - num_orig_vars; var_str = ""; ## This double 'for loop' weeds out only the loaded vars for ## inclusion. if ( num_new_vars ) for i=1:num_current_vars current_var = env2{i,1}; old_bool = 0; for j=1:num_orig_vars if ( strcmp( env1{j,1}, env2{i,1} ) || strcmp( env2{i,1}, "env1" ) ) old_bool = 1; endif endfor if ( old_bool == 0 ) var_name = env2{i,1}; var_str = [ var_str, " ", var_name, " " ]; endif endfor endif ## Second step: load into the environment the variable pairs. Then, ## add the name to the string for "save". var_name = var_val_cell{1}; var_val = var_val_cell{2}; temp = var_val; eval([ var_name, "=temp;" ]); var_str = [ var_str, " ", var_name, " " ]; ## Third step: do the same as step two, but loop through the possible ## variable arguments. for i=1:(nargin-3) current_cell = varargin(i); var_name = current_cell{1}; var_val = current_cell{2}; temp = var_val; eval([ var_name, "=temp;" ]); var_str = [ var_str, " ", var_name, " " ]; var_str endfor ## Finally, save all of the variables into the target file: eval( [ "save ", ... option, " ", ... filename, " ", var_str; ] ); endfunction io/inst/calccelladdress.m0000644000076400010400000000510712217071420016735 0ustar PhilipAdministrators## Copyright (C) 2009,2010,2011 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 . ## calccelladdress (R, C) - compute spreadsheet style cell address from ## row & column index (both 1-based). ## ## Max column index currently set to 18278 (max ODS: 1024, OOXML: 16384). ## Row limits for ODF and OOXML are 65536 and 1048576, resp. ## Author: Philip Nienhuis ## Created: 2009-12-12 ## Updates: ## 2009-12-27 Fixed OOXML limits ## 2010-03-17 Simplified argument list, only row + column needed ## 2010-09-27 Made error message more comprehensible ## 2010-10-11 Added check for row range ## 2011-04-21 Added tests ## 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 function [ celladdress ] = calccelladdress (row, column) if (nargin < 2) error ("calccelladdress: Two arguments needed") endif if (column > 18278 || column < 1) error ("Specified column out of range (1..18278)"); endif if (row > 1048576 || row < 1) 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 celladdress = sprintf ("%s%d", str, row); endfunction %!test %! a = calccelladdress (1, 1); %! assert (a, 'A1'); %!test %! a = calccelladdress (378, 28); %! assert (a, 'AB378'); %!test %! a = calccelladdress (65536, 1024); %! assert (a, 'AMJ65536'); %!test %! a = calccelladdress (1048576, 16384); %! assert (a, 'XFD1048576'); %!test %! a = calccelladdress (378, 26); %! assert (a, 'Z378'); %!test %! a = calccelladdress (378, 702); %! assert (a, 'ZZ378'); %!test %! a = calccelladdress (378, 701); %! assert (a, 'ZY378'); %!test %! a = calccelladdress (378, 703); %! assert (a, 'AAA378'); %!test %! a = calccelladdress (378, 676); %! assert (a, 'YZ378'); io/inst/chk_spreadsheet_support.m0000644000076400010400000007132712263346406020576 0ustar PhilipAdministrators## 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 ## 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 . ## -*- texinfo -*- ## @deftypefn {Function File} {[ @var{retval}, @var{intfs}, @var{ljars} ]} = chk_spreadsheet_support () ## @deftypefnx {Function File} {[ @var{retval}, @var{intfs}, @var{ljars} ]} = chk_spreadsheet_support ( @var{path_to_jars} ) ## @deftypefnx {Function File} {[ @var{retval}, @var{intfs}, @var{ljars} ]} = chk_spreadsheet_support ( @var{path_to_jars}, @var{debug_level} ) ## @deftypefnx {Function File} {[ @var{retval}, @var{intfs}, @var{ljars} ]} = chk_spreadsheet_support ( @var{path_to_jars}, @var{debug_level}, @var{path_to_ooo} ) ## Check Octave environment for spreadsheet I/O support, report any problems, ## and optionally add or remove Java class libs for spreadsheet support. ## ## chk_spreadsheet_support first checks ActiveX (native MS-Excel); then ## Java JRE presence, then Java support (if builtin); then checks existing ## javaclasspath for Java class libraries (.jar files) needed for various ## Java-based spreadsheet I/O interfaces. If requested chk_spreadsheet_support ## will try to add the relevant Java class libs to the dynamic javaclasspath. ## chk_spreadsheet_support remembers which Java class libs it has added to ## the javaclasspath; optionally it can unload them as well. ## ## @var{path_to_jars} - relative or absolute path name to subdirectory ## containing these classes. TAKE NOTICE: /forward/ slashes are needed! ## chk_spreadsheet_support() will recurse into at most two subdir levels; ## if the Java class libs are scattered across deeper subdir levels or ## further apart in the file system, multiple calls to ## chk_spreadsheet_support may be required. @var{path_to_jars} can be [] ## or '' if no class libs need to be added to the javaclasspath. ## ## @var{debug_level}: (integer) between [0 (no output) .. 3 (full output] ## @table @asis ## @indent ## @item 0 ## No debug output is generated. ## ## @item 1 ## Only proper operation of main interface groups (COM, Java) is shown. ## If @var{path_to_jars} and/or @var{path_to_ooo} was supplied, ## chk_spreadsheet_support indicates whether it could find the required ## Java class libs for all interfaces ## ## @item 2 ## Like 1, proper working of individual implemented Java-based interfaces is ## shown as well. If @var{path_to_jars} and/or @var{path_to_ooo} was supplied, ## chk_spreadsheet_support indicates for each individual Java-based interface ## whether it could add the required Java class libs. ## ## @item 3 ## Like 2, also presence of individual javaclass libs in javaclasspath is ## indicated. If @var{path_to_jars} and/or @var{path_to_ooo} was supplied, ## chk_spreadsheet_support reports for each individual Java-based interface ## which required Java class libs it could find and add to the javaclasspath. ## ## @item -1 (or any negative number) ## Remove all directories and Java class libs that chk_spreadsheet_support ## added to the javaclasspath. If @var{debug_level} < 1 report number of ## removed javclasspath entries; if @var{debug_level} < 2 report each ## individual removed entry. ## @noindent ## @end table ## ## @var{path_to_ooo} - installation directory of OpenOffice.org (again with ## /forward/ slashes). Usually that is something like (but no guarantees): ## @table @asis ## - Windows: C:/Program Files/OpenOffice.org or ## C:/Program Files (X86)/LibreOffice ## ## - *nix: /usr/lib/ooo or /opt/libreoffice ## ## - Mac OSX: ????? ## ## IMPORTANT: @var{path_to_ooo} should be such that both: ## @example ## @group ## 1. PATH_TO_OOO/program/ ## and ## 2. PATH_TO_OOO/ure/.../ridl.jar ## resolve OK. ## @end group ## @end example ## @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: At least one read/write spreadsheet I/O ## interface found. ## 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: ---------- ## 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 ---- ## 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) ## 128 = UNO (Java/UNO bridge - OpenOffice.org) (any format supported by OOo) ## @end example ## ## @var{INTFS}: listing of supported spreadsheet interfaces. The OCT ## interface is always supported. ## ## @var{ljars}: listing of full paths of Java class libs and directories ## that chk_spreadsheet_support has added to the javaclasspath. ## ## @end deftypefn ## Author: Philip Nienhuis ## Created 2010-11-03 for Octave & Matlab ## Updates: ## 2010-12-19 Found that dom4j-1.6.1.jar is needed regardless of ML's dom4j ## presence in static classpath (ML r2007a) ## 2011-01-04 Adapted for general checks, debugging & set up, both Octave & ML ## 2011-04-04 Rebuilt into general setup/debug tool for spreadsheet I/O support ## and renamed chk_spreadsheet_support() ## 2011-05-04 Added in UNO support (OpenOffice.org & clones) ## '' Improved finding jar names in javaclasspath ## 2011-05-07 Improved help text ## 2011-05-15 Better error msg if OOo instal dir isn't found ## 2011-05-20 Attempt to cope with case variations in subdir names of OOo install dir (_get_dir_) ## 2011-05-27 Fix proper return value (retval); header text improved ## 2011-05-29 Made retval value dependent on detected interfaces & adapted help text ## 2011-06-06 Fix for javaclasspath format in *nix w. octave-java-1.2.8 pkg ## '' Fixed wrong return value update when adding UNO classes ## 2011-09-03 Small fix to better detect Basis* subdir when searching unoil.jar ## 2011-09-18 Fixed 'Matlab style short circuit' warning in L. 152 ## 2012-12-24 Amended code stanza to find unoil.jar; now works in LibreOffice 3.5b2 as well ## 2012-06-07 Replaced all tabs by double space ## 2012-06-24 Replaced error msg by printf & return ## '' Added Java pkg inquiry (Octave) before attempting javaclasspath() ## '' Updated check for odfdom version (now supports 0.8.8) ## 2012-10-07 Moved common classpath entry code to private function ## 2012-12-21 POI 3.9 support (w. either xmlbeans.jar or xbeans.jar) ## 2013-01-16 Updated to Octave w built-in Java (3.7.1+) ## 2013-06-23 More informative error messages: ## '' COM section: only called on Windows ## '' Java section: first check for Java support in Octave ## '' Restyled into Octave conventions ## 2013-07-18 Add Fedora naming scheme to POI jar entries (the "old" ones are symlinks) ## 2013-08-12 More restyling ## '' odfdom 0.8.9 support (incubator-0.6) - alas that is buggy :-( => dropped ## '' Removed all Matlab-specific code ## 2013-08-19 Fixed wrong reference to path_to_jars where path_to_ooo was intended ## '' Fixed wrong echo of argument nr in checks on path_to_ooo ## 2013-08-20 Allow subdir searches for Java class libs ## 2013-09-01 Adapt recursive file search proc name (now rfsearch.m) ## 2013-12-14 Texinfo header updated to OCT ## 2013-12-20 More Texinfo header improvements ## 2013-12-28 Added check for OpenXLS version 10 ## 2013-12-29 Added gwt-servlet-deps.jar to OpenXLS dependencies ## 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 function [ retval, sinterfaces, loaded_jars ] = chk_spreadsheet_support (path_to_jars, dbug, path_to_ooo) ## Keep track of which Java class libs were loaded persistent loaded_jars; persistent sinterfaces; sinterfaces = {"OCT"}; jcp = []; retval = 0; if (nargin < 3) path_to_ooo= ""; endif if (nargin < 2) dbug = 0; endif if (dbug < 0 && octave_config_info ("features").JAVA) ## Remove loaded Java class libs from the javaclasspath if (dbug < -2 && numel (loaded_jars)) printf ("Removing javaclasspath entries loaded by chk_spreadsheet_support:\n"); endif for ii=1:numel (loaded_jars) javarmpath (loaded_jars{ii}); if (dbug < -2) printf ("%s\n", loaded_jars{ii}); endif endfor if (dbug < -1) printf ("%d jars removed from javaclasspath\n", numel (loaded_jars)); endif loaded_jars = {}; ## Re-assess supported interfaces sinterfaces = {"OCT"}; retval = 0; if (ismember ("COM", sinterfaces)) sinterfaces = [sinterfaces, "COM"]; retval = 1; endif return elseif (dbug > 0) printf ('\n'); endif interfaces = {"COM", "POI", "POI+OOXML", "JXL", "OXS", "OTK", "JOD", "UNO", "OCT"}; ## Order = vital ## Check if MS-Excel COM ActiveX server runs. Only needed on Windows systems if (ispc) if (dbug) printf ("Checking Excel/ActiveX/COM... "); endif try app = actxserver ("Excel.application"); ## If we get here, the call succeeded & COM works. xlsinterfaces.COM = 1; ## Close Excel to avoid zombie Excel invocation app.Quit(); delete(app); if (dbug) printf ("OK.\n\n"); endif retval = retval + 1; sinterfaces = [ sinterfaces, "COM" ]; catch ## COM not supported if (dbug) printf ("not working.\n"); endif ## Check if Windows package is installed and loaded pkglist = pkg ("list"); 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"); endif else printf ("(windows package is required for COM/ActiveX support)\n"); endif printf ("\n"); end_try_catch endif ## Check Java if (dbug) printf ("Checking Java support...\n"); endif if (dbug > 1) printf (" 1. Checking Java JRE presence.... "); endif ## Try if Java is installed at all if (ispc) ## FIXME the following call fails on 64-bit Windows jtst = (system ("java -version 2> nul")); else jtst = (system ("java -version 2> /dev/null")); endif if (dbug) 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"); endif return; else if (dbug > 1) printf ("OK, found one.\n"); endif endif if (dbug > 1) printf (" 2. Checking Octave Java support... "); endif endif ## Check core Java support (newer Octave) try ## The following stanza is meant for older Octave w/o built-in Java if (compare_versions (OCTAVE_VERSION, "3.7.2", "<")) ## Check Java package [~, b] = pkg ("describe", "java"); if (strcmpi (b{:}, "Not loaded")) if (dbug > 1) printf ('Java package found but not loaded. First do: "pkg load java"\n'); endif elseif strcmpi (b{:}, "Not installed") if (dbug > 1) printf ("Java package is not installed.\n"); endif endif else ## Check for proper look of UGLY_DEFS/features (only needed for 3.7.2+ version) if (isfield (octave_config_info, "features")) if (! octave_config_info.features.JAVA) if (dbug) printf ("none.\n"); printf (" (Octave was built without core 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"); endif endif endif endif ## OK sufficient info to give it a try [tmp1, jcp] = __chk_java_sprt__ (dbug); if (tmp1) if (dbug > 1) ## Check JVM virtual memory settings jrt = javaMethod ("getRuntime", "java.lang.Runtime"); jmem = jrt.maxMemory (); ## Some Java versions return jmem as octave_value => convert to double if (! isnumeric (jmem)) jmem = jmem.doubleValue(); endif jmem = int16 (jmem/1024/1024); printf (" Maximum JVM memory: %5d MiB; ", jmem); if (jmem < 400) printf ("should better be at least 400 MB!\n"); printf (' Hint: adapt setting -Xmx in file "java.opts" (supposed to be here:)\n'); printf (" %s\n", [matlabroot filesep "share" filesep "octave" filesep "packages" filesep "java-" filesep "java.opts"]); else printf ("sufficient.\n"); endif endif if (dbug) printf ("Java support OK\n"); endif endif catch ## No Java support end_try_catch if (! tmp1) ## We can return as for below code Java is required. if (dbug) printf ("No Java support found.\n"); if (! retval) printf ("Only read support for ODS 1.2 (.ods), OOXML (.xlsx) and .gnumeric\n"); endif endif return endif if (dbug) printf ("\nChecking javaclasspath for .jar class libraries needed for spreadsheet I/O...:\n"); endif ## Try Java & Apache POI. First Check basic .xls (BIFF8) support if (dbug > 1) printf ("\nBasic POI (.xls) :\n"); endif entries1 = {{"apache-poi.", "poi-3"}, {"apache-poi-ooxml.", "poi-ooxml-3"}}; missing1 = zeros (1, numel (entries1)); ## Only under *nix we might use brute force: e.g., strfind (javaclasspath, classname) ## as javaclasspath is one long string. Under Windows however classpath is a cell array ## so we need the following more subtle, platform-independent approach: [jpchk1, missing1] = chk_jar_entries (jcp, entries1, dbug); if (jpchk1 >= numel (entries1)) retval = retval + 2; sinterfaces = [ sinterfaces, "POI" ]; endif if (dbug > 1) if (jpchk1 >= numel (entries1)) printf (" => Apache (POI) OK\n"); else printf (" => Not all classes (.jar) required for POI in classpath\n"); endif endif ## Next, check OOXML support if (dbug > 1) printf ("\nPOI OOXML (.xlsx) :\n"); endif entries2 = {{"xbean", "xmlbean"}, {"apache-poi-ooxml-schemas", "poi-ooxml-schemas"}, "dom4j"}; ## Only update retval if all classes for basic POI have been found in javaclasspath [jpchk2, missing2] = chk_jar_entries (jcp, entries2, dbug); if (jpchk1 >= numel (entries1) && jpchk2 >= numel (entries2)) retval = retval + 4; sinterfaces = [ sinterfaces, "POI+OOXML" ]; endif if (dbug > 1) if (jpchk2 >= numel (entries2)) printf (" => POI OOXML OK\n"); else printf (" => Some classes for POI OOXML support missing\n"); endif endif ## Try Java & JExcelAPI if (dbug > 1) printf ("\nJExcelAPI (.xls (incl. BIFF5 read)) :\n"); endif entries3 = {"jxl"}; missing3 = zeros (1, numel (entries3)); [jpchk, missing3] = chk_jar_entries (jcp, entries3, dbug); if (jpchk >= numel (entries3)) retval = retval + 8; sinterfaces = [ sinterfaces, "JXL" ]; endif if (dbug > 1) if (jpchk >= numel (entries3)) printf (" => Java/JExcelAPI (JXL) OK.\n"); else printf (" => Not all classes (.jar) required for JXL in classpath\n"); endif endif ## Try Java & OpenXLS if (dbug > 1) printf ("\nOpenXLS (.xls - BIFF8 & .xlsx - OOXML) :\n"); endif entries4 = {"OpenXLS", "gwt-servlet-deps"}; missing4 = zeros (1, numel (entries4)); [jpchk, missing4] = chk_jar_entries (jcp, entries4, dbug); if (jpchk >= numel (entries4)) ## Check OpenXLS.jar version try ## ...a method that is first introduced in OpenXLS v.10 javaMethod ("getVersion", "com.extentech.ExtenXLS.GetInfo"); ## If we get here, we do have v. 10 retval = retval + 16; sinterfaces = [ sinterfaces, "OXS" ]; if (dbug > 1) if (jpchk >= numel (entries4)) printf (" => Java/OpenXLS (OXS) OK.\n"); else printf (" => Not all classes (.jar) required for OXS in classpath\n"); endif endif catch ## Wrong OpenXLS.jar version (probably <= 6.08). V. 10 is required now warning ("OpenXLS.jar version is outdated; please upgrade to v.10"); end_try_catch endif ## Try Java & ODF toolkit if (dbug > 1) printf ("\nODF Toolkit (.ods) :\n"); endif entries5 = {"odfdom", "xercesImpl"}; missing5 = zeros (1, numel (entries5)); [jpchk, missing5] = chk_jar_entries (jcp, entries5, dbug); if (jpchk >= numel (entries5)) ## Apparently all requested classes present. ## Only now we can check for proper odfdom version (only 0.7.5 & 0.8.6-0.8.8 work OK). ## The odfdom team deemed it necessary to change the version call so we need this: odfvsn = " "; try ## New in 0.8.6 odfvsn = javaMethod ("getOdfdomVersion", "org.odftoolkit.odfdom.JarManifest"); catch ## Worked in 0.7.5 odfvsn = javaMethod ("getApplicationVersion", "org.odftoolkit.odfdom.Version"); end_try_catch ## For odfdom-incubator (= 0.8.8+), strip extra info odfvsn = regexp (odfvsn, '\d\.\d\.\d', "match"){1}; if (! (strcmp (odfvsn, "0.7.5") || (compare_versions (odfvsn, "0.8.6", ">=") ... && compare_versions (odfvsn, "0.8.9", "<")))) warning (" *** odfdom version (%s) is not supported - use v. 0.8.6 - 0.8.8\n", odfvsn); else if (dbug > 1) printf (" => ODFtoolkit (OTK) OK.\n"); endif retval = retval + 32; sinterfaces = [ sinterfaces, "OTK" ]; endif elseif (dbug > 1) printf (" => Not all required classes (.jar) in classpath for OTK\n"); endif ## Try Java & jOpenDocument if (dbug > 1) printf ("\njOpenDocument (.ods + experimental .sxc readonly) :\n"); endif entries6 = {"jOpenDocument"}; missing6 = zeros (1, numel (entries6)); [jpchk, missing6] = chk_jar_entries (jcp, entries6, dbug); if (jpchk >= numel (entries6)) retval = retval + 64; sinterfaces = [ sinterfaces, "JOD" ]; endif if (dbug > 1) if (jpchk >= numel(entries6)) printf (" => jOpenDocument (JOD) OK.\n"); else printf (" => Not all required classes (.jar) in classpath for JOD\n"); endif endif ## Try Java & UNO if (dbug > 1) printf ("\nUNO/Java (.ods, .xls, .xlsx, .sxc) :\n"); endif ## entries0(1) = not a jar but a directory (<000_install_dir/program/>) entries0 = {"program", "unoil", "jurt", "juh", "unoloader", "ridl"}; [jpchk, missing0] = chk_jar_entries (jcp, entries0, dbug); if (jpchk >= numel (entries0)) retval = retval + 128; sinterfaces = [ sinterfaces, "UNO" ]; endif if (dbug > 1) if (jpchk >= numel (entries0)) printf (" => UNO (OOo) OK\n"); else printf (" => One or more UNO classes (.jar) missing in javaclasspath\n"); endif endif ## If requested, try to add UNO stuff to javaclasspath ujars_complete = isempty (find (missing0, 1)); if ((! ujars_complete) && nargin > 0 && (! isempty (path_to_ooo))) if (dbug) printf ("\nTrying to add missing program subdir & UNO java class libs to javaclasspath...\n"); endif if (! ischar (path_to_ooo)) printf ("Path expected for arg # 3\n"); return; endif if (dbug && ! isempty (strfind (path_to_ooo, '\'))) printf ("\n(Hmmm... forward slashes are preferred over backward slashes in path)\n"); endif ## Add missing jars to javaclasspath. First combine all entries targt = sum (missing0); if (missing0(1)) ## Add program dir (= where soffice or soffice.exe or ooffice resides) programdir = [path_to_ooo filesep entries0{1}]; if (exist (programdir, "dir")) if (dbug > 2) printf (" Found %s, adding it to javaclasspath ... ", programdir); endif try javaaddpath (programdir); targt = targt - 1; if (dbug > 2) printf ("OK\n"); endif if (isempty (loaded_jars)) loaded_jars = { programdir }; else loaded_jars = [ loaded_jars, programdir] ; endif catch if (dbug > 2) printf ("FAILED\n"); endif end_try_catch else if (dbug > 2) printf ("Suggested OpenOffice.org install directory: %s not found!\n", path_to_ooo); return endif endif endif ## Rest of missing entries. Find where URE is located. Watch out because ## case of ./ure is unknown uredir = get_dir_ (path_to_ooo, "ure"); if (isempty (uredir)) return endif ## Now search for UNO jars for ii=2:length (entries0) if (missing0(ii)) if (ii == 2) ## Special case as unoil.jar usually resides in ./Basis/program/classes ## Find out the exact name of Basis..... basisdirlst = dir ([path_to_ooo filesep "?asis" "*"]); jj = 1; if (numel (basisdirlst) > 0) while (jj <= size (basisdirlst, 1) && jj > 0) basisdir = basisdirlst(jj).name; if (basisdirlst(jj).isdir) basisdir = basisdirlst(jj).name; jj = 0; else jj = jj + 1; endif endwhile basisdir = [path_to_ooo filesep basisdir ]; else basisdir = path_to_ooo; endif basisdirentries = {"program", "classes"}; tmp = basisdir; jj=1; while (! isempty (tmp) && jj <= numel (basisdirentries)) tmp = get_dir_ (tmp, basisdirentries{jj}); jj = jj + 1; endwhile 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; endif unojarpath = get_dir_ (tmp, "java"); file = dir ([unojarpath filesep entries0{ii} "*"]); endif ## Path found, now try to add jar if (isempty (file)) if (dbug > 2) printf (" ? %s<...>.jar ?\n", entries0{ii}); endif else if (dbug > 2) printf (" Found %s, adding it to javaclasspath ... ", file.name); endif try javaaddpath ([unojarpath filesep file.name]); targt = targt - 1; if (dbug > 2) printf ("OK\n"); endif if (isempty (loaded_jars)) loaded_jars = {[unojarpath filesep file.name]}; else loaded_jars = [ loaded_jars; [unojarpath filesep file.name] ]; endif catch if (dbug > 2) printf ("FAILED\n"); endif end_try_catch endif endif endfor if (! targt) retval = retval + 128; sinterfaces = [sinterfaces, "UNO"]; endif if (dbug) if (targt) printf ("Some UNO class libs still lacking...\n\n"); else printf ("UNO interface supported now.\n\n"); endif endif endif ## ----------Rest of Java interfaces---------------------------------- missing = [missing1 missing2 missing3 missing4 missing5 missing6]; jars_complete = isempty (find (missing, 1)); if (dbug) if (jars_complete) printf ("All Java-based interfaces (save UNO) fully supported.\n\n"); else printf ("Some class libs lacking yet...\n\n"); endif endif 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 if (dbug) printf ("Trying to add missing java class libs to javaclasspath...\n"); endif if (! ischar (path_to_jars)) printf ("Path expected for arg # 1\n"); return; endif ## First combine all entries targt = sum (missing); ## For each interface, search tru list of missing entries for ii=1:6 ## Adapt number in case of future new interfaces tmpe = eval ([ "entries" char(ii + "0") ]); tmpm = eval ([ "missing" char(ii + "0") ]); tmpmcnt = sum (tmpm); if (tmpmcnt) for jj=1:numel (tmpe) if (tmpm(jj)) if (iscellstr (tmpe{jj})) rtval = 0; kk = 1; while (kk <= numel (tmpe{jj}) && isnumeric (rtval)) jtmpe = tmpe{jj}{kk}; rtval = add_jars_to_jcp (path_to_jars, jtmpe, dbug); ++kk; endwhile else rtval = add_jars_to_jcp (path_to_jars, tmpe{jj}, dbug); endif if (ischar (rtval)) --targt; --tmpmcnt; tmpm(jj) = 0; if (isempty (loaded_jars)) ## Make sue we get a cellstr array loaded_jars = {rtval}; else loaded_jars = [ loaded_jars; rtval ]; endif endif endif endfor if (! sum (tmpm)) retval = retval + 2^ii; endif endif if (! tmpmcnt) sinterfaces = [ sinterfaces, interfaces{ii} ]; endif endfor if (dbug) if (targt) printf ("Some other class libs still lacking...\n\n"); else printf ("All Java-based interfaces fully supported.now.\n\n"); endif endif endif endfunction function [ ret_dir ] = get_dir_ (base_dir, req_dir) ## Construct path to subdirectory req_dir in a subdir tree, aimed ## at taking care of proper case (esp. for *nix) of existing subdir ## in the result. Case of input var req_dir is ignored on purpose. ret_dir = ''; ## Get list of directory entries ret_dir_list = dir (base_dir); ## Find matching entries idx = find (strcmpi ({ret_dir_list.name}, req_dir)); ## On *nix, several files and subdirs in one dir may have the same name as long as case differs if (! isempty (idx)) ii = 1; while (! ret_dir_list(idx(ii)).isdir) ii = ii + 1; 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 ]; endif endfunction function [ retval ] = add_jars_to_jcp (path_to_jars, jarname, dbug) ## Given a subdirectory path and a (sufficiently unique part of a) Java class ## lib file (.jar) name, checks if it can find the file in the subdir and ## tries to add it to the javaclasspath. Only two more subdir levels below the ## path_to_jar subdir will be searched to limit excessive search time. ## If found, return the full pathname retval = 0; ## Search subdirs. Max search depth = 2 to avoid undue search time file = rfsearch (path_to_jars, jarname, 2); if (isempty (file)) ## Still not found... if (dbug > 2) printf (' ? %s<...>.jar ?\n', jarname); endif elseif (stat ([path_to_jars filesep file]).size < 1024) ## Probably too small for a jar => apparently a symlink if (dbug > 2) printf (' File %s is probably a symlink ... \n', file); endif else ## FIXME: cache subdir in file name to speed up search if (dbug > 2) printf (' Found %s, adding it to javaclasspath ... ', file); endif try javaaddpath ([path_to_jars filesep file]); if (dbug > 2) printf ('OK\n'); endif retval = [path_to_jars filesep file]; catch if (dbug > 2) printf ('FAILED\n'); endif end_try_catch endif endfunction io/inst/fexist.m0000644000076400010400000000467112217071420015134 0ustar PhilipAdministrators## Copyright (C) 2008 Jaroslav Hajek ## ## 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 . ## -*- texinfo -*- ## @deftypefn{Function File} ex = fexist (file, tspec, aspec) ## Checks whether a file exists. ## @var{file} is the queried file path. ## @var{tspec} is a combination of letters f,d,p,S, corresponding ## to file types: ## @itemize ## @item f: regular file ## @item d: directory ## @item p: named pipe (FIFO special file) ## @item S: socket ## @end itemize ## ## The query is true if the actual file type matches any of ## the specified options. ## ## @var{aspec} is a combination of letters r,w,x, corresponding ## to queried access privileges to the file. The query is true ## if the current user has all the spefied types of access, either ## through "user", "group" or "other" specs. ## ## @seealso{stat, lstat} ## @end deftypefn function ex = fexist (file, tspec, aspec) s = stat (file); if (isempty (s)) ex = 0; else ex = 1; if (nargin >= 2 && ! isempty (tspec)) ft = 0; for c = tspec switch (c) case 'f' ft |= S_ISREG (s.mode); case 'd' ft |= S_ISDIR (s.mode); case 'p' ft |= S_ISFIFO (s.mode); case 'S' ft |= S_ISSOCK (s.mode); otherwise error ("invalid file type spec: %s", c) endswitch endfor ex &= ft; endif if (ex && nargin >= 3 && ! isempty (aspec)) at = 1; mypid = (s.uid == getuid ()); mygid = (s.gid == getgid ()); mstr = s.modestr(2:end); for c = aspec switch (c) case 'r' at &= (mypid && mstr(1) == c) || (mygid && mstr(4) == c) || mstr(7) == c; case 'w' at &= (mypid && mstr(2) == c) || (mygid && mstr(5) == c) || mstr(8) == c; case 'x' at &= (mypid && mstr(3) == c) || (mygid && mstr(6) == c) || mstr(9) == c; otherwise error ("invalid access type spec: %s", c) endswitch endfor ex &= at; endif endif io/inst/getxmlattv.m0000644000076400010400000000302512246626224016033 0ustar PhilipAdministrators## Copyright (C) 2013 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 Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} [@var{retval}] = getxmlattv (@var{xmlnode}, @var{att}) ## Get value of attribute @var{att} in xml node (char string) @var{xmlnode}, ## return empty if attribute isn't present. ## ## @seealso{getxmlnode} ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2013-09-08 function [retval] = getxmlattv (xmlnode, att) retval = ''; ## Get end of first tag iend = index (xmlnode, ">"); ## Get start of value string. Concat '="' to ensure minimal ambiguity vals = index (xmlnode, [att '="']); if (vals == 0) ## Attribute not in current tag return elseif (vals) vals = vals + length (att) + 2; vale = regexp (xmlnode(vals:end), '"[ >/]'); if (! isempty (vale)) retval = xmlnode(vals:vals+vale-2); endif endif endfunction io/inst/getxmlnode.m0000644000076400010400000000715712246626246016020 0ustar PhilipAdministrators## Copyright (C) 2013 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 Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} [ @var{node}, @var{s}, @var{e} ] = getxmlnode (@var{xml}, @var{tag}) ## @deftypefnx {Function File} [ @var{node}, @var{s}, @var{e} ] = getxmlnode (@var{xml}, @var{tag}, @var{is}) ## @deftypefnx {Function File} [ @var{node}, @var{s}, @var{e} ] = getxmlnode (@var{xml}, @var{tag}, @var{is}, @var{contnt}) ## Get a string representing the first xml @var{tag} node starting at position ## @var{is} in xml text string @var{xml}, and return start and end indices. If ## @var{is} is omitted it defaults to 1 (start of @var{xml}). If @var{contnt} ## is TRUE, return the portion of the node between the outer tags. ## ## @seealso{getxmlattv} ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2013-09-08 ## Updates ## 2013-09-30 Use regexp for start & end positions as index catches false positives ## 2013-10-01 Input validation ## '' Further simplified using regexp ## '' Option to return just node contents ## 2013-10-02 Speed up using regexp options ## 2013-10-20 Fix typos in input validation error messages ## '' Better input validation ## 2013-11-04 More robust detection function [ node, spos, epos ] = getxmlnode (xml, tag, is=1, contnt=0) if (nargin < 2) print_usage; endif if (nargin >= 3 && isempty (is)) is = 1; endif ## Input validation if (! ischar (xml) || ! ischar (tag)) error ("getxmlnode: text strings expected for first two args"); elseif (nargin==3 && (! islogical (is) && ! isnumeric (is))) error ("getxmlnode: logical or numerical value expected for arg #3"); elseif (nargin==4 && (! islogical (contnt) && ! isnumeric (contnt))) error ("getxmlnode: logical or numerical value expected for arg #3"); endif is = max (is, 1); node = ''; ## Start tag must end with either />, a space preceding an attribute, or > ## Search order is vital as /> (single node) is otherwise easily missed spos = regexp (xml(is:end), sprintf ("<%s(/>| |>)", tag), "once"); if (! isempty (spos)) ## Apparently a node exists. Get its end. Maybe it is a single node ## ending in "/>" spos = spos(1); [~, epos] = regexp (xml(is+spos:end), sprintf ("(|%s[^><]*/>)", tag, tag), "once"); if (! isempty (epos)) epos = epos(1); node = xml(is+spos-1 : is+spos+epos(1)-1); if (contnt) if (strcmp (node(end-1:end), "/>")) ## Single node tag. Return empty string node = ''; else ## Get contents between end of opening tag en start of end tag node = node(index (node, ">", "first")+1 : index (node, "<", "last")-1); endif endif else error ("getxmlnode: couldn't find matching end tag for %s", tag); endif ## Update position pointers relative to input string epos += is + spos - 1; spos += is - 1; else ## No node found; reset pointers spos = 0; epos = 0; endif endfunction io/inst/io_ods_testscript.m0000644000076400010400000001515412261114536017375 0ustar PhilipAdministrators## Copyright (C) 2012,2013 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 . ## -*- texinfo -*- ## @deftypefn {Function File} io_ods_testscript (@var{intf1}) ## @deftypefnx {Function File} io_ods_testscript (@var{intf1}, @var{fname}) ## @deftypefnx {Function File} io_ods_testscript (@var{intf1}, @var{fname}, @var{intf2}) ## Try to check proper operation of ODS spreadsheet scripts using ## interface @var{intf1}. ## ## @var{intf1} can be one of OTK, JOD, UNO, or OCT. No checks ## are made as to whether the requested interface is supported at all. If ## @var{fname} is supplied, that filename is used for the tests, otherwise ## filename "io-test.ods" is chosen by default. This parameter is required ## to have e.g., JOD distinguish between testing (reading) .ods (ODS 1.2) ## and .sxc (old OpenOffice.org & StarOffice) files (that UNO can write). ## ## If @var{intf2} is supplied, that interface will be used for writing the ## spreadsheet file and @var{intf1} will be used for reading. The OCT ## interface doesn't have write support (yet), so it will read spreadsheet ## files made by OTK (if supported) unless another interface is supplied ## for @var{intf2}. ## ## As the tests are meant to be run interactively, no output arguments are ## returned. The results of all test steps are printed on the terminal. ## ## @seealso {test_spsh, io_xls_testscript} ## ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2012-02-25 ## Updates: ## 2012-09-04 Add small delay between LibreOffice calls to avoid lock-ups with UNO ## 2013-04-21 Made it into a function ## 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 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 printf ("(Writing files is done with interface %s)\n", upper (intf2)); endif if (strcmpi (intf, "uno") || strcmpi (intf2, "uno")); isuno = true; endif ## 1. Initialize test arrays printf ("\n 1. Initialize arrays.\n"); arr1 = [ 1 2; 3 4.5]; arr2 = {'r1c1', '=c2+d2'; '', 'r2c2'; true, -83.4}; opts = struct ("formulas_as_text", 0); ## 2. Insert empty sheet printf ("\n 2. Insert first empty sheet.\n"); odswrite (fname, {''}, 'EmptySheet', 'b4', intf2); if (isuno); sleep (dly); endif ## 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 ## 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 ## 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 shnr = strmatch ('Testsheet', shts(:, 1)); # Note case! crange = shts{shnr, 2}; ## 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 ## First check: has anything been read at all? if (isempty (raw)) printf ("No data at all have been read... test failed.\n"); return elseif (isempty (num)) printf ("No numeric data have been read... test failed.\n"); return elseif (isempty (txt)) printf ("No text data have been read... test failed.\n"); return endif ## 7. Here come the tests, part 1 printf ("\n 7. Tests part 1 (basic I/O):\n"); try printf (" ...Numeric array... "); assert (num(1:2, 1:3), [1, 2, NaN; 3, 4.5, NaN], 1e-10); assert (num(4:5, 1:3), [NaN, NaN, NaN; NaN, 1, -83.4], 1e-10); assert (num(3, 1:2), [NaN, NaN], 1e-10); # Just check if it's numeric, the value depends too much on cached results assert (isnumeric (num(3,3)), true); printf ("matches.\n"); catch printf ("Hmmm.... error, see 'num'\n"); end_try_catch try printf (" ...Cellstr array... "); assert (txt{1, 1}, 'r1c1'); assert (txt{2, 2}, 'r2c2'); printf ("matches.\n"); catch printf ("Hmmm.... error, see 'txt'\n"); end_try_catch try printf (" ...Boolean... "); assert (islogical (raw{5, 2}), true); ## Fails on JOD printf ("recovered.\n"); catch if (isnumeric (raw{5, 2})) printf ("recovered as numeric '1' rather than logical TRUE\n"); else printf ("Hmmm.... error, see 'raw'\n"); endif end_try_catch ## 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 clear ods; ## 9. Here come the tests, part 2. Fails on COM printf ("\n 9. Tests part 2 (read back formula):\n"); try # Just check if it contains any string assert ( (ischar (raw{3, 3}) && ~isempty (raw(3, 3))), true); printf (" ...OK, formula recovered ('%s').\n", raw{3, 3}); catch printf ("Hmmm.... error, see 'raw(3, 3)'"); if (isempty (raw{3, 3})) printf (" (, should be a string like '=c2+d2')\n"); elseif (isnumeric (raw{3, 3})) printf (" (equals %f, should be a string like '=c2+d2')\n", raw{3, 3}); else printf ("\n"); endif end_try_catch ## 10. Clean up printf ("\n10. Cleaning up....."); delete (fname); clear arr1 arr2 ods num txt raw lims opts shnr shts crange; printf (" OK\n"); endfunction io/inst/io_xls_testscript.m0000644000076400010400000002023212261114546017410 0ustar PhilipAdministrators## Copyright (C) 2012,2013 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 . ## -*- texinfo -*- ## @deftypefn {Function File} io_xls_testscript (@var{intf1}) ## @deftypefnx {Function File} io_xls_testscript (@var{intf1}, @var{fname}) ## @deftypefnx {Function File} io_xls_testscript (@var{intf1}, @var{fname}, @var{intf2}) ## Try to check proper operation of XLS / XLSX spreadsheet scripts using ## interface @var{intf1}. ## ## @var{intf1} can be one of COM, POI, JXL, OXS, UNO, or OCT. No checks ## are made as to whether the requested interface is supported at all. If ## @var{fname} is supplied, that filename is used for the tests, otherwise ## filename "io-test.xls" is chosen by default. This parameter is required ## to have e.g., POI distinguish between testing .xls (BIFF8) and .xlsx ## (OOXML) files. ## ## If @var{intf2} is supplied, that interface will be used for writing the ## spreadsheet file and @var{intf1} will be used for reading. The OCT ## interface doesn't have write support (yet), so it will read spreadsheet ## files made by POI (if supported) unless another interface is supplied ## for @var{intf2}. ## ## As the tests are meant to be run interactively, no output arguments are ## returned. The results of all test steps are printed on the terminal. ## ## @seealso {test_spsh, io_ods_testscript} ## ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2012-02-25 ## Updates: ## 2012-06-06 Adapted to COM implementation for "formulas_as_text" option ## 2012-09-04 Added delay between LibreOffice calls to avoid lockups with UNO ## 2013-04-21 Made it into a function ## 2013-12-12 Updated copyright strings ## 2013-12-19 Add option to write and read with different interfaces (needed for OCT) ## 2013-12-31 More extensive texinfo help text ## 2013-12-31 Style fixes ## '' Also delay a bit if write intf2 = UNO to avoid unzip errors ## 2014-01-01 Provisionally fall back to COM or POI for intf2 ## '' Provide default test file name function io_xls_testscript (intf, fname="io-test.xls", intf2=[]) printf ("\nTesting .xls interface %s using file %s...\n", upper (intf), fname); 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 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")); isuno = true; endif ## 1. Initialize test arrays printf ("\n 1. Initialize arrays.\n"); arr1 = [ 1 2; 3 4.5]; arr2 = {'r1c1', '=c2+d2'; '', 'r2c2'; true, -83.4}; opts = struct ("formulas_as_text", 0); ## 2. Insert empty sheet printf ("\n 2. Insert first empty sheet.\n"); xlswrite (fname, {''}, 'EmptySheet', 'b4', intf2); if (isuno) sleep (dly); endif ## 3. Add data to test sheet printf ("\n 3. Add data to test sheet.\n"); xlswrite (fname, arr1, 'Testsheet', 'c2:d3', intf2); if (isuno) sleep (dly); endif xlswrite (fname, arr2, 'Testsheet', 'd4:z20', intf2); if (isuno) sleep (dly); endif ## 4. Insert another sheet printf ("\n 4. Add another sheet with just one number in A1.\n"); xlswrite (fname, [1], 'JustOne', 'A1', intf2); if (isuno) sleep (dly); endif ## 5. Get sheet info & find sheet with data and data range printf ("\n 5. Explore sheet info.\n"); [~, shts] = xlsfinfo (fname, intf); if (isuno) sleep (dly); endif shnr = strmatch ('Testsheet', shts(:, 1)); ## Note case! if (isempty (shnr)) printf ("Worksheet with data not found - not properly written ... test failed.\n"); return endif crange = shts{shnr, 2}; ## Range can be unreliable 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); if (isuno) sleep (dly); endif ## First check: has anything been read at all?x if (isempty (raw)) printf ("No data at all have been read... test failed.\n"); return elseif (isempty (num)) printf ("No numeric data have been read... test failed.\n"); return elseif (isempty (txt)) printf ("No text data have been read... test failed.\n"); return endif ## 7. Here come the tests, part 1 err = 0; printf ("\n 7. Tests part 1 (basic I/O):\n"); try printf (" ...Numeric array... "); assert (num(1:2, 1:3), [1, 2, NaN; 3, 4.5, NaN], 1e-10); assert (num(4:5, 1:3), [NaN, NaN, NaN; NaN, 1, -83.4], 1e-10); assert (num(3, 1:2), [NaN, NaN], 1e-10); # Just check if it's numeric, the value depends too much on cached results assert (isnumeric (num(3,3)), true); printf ("matches...\n"); catch printf ("Hmmm.... error, see 'num'\n"); err = 1; end_try_catch try printf (" ...Cellstr array... "); assert (txt{1, 1}, 'r1c1'); assert (txt{2, 2}, 'r2c2'); printf ("matches...\n"); catch printf ("Hmmm.... error, see 'txt'\n"); err = 1; end_try_catch try printf (" ...Boolean... "); assert (islogical (raw{5, 2}), true); ## Fails on COM printf ("recovered...\n"); catch try if (isnumeric (raw{5, 2})) printf ("returned as numeric '1' rather than logical TRUE.\n"); else printf ("Hmmm.... error, see 'raw{5, 2}'\n"); endif catch err = 1; printf ("Hmmm.... error....\n"); end_try_catch end_try_catch if (err) ## Echo array to screen printf ("These are the data read back:\n"); raw printf ("...and this what they should look like:\n"); printf ("%s\n", ... "{\n [1,1] = 1\n [2,1] = 3\n [3,1] = [](0x0)\n [4,1] = [](0x0)\n [5,1] = [](0x0)\n [1,2] = 2\n [2,2] = 4.5000\n [3,2] = r1c1\n [4,2] =\n [5,2] = 1\n [1,3] = [](0x0)\n [2,3] = [](0x0)\n [3,3] = 3\n [4,3] = r2c2\n [5,3] = -83.400\n}"); endif ## Check if "formulas_as_text" option works: printf ("\n 8. Repeat reading, now return formulas as text\n"); opts.formulas_as_text = 1; xls = xlsopen (fname, 0, intf); if (isuno) sleep (dly); endif raw = xls2oct (xls, shnr, crange, opts); if (isuno) sleep (dly); endif xls = xlsclose (xls); if (isuno) sleep (dly); endif clear xls; ## 9. Here come the tests, part 2. printf ("\n 9. Tests part 2 (read back formula):\n"); try # Just check if it contains any string assert ( (ischar (raw{3, 3}) && ! isempty (raw(3, 3)) && raw{3, 3}(1) == "="), true); printf (" ...OK, formula recovered ('%s').\n", raw{3, 3}); catch printf ("Hmmm.... error, see 'raw(3, 3)'"); if (size (raw, 1) >= 3 && size (raw, 2) >= 3) if (isempty (raw{3, 3})) printf (" (empty, should be a string like '=c2+d2')\n"); elseif (isnumeric (raw{3, 3})) printf (" (equals %f, should be a string like '=c2+d2')\n", raw{3, 3}); else printf ("\n"); endif else printf (".. raw{3, 3} doesn't even exist, array too small... Test failed.\n"); endif end_try_catch ## 10. Clean up printf ("\n10. Cleaning up....."); delete (fname); clear arr1 arr2 xls num txt raw lims opts shnr shts crange intf2 err; printf (" OK\n"); endfunction io/inst/object2json.m0000644000076400010400000001707712217071420016060 0ustar PhilipAdministrators%% Copyright (C) 2010 Torre Herrera, Daniel de %% %% 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 . %% Returns a valid json string that will describe object; the string will %% be in a compact form (no spaces or line breaks). %% %% It will map simple octave values this way: %% function handles: string with the name of the function %% double (numbers): depends: %% If it's real it will map to a string representing that number %% If it's complex it will map to an object with the next properties: %% real: real part of the number %% imag: imaginary part of the number %% char: A string enclosed by double quotes representing that character %% logical: text sring "true" or "false" (w/o double quotes) %% And will map more complex octave values this other way: %% struct: an object with properties equal to the struct's field names %% and value equal to the json counterpart of that field %% cell: it will be mapped depending on the value of the cell (for %% example {i} will be mapped to an object with real=0 and imag=1) %% vectors or cell arrays: it will map them to a corresponding js %% array (same size) with the values transformed to their json %% counterpart (Note: that in javascript all arrays are like octave's %% cells ,i.e. they can store different type and size variables) %% strings or char vectors: they will be mapped to the same string %% enclosed by double quotes %% Other octave values will be mapped to a string enclosed by double %% quotes with the value that the class() function returns %% It can handle escape sequences and special chars automatically. %% If they're valid in JSON it will keep them if not they'll be %% escaped so they can become valid %% object2json.m %% Created: 2010-12-06 %% Updates: %% 2011-01-23 Added support for especial chars and escaped sequences %% 2011-04-01 Fixed error: Column vectors not working correctly %% 2011-09-08 (Philip Nienhuis) layout & style changes cf. Octave coding style %% 2011-08-13 (Keith Sheppard) Added logical types to object2json (bug #39429) function json = object2json (object) s = size (object); if (all (s==1)) % It's not a vector so we must check how to map it % Depending on the class of the object we must do one or another thing switch (class (object)) case 'function_handle' % For a function handle we will only print the name fun = functions (object); json = [ '"', fun.function, '"' ]; case 'struct' fields = fieldnames (object); results = cellfun (@object2json, struct2cell (object), "UniformOutput", false); json = '{'; if (numel (fields) > 1) sep = ','; else sep = ''; endif for (tmp = 1:numel (fields)) json = [ json, '"', fields{tmp}, '":', results{tmp}, sep ]; if(tmp >= numel (fields)-1) sep = ''; endif endfor json(end+1) = '}'; case 'cell' % We dereference the cell and use it as a new value json = object2json (object{1}); case 'double' if (isreal (object)) json = num2str (object); else if (iscomplex (object)) json = [ '{"real":', num2str(real(object)), ',"imag":' , num2str(imag(object)), '}' ]; endif endif case 'char' % Here we handle a single char % JSON only admits the next escape sequences: % \", \\, \/, \b, \f, \n, \r, \t and \u four-hex-digits % so we must be sure that every other sequence gets replaced object = replace_non_JSON_escapes (object); json = [ '"', object, '"' ]; case 'logical' if object json = 'true'; else json = 'false'; endif otherwise % We don't know what is it so we'll put the class name json = [ '"', class(object), '"' ]; endswitch else % It's a vector so it maps to an array sep = ''; if (numel (s) > 2) json = '['; for (tmp=1:s(1)) json = [ json, sep, object2json(reshape(object(tmp, :), s(2:end))) ]; sep = ','; endfor json(end+1) = ']'; else % We can have three cases here: % Object is a row -> array with all the elements % Object is a column -> each element is an array in it's own % Object is a 2D matrix -> separate each row if (s(1) == 1) % Object is a row if (ischar (object)) % If it's a row of chars we will take it as a string % JSON only admits the next escape sequences: % \", \\, \/, \b, \f, \n, \r, \t and \u four-hex-digits % so we must be sure that every other sequence gets replaced object = replace_non_JSON_escapes (object); json = [ '"', object, '"']; else json = '['; for (tmp=1:s(2)) json = [ json, sep, object2json(object(1, tmp)) ]; sep = ','; endfor json(end+1) = ']'; endif elseif (s(2) == 1) % Object is a column json = '['; for (tmp=1:s(1)) json = [ json, sep, '[', object2json(object(tmp, 1)), ']' ]; sep = ','; endfor json(end+1) = ']'; else % Object is a 2D matrix json = '['; for (tmp=1:s(1)) json = [ json, sep, object2json(object(tmp, :)) ]; sep = ','; endfor json(end+1) = ']'; endif endif endif endfunction % JSON only admits the next escape sequences: % \", \\, \/, \b, \f, \n, \r, \t and \u four-hex-digits % This function replace every escaped sequence that isn't on that list % with a compatible version % Note that this function uses typeinfo so it may need to be updated % with each octave release function object = replace_non_JSON_escapes (object) if (strcmp (typeinfo (object), 'string')) % It's a double quoted string so newlines and other chars need % to be converted back into escape sequences before anything object = undo_string_escapes (object); endif % This first regex handles double quotes and slashes that are not % after a backslash and thus aren't escaped object = regexprep (object, '(?= 90; %! car.leased = logical(1); %! car.european = logical(0); %! assert(object2json(car), '{"name":"Mzd R8","speedsamples":[[98,33,50],[56,120,102],[77,82,93]],"toofast":[[true,false,false],[false,true,true],[false,false,true]],"leased":true,"european":false}'); io/inst/oct2ods.m0000644000076400010400000002144612254405352015214 0ustar PhilipAdministrators## Copyright (C) 2009,2010,2011,2012,2013 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 . ## -*- texinfo -*- ## @deftypefn {Function File} [ @var{ods}, @var{rstatus} ] = oct2ods (@var{arr}, @var{ods}) ## @deftypefnx {Function File} [ @var{ods}, @var{rstatus} ] = oct2ods (@var{arr}, @var{ods}, @var{wsh}) ## @deftypefnx {Function File} [ @var{ods}, @var{rstatus} ] = oct2ods (@var{arr}, @var{ods}, @var{wsh}, @var{range}) ## @deftypefnx {Function File} [ @var{ods}, @var{rstatus} ] = oct2ods (@var{arr}, @var{ods}, @var{wsh}, @var{range}, @var{options}) ## ## Transfer data to an OpenOffice_org Calc spreadsheet previously opened ## by odsopen(). ## ## Data in 1D/2D array @var{arr} are transferred into a cell range ## @var{range} in sheet @var{wsh}. @var{ods} must have been made earlier ## by odsopen(). Return argument @var{ods} should be the same as supplied ## argument @var{ods} and is updated by oct2ods. A subsequent call to ## odsclose is needed to write the updated spreadsheet to disk (and ## -if needed- close the Java invocation holding the file pointer). ## ## @var{arr} can be any 1D or 2D array containing numerical or character ## data (cellstr) except complex. Mixed numeric/text arrays can only be ## cell arrays. ## ## @var{ods} must be a valid pointer struct created earlier by odsopen. ## ## @var{wsh} can be a number (sheet name) or string (sheet number). ## In case of a yet non-existing Calc file, the first sheet will be ## used & named according to @var{wsh}. ## In case of existing files, some checks are made for existing sheet ## names or numbers. ## When new sheets are to be added to the Calc file, they are ## inserted to the right of all existing sheets. The pointer to the ## "active" sheet (shown when Calc opens the file) remains untouched. ## ## If @var{range} omitted, the top left cell where the data will be put ## is supposed to be 'A1'; only a top left cell address can be specified ## as well. In these cases the actual range to be used is determined by ## the size of @var{arr}. ## Be aware that large data array sizes may exhaust the java shared ## memory space. For larger arrays, appropriate memory settings are ## needed in the file java.opts; then the maximum array size for the ## java-based spreadsheet options can be in the order of perhaps 10^6 ## elements. ## ## Optional argument @var{options}, a structure, can be used to specify ## various write modes. ## Currently the only option field is "formulas_as_text", which -if set ## to 1 or TRUE- specifies that formula strings (i.e., text strings ## starting with "=" and ending in a ")" ) should be entered as litteral ## text strings rather than as spreadsheet formulas (the latter is the ## default). As jOpenDocument doesn't support formula I/O at all yet, ## this option is ignored for the JOD interface. ## ## Data are added to the sheet, ignoring other data already present; ## existing data in the range to be used will be overwritten. ## ## If @var{range} contains merged cells, also the elements of @var{arr} ## not corresponding to the top or left Calc cells of those merged cells ## will be written, however they won't be shown until in Calc the merge is ## undone. ## ## Examples: ## ## @example ## [ods, status] = ods2oct (arr, ods, 'Newsheet1', 'AA31:GH165'); ## Write array arr into sheet Newsheet1 with upperleft cell at AA31 ## @end example ## ## @example ## [ods, status] = ods2oct (@{'String'@}, ods, 'Oldsheet3', 'B15:B15'); ## Put a character string into cell B15 in sheet Oldsheet3 ## @end example ## ## @seealso {ods2oct, odsopen, odsclose, odsread, odswrite, odsfinfo} ## ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2009-12-13 ## Updates: ## 2010-01-15 Updated texinfo header ## 2010-03-14 Updated help text (a.o. on java memory usage) ## 2010-03-25 see oct2jotk2ods ## 2010-03-28 Added basic support for ofdom v.0.8. Everything works except adding cols/rows ## 2010-03-29 Removed odfdom-0.8 support, it's simply too buggy :-( Added a warning instead ## 2010-06-01 Almost complete support for upcoming jOpenDocument 1.2b4. 1.2b3 still lacks a bit ## 2010-07-05 Added example for writng character strings ## 2010-07-29 Added option for entering / reading back spreadsheet formulas ## 2010-08-14 Moved check on input cell array to main function ## 2010-08-15 Texinfo header edits ## 2010-08-16 Added check on presence of output argument ## 2010-08-23 Added check on validity of ods file ptr ## '' Experimental support for odfdom 0.8.6 (in separate subfunc, to be integrated later) ## 2010-08-25 Improved help text (java memory, ranges) ## 2010-10-27 Improved file change tracking tru ods.changed ## 2010-11-12 Better input argument checks ## 2010-11-13 Reset ods.limits when read was successful ## 2010-11-13 Added check for 2-D input array ## 2011-03-23 First try of odfdom 0.8.7 ## 2011-05-15 Experimental UNO support added ## 2011-11-18 Fixed bug in test for range parameter being character string ## 2012-01-26 Fixed "seealso" help string ## 2012-02-20 Fixed range parameter to be default empty string rather than empty numeral ## 2012-02-27 More range arg fixes ## 2012-03-07 Updated texinfo help text ## 2012-06-08 Support for odfdom-incubator-0.8.8 ## '' Tabs replaced by double space ## 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 ## ## Latest subfunc update: 2012-10-12 function [ ods, rstatus ] = oct2ods (c_arr, ods, wsh=1, crange="", spsh_opts=[]) if (nargin < 2) error ("oct2xls needs a minimum of 2 arguments."); endif ## Check if input array is cell if (isempty (c_arr)) warning ("oct2ods: request to write empty matrix - ignored."); rstatus = 1; return; elseif (isnumeric (c_arr)) c_arr = num2cell (c_arr); elseif (ischar(c_arr)) c_arr = {c_arr}; printf ("(oct2ods: input character array converted to 1x1 cell)\n"); elseif (~iscell (c_arr)) error ("oct2ods: input array neither cell nor numeric array"); endif if (ndims (c_arr) > 2) error ("oct2ods: only 2-dimensional arrays can be written to spreadsheet"); endif ## Check ods file pointer struct test1 = ! isfield (ods, "xtype"); test1 = test1 || ! isfield (ods, "workbook"); test1 = test1 || isempty (ods.workbook); test1 = test1 || isempty (ods.app); if test1 error ("oct2ods: arg #2: Invalid ods file pointer struct"); endif ## Check worksheet ptr if (! (ischar (wsh) || isnumeric (wsh))) error ("oct2ods: integer (index) or text (wsh name) expected for arg # 3"); endif ## Check range if (! isempty (crange) && ! ischar (crange)) error ("oct2ods: character string (range) expected for arg # 4"); elseif (isempty (crange)) crange = ""; endif ## Various options if (isempty (spsh_opts)) spsh_opts.formulas_as_text = 0; ## other options to be implemented here elseif (isstruct (spsh_opts)) if (! isfield (spsh_opts, "formulas_as_text")) spsh_opts.formulas_as_text = 0; endif ## other options to be implemented here: else error ("oct2ods: structure expected for arg # 5" (options)); endif if (nargout < 1) printf ("oct2ods: warning: no output spreadsheet file pointer specified.\n"); endif if (strcmp (ods.xtype, "OTK")) ## Write ods file tru Java & ODF toolkit. switch ods.odfvsn case "0.7.5" [ ods, rstatus ] = __OTK_oct2ods__ (c_arr, ods, wsh, crange, spsh_opts); case {"0.8.6", "0.8.7", "0.8.8"} [ ods, rstatus ] = __OTK_oct2spsh__ (c_arr, ods, wsh, crange, spsh_opts); otherwise error ("oct2ods: unsupported odfdom version"); endswitch 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 Java & UNO bridge (OpenOffice.org & clones) [ ods, rstatus ] = __UNO_oct2spsh__ (c_arr, ods, wsh, crange, spsh_opts); ##elseif ##---- < Other interfaces here > else error (sprintf ("ods2oct: unknown OpenOffice.org .ods interface - %s.",... ods.xtype)); endif if (rstatus), ods.limits = []; endif endfunction io/inst/oct2xls.m0000644000076400010400000002202612260076024015225 0ustar PhilipAdministrators## Copyright (C) 2009,2010,2011,2012 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 . ## -*- texinfo -*- ## @deftypefn {Function File} [ @var{xls}, @var{rstatus} ] = oct2xls (@var{arr}, @var{xls}) ## @deftypefnx {Function File} [ @var{xls}, @var{rstatus} ] = oct2xls (@var{arr}, @var{xls}, @var{wsh}) ## @deftypefnx {Function File} [ @var{xls}, @var{rstatus} ] = oct2xls (@var{arr}, @var{xls}, @var{wsh}, @var{range}) ## @deftypefnx {Function File} [ @var{xls}, @var{rstatus} ] = oct2xls (@var{arr}, @var{xls}, @var{wsh}, @var{range}, @var{options}) ## ## Add data in 1D/2D CELL array @var{arr} into a cell range specified in ## @var{range} in worksheet @var{wsh} in an Excel spreadsheet file ## pointed to in structure @var{xls}. ## Return argument @var{xls} equals supplied argument @var{xls} and is ## updated by oct2xls. ## ## A subsequent call to xlsclose is needed to write the updated spreadsheet ## to disk (and -if needed- close the Excel or Java invocation). ## ## @var{arr} can be any 1D or 2D array containing numerical or character ## data (cellstr) except complex. Mixed numeric/text arrays can only be ## cell arrays. ## ## @var{xls} must be a valid pointer struct created earlier by xlsopen. ## ## @var{wsh} can be a number or string (max. 31 chars). ## In case of a yet non-existing Excel file, the first worksheet will be ## used & named according to @var{wsh} - extra empty worksheets that Excel ## creates by default are deleted. ## 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). ## When new worksheets are to be added to the Excel file, they are ## inserted to the right of all existing worksheets. The pointer to the ## "active" sheet (shown when Excel opens the file) remains untouched. ## ## If @var{range} is omitted or just the top left cell of the range is ## specified, the actual range to be used is determined by the size of ## @var{arr}. If nothing is specified for @var{range} the top left cell ## is assumed to be 'A1'. ## ## Data are added to the worksheet, ignoring other data already present; ## existing data in the range to be used will be overwritten. ## ## If @var{range} contains merged cells, only the elements of @var{arr} ## corresponding to the top or left Excel cells of those merged cells ## will be written, other array cells corresponding to that cell will be ## ignored. ## ## Optional argument @var{options}, a structure, can be used to specify ## various write modes. ## Currently the only option field is "formulas_as_text", which -if set ## to 1 or TRUE- specifies that formula strings (i.e., text strings ## starting with "=" and ending in a ")" ) should be entered as litteral ## text strings rather than as spreadsheet formulas (the latter is the ## default). ## ## Beware that -if invoked- Excel invocations may be left running silently ## in case of COM errors. Invoke xlsclose with proper pointer struct to ## close them. ## When using Java, note that large data array sizes elements may exhaust ## the Java shared memory space for the default java memory settings. ## For larger arrays, appropriate memory settings are needed in the file ## java.opts; then the maximum array size for the Java-based spreadsheet ## options may be in the order of 10^6 elements. In caso of UNO this ## limit is not applicable and spreadsheets may be much larger. ## ## Examples: ## ## @example ## [xlso, status] = xls2oct ('arr', xlsi, 'Third_sheet', 'AA31:AB278'); ## @end example ## ## @seealso {xls2oct, xlsopen, xlsclose, xlsread, xlswrite, xlsfinfo} ## ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2009-12-01 ## Updates: ## 2010-01-03 (OOXML support) ## 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 ## '' old argument version (just topleft cell) is still recognized, though ## 2010-08014 Added char array conversion to 1x1 cell for character input arrays ## 2010-08-16 Added check on presence of output argument. Made wsh = 1 default ## 2010-08-17 Corrected texinfo ("topleft" => "range") ## 2010-08-25 Improved help text (section on java memory usage) ## 2010-11-12 Moved ptr struct check into main func. More input validity checks ## 2010-11-13 Added check for 2-D input array ## 2010-12-01 Better check on file pointer struct (ischar (xls.xtype)) ## 2011-03-29 OpenXLS support added. Works but saving to file (xlsclose) doesn't work yet ## '' Bug fixes (stray variable c_arr, and wrong test for valid xls struct) ## 2011-05-18 Experimental UNO support ## 2011-09-08 Bug fix in range arg check; code cleanup ## 2011-11-18 Fixed another bug in test for range parameter being character string ## 2012-01-26 Fixed "seealso" help string ## 2012-02-20 Fixed range parameter to be default empty string rather than empty numeral ## 2012-02-27 More range param fixes ## 2012-03-07 Updated texinfo help text ## 2012-05-22 Cast all numeric data in input array to double ## 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 function [ xls, rstatus ] = oct2xls (obj, xls, wsh=1, crange="", spsh_opts=[]) if (nargin < 2) error ("oct2xls needs a minimum of 2 arguments."); endif ## Validate input array, make sure it is a cell array if (isempty (obj)) warning ("oct2xls: request to write empty matrix - ignored."); rstatus = 1; return; elseif (isnumeric (obj)) obj = num2cell (obj); elseif (ischar (obj)) obj = {obj}; printf ("(oct2xls: input character array converted to 1x1 cell)\n"); elseif (! iscell (obj)) error ("oct2xls: input array neither cell nor numeric array"); endif if (ndims (obj) > 2) error ("oct2xls: only 2-dimensional arrays can be written to spreadsheet"); endif ## Cast all numerical values to double as spreadsheets only have double/boolean/text type idx = cellfun (@isnumeric, obj, "UniformOutput", true); obj(idx) = cellfun (@double, obj(idx), "UniformOutput", false); ## Check xls file pointer struct test1 = ! isfield (xls, "xtype"); test1 = test1 || ! isfield (xls, "workbook"); test1 = test1 || isempty (xls.workbook); test1 = test1 || isempty (xls.app); test1 = test1 || ! ischar (xls.xtype); if (test1) error ("oct2xls: invalid xls file pointer struct"); endif ## Check worksheet ptr if (! (ischar (wsh) || isnumeric (wsh))) error ("Integer (index) or text (wsh name) expected for arg # 3"); endif ## Check range if (! isempty (crange) && ! ischar (crange)) error ("oct2xls: character string expected for arg # 4 (range)"); elseif (isempty (crange)) crange = ""; endif ## Various options if (isempty (spsh_opts)) spsh_opts.formulas_as_text = 0; ## other options to be implemented here elseif (isstruct (spsh_opts)) if (! isfield (spsh_opts, "formulas_as_text")) spsh_opts.formulas_as_text = 0; endif ## other options to be implemented here else error ("oct2xls: structure expected for arg # 5"); endif if (nargout < 1) printf ("oct2xls: warning: no output spreadsheet file pointer specified.\n"); endif ## Select interface to be used if (strcmpi (xls.xtype, "COM")) ## ActiveX / COM [xls, rstatus] = __COM_oct2spsh__ (obj, xls, wsh, crange, spsh_opts); elseif (strcmpi (xls.xtype, "POI")) ## Invoke Java and Apache POI [xls, rstatus] = __POI_oct2spsh__ (obj, xls, wsh, crange, spsh_opts); elseif (strcmpi (xls.xtype, "JXL")) ## 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"); [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, "")) ## else error (sprintf ("oct2xls: unknown Excel .xls interface - %s.", xls.xtype)); endif endfunction io/inst/ods2oct.m0000644000076400010400000002307012257323306015210 0ustar PhilipAdministrators## Copyright (C) 2009,2010,2011,2012,2013 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 . ## -*- texinfo -*- ## @deftypefn {Function File} [ @var{rawarr}, @var{ods}, @var{rstatus} ] = ods2oct (@var{ods}) ## @deftypefnx {Function File} [ @var{rawarr}, @var{ods}, @var{rstatus} ] = ods2oct (@var{ods}, @var{wsh}) ## @deftypefnx {Function File} [ @var{rawarr}, @var{ods}, @var{rstatus} ] = ods2oct (@var{ods}, @var{wsh}, @var{range}) ## @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}. ## ## @var{ods} is supposed to have been created earlier by odsopen in the ## same octave session. ## ## @var{wsh} is either numerical or text, in the latter case it is ## case-sensitive. ## 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. ## ## @var{range} is expected to be a regular spreadsheet range format, ## or "" (empty string, indicating all data in a worksheet). ## If no range is specified the occupied cell range will have to be ## determined behind the scenes first; this can take some time. ## ## Optional argument @var{options}, a structure, can be used to ## specify various read modes by setting option fields in the struct ## to true (1) or false (0). Currently recognized option fields are: ## ## @table @asis ## @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. ## The default value is 0 (FALSE). ## ## @item 'strip_array' ## Set the value of this field set to TRUE or 1 to strip the returned ## output array @var{rawarr} from empty outer columns and rows. The ## spreadsheet cell rectangle limits from where the data actually ## came will be updated. The default value is FALSE or 0 (no cropping). ## @end table ## ## If only the first argument @var{ods} is specified, ods2oct will ## try to read all contents from the first = leftmost (or the only) ## worksheet (as if a range of @'' (empty string) was specified). ## ## If only two arguments are specified, ods2oct assumes the second ## argument to be @var{wsh}. In that case ods2oct will try to read ## all data contained in that worksheet. ## ## Return argument @var{rawarr} contains the raw spreadsheet cell data. ## Use parsecell() to separate numeric and text values from @var{rawarr}. ## ## Optional return argument @var{ods} contains the pointer struct. Field ## @var{ods}.limits contains the outermost column and row numbers of the ## actually read cell range. ## ## Optional return argument @var{rstatus} will be set to 1 if the ## 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). ## ## 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. ## ## Examples: ## ## @example ## A = ods2oct (ods1, '2nd_sheet', 'C3:ABS40000'); ## (which returns the numeric contents in range C3:ABS40000 in worksheet ## '2nd_sheet' from a spreadsheet file pointed to in pointer struct ods1, ## into numeric array A) ## @end example ## ## @example ## [An, ods2, status] = ods2oct (ods2, 'Third_sheet'); ## @end example ## ## @seealso {odsopen, odsclose, parsecell, odsread, odsfinfo, oct2ods, odswrite} ## ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2009-12-13 ## Updates: ## 2009-12-30 First working version ## 2010-03-19 Added check for odfdom version (should be 0.7.5 until further notice) ## 2010-03-20 Works for odfdom v 0.8 too. Added subfunction ods3jotk2oct for that ## 2010-04-06 Benchmarked odfdom versions. v0.7.5 is up to 7 times faster than v0.8! ## So I added a warning for users using odfdom 0.8. ## 2010-04-11 Removed support for odfdom-0.8 - it's painfully slow and unreliable ## 2010-05-31 Updated help text (delay i.c.o. empty range due to getusedrange call) ## 2010-08-03 Added support for reading back formulas (works only in OTK) ## 2010-08-12 Added explicit support for jOpenDocument v 1.2b3+ ## 2010-08-25 Improved helptext (moved some text around) ## 2010-08-27 Added ods3jotk2oct - internal function for odfdom-0.8.6.jar ## '' Extended check on spsh_opts (must be a struct) ## 2010-10-27 Moved cropping rawarr from empty outer rows & columns to here ## 2011-05-06 Experimental UNO support ## 2011-09-18 Set rstatus var here ## 2012-01-26 Fixed "seealso" help string ## 2012-02-25 Added 0.8.7 to supported odfdom versions in L.155 ## 2012-02-26 Updated texinfo header help text ## 2012-06-08 Support for odfdom-incubator 0.8.8 ## '' Replaced tabs by double space ## 2012-10-12 Moved all interface-specific subfubcs into ./private ## 2012-10-24 Style fixes ## 2013-09-09 Native Octave interface ("OCT") for reading ## 2013-09-23 Updated copyright messages ## 2013-10-02 Some adaptations for gnumeric ## 2013-12-01 Style fixes ## 2013-12-27 More style fixes ## ## Latest subfunc update: 2012-10-12 function [ rawarr, ods, rstatus ] = ods2oct (ods, wsh=1, datrange=[], spsh_opts=[]) ## Check if ods struct pointer seems valid if (! isstruct (ods)) error ("File ptr struct expected for arg @ 1"); endif test1 = ! isfield (ods, "xtype"); test1 = test1 || ! isfield (ods, "workbook"); test1 = test1 || isempty (ods.workbook); test1 = test1 || isempty (ods.app); if (test1) error ("Arg #1 is an invalid ods file struct"); endif ## Check worksheet ptr if (! (ischar (wsh) || isnumeric (wsh))) error ("Integer (index) or text (wsh name) expected for arg # 2"); endif ## Check range if (! (isempty (datrange) || ischar (datrange))) error ("Character string (range) expected for arg # 3"); endif ## Check & setup options struct if (nargin < 4 || isempty (spsh_opts)) spsh_opts.formulas_as_text = 0; spsh_opts.strip_array = 1; ## Other options here: elseif (! isstruct (spsh_opts)) error ("struct expected for OPTIONS argument (# 4)"); else if (! isfield (spsh_opts, "formulas_as_text")) spsh_opts.formulas_as_text = 0; endif if (! isfield (spsh_opts, "strip_array")) spsh_opts.strip_array = 1; endif ## Future options: endif ## Select the proper interfaces if (strcmp (ods.xtype, "OTK")) ## Read ods file tru Java & ODF toolkit switch ods.odfvsn case "0.7.5" [rawarr, ods] = __OTK_ods2oct__ (ods, wsh, datrange, spsh_opts); case {"0.8.6", "0.8.7", "0.8.8"} [rawarr, ods] = __OTK_spsh2oct__ (ods, wsh, datrange, spsh_opts); otherwise error ("Unsupported odfdom version or invalid ods file pointer."); endswitch elseif (strcmp (ods.xtype, "JOD")) ## Read ods file tru Java & jOpenDocument. JOD doesn't know about formulas :-( [rawarr, ods] = __JOD_spsh2oct__ (ods, wsh, datrange); elseif (strcmp (ods.xtype, "UNO")) ## Read ods file tru Java & UNO [rawarr, ods] = __UNO_spsh2oct__ (ods, wsh, datrange, spsh_opts); elseif (strcmp (ods.xtype, "OCT")) if (strcmpi (ods.app, 'ods')) ## Read ods file tru native Octave [rawarr, ods] = __OCT_ods2oct__ (ods, wsh, datrange, spsh_opts); elseif (strcmpi (ods.app, 'gnumeric')) ## Read gnumeric. Gnumeric does not support formula evaluation nor supports ## cached values. Stripping output is processed below, spsh_opts is ignored [rawarr, ods] = __OCT_gnm2oct__ (ods, wsh, datrange); endif ##elseif ## ---- < Other interfaces here > else error (sprintf ("ods2oct: unknown OpenOffice.org .ods interface - %s.", ods.xtype)); endif rstatus = ! isempty (rawarr); ## Optionally strip empty outer rows and columns & keep track of original data location if (spsh_opts.strip_array && rstatus) emptr = cellfun ("isempty", rawarr); if (all (all (emptr))) rawarr = {}; ods.limits= []; else nrows = size (rawarr, 1); ncols = size (rawarr, 2); irowt = 1; while (all (emptr(irowt, :))); irowt++; endwhile irowb = nrows; while (all (emptr(irowb, :))); irowb--; endwhile icoll = 1; while (all (emptr(:, icoll))); icoll++; endwhile icolr = ncols; while (all (emptr(:, icolr))); icolr--; endwhile # Crop outer rows and columns and update limits rawarr = rawarr(irowt:irowb, icoll:icolr); ods.limits = ods.limits + [icoll-1, icolr-ncols; irowt-1, irowb-nrows]; endif endif endfunction io/inst/odsclose.m0000644000076400010400000001331712260630460015445 0ustar PhilipAdministrators## Copyright (C) 2009,2010,2011,2012,2013 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 . ## -*- texinfo -*- ## @deftypefn {Function File} [@var{ods}] = odsclose (@var{ods}) ## @deftypefnx {Function File} [@var{ods}] = odsclose (@var{ods}, @var{filename}) ## @deftypefnx {Function File} [@var{ods}] = odsclose (@var{ods}, "FORCE") ## Close the OpenOffice_org Calc / Gnumeric spreadsheet pointed to in struct ## @var{ods}, if needed write the file to disk. ## odsclose will determine if the file must be written to disk based on ## information contained in @var{ods}. ## An empty pointer struct will be returned if no errors occurred. ## Optional argument @var{filename} can be used to write changed spreadsheet ## files to an other file than opened by odsopen(). ## Optional string argument "FORCE" can be specified to force resetting the ## file pointer struct. However, in case of UNO, a hidden OOo invocation ## may linger on in memory then, preventing proper closing of Octave. ## ## For writing .ods files you need the Java package >= 1.2.6 plus odfdom.jar ## + xercesImpl.jar and/or jopendocument-.jar installed on your ## computer + proper javaclasspath set, to make this function work at all. ## For UNO support, Octave-Java package >= 1.2.9 is imperative; ## furthermore the relevant classes had best be added to the javaclasspath by ## utility function chk_spreadsheet_support(). ## ## @var{ods} must be a valid pointer struct made by odsopen() in the same ## octave session. ## ## Examples: ## ## @example ## ods1 = odsclose (ods1); ## (Close spreadsheet file pointed to in pointer struct ods1; ods1 is reset) ## @end example ## ## @seealso {odsopen, odsread, odswrite, ods2oct, oct2ods, odsfinfo, chk_spreadsheet_support} ## ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2009-12-13 ## Updates: ## 2010-01-08 (OTK ODS write support) ## 2010-04-13 Improved help text a little bit ## 2010-08-25 Swapped in texinfo help text ## 2010-10-17 Fixed typo in error message about unknown interface ## 2010-10-27 Improved file change tracking tru ods.changed ## 2010-11-12 Keep ods file pointer when write errors occur. ## '' Added optional filename arg to change filename to be written to ## 2011-05-06 Experimental UNO support ## 2011-05-07 In case of UNO, soffice now properly closed using xDesk ## 2011-05-18 Saving newly created files using UNO supported now ## 2011-09-08 FIXME - closing OOo kills all other OOo invocations (known Java-UNO issue) ## 2012-01-26 Fixed "seealso" help string ## 2012-06-08 tabs replaced by double space ## 2012-09-03 Extended file renaming section to xlsclose equivalent ## 2012-10-12 Move most interface-specific code to ./private subfuncs ## '' Move "file ptr preserved" message to proper else clause ## 2012-10-23 Style fixes ## 2012-12-18 Improved error/warning messages ## 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 function [ ods ] = odsclose (ods, varargs) ## If needed warn that dangling spreadsheet pointers may be left if (nargout < 1) warning ("odsclose.m: return argument missing - ods invocation not reset."); endif force = 0; if (isempty (ods)) warning ("odsclose: file pointer struct is empty; was it already closed?")'; return endif if (nargin > 1) for ii=2:nargin if (strcmpi(varargin{ii}, "force")) ## Close .ods anyway even if write errors occur force = 1; elseif (! isempty (strfind (tolower (varargin{ii}), "."))) ## Apparently a file name. First some checks.... if (ods.changed == 0 || ods.changed > 2) warning ("odsclose.m: file %s wasn't changed, new filename ignored.", ods.filename); elseif (! strcmp (xls.xtype, "UNO") && ... isempty (strfind ( lower (filename), ".ods"))) ## UNO will write any file type, all other interfaces only .ods error ("odsclose.m: .ods suffix lacking in filename %s", filename); else ## Preprocessing / -checking ready. ## Assign filename arg to file ptr struct ods.nfilename = filename; endif endif endfor endif if (strcmp (ods.xtype, "OTK")) ## Java & ODF toolkit ods = __OTK_spsh_close__ (ods, force); elseif (strcmp (ods.xtype, "JOD")) ## Java & jOpenDocument ods = __JOD_spsh_close__ (ods); elseif (strcmp (ods.xtype, "UNO")) ## Java & UNO bridge ods = __UNO_spsh_close__ (ods, force); elseif (strcmp (ods.xtype, "OCT")) ## Native Octave ods = __OCT_spsh_close__ (ods); ##elseif ---- < Other interfaces here > else error (sprintf ("ods2close: unknown OpenOffice.org .ods interface - %s.",... ods.xtype)); endif if (ods.changed && ods.changed < 3) error (sprintf ("odsclose.m: could not save file %s - read-only or in use elsewhere?",... ods.filename)); if (force) ods = []; else printf ("(File pointer preserved)\n"); endif else ## Reset file pointer ods = []; endif endfunction io/inst/odsfinfo.m0000644000076400010400000001322712246632224015445 0ustar PhilipAdministrators## Copyright (C) 2009,2010,2011,2012,2013 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 . ## -*- 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. ## ## 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 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 ## to right) in which they occur in the sheet stack. ## ## If you omit return arguments @var{filetype} and @var{sh_names} altogether, ## odsfinfo returns the sheet names and for each sheet the actual occupied ## data ranges to the screen.The occupied cell range will have to be ## determined behind the scenes first; this can take some time. ## ## odsfinfo execution can take its time for large spreadsheets as the entire ## spreadsheet has to be parsed to get the sheet names, let alone exploring ## 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 ## interface will be used (if at all present). ## ## Examples: ## ## @example ## exist = odsfinfo ('test4.ods'); ## (Just checks if file test4.ods is a readable Calc file) ## @end example ## ## @example ## [exist, names] = odsfinfo ('test4.ods'); ## (Checks if file test4.ods is a readable Calc file and return a ## list of sheet names) ## @end example ## ## @seealso {odsread, odsopen, ods2oct, odsclose} ## ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2009-12-17 ## Updates: ## 2010-01-03 Added functionality for JOD as well ## 2010-03-03 Fixed echo of proper number of occupied data rows ## 2010-03-18 Fixed proper echo of occupied data range ## (ah those pesky table-row-repeated & table-column-repeated attr.... :-( ) ## 2010-03-18 Separated range exploration (for OTK only yet) in separate function file ## 2010-03-20 "Beautified" output (for OTK ), used range now in more tabular form ## 2010-05-23 Updated jOpenDocument support (can also get occupied data range now) ## 2010-05-31 Added remark about delays when determining occupied data range ## 2011-03-23 Adapted to odfdom 0.8.7 (changed getXPath method call) ## 2011-05-07 Experimental UNO support added ## 2011-09-03 Normal return in case of no ODS support (empty ods struct) ## 2012-01-26 Fixed "seealso" help string ## 2012-02-25 Return occupied sheet ranges in output args ## '' Improve echo of sheet names & ranges if interactive ## 2012-03-01 Fix wrong cell refs in UNO section ("(..)" rather than "{..}" ## 2012-06-08 Support for odfdom-0.8.8-incubator ## 2012-10-12 Moved all interface-specific code into ./private subfuncs ## 2012-10-24 Style fixes ## 2013-09-09 Native Octave interface ("OCT") for reading ## 2013-09-23 Header updated to OCT interface ## 2013-12-01 Output arg #2 adapted to file type tru switch stmt function [ filetype, sh_names ] = odsfinfo (filename, reqintf=[]) persistent str2; str2 = " "; # 33 spaces persistent lstr2; lstr2 = length (str2); toscreen = nargout < 1; ods = odsopen (filename, 0, reqintf); ## If no ods support was found, odsopen will have complained. Just return here if (isempty (ods)), return; endif ## If any valid xls-pointer struct has been returned, it must be a valid ## spreadsheet. Find out what format [~, ~, ext] = fileparts (ods.filename); switch ext case {"ods", "sxc"} filetype = "OpenOffice.org Calc Document"; case "gnumeric" filetype = "Gnumeric spreadsheet"; otherwise endswitch ## To save execution time, only proceed if sheet names are wanted if ~(nargout == 1) if (strcmp (ods.xtype, "OTK")) [sh_names] = __OTK_spsh_info__ (ods); elseif (strcmp (ods.xtype, "JOD")) [sh_names] = __JOD_spsh_info__ (ods); elseif (strcmp (ods.xtype, "UNO")) [sh_names] = __UNO_spsh_info__ (ods); elseif (strcmp (ods.xtype, "OCT")) [sh_names] = __OCT_spsh_info__ (ods); else ## Below error will have been catched in odsopen() above ##error (sprintf ("odsfinfo: unknown OpenOffice.org .ods interface - %s.",... ## ods.xtype)); endif endif if (toscreen) sh_cnt = size (sh_names, 1); # Echo sheet names to screen for ii=1:sh_cnt str1 = sprintf ("%3d: %s", ii, sh_names{ii, 1}); if (index (sh_names{ii, 2}, ":")) str3 = ["(Used range ~ " sh_names{ii, 2} ")"]; else str3 = sh_names{ii, 2}; endif printf ("%s%s%s\n", str1, str2(1:lstr2-length (sh_names{ii, 1})), str3); endfor endif ods = odsclose (ods); endfunction io/inst/odsopen.m0000644000076400010400000003245512261102424015300 0ustar PhilipAdministrators## 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 Foundation; either version 2 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 Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} @var{ods} = odsopen (@var{filename}) ## @deftypefnx {Function File} @var{ods} = odsopen (@var{filename}, @var{readwrite}) ## @deftypefnx {Function File} @var{ods} = odsopen (@var{filename}, @var{readwrite}, @var{reqintf}) ## Get a pointer to an OpenOffice_org spreadsheet in the form of return ## argument @var{ods}. ## ## 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 ## 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 ## to as OTK, JOD, and UNO resp., and are preferred in that order by default ## (depending on their presence; the OCT interface has lowest priority). ## 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:////filename"; ## a URL will also work. If a plain file name is given (absolute or relative), ## odsopen() will 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. ## ## Beware: ## The UNO interface is still experimental. While in itself reliable, it may ## have undesired side effects on Open-/LibreOffice windows outside Octave. ## ## Examples: ## ## @example ## ods = odsopen ('test1.ods'); ## (get a pointer for reading from spreadsheet test1.ods) ## ## ods = odsopen ('test2.ods', [], 'JOD'); ## (as above, indicate test2.ods will be read from; in this case using ## the jOpenDocument interface is requested) ## @end example ## ## @seealso {odsclose, odsread, oct2ods, ods2oct, odsfinfo, chk_spreadsheet_support} ## ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2009-12-13 ## Updates: ## 2009-12-30 .... ## 2010-01-17 Make sure proper dimensions are checked in parsed javaclasspath ## 2010-01-24 Added warning when trying to create a new spreadsheet using ## jOpenDocument ## 2010-03-01 Removed check for rt.jar in javaclasspath ## 2010-03-04 Slight texinfo adaptation (reqd. odfdom version = 0.7.5) ## 2010-03-14 Updated help text (section on readwrite) ## 2010-06-01 Added check for jOpenDocument version + suitable warning ## 2010-06-02 Added ";" to supress debug stuff around lines 115 ## '' Moved JOD version check to subfunc getodsinterfaces ## '' Fiddled ods.changed flag when creating a spreadsheet to avoid ## unnamed 1st sheets ## 2010-08-23 Added version field "odfvsn" to ods file ptr, set in ## getodsinterfaces() (odfdom) ## '' Moved JOD version check to this func from subfunc ## getodsinterfaces() ## '' Full support for odfdom 0.8.6 (in subfunc) ## 2010-08-27 Improved help text ## 2010-10-27 Improved tracking of file changes tru ods.changed ## 2010-11-12 Small changes to help text ## '' Added try-catch to file open sections to create fallback to other ## interface ## 2011-05-06 Experimental UNO support ## 2011-05-18 Creating new spreadsheet docs in UNO now works ## 2011-06-06 Tamed down interface verbosity on first startup ## '' Multiple requested interfaces now possible ## 2011-09-03 Reset chkintf if no ods support found to allow full interface ## rediscovery (otherwise javaclasspath additions will never be ## picked up) ## 2012-01-26 Fixed "seealso" help string ## 2012-02-26 Added ";" to suppress echo of filename f UNO ## 2012-06-06 Made interface checking routine less verbose when same requested ## interface was used consecutively ## 2012-09-03 (in UNO section) replace canonicalize_file_name on non-Windows to ## make_absolute_filename (see bug #36677) ## '' (in UNO section) web adresses need only two consecutive slashes ## 2012-10-07 Moved subfunc getodsinterfaces to ./private ## 2012-10-12 Moved all interface-specific file open stanzas to separate ## ./private funcs ## 2012-10-24 Style fixes ## '' Removed fall-back options for .sxc. Other than .xls this can be ## inferred from file suffix ## 2012-12-18 Improved error messages ## 2013-02-24 Temporarily disabled UNO ## 2013-06-18 Re-enabled UNO ## 2013-09-09 Native Octave interface ("OCT") for reading ## 2013-09-23 Check and catch write requests for OCT interface ## '' Relax check for lowercase filename extension ## 2013-09-29 Initially set OCT interface to not detected ## 2013-11-04 Revert above ## 2013-11-08 Better filetype / file extension detection (bug #40490) ## '' Removed stray ';' ## 2013-11-12 Fix syntax error + missing initialization in file ext switch stmt ## 2013-12-01 Updated texinfo header ## 2013-12-18 Style fixes ## 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 function [ ods ] = odsopen (filename, rw=0, reqinterface=[]) persistent odsinterfaces; persistent chkintf; persistent lastintf; if (isempty (chkintf)) odsinterfaces = struct ( "OTK", [], "JOD", [], "UNO", [] , "OCT", 1); chkintf = 1; endif if (isempty (lastintf)); lastintf = "---"; endif odsintf_cnt = 1; if (nargout < 1) usage ("ODS = odsopen (ODSfile, [Rw]). But no return argument specified!"); endif if (! isempty (reqinterface)) if (! (ischar (reqinterface) || iscell (reqinterface))) usage ("odsopen.m: arg # 3 (interface) not recognized"); endif ## Turn arg3 into cell array if needed if (! iscell (reqinterface)) reqinterface = {reqinterface}; endif ## Check if previously used interface matches a requested interface if (isempty (regexpi (reqinterface, lastintf, "once"){1})) ## New interface requested. OCT is always supported but it must be ## possible to disable it odsinterfaces.OTK = 0; odsinterfaces.JOD = 0; odsinterfaces.UNO = 0; odsinterfaces.OCT = 0; for ii=1:numel (reqinterface) reqintf = toupper (reqinterface {ii}); ## Try to invoke requested interface(s) for this call. Check if it ## is supported anyway by emptying the corresponding var. if (strcmpi (reqintf, "OTK")) odsinterfaces.OTK = []; elseif (strcmpi (reqintf, "JOD")) odsinterfaces.JOD = []; elseif (strcmpi (reqintf, "UNO")) odsinterfaces.UNO = []; elseif (strcmpi (reqintf, "OCT")) odsinterfaces.OCT = []; else usage (sprintf (["odsopen.m: unknown .ods interface \"%s\" requested.\n" ... "Only OTK, JOD, UNO and OCT supported\n"], reqinterface{})); endif endfor printf ("Checking requested interface(s):\n"); odsinterfaces = getodsinterfaces (odsinterfaces); ## Well, is/are the requested interface(s) supported on the system? for ii=1:numel (reqinterface) if (! odsinterfaces.(toupper (reqinterface{ii}))) ## No it aint printf ("%s is not supported.\n", toupper (reqinterface{ii})); else ++odsintf_cnt; endif endfor ## Reset interface check indicator if no requested support found if (! odsintf_cnt) chkintf = []; ods = []; return endif endif endif ## 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) ## Check if OCT is only interface and writing is requested error ("OCT interface doesn't support writing files"); endif rw = 1; endif ## Check if ODS file exists. Set open mode based on rw argument if (rw) fmode = "r+b"; else fmode = "rb"; endif fid = fopen (filename, fmode); if (fid < 0) if (! rw) ## Read mode requested but file doesn't exist err_str = sprintf ("odsopen.m: file %s not found\n", filename); error (err_str) else ## For writing we need more info: fid = fopen (filename, "rb"); ## Check if it can be opened for reading if (fid < 0) ## Not found => create it printf ("Creating file %s\n", filename); rw = 3; else ## Found but not writable = error fclose (fid); ## Do not forget to close the handle neatly error (sprintf ("odsopen.m: write mode requested but file %s is not writable\n",... filename)) endif endif else ## Close file anyway to avoid Java errors fclose (fid); endif ## Check for the various ODS interfaces. No problem if they've already ## been checked, getodsinterfaces (far below) just returns immediately then. [odsinterfaces] = getodsinterfaces (odsinterfaces); ## Supported interfaces determined; now check ODS file type. ftype = 0; [~, ~, ext] = fileparts (filename); switch ext case ".ods" ## ODS 1.2 ftype = 3; case ".sxc" ## jOpenDocument (JOD) can read from .sxc files, ftype = 4; ## but only if odfvsn = 2 case ".gnumeric" ## Zipped XML / gnumeric ftype = 5; otherwise endswitch ods = struct ("xtype", [], "app", [], "filename", [], "workbook", [], "changed", 0, "limits", [], "odfvsn", []); ## Preferred interface = OTK (ODS toolkit & xerces), so it comes first. ## Keep track of which interface is selected. Can be used (later) for ## fallback to other interface odssupport = 0; if (odsinterfaces.OTK && ! odssupport && ftype == 3) [ ods, odssupport, lastintf ] = ... __OTK_spsh_open__ (ods, rw, filename, odssupport); endif if (odsinterfaces.JOD && ! odssupport && (ftype == 3 || ftype == 4)) [ ods, odssupport, lastintf ] = ... __JOD_spsh_open__ (ods, rw, filename, odssupport); endif if (odsinterfaces.UNO && ! odssupport && ftype < 5) ## Warn for LO / OOo stubbornness if (ftype == 0 || ftype == 5 || ftype == 6) warning ("UNO interface will write ODS format for unsupported file extensions") endif [ ods, odssupport, lastintf ] = ... __UNO_spsh_open__ (ods, rw, filename, odssupport); endif if (odsinterfaces.OCT && ! odssupport && ... (ftype == 2 || ftype == 3 || ftype == 5)) [ ods, odssupport, lastintf ] = ... __OCT_spsh_open__ (ods, rw, filename, odssupport, ftype); endif ## if ## if (! odssupport) ## Below message follows after getodsinterfaces printf ("None.\n"); warning ("odsopen.m: no support for OpenOffice.org .ods I/O"); ods = []; chkintf = []; else # From here on rw is tracked via ods.changed in the various lower # level r/w routines and it is only used to determine if an informative # message is to be given when saving a newly created ods file. ods.changed = rw; # ods.changed = 0 (existing/only read from), 1 (existing/data added), 2 (new, # data added) or 3 (pristine, no data added). # Until something was written to existing files we keep status "unchanged". if (ods.changed == 1); ods.changed = 0; endif endif endfunction io/inst/odsread.m0000644000076400010400000001752012246627736015273 0ustar PhilipAdministrators## Copyright (C) 2009,2010,2011,2012,2013 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 . ## -*- texinfo -*- ## @deftypefn {Function File} [@var{numarr}, @var{txtarr}, @var{rawarr}, @var{limits}] = odsread (@var{filename}) ## @deftypefnx {Function File} [@var{numarr}, @var{txtarr}, @var{rawarr}, @var{limits}] = odsread (@var{filename}, @var{wsh}) ## @deftypefnx {Function File} [@var{numarr}, @var{txtarr}, @var{rawarr}, @var{limits}] = odsread (@var{filename}, @var{wsh}, @var{range}) ## @deftypefnx {Function File} [@var{numarr}, @var{txtarr}, @var{rawarr}, @var{limits}] = odsread (@var{filename}, @var{wsh}, @var{range}, @var{reqintf}) ## ## Read data contained from cell range @var{range} in worksheet @var{wsh} ## 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 ## and one or both of jopendocument-.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. ## ## Return argument @var{numarr} contains the numeric data, optional ## return arguments @var{txtarr} and @var{rawarr} contain text strings ## and the raw spreadsheet cell data, respectively, and @var{limits} is ## a struct containing the data origins of the various returned arrays. ## ## If @var{filename} does not contain any directory, the file is ## assumed to be in the current directory. @var{filename} should include ## 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. ## 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 Calc file. ## ## @var{range} is expected to be a regular spreadsheet range format, ## or "" (empty string, indicating all data in a worksheet). ## If no range is specified the occupied cell range will have to be ## determined behind the scenes first; this can take some time. ## ## If only the first argument is specified, odsread will try to read ## all contents from the first = leftmost (or the only) worksheet (as ## if a range of @'' (empty string) was specified). ## ## If only two arguments are specified, odsread assumes the second ## argument to be @var{wsh} and to refer to a worksheet. In that case ## odsread tries to read all data contained in that worksheet. ## ## 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. ## ## 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 date/time formatted cells are returned as numerical values in ## @var{obj} with base 1-1-000. Note that OpenOfice.org and MS-Excel ## have different date base values (1/1/0000 & 1/1/1900, resp.) and ## internal representation so MS-Excel spreadsheets rewritten into ## .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. ## ## @var{numarr} and @var{txtarr} are trimmed from empty outer rows ## and columns, so any returned array may turn out to be smaller than ## requested in @var{range}. ## ## When reading from merged cells, all array elements NOT corresponding ## to the leftmost or upper spreadsheet cell will be treated as if the ## "corresponding" cells are empty. ## ## odsread is just a wrapper for a collection of scripts that find out ## the interface to be used and do the actual reading. For each call ## to odsread the interface must be started and the spreadsheet file read into ## memory. When reading multiple ranges (in optionally multiple worksheets) ## a significant speed boost can be obtained by invoking those scripts ## directly (odsopen / ods2oct [/ parsecell] / ... / odsclose). This also ## offers more flexibility (e.g. formula results or the formulas ## themselves; stripping output arrays from empty enveloping rows/columns). ## ## Examples: ## ## @example ## A = odsread ('test4.ods', '2nd_sheet', 'C3:AB40'); ## (which returns the numeric contents in range C3:AB40 in worksheet ## '2nd_sheet' from file test4.ods into numeric array A) ## @end example ## ## @example ## [An, Tn, Ra, limits] = odsread ('Sales2009.ods', 'Third_sheet'); ## (which returns all data in worksheet 'Third_sheet' in file test4.ods ## into array An, the text data into array Tn, the raw cell data into ## cell array Ra and the ranges from where the actual data came in limits) ## @end example ## ## @seealso {odsopen, ods2oct, oct2ods, odsclose, odswrite, odsfinfo, parsecell} ## ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2009-12-12 ## Updates: ## 2010-01-05 (....) ## 2010-03-04 Slight adaptations in texinfo ## 2010-05-31 Updated help text (delays i.c.o. empty range due to getusedrange call) ## 2010-11-10 Updated help text (filename extension req'd) ## 2010-11-13 Added some input validity checks ## 2011-09-08 Catch empty ods structs after failed odsopen attempts ## 2011-09-18 Return empty output arg in case of empty rawarr ## 2012-01-26 Fixed "seealso" help string ## 2012-03-07 Updated texinfo help text ## 2012-06-08 Tabs replaced by double space ## 2012-10-24 Style fixes ## 2013-09-24 Drop requirement of having at least one output arg ## 2013-09-27 Check for proper filename in input ## 2013-09-27 Better filename suffix check ## '' Updated header ## 2013-10-02 Some adaptations for gnumeric support ## '' 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 function [ numarr, txtarr, rawarr, lim ] = odsread (filename, wsh=1, datrange=[], reqintf=[]) if (! ischar (filename)) error ("filename (text string) expected for argument #1, not a %s", class (filename)); endif if (nargin < 1 || ! (strcmpi (".ods", filename(end-3:end)) || ... strcmpi (".sxc", filename(end-3:end)) || ... strcmpi (".gnumeric", filename(end-8:end)))) usage ("odsread: filename (incl. suffix) of a supported file type is required"); endif ods = odsopen (filename, 0, reqintf); if (~isempty (ods)) [rawarr, ods, rstatus] = ods2oct (ods, wsh, datrange); if (rstatus) [numarr, txtarr, lim] = parsecell (rawarr, ods.limits); else warning (sprintf ("No data read from %s.", filename)); numarr = []; endif ods = odsclose (ods); endif endfunction io/inst/odswrite.m0000644000076400010400000001246712261112416015474 0ustar PhilipAdministrators## Copyright (C) 2009,2010,2011,2012,2013 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 . ## -*- texinfo -*- ## @deftypefn {Function File} @var{rstatus} = odswrite (@var{filename}, @var{arr}) ## @deftypefnx {Function File} @var{rstatus} = odswrite (@var{filename}, @var{arr}, @var{wsh}) ## @deftypefnx {Function File} @var{rstatus} = odswrite (@var{filename}, @var{arr}, @var{wsh}, @var{range}) ## @deftypefnx {Function File} @var{rstatus} = odswrite (@var{filename}, @var{arr}, @var{wsh}, @var{range}, @var{reqintf}) ## Add data in 1D/2D array @var{arr} into sheet @var{wsh} in ## OpenOffice_org Calc spreadsheet file @var{filename} in cell range @var{range}. ## ## @var{rstatus} returns 1 if write succeeded, 0 otherwise. ## ## @var{filename} must be a valid .ods OpenOffice.org file name (including ## file name extension). If @var{filename} does not contain any directory ## path, the file is saved in the current directory. ## ## @var{arr} can be any 1D or 2D array containing numerical or character ## data (cellstr) except complex. Mixed numeric/text arrays can only be ## cell arrays. ## ## @var{wsh} can be a number or string. In case of a not yet existing ## OpenOffice.org spreadsheet, the first sheet will be used & named ## according to @var{wsh} - no extra empty sheets are created. ## In case of existing files, some checks are made for existing sheet ## names or numbers, or whether @var{wsh} refers to an existing sheet with ## a type other than sheet (e.g., chart). ## When new sheets are to be added to the spreadsheet file, they are ## inserted to the right of all existing sheets. The pointer to the ## "active" sheet (shown when OpenOffice.org Calc opens the file) remains ## untouched. ## ## @var{range} is expected to be a regular spreadsheet range. ## Data is added to the sheet; existing data in the requested ## range will be overwritten. ## Array @var{arr} will be clipped at the right and/or bottom if its size ## is bigger than can be accommodated in @var{range}. ## If @var{arr} is smaller than the @var{range} allows, it is placed ## in the top left rectangle of @var{range} and cell values outside that ## rectangle will be untouched. ## ## If @var{range} contains merged cells, only the elements of @var{arr} ## corresponding to the top or left Calc cells of those merged cells ## will be written, other array cells corresponding to that cell will be ## ignored. ## ## 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'). ## ## 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. ## ## Example: ## ## @example ## status = odswrite ('test4.ods', 'arr', 'Eight_sheet', 'C3:AB40'); ## (which adds the contents of array arr (any type) to range C3:AB40 ## in sheet 'Eight_sheet' in file test4.ods and returns a logical ## True (= numerical 1) in status if al went well) ## @end example ## ## @seealso {odsread, oct2ods, ods2oct, odsopen, odsclose, odsfinfo} ## ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2009-12-14 ## Updates: ## 2010-01-14 Finalized write support tru ODS toolkit ## 2010-01-15 Added texinfo help ## 2010-08-25 Removed text about 31 char limit for sheet names (invalid) ## 2010-11-13 Added note about required file extension in help text ## 2010-11-13 Added some input arg checks ## 2011-09-08 Minor filename error text adaptation ## 2012-01-26 Fixed "seealso" help string ## 2012-02-20 Fixed range parameter to be default empty string rather than empty numeral ## 2010-03-07 Updated texinfo help text ## 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 function [ rstatus ] = odswrite (filename, data, wsh=1, crange="", reqintf=[]) ## Input validity checks if (nargin < 2) usage ("Insufficient arguments - see 'help odswrite'"); endif ods = odsopen (filename, 1, reqintf); if (! isempty (ods)) [ods, rstatus] = oct2ods (data, ods, wsh, crange); ## If rstatus was not OK, reset change indicator in ods pointer if (! rstatus) ods.changed = rstatus; warning ("odswrite: data transfer errors, file not rewritten"); endif ods = odsclose (ods); endif endfunction io/inst/parsecell.m0000644000076400010400000001417612246627322015617 0ustar PhilipAdministrators## Copyright (C) 2009,2010,2011,2012,2013 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 . ## -*- texinfo -*- ## @deftypefn {Function File} [ @var{numarr}, @var{txtarr}, @var{lim} ] = parsecell (@var{rawarr}) ## @deftypefnx {Function File} [ @var{numarr}, @var{txtarr}, @var{lim} ] = parsecell (@var{rawarr}, @var{limits}) ## ## Divide a heterogeneous 2D cell array into a 2D numeric array and a ## 2D cell array containing only strings. Both returned arrays are ## trimmed from empty outer rows and columns. ## This function is particularly useful for parsing cell arrays returned ## by functions reading spreadsheets (e.g., xlsread, odsread). ## ## Optional return argument @var{lim} contains two field with the outer ## column and row numbers of @var{numarr} and @var{txtarr} in the ## original array @var{rawarr}. ## Optional input argument @var{limits} can either be the spreadsheet ## data limits returned in the spreadsheet file pointer struct ## (field xls.limits or ods.limits), or the file ptr struct itself. ## If one of these is specified, optional return argument @var{lim} ## will contain the real spreadsheet row & column numbers enclosing ## the origins of the numerical and text data returned in @var{numarr} ## and @var{txtarr}. ## ## Examples: ## ## @example ## [An, Tn] = parsecell (Rn); ## (which returns the numeric contents of Rn into array An and the ## text data into array Tn) ## @end example ## ## @example ## [An, Tn, lims] = parsecell (Rn, xls.limits); ## (which returns the numeric contents of Rn into array An and the ## text data into array Tn.) ## @end example ## ## @seealso {xlsread, odsread, xls2oct, ods2oct} ## ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2009-12-13 ## Updates: ## 2009-12-29 ## 2010-08-25 Added option for second argument to be a file ptr ## 2010-10-15 Simplified code for numerical array ## 2011-05-17 Fixed subscript indexing bug in cropping section when rawarr is ## '' numeric scalar ## 2011-09-08 Copyright string updated ## 2012-01-26 Fixed "seealso" help string ## 2012-10-24 Style fixes ## 2013-12-01 More style fixes function [ numarr, txtarr, lim ] = parsecell (rawarr, arg2=[]) if (isstruct (arg2)) ## Assume a file ptr has been supplied if (isfield (arg2, "limits")) rawlimits = arg2.limits; else warning ("Invalid file ptr supplied to parsecell() - limits ignored."); endif else rawlimits = arg2; endif lim = struct ( "numlimits", [], "txtlimits", []); numarr = []; txtarr = {}; if (! isempty (rawarr)) ## Valid data returned. Divide into numeric & text arrays no_txt = 0; no_num = 0; if (isnumeric ([rawarr{:}])) numarr = num2cell (rawarr); no_txt = 1; elseif (iscellstr (rawarr)) txtarr = cellstr (rawarr); no_num = 1; endif ## Prepare parsing [nrows, ncols] = size (rawarr); ## Find text entries in raw data cell array txtptr = cellfun ("isclass", rawarr, "char"); if (~no_txt) ## Prepare text array. Create placeholder for text cells txtarr = cell (size (rawarr)); txtarr(:) = {""}; if (any (any (txtptr))) ## Copy any text cells found into place holder txtarr(txtptr) = rawarr(txtptr); ## Clean up text array (find leading / trailing empty ## rows & columns) irowt = 1; while (! any (txtptr(irowt, :))); irowt++; endwhile irowb = nrows; while (! any (txtptr(irowb, :))); irowb--; endwhile icoll = 1; while (! any (txtptr(:, icoll))); icoll++; endwhile icolr = ncols; while (! any (txtptr(:, icolr))); icolr--; endwhile ## Crop textarray txtarr = txtarr(irowt:irowb, icoll:icolr); lim.txtlimits = [icoll, icolr; irowt, irowb]; if (! isempty (rawlimits)) correction = [1; 1]; lim.txtlimits(:,1) = lim.txtlimits(:,1) + rawlimits(:,1) - correction; lim.txtlimits(:,2) = lim.txtlimits(:,2) + rawlimits(:,1) - correction; endif else ## If no text cells found return empty text array txtarr = {}; endif endif if (! no_num) ## Prepare numeric array. Set all text & empty cells to NaN. ## First get their locations emptr = cellfun ("isempty", rawarr); emptr(find (txtptr)) = 1; if (all (all (emptr))) numarr= []; else ## Find leading & trailing empty rows irowt = 1; while (all(emptr(irowt, :))); irowt++; endwhile irowb = nrows; while (all(emptr(irowb, :))); irowb--; endwhile icoll = 1; while (all(emptr(:, icoll))); icoll++; endwhile icolr = ncols; while (all(emptr(:, icolr))); icolr--; endwhile ## Pre-crop rawarr rawarr = rawarr (irowt:irowb, icoll:icolr); ## Build numerical array numarr = zeros (irowb-irowt+1, icolr-icoll+1); ## Watch out for scalar (non-empty) numarr where emptr = 0 if (sum (emptr(:)) > 0) numarr(emptr(irowt:irowb, icoll:icolr)) = NaN; endif numarr(! emptr(irowt:irowb, icoll:icolr)) = ... cell2mat (rawarr(~emptr(irowt:irowb, icoll:icolr))); ## Save limits lim.numlimits = [icoll, icolr; irowt, irowb]; if (! isempty (rawlimits)) correction = [1; 1]; lim.numlimits(:,1) = lim.numlimits(:,1) + rawlimits(:,1) - correction(:); lim.numlimits(:,2) = lim.numlimits(:,2) + rawlimits(:,1) - correction(:); endif endif endif lim.rawlimits = rawlimits; endif endfunction io/inst/pch2mat.m0000644000076400010400000001011112217071420015152 0ustar PhilipAdministrators%% Copyright (C) 2011, Bilen Oytun Peksel %% All rights reserved. %% %% Redistribution and use in source and binary forms, with or without %% modification, are permitted provided that the following conditions are met: %% %% 1 Redistributions of source code must retain the above copyright notice, %% this list of conditions and the following disclaimer. %% 2 Redistributions in binary form must reproduce the above copyright %% notice, this list of conditions and the following disclaimer in the %% documentation and/or other materials provided with the distribution. %% %% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS'' %% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE %% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE %% ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR %% ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL %% DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR %% SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER %% CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, %% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE %% OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. %% -*- texinfo -*- %% @deftypefn {Function File} {@var{data} =} pch2mat (@var{filename}) %% Converts NASTRAN PCH file (SORT2) to a data structure and frequency vector. A %% filename as a string is the only needed input. %% %% The output is in the form of struct. containing a freq vector n x 1 called %% data.f, and the remaining data are in the form of subcases, point ids %% and directions respectively. for ex. data.S1.p254686.x and they are n x 2 %% %% @end deftypefn function [data] = pch2mat(filename); %% Open the file and read the file line by line to form a line character array fid = fopen(filename); l = 1; while (~feof(fid)) raw{l} = fgets(fid); l = l + 1; end %% Determine Freq_count and number of lines for each case a = strmatch('$TITLE',raw); lines = a(2) -a(1); %number of lines on each subcase and related point id freq_count = (lines-7)/4; %% Read from array C = length(raw) / lines; %number of subcase and related point id for k = 1 : C; %looping through every case scase = char(raw{(k-1) * lines + 3}(12:16)); scase = genvarname(scase); pid = char(raw{(k-1) * lines + 7}(16:25)); pid = genvarname(['p' pid]); if (k==1) data.f = zeros(freq_count,1); end; data.(scase).(pid).x = zeros(freq_count,2); data.(scase).(pid).y = zeros(freq_count,2); data.(scase).(pid).z = zeros(freq_count,2); data.(scase).(pid).r1 = zeros(freq_count,2); data.(scase).(pid).r2 = zeros(freq_count,2); data.(scase).(pid).r3 = zeros(freq_count,2); i = (k-1) * lines + 8 ; j = 0; while( i <= (lines * k)) %loop for each case j=j+1; if (k==1) data.f(j) = str2double(raw{i}(5:17)); end data.(scase).(pid).x(j,1) = str2double(raw{i}(25:37)); data.(scase).(pid).y(j,1) = str2double(raw{i}(43:55)); data.(scase).(pid).z(j,1) = str2double(raw{i}(61:73)); i=i+1; data.(scase).(pid).r1(j,1) = str2double(raw{i}(25:37)); data.(scase).(pid).r2(j,1) = str2double(raw{i}(43:55)); data.(scase).(pid).r3(j,1) = str2double(raw{i}(61:73)); i=i+1; data.(scase).(pid).x(j,2) = str2double(raw{i}(25:37)); data.(scase).(pid).y(j,2) = str2double(raw{i}(43:55)); data.(scase).(pid).z(j,2) = str2double(raw{i}(61:73)); i=i+1; data.(scase).(pid).r1(j,2) = str2double(raw{i}(25:37)); data.(scase).(pid).r2(j,2) = str2double(raw{i}(43:55)); data.(scase).(pid).r3(j,2) = str2double(raw{i}(61:73)); i=i+1; end end end io/inst/private/0000755000076400010400000000000012263601446015126 5ustar PhilipAdministratorsio/inst/private/chk_jar_entries.m0000644000076400010400000000550512250427376020447 0ustar PhilipAdministrators## Copyright (C) 2012,2013 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 Octave; see the file COPYING. If not, see ## . ## chk_jar_entries - internal function finding Java .jar names in javaclasspath ## Author: Philip Nienhuis ## Created: 2012-10-07 ## Updates: ## 2012-10-23 Style fixes ## 2012-12-18 Add option for range of names per required entry ## '' Tests added ## 2013-07-12 Trim implied padding of range of names per entry ## 2012-07-18 Fix multiple equivalent jar entries bug (padding w. spaces ## overlooked) ## 2013-12-06 Updated copyright strings; style fixes ## '' Commented out tests function [ retval, missing ] = chk_jar_entries (jcp, entries, dbug=0) retval = 0; missing = zeros (1, numel (entries)); for jj=1:length (entries) found = 0; for ii=1:length (jcp) ## Get jar (or folder/map/subdir) name from java classpath entry jentry = strsplit (lower (jcp{ii}), filesep){end}; kk = 0; while (++kk <= size (char (entries{jj}), 1) && ! found) if (! isempty (strfind (jentry, strtrim (lower (char (entries{jj})(kk, :)))))) ++retval; found = 1; if (dbug > 2) fprintf (" - %s OK\n", jentry); endif endif endwhile endfor if (! found) if (dbug > 2) if (iscellstr (entries{jj})) entrtxt = sprintf ("%s/", entries{jj}{:}); entrtxt(end) = ""; else entrtxt = entries{jj}; endif printf (" %s....jar missing\n", entrtxt); endif missing(jj) = 1; endif endfor endfunction ## FIXME -- reinstate these tests one there if a way is found to test private ## functions directly ##%!test ##%! entries = {"abc", {"def", "ghi"}, "jkl"}; ##%! jcp1 = {"/usr/lib/java/abcx.jar", "/usr/lib/java/defz.jar", "/usr/lib/java/jkl3.jar"}; ##%! jcp1 = strrep (jcp1, "/", filesep); ##%! assert (chk_jar_entries (jcp1, entries), 3); ##%!test ##%! entries = {"abc", {"def", "ghi"}, "xyz"}; ##%! jcp2 = {"/usr/lib/java/abcy.jar", "/usr/lib/java/ghiw.jar", "/usr/lib/java/jkl6.jar"}; ##%! jcp2 = strrep (jcp2, "/", filesep); ##%! [aaa, bbb] = chk_jar_entries (jcp2, entries); ##%! assert (aaa, 2); ##%! assert (bbb, [0 0 1]); io/inst/private/getodsinterfaces.m0000644000076400010400000002236312255140542020637 0ustar PhilipAdministrators## Copyright (C) 2009,2010,2011,2012,2013 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 2 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 Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} @var{odsinterfaces} = getodsinterfaces (@var{odsinterfaces}) ## Get supported OpenOffice.org .ods file read/write interfaces from ## the system. ## Each interface for which the corresponding field is set to empty ## will be checked. So by manipulating the fields of input argument ## @var{odsinterfaces} it is possible to specify which ## interface(s) should be checked. ## ## Currently implemented interfaces comprise: ## - Java & ODFtoolkit (www.apache.org) ## - Java & jOpenDocument (www.jopendocument.org) ## - Java & UNO bridge (OpenOffice.org) ## ## Examples: ## ## @example ## odsinterfaces = getodsinterfaces (odsinterfaces); ## @end example ## Author: Philip Nienhuis ## Created: 2009-12-27 ## Updates: ## 2010-01-14 (yeah what was it...> ## 2010-01-17 Make sure proper dimensions are checked in parsed javaclasspath ## 2010-04-11 Introduced check on odfdom.jar version - only 0.7.5 works properly ## 2010-06-02 Moved in check on JOD version ## 2010-06-05 Experimental odfdom 0.8.5 support ## 2010-06-## dropped 0.8.5, too buggy ## 2010-08-22 Experimental odfdom 0.8.6 support ## 2010-08-23 Added odfvsn (odfdom version string) to output struct argument ## '' Bugfix: moved JOD version check to main function (it can't work here) ## '' Finalized odfdom 0.8.6 support (even prefered version now) ## 2010-09-11 Somewhat clarified messages about missing java classes ## '' Rearranged code a bit; fixed typos in OTK detection code (odfdvsn -> odfvsn) ## 2010-09-27 More code cleanup ## 2010-11-12 Warning added about waning support for odfdom v. 0.7.5 ## 2011-05-06 Fixed wrong strfind tests ## '' Experimental UNO support added ## 2011-05-18 Forgot to initialize odsinterfaces.UNO ## 2011-06-06 Fix for javaclasspath format in *nix w. java-1.2.8 pkg ## '' Implemented more rigid Java check ## '' Tamed down verbosity ## 2011-09-03 Fixed order of odsinterfaces. statement in Java detection try-catch ## '' Reset tmp1 (always allow interface rediscovery) for empty odsinterfaces arg ## 2011-09-18 Added temporary warning about UNO interface ## 2012-03-22 Improved Java checks (analogous to xlsopen) ## 2012-06-06 Again improved & simplified Java-based interface checking support ## 2012-06-08 Support for odfdom-0.8.8 (-incubator) ## 2012-10-07 Moved common classpath entry code to ./private function ## 2012-10-07 Moved into ./private ## 2012-10-24 Style fixes ## 2013-03-01 active -> default interface ## '' Moved check for Java support to separate file in private/ ## '' Fixed javaclasspath info resync in case of requested interfaces ## 2013-08-13 Tested odfdom 0.8.9 (odfdom-0.6-incubator); found it doesn't work :-( ## 2013-09-09 Native Octave interface ("OCT")for reading ## 2013-09-11 Check Java again when requesting a specific Java interface ## 2013-09-29 Treat OCT as any other interface ## 2013-12-06 Updated copyright strings; style fixes ## 2013-12-20 java_invoke -> javaMethod function [odsinterfaces] = getodsinterfaces (odsinterfaces) ## tmp1 = [] (not initialized), 0 (No Java detected), or 1 (Working Java found) persistent tmp1 = []; persistent jcp; # Java class path persistent uno_1st_time = 0; if (isempty (odsinterfaces.OTK) && isempty (odsinterfaces.JOD) ... && isempty (odsinterfaces.UNO)) ## Assume no interface detection has happened yet printf ("Detected ODS interfaces: "); tmp1 = []; elseif (isempty (odsinterfaces.OTK) || isempty (odsinterfaces.JOD) ... || isempty (odsinterfaces.UNO)) ## Can't be first call. Here one of the Java interfaces is requested if (tmp1) # Check Java support again tmp1 = []; else ## Renew jcp (javaclasspath) as it may have been updated since last call jcp = javaclasspath ("-all"); ## For java pkg >= 1.2.8 if (isempty (jcp)); jcp = javaclasspath; endif ## For java pkg < 1.2.8 if (isunix && ! iscell (jcp)); jcp = strsplit (char (jcp), pathsep ()); endif endif endif deflt = 0; if (isempty (tmp1)) ## Check Java support [tmp1, jcp] = __chk_java_sprt__ (); if (! tmp1) ## No Java support found if (isempty (odsinterfaces.OTK) || isempty (odsinterfaces.JOD) ... || isempty (odsinterfaces.UNO)) ## Some or all Java-based interface explicitly requested; but no Java support warning ... (" No Java support found (no Java JRE? no Java pkg installed AND loaded?)"); endif ## Set Java interfaces to 0 anyway as there's no Java support odsinterfaces.OTK = 0; odsinterfaces.JOD = 0; odsinterfaces.UNO = 0; printf ("\n"); ## No more need to try any Java interface return; endif endif ## Try Java & ODF toolkit if (isempty (odsinterfaces.OTK)) odsinterfaces.OTK = 0; entries = {"odfdom", "xercesImpl"}; ## Only under *nix we might use brute force: e.g., strfind(classpath, classname); ## under Windows we need the following more subtle, platform-independent approach: if (chk_jar_entries (jcp, entries) >= numel (entries)) ## Apparently all requested classes present. ## Only now we can check for proper odfdom version (only 0.7.5 & 0.8.6-0.8.8 work OK). ## The odfdom team deemed it necessary to change the version call so we need this: odfvsn = " "; try ## New in 0.8.6 odfvsn = ... javaMethod ("getOdfdomVersion", "org.odftoolkit.odfdom.JarManifest"); catch odfvsn = ... javaMethod ("getApplicationVersion", "org.odftoolkit.odfdom.Version"); end_try_catch ## For odfdom-incubator (= 0.8.8+), strip extra info odfvsn = regexp (odfvsn, '\d\.\d\.\d', "match"){1}; if (! (strcmp (odfvsn, "0.7.5") || strcmp (odfvsn, "0.8.6") ... || strcmp (odfvsn, "0.8.7") || strfind (odfvsn, "0.8.8"))) warning ("\nodfdom version %s is not supported - use v. 0.8.6, 0.8.7 or 0.8.8\n", odfvsn); else if (strcmp (odfvsn, "0.7.5")) warning (["odfdom v. 0.7.5 support won't be maintained " ... "- please upgrade to 0.8.8"]); endif odsinterfaces.OTK = 1; printf ("OTK"); if (deflt) printf ("; "); else printf ("*; "); deflt = 1; endif endif odsinterfaces.odfvsn = odfvsn; else warning ("\nNot all required classes (.jar) in classpath for OTK"); endif endif ## Try Java & jOpenDocument if (isempty (odsinterfaces.JOD)) odsinterfaces.JOD = 0; entries = {"jOpenDocument"}; if (chk_jar_entries (jcp, entries) >= numel (entries)) odsinterfaces.JOD = 1; printf ("JOD"); if (deflt) printf ("; "); else printf ("*; "); deflt = 1; endif else warning ("\nNot all required classes (.jar) in classpath for JOD"); endif endif ## Try Java & UNO if (isempty (odsinterfaces.UNO)) odsinterfaces.UNO = 0; ## entries(1) = not a jar but a directory () entries = {"program", "unoil", "jurt", "juh", "unoloader", "ridl"}; if (chk_jar_entries (jcp, entries) >= numel (entries)) odsinterfaces.UNO = 1; printf ("UNO"); if (deflt) printf ("; "); else printf ("*; "); deflt = 1; uno_1st_time = min (++uno_1st_time, 2); endif else warning ("\nOne or more UNO classes (.jar) missing in javaclasspath"); endif endif ## Native Octave if (isempty (odsinterfaces.OCT)) ## Nothing to check, always supported odsinterfaces.OCT = 1; printf ("OCT"); if (deflt) printf ("; "); else printf ("*; "); deflt = 1; endif endif ## ---- Other interfaces here, similar to the ones above if (deflt) printf ("(* = default interface)\n"); endif ## FIXME the below stanza should be dropped once UNO is stable. ## Echo a suitable warning about experimental status: if (uno_1st_time == 1) ++uno_1st_time; printf ("\nPLEASE NOTE: UNO (=OpenOffice.org-behind-the-scenes) is EXPERIMENTAL\n"); printf ("After you've opened a spreadsheet file using the UNO interface,\n"); printf ("odsclose on that file will kill ALL OpenOffice.org invocations,\n"); printf ("also those that were started outside and/or before Octave!\n"); printf ("Trying to quit Octave w/o invoking odsclose will only hang Octave.\n\n"); endif endfunction io/inst/private/getusedrange.m0000644000076400010400000001071512250427372017765 0ustar PhilipAdministrators## Copyright (C) 2010,2011,2012,2013 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 . ## -*- texinfo -*- ## @deftypefn {Function File} [ @var{toprow#}, @var{bottomrow#}, @var{leftcol#}, @var{rightcol#} ] = getusedrange (@var{spptr}, @var{shindex#}) ## Find occupied data range in worksheet @var{shindex#} in a spreadsheet ## pointed to in struct @var{spptr} (either MS-Excel or ## OpenOffice_org Calc). ## ## @var{shindex#} must be numeric and is 1-based. @var{spptr} can either ## refer to an MS-Excel spreadsheet (spptr returned by xlsopen) or an ## OpenOffice.org Calc spreadsheet (spptr returned by odsopen). ## None of these inputs are checked! ## ## Be aware that especially for OpenOffice.org Calc (ODS) spreadsheets ## the results can only be obtained by counting all cells in all rows; ## this can be fairly time-consuming. Reliable ods data size results can ## only be obtained using UNO interface. ## For the ActiveX (COM) interface the underlying Visual Basic call relies ## on cached range values and counts empty cells with only formatting too, ## so COM returns only approximate (but then usually too big) range values. ## ## Examples: ## ## @example ## [trow, brow, lcol, rcol] = getusedrange (ods2, 3); ## (which returns the outermost row & column numbers of the rectangle ## enveloping the occupied cells in the third sheet of an OpenOffice_org ## Calc spreadsheet pointedto in struct ods2) ## @end example ## ## @example ## [trow, brow, lcol, rcol] = getusedrange (xls3, 3); ## (which returns the outermost row & column numbers of the rectangle ## enveloping the occupied cells in the third sheet of an Excel ## spreadsheet pointed to in struct xls3) ## @end example ## ## @seealso {xlsopen, xlsclose, odsopen, odsclose, xlsfinfo, odsfinfo} ## ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2010-03-18 (First usable version) for ODS (java/OTK) ## Updates: ## 2010-03-20 Added Excel support (Java/POI) ## 2010-05-23 Added in support for jOpenDocument ODS ## 2010-05-31 Fixed bugs in getusedrange_jod.m ## 2010-08-24 Added support for odfdom 0.8.6 (ODF Toolkit) ## 2010-08-27 Added checks for input arguments ## '' Indentation changed from tab to doublespace ## 2010-10-07 Added COM support (at last!) ## 2011-05-06 Experimental support for Java/UNO bridge ## 2011-06-13 OpenXLS support added ## 2011-09-08 Style & layout updates ## 2012-01-26 Fixed "seealso" help string ## 2012-06-08 Replaced tabs by double space ## '' Added COM and OXS to message about supported interfaces ## 2012-10-12 Moved all interface-specific subfuncs to . /private ## 2012-10-23 Added UNO to error message ## '' Style fixes ## 2013-09-08 Added OCT (native ods & xlsx) interface ## 2013-12-06 Updated copyright strings function [ trow, lrow, lcol, rcol ] = getusedrange (spptr, ii) ## Some checks if ~isstruct (spptr), error ("Illegal spreadsheet pointer argument"); endif if (strcmp (spptr.xtype, 'OTK')) [ trow, lrow, lcol, rcol ] = __OTK_getusedrange__ (spptr, ii); elseif (strcmp (spptr.xtype, "JOD")) [ trow, lrow, lcol, rcol ] = __JOD_getusedrange__ (spptr, ii); elseif (strcmp (spptr.xtype, "UNO")) [ trow, lrow, lcol, rcol ] = __UNO_getusedrange__ (spptr, ii); elseif (strcmp (spptr.xtype, "COM")) [ trow, lrow, lcol, rcol ] = __COM_getusedrange__ (spptr, ii); elseif (strcmp (spptr.xtype, "POI")) [ trow, lrow, lcol, rcol ] = __POI_getusedrange__ (spptr, ii); elseif (strcmp (spptr.xtype, "JXL")) [ trow, lrow, lcol, rcol ] = __JXL_getusedrange__ (spptr, ii); elseif (strcmp (spptr.xtype, "OXS")) [ trow, lrow, lcol, rcol ] = __OXS_getusedrange__ (spptr, ii); elseif (strcmp (spptr.xtype, "OCT")) [ trow, lrow, lcol, rcol ] = __OCT_getusedrange__ (spptr, ii); else error ... ("Unknown interface - only OTK, JOD, COM, POI, JXL, OXS, UNO and OCT implemented"); endif endfunction io/inst/private/getxlsinterfaces.m0000644000076400010400000002444012260012754020655 0ustar PhilipAdministrators## Copyright (C) 2009,2010,2011,2012,2013 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 2 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 Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} @var{xlsinterfaces} = getxlsinterfaces (@var{xlsinterfaces}) ## Get supported Excel .xls file read/write interfaces from the system. ## Each interface for which the corresponding field is set to empty ## will be checked. So by manipulating the fields of input argument ## @var{xlsinterfaces} it is possible to specify which ## interface(s) should be checked. ## ## Currently implemented interfaces comprise: ## - ActiveX / COM (native Excel in the background) ## - Java & Apache POI ## - Java & JExcelAPI ## - Java & OpenXLS (only JRE >= 1.4 needed) ## - Java & UNO bridge (native OpenOffice.org in background) - EXPERIMENTAL!! ## - native Octave, only for .xlsx (OOXML), .ODS1.2, . gnumeric ## ## Examples: ## ## @example ## xlsinterfaces = getxlsinterfaces (xlsinterfaces); ## @end example ## Author: Philip Nienhuis ## Created: 2009-11-29 ## Last updates: ## 2009-12-27 Make sure proper dimensions are checked in parsed javaclasspath ## 2010-09-11 Rearranged code and clarified messages about missing classes ## 2010-09-27 More code cleanup ## 2010-10-20 Added check for minimum Java version (should be >= 6 / 1.6) ## 2010-11-05 Slight change to reporting to screen ## 2011-02-15 Adapted to javaclasspath calling style of java-1.2.8 pkg ## 2011-03-26 OpenXLS support added ## '' Bug fix: javaclasspath change wasn't picked up between calls with req.intf ## 2011-05-18 Experimental UNO support added ## 2011-05-29 Reduced verbosity ## 2011-06-06 Fix for javaclasspath format in *nix w java-1.2.8 pkg ## 2011-06-13 Fixed potentially faulty tests for java classlib presence ## 2011-09-03 Fixed order of xlsinterfaces. statements in Java detection try-catch ## '' Reset tmp1 (always allow interface rediscovery) for empty xlsinterfaces arg ## 2011-09-08 Minor code cleanup ## 2011-09-18 Added temporary warning about UNO interface ## 2012-03-01 Changed UNO warning so that it is suppressed when UNO is not yet chosen ## 2012-03-07 Only check for COM if run on Windows ## 2012-03-21 Print newline if COM found but no Java support ## '' Improved logic for finding out what interfaces to check ## '' Fixed bugs with Java interface checking (tmp1 initialization) ## 2012-06-06 Improved & simplified Java check code ## 2012-09-03 Check for matching .jar names & javaclasspath was reversed (oops) ## 2012-10-07 Moved common classpath entry code to private function ## 2012-10-24 Style fixes ## 2012-12-18 POI 3.9 support (either xbeans.jar or xmlbeans.jar), see chk_jar_entries.m ## 2013-01-20 Adapted to ML-compatible Java calls ## 2013-03-01 active -> default interface ## '' Moved check for Java support to separate file in private/ ## '' Fixed javaclasspath info resync in case of requested interfaces ## 2013-07-18 Add Fedora naming scheme to POI jar entries (official ones are symlinks) ## 2013-09-30 Native Octave interface ("OCT") for reading ## 2013-12-06 Updated copyright strings; style fixes ## 2013-12-27 Slight updates to texinfo header ## 2013-12-28 Added check for OpenXLS version 10 ## 2013-12-29 Added gwt-servlet-deps.jar to OpenXLS dependencies function [xlsinterfaces] = getxlsinterfaces (xlsinterfaces) ## tmp1 = [] (not initialized), 0 (No Java detected), or 1 (Working Java found) persistent tmp1 = []; persistent tmp2 = []; persistent jcp; ## Java class path persistent uno_1st_time = 0; if (isempty (xlsinterfaces.COM) && isempty (xlsinterfaces.POI) ... && isempty (xlsinterfaces.JXL) && isempty (xlsinterfaces.OXS) ... && isempty (xlsinterfaces.UNO)) ## Looks like first call to xlsopen. Check Java support printf ("Detected XLS interfaces: "); tmp1 = []; elseif (isempty (xlsinterfaces.COM) || isempty (xlsinterfaces.POI) ... || isempty (xlsinterfaces.JXL) || isempty (xlsinterfaces.OXS) ... || isempty (xlsinterfaces.UNO)) ## Can't be first call. Here one of the Java interfaces is requested if (! tmp1) ## Check Java support again tmp1 = []; else ## Renew jcp (javaclasspath) as it may have been updated since last call jcp = javaclasspath ("-all"); ## For java pkg >= 1.2.8 if (isempty (jcp)) ## For java pkg < 1.2.8 jcp = javaclasspath; endif if (isunix && ! iscell (jcp)); jcp = strsplit (char (jcp), pathsep ()); endif endif endif deflt = 0; ## Check if MS-Excel COM ActiveX server runs (only on Windows!) if (ispc && isempty (xlsinterfaces.COM)) xlsinterfaces.COM = 0; try app = actxserver ("Excel.application"); ## If we get here, the call succeeded & COM works. xlsinterfaces.COM = 1; ## Close Excel. Yep this is inefficient when we need only one r/w action, ## but it quickly pays off when we need to do more with the same file ## (+, MS-Excel code is in OS cache anyway after this call so no big deal) app.Quit(); delete (app); printf ("COM"); if (deflt) printf ("; "); else printf ("*; "); deflt = 1; endif catch ## COM non-existent. Only print message if COM is explicitly requested (tmp1==[]) if (! isempty (tmp1)) printf ("ActiveX not working; no Excel installed?\n"); endif end_try_catch endif if (isempty (tmp1)) ## Check Java support [tmp1, jcp] = __chk_java_sprt__ (); if (! tmp1) ## No Java support found tmp1 = 0; if (isempty (xlsinterfaces.POI) || isempty (xlsinterfaces.JXL)... || isempty (xlsinterfaces.OXS) || isempty (xlsinterfaces.UNO)) ## Some or all Java-based interface(s) explicitly requested but no Java support warning ... (" No Java support found (no Java JRE? no Java pkg installed AND loaded?)"); endif ## Set Java interfaces to 0 anyway as there's no Java support xlsinterfaces.POI = 0; xlsinterfaces.JXL = 0; xlsinterfaces.OXS = 0; xlsinterfaces.UNO = 0; printf ("\n"); ## No more need to try any Java interface return endif endif ## Try Java & Apache POI if (isempty (xlsinterfaces.POI)) xlsinterfaces.POI = 0; ## Check basic .xls (BIFF8) support entries = {{"apache-poi.", "poi-3"}, {"apache-poi-ooxml.", "poi-ooxml-3"}}; ## Only under *nix we might use brute force: e.g., strfind (classname, classpath); ## under Windows we need the following more subtle, platform-independent approach: if (chk_jar_entries (jcp, entries) >= numel (entries)) xlsinterfaces.POI = 1; printf ("POI"); endif ## Check OOXML support entries = {{"xbean", "xmlbean"}, {"apache-poi-ooxml-schemas", "poi-ooxml-schemas"}, "dom4j"}; if (chk_jar_entries (jcp, entries) >= numel (entries)) printf (" (& OOXML)"); endif if (xlsinterfaces.POI) if (deflt) printf ("; "); else printf ("*; "); deflt = 1; endif endif endif ## Try Java & JExcelAPI if (isempty (xlsinterfaces.JXL)) xlsinterfaces.JXL = 0; entries = {"jxl"}; if (chk_jar_entries (jcp, entries) >= numel (entries)) xlsinterfaces.JXL = 1; printf ("JXL"); if (deflt) printf ("; "); else printf ("*; "); deflt = 1; endif endif endif ## Try Java & OpenXLS if (isempty (xlsinterfaces.OXS)) xlsinterfaces.OXS = 0; entries = {"openxls", "gwt-servlet-deps"}; if (chk_jar_entries (jcp, entries) >= numel (entries)) ## OK, jar in the javaclasspath. Check version (should be >= 10 try ## ...a method that is first introduced in OpenXLS v.10 javaMethod ("getVersion", "com.extentech.ExtenXLS.GetInfo"); ## If we get here, we do have v. 10 xlsinterfaces.OXS = 1; printf ("OXS"); if (deflt) printf ("; "); else printf ("*; "); deflt = 1; endif catch ## Wrong OpenXLS.jar version (probably <= 6.08). V. 10 is required now warning ("OpenXLS.jar version is outdated; please upgrade to v.10"); end_try_catch endif endif ## Try Java & UNO if (isempty (xlsinterfaces.UNO)) xlsinterfaces.UNO = 0; ## entries0(1) = not a jar but a directory (<00o_install_dir/program/>) entries = {"program", "unoil", "jurt", "juh", "unoloader", "ridl"}; if (chk_jar_entries (jcp, entries) >= numel (entries)) xlsinterfaces.UNO = 1; printf ("UNO"); if (deflt); printf ("; "); else printf ("*; "); deflt = 1; uno_1st_time = min (++uno_1st_time, 2); endif endif endif ## Native Octave if (isempty (xlsinterfaces.OCT)) ## Nothing to check, always supported xlsinterfaces.OCT = 1; printf ("OCT"); if (deflt) printf ("; "); else printf ("*; "); deflt = 1; endif endif ## ---- Other interfaces here, similar to the ones above if (deflt) printf ("(* = default interface)\n"); endif ## FIXME the below stanza should be dropped once UNO is stable. # Echo a suitable warning about experimental status: if (uno_1st_time == 1) ++uno_1st_time; printf ("\nPLEASE NOTE: UNO (=OpenOffice.org-behind-the-scenes) is EXPERIMENTAL\n"); printf ("After you've opened a spreadsheet file using the UNO interface,\n"); printf ("xlsclose on that file will kill ALL OpenOffice.org invocations,\n"); printf ("also those that were started outside and/or before Octave!\n"); printf ("Trying to quit Octave w/o invoking xlsclose will only hang Octave.\n\n"); endif endfunction io/inst/private/parse_sp_range.m0000644000076400010400000000700312250431272020266 0ustar PhilipAdministrators## Copyright (C) 2009,2010.2011,2012,2013 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 . ## Parse a string representing a range of cells for a spreadsheet ## into nr of rows and nr of columns and also extract top left ## cell address + top row + left column. Some error checks are implemented. ## Author: Philip Nienhuis ## Created: 2009-06-20 ## Latest update 2010-01-13 ## 2013-12-06 Updated copyright strings; style fixes function [topleft, nrows, ncols, toprow, lcol] = parse_sp_range (range_org) range = deblank (upper (range_org)); range_error = 0; nrows = 0; ncols = 0; # Basic checks if (index (range, ':') == 0) if (isempty (range)) range_error = 0; leftcol = 'A'; rightcol = 'A'; else # Only upperleft cell given, just complete range to 1x1 # (needed for some routines) range = [range ":" range]; endif endif # Split up both sides of the range [topleft, lowerright] = strtok (range, ':'); # 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); # 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); # Check nr. of rows nrows = bottomrow - toprow + 1; if (nrows < 1) range_error = 1; 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 # Check ncols = rcol - lcol + 1; if (ncols < 1) range_error = 1; endif endif if (range_error > 0) ncols = 0; nrows = 0; error ("Spreadsheet range error!"); endif 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]); io/inst/private/spsh_chkrange.m0000644000076400010400000000724312250431472020125 0ustar PhilipAdministrators## Copyright (C) 2010,2011,2012,2013 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 . ## -*- texinfo -*- ## @deftypefn {Function File} [ @var{topleftaddr}, @var{nrows}, @var{ncols}, @var{toprow}, @var{leftcol} ] = spsh_chkrange ( @var{range}, @var{rowsize}, @var{colsize}, @var{intf-type}, @var{filename}) ## (Internal function) Get and check various cell and range address parameters for spreadsheet input. ## ## spsh_chkrange should not be invoked directly but rather through oct2xls or oct2ods. ## ## Example: ## ## @example ## [tl, nrw, ncl, trw, lcl] = spsh_chkrange (crange, nr, nc, xtype, fileptr); ## @end example ## ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2010-08-02 ## Updates: ## 2010-08-25 Option for supplying file pointer rather than interface_type & filename ## (but this can be wasteful if the file ptr is copied) ## 2011-03-29 Bug fix - unrecognized pointer struct & wrong type error msg ## 2011-05-15 Experimental UNO support added (OpenOffice.org & clones) ## 2011-09-18 Updated UNO data row capacity for LibreOffice 3.4+ (now 1,048,576 rows) ## 2012-10-23 Style fixes ## 2013-12-06 Updated copyright strings function [ topleft, nrows, ncols, trow, lcol ] = spsh_chkrange (crange, nr, nc, intf, filename=[]) if (nargin == 4) ## File pointer input assumed if (isstruct (intf)) xtype = intf.xtype; filename = intf.filename; else error ("Too few or improper arguments supplied."); endif else ## Interface type & filename supplied xtype = intf; endif ## Define max row & column capacity from interface type & file suffix switch xtype case { 'COM', 'POI' } if (strmatch (tolower (filename(end-3:end)), '.xls')) ## BIFF5 & BIFF8 ROW_CAP = 65536; COL_CAP = 256; else ## OOXML (COM needs Excel 2007+ for this) ROW_CAP = 1048576; COL_CAP = 16384; endif case { 'JXL', 'OXS' } ## JExcelAPI & OpenXLS can only process BIFF5 & BIFF8 ROW_CAP = 65536; COL_CAP = 256; case { 'OTK', 'JOD' } ## ODS ROW_CAP = 65536; COL_CAP = 1024; case { 'UNO' } ## ODS; LibreOffice has a higher row capacity ## FIXME - use UNO calls to check physical row capacity ## FIXME - LibreOffice has higher row capacity but its Java classes haven't been updated ROW_CAP = 1048576; COL_CAP = 1024; otherwise error (sprintf ("Unknown interface type - %s\n", xtype)); endswitch if (isempty (deblank (crange))) trow = 1; lcol = 1; nrows = nr; ncols = nc; topleft = 'A1'; elseif (isempty (strfind (deblank (crange), ':'))) ## Only top left cell specified [topleft, dummy1, dummy2, trow, lcol] = parse_sp_range (crange); nrows = nr; ncols = nc; else [topleft, nrows, ncols, trow, lcol] = parse_sp_range (crange); endif if (trow > ROW_CAP || lcol > COL_CAP) error ("Topleft cell (%s) beyond spreadsheet limits."); endif ## Check spreadsheet capacity beyond requested topleft cell nrows = min (nrows, ROW_CAP - trow + 1); ncols = min (ncols, COL_CAP - lcol + 1); ## Check array size and requested range nrows = min (nrows, nr); ncols = min (ncols, nc); endfunction io/inst/private/spsh_prstype.m0000644000076400010400000000765512250431734020061 0ustar PhilipAdministrators## Copyright (C) 2010,2011,2012,2013 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 . ## -*- texinfo -*- ## @deftypefn {Function File} [ @var{type-array} ] = spsh_prstype ( @var{iarray}, @var{rowsize}, @var{colsize}, @var{celltypes}, @var{options}) ## (Internal function) Return rectangular array with codes for cell types in rectangular input cell array @var{iarray}. ## Codes are contained in input vector in order of Numeric, Boolean, Text, Formula and Empty, resp. ## ## spsh_prstype should not be invoked directly but rather through oct2xls or oct2ods. ## ## Example: ## ## @example ## typarr = spsh_chkrange (cellarray, nr, nc, ctypes, options); ## @end example ## ## @end deftypefn ## Author: Philip Nienhuis, ## Created: 2010-08-02 ## Updates: ## 2010-08-25 Corrected help text (square -> rectangular; stressed "internal" use) ## 2011-04-21 Formulas now don't need closing ")" (e.g., =A1+B1 is OK as well) ## '' Formula ptrs in output arg now OK (cellfun(@(x).... skips empty cells) ## 2012-10-23 Style fixes ## 2013-12-06 Updated copyright strings function [ typearr ] = spsh_prstype (obj, nrows, ncols, ctype, spsh_opts) ## ctype index: ## 1 = numeric ## 2 = boolean ## 3 = text ## 4 = formula ## 5 = error / NaN / empty typearr = ctype(5) * ones (nrows, ncols); ## type "EMPTY", provisionally obj2 = cell (size (obj)); ## Temporary storage for strings txtptr = cellfun ('isclass', obj, 'char'); ## type "STRING" replaced by "NUMERIC" obj2(txtptr) = obj(txtptr); obj(txtptr) = ctype(3); ## Save strings in a safe place emptr = cellfun ("isempty", obj); obj(emptr) = ctype(5); ## Set empty cells to NUMERIC lptr = cellfun ("islogical" , obj); ## Find logicals... obj2(lptr) = obj(lptr); ## .. and set them to BOOLEAN ptr = cellfun ("isnan", obj); ## Find NaNs & set to BLANK typearr(ptr) = ctype(5); typearr(! ptr) = ctype(1); ## All other cells are now numeric obj(txtptr) = obj2(txtptr); ## Copy strings back into place obj(lptr) = obj2(lptr); ## Same for logicals obj(emptr) = -1; ## Add in a filler value for empty cells typearr(txtptr) = ctype(3); ## ...and clean up typearr(emptr) = ctype(5); ## EMPTY typearr(lptr) = ctype(2); ## BOOLEAN if (! spsh_opts.formulas_as_text) ## Find formulas (designated by a string starting with "=" and ending in ")") ## fptr = cellfun (@(x) ischar (x) && strncmp (x, "=", 1) ## && strncmp (x(end:end), ")", 1), obj); ## Find formulas (designated by a string starting with "=") fptr = cellfun (@(x) ischar (x) && strncmp (x, "=", 1), obj); typearr(fptr) = ctype(4); ## FORMULA endif endfunction ## FIXME -- reinstate these tests one there if a way is found to test private ## functions directly ##%!test ##%! tstobj = {1.5, true, []; 'Text1', '=A1+B1', '=SQRT(A1)'; NaN, {}, 0}; ##%! typarr = spsh_prstype (tstobj, 3, 3, [1 2 3 4 5], struct ("formulas_as_text", 0)); ##%! assert (typarr, [1 2 5; 3 4 4; 5 5 1]); ##%!test ##%! tstobj = {1.5, true, []; 'Text1', '=A1+B1', '=SQRT(A1)'; NaN, {}, 0}; ##%! typarr = spsh_prstype (tstobj, 3, 3, [1 2 3 4 5], struct ("formulas_as_text", 1)); ##%! assert (typarr, [1 2 5; 3 3 3; 5 5 1]); io/inst/private/__chk_java_sprt__.m0000644000076400010400000000443412263332544020723 0ustar PhilipAdministrators## Copyright (C) 2013 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 Octave; see the file COPYING. If not, see ## . ## __chk_java_sprt__ Internal io package function ## Author: Philip Nienhuis ## Created: 2013-03-01 ## 2013-11-05 Provide default values for jcp & tmp1 ## 2013-12-20 Copyright string updates ## '' dbug info argument added (for chk_spreadsheet_support) ## '' java_invoke -> javaMethod ## 2014-01-08 Tiny style fix function [ tmp1, jcp ] = __chk_java_sprt__ (dbug=0) jcp = {}; tmp1 = 0; try jcp = javaclasspath ("-all"); # For java pkg >= 1.2.8 if (isempty (jcp)), jcp = javaclasspath; endif # For java pkg < 1.2.8 ## If we get here, at least Java works. if (dbug > 1) printf ("Java seems to work OK.\n"); endif ## Now check for proper version (>= 1.6) jver = ... char (javaMethod ("getProperty", "java.lang.System", "java.version")); cjver = strsplit (jver, "."); if (sscanf (cjver{2}, "%d") < 6) warning ... ("\nJava version too old - you need at least Java 6 (v. 1.6.x.x)\n"); if (dbug) printf (' At Octave prompt, try "!system ("java -version")"'); endif return else if (dbug > 2) printf (" Java (version %s) seems OK.\n", jver); endif endif ## Now check for proper entries in class path. Under *nix the classpath ## must first be split up. In java 1.2.8+ javaclasspath is already a cell array if (isunix && ! iscell (jcp)); jcp = strsplit (char (jcp), pathsep ()); endif tmp1 = 1; catch ## No Java support if (dbug) printf ("No Java support found.\n"); endif end_try_catch endfunction io/inst/private/__COM_getusedrange__.m0000644000076400010400000000353312246716126021262 0ustar PhilipAdministrators## Copyright (C) 2010,2011,2012,2013 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 . ## __COM_getusedrange__ ## Author: Philip Nienhuis ## Created: 2010-10-07 ## Updates: ## 2012-10-12 Renamed & moved into ./private ## 2012-10-24 Style fixes ## 2012-12-01 Copyright string adapted function [ trow, brow, lcol, rcol ] = __COM_getusedrange__ (xls, ii) sh = xls.workbook.Worksheets (ii); ## Decipher used range. Beware, UsedRange() returns *cached* rectangle of ## all spreadsheet cells containing *anything*, including just formatting ## (i.e., empty cells are included too). ==> This is an approximation only allcells = sh.UsedRange; ## Get top left cell as a Range object toplftcl = allcells.Columns(1).Rows(1); ## Count number of rows & cols in virtual range from A1 to top left cell lcol = sh.Range ("A1", toplftcl).columns.Count; trow = sh.Range ("A1", toplftcl).rows.Count; ## Add real occupied rows & cols to obtain end row & col brow = trow + allcells.rows.Count() - 1; rcol = lcol + allcells.columns.Count() - 1; ## Check if there are real data if ((lcol == rcol) && (trow = brow)) if (isempty (toplftcl.Value)) trow = brow = lcol = rcol = 0; endif endif endfunction io/inst/private/__COM_oct2spsh__.m0000644000076400010400000002221712246717124020351 0ustar PhilipAdministrators## Copyright (C) 2009,2010,2011,2012,2013 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 . ## -*- texinfo -*- ## @deftypefn {Function File} [@var{xlso}, @var{status}] = __COM_oct2spsh__ (@var{obj}, @var{xlsi}) ## @deftypefnx {Function File} [@var{xlso}, @var{status}] = __COM_oct2spsh__ (@var{obj}, @var{xlsi}, @var{wsh}) ## @deftypefnx {Function File} [@var{xlso}, @var{status}] = __COM_oct2spsh__ (@var{obj}, @var{xlsi}, @var{wsh}, @var{top_left_cell}) ## Save matrix @var{obj} into worksheet @var{wsh} in Excel file pointed ## to in struct @var{xlsi}. All elements of @var{obj} are converted into ## Excel cells, starting at cell @var{top_left_cell}. Return argument ## @var{xlso} is @var{xlsi} with updated fields. ## ## __COM_oct2spsh__ should not be invoked directly but rather through oct2xls. ## ## Excel invocations may be left running invisibly in case of COM errors. ## ## Example: ## ## @example ## xls = __COM_oct2spsh__ (rand (10, 15), xls, 'Third_sheet', 'BF24'); ## @end example ## ## @seealso {oct2xls, xls2oct, xlsopen, xlsclose, xlswrite, xlsread, xls2com2oct} ## ## @end deftypefn ## Author: Philip Nienhuis ## (originally based on mat2xls by Michael Goffioul) ## Rewritten: 2009-09-26 ## Updates: ## 2009-12-11 ## 2010-01-12 Fixed typearr sorting out (was only 1-dim & braces rather than parens)) ## Set cells corresponding to empty array cells empty (cf. Matlab) ## 2010-01-13 Removed an extraneous statement used for debugging ## I plan look at it when octave v.3.4 is about to arrive. ## 2010-08-01 Added checks for input array size vs check on capacity ## '' Changed topleft arg into range arg (just topleft still recognized) ## '' Some code cleanup ## '' Added option for formula input as text string ## 2010-08-01 Added range vs. array size vs. capacity checks ## 2010-08-03 Moved range checks and type array parsing to separate functions ## 2010-10-20 Bug fix removing new empty sheets in new workbook that haven't been ## created in the first place due to Excel setting (thanks Ian Journeaux) ## '' Changed range use in COM transfer call ## 2010-10-21 Improved file change tracking (var xls.changed) ## 2010-10-24 Fixed bug introduced in above fix: for loops have no stride param, ## '' replaced by while loop ## '' Added check for "live" ActiveX server ## 2010-11-12 Moved ptr struct check into main func ## 2012-01-26 Fixed "seealso" help string ## 2012-02-27 Copyright strings updated ## 2012-10-12 Renamed & moved into ./private ## 2012-10-24 Style fixes ## 2012-12-21 Search for exact match when searching sheet names ## 2012-12-01 Style fixes; copyright string adapted function [ xls, status ] = __COM_oct2spsh__ (obj, xls, wsh, crange, spsh_opts) ## Preliminary sanity checks ## FIXME - Excel can write to much more than .xls/.xlsx (but not to all ## formats with multiple sheets): ## .wk1 .wk3 .wk4 .csv .pxl .html .dbf .txt .prn .wks .wq1 .dif if (! strmatch (lower (xls.filename(end-4:end)), '.xls')) error ("COM interface can only write to Excel .xls or .xlsx files") endif if (isnumeric (wsh)) if (wsh < 1) error ("Illegal worksheet number: %i\n", wsh); endif elseif (size (wsh, 2) > 31) error ("Illegal worksheet name - too long") endif ## Check to see if ActiveX is still alive try wb_cnt = xls.workbook.Worksheets.count; catch error ("ActiveX invocation in file ptr struct seems non-functional"); end_try_catch ## define some constants not yet in __COM__.cc xlWorksheet = -4167; ## xlChart= 4; ## scratch vars status = 0; ## Parse date ranges [nr, nc] = size (obj); [topleft, nrows, ncols, trow, lcol] = ... spsh_chkrange (crange, nr, nc, xls.xtype, xls.filename); lowerright = calccelladdress (trow + nrows - 1, lcol + ncols - 1); crange = [topleft ":" lowerright]; if (nrows < nr || ncols < nc) warning ("Array truncated to fit in range"); obj = obj(1:nrows, 1:ncols); endif ## Cleanup NaNs. Find where they are and mark as empty ctype = [0 1 2 3 4]; ## Numeric Boolean Text Formula Empty typearr = spsh_prstype (obj, nrows, ncols, ctype, spsh_opts); ## Make cells now indicated to be empty, empty fptr = ! (4 * (ones (size (typearr))) .- typearr); obj(fptr) = cellfun (@(x) [], obj(fptr), "Uniformoutput", false); if (spsh_opts.formulas_as_text) ## find formulas (designated by a string starting with "=" and ending in ")") fptr = cellfun (@(x) ischar (x) && strncmp (x, "=", 1) ... && strncmp (x(end:end), ")", 1), obj); ## ... and add leading "'" character obj(fptr) = cellfun (@(x) ["'" x], obj(fptr), "Uniformoutput", false); endif clear fptr; if (xls.changed < 3) ## Existing file OR a new file with data added in a previous oct2xls call. ## Some involved investigation is needed to preserve ## existing data that shouldn't be touched. ## ## See if desired *sheet* name exists. old_sh = 0; ws_cnt = xls.workbook.Sheets.count; if (isnumeric (wsh)) if (wsh <= ws_cnt) ## Here we check for sheet *position* in the sheet stack ## rather than a name like "Sheet" old_sh = wsh; else ## wsh > nr of sheets; proposed new sheet name. ## This sheet name can already exist to the left in the sheet stack! shnm = sprintf ("Sheet%d", wsh); shnm1 = shnm; endif endif if (! old_sh) ## Check if the requested (or proposed) sheet already exists ## COM objects are not OO (yet?), so we need a WHILE loop ii = 1; jj = 1; while ((ii <= ws_cnt) && ~old_sh) ## Get existing sheet names one by one sh_name = xls.workbook.Sheets(ii).name; if (~isnumeric (wsh) && strcmp (sh_name, wsh)) ## ...and check with requested sheet *name*... old_sh = ii; elseif (isnumeric (wsh) && strcmp (sh_name, shnm)) ## ... or proposed new sheet name (corresp. to requested sheet *number*) shnm = [shnm "_"]; ii = 0; ## Also check if this new augmented sheet name exists... if (strmatch (shnm1, sh_name, "exact")), jj++; endif if (jj > 5) ## ... but not unlimited times... error (sprintf ... (" > 5 sheets named [_]Sheet%d already present!", wsh)); endif endif ++ii; endwhile endif if (old_sh) ## Requested sheet exists. Check if it is a *work*sheet if (! (xls.workbook.Sheets(old_sh).Type == xlWorksheet)) ## Error as you can't write data to Chart sheet error (sprintf ("Existing sheet '%s' is not type worksheet.", wsh)); else ## Simply point to the relevant sheet sh = xls.workbook.Worksheets (old_sh); endif else ## Add a new worksheet. Earlier it was checked whether this is safe try sh = xls.workbook.Worksheets.Add (); catch error (sprintf ("Cannot add new worksheet to file %s\n", xls.filename)); end_try_catch if (! isnumeric (wsh)) sh.Name = wsh; else sh.Name = shnm; printf ("Writing to worksheet %s\n", shnm); endif ## Prepare to move new sheet to right of the worksheet stack anyway ws_cnt = xls.workbook.Worksheets.count; ## New count needed ## Find where Excel has left it. We have to, depends on Excel version :-( ii = 1; while ((ii < ws_cnt+1) && ! strcmp (sh.Name, xls.workbook.Worksheets(ii).Name) == 1) ++ii; endwhile ## Excel can't move it beyond the current last one, so we need a trick. ## First move it to just before the last one.... xls.workbook.Worksheets(ii).Move (before = xls.workbook.Worksheets(ws_cnt)); ## ....then move the last one before the new sheet. xls.workbook.Worksheets (ws_cnt).Move (before = xls.workbook.Worksheets(ws_cnt - 1)); endif else ## The easy case: a new Excel file. Workbook was created in xlsopen. ## Delete empty non-used sheets, last one first xls.app.Application.DisplayAlerts = 0; ii = xls.workbook.Sheets.count; while (ii > 1) xls.workbook.Worksheets(ii).Delete(); --ii; endwhile xls.app.Application.DisplayAlerts = 1; ## Write to first worksheet: sh = xls.workbook.Worksheets (1); ## Rename the sheet if (isnumeric (wsh)) sh.Name = sprintf ("Sheet%i", wsh); else sh.Name = wsh; endif xls.changed = 2; ## 3 => 2 endif ## MG's original part. ## Save object in Excel sheet, starting at cell top_left_cell if (! isempty(obj)) r = sh.Range (crange); try r.Value = obj; catch error (sprintf ("Cannot add data to worksheet %s in file %s\n",... sh.Name, xls.filename)); end_try_catch delete (r); endif ## If we get here, all went OK status = 1; xls.changed = max (xls.changed, 1); ## If it was 2, preserve it. endfunction io/inst/private/__COM_spsh2oct__.m0000644000076400010400000001215112246716540020346 0ustar PhilipAdministrators## Copyright (C) 2009,2010,2011,2012,2013 P.R. Nienhuis ## parts Copyright (C) 2007 Michael Goffioul ## ## 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 . ## -*- texinfo -*- ## @deftypefn {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = __COM_spsh2oct__ (@var{xls}) ## @deftypefnx {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = __COM_spsh2oct__ (@var{xls}, @var{wsh}) ## @deftypefnx {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = __COM_spsh2oct__ (@var{xls}, @var{wsh}, @var{range}) ## @deftypefnx {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = __COM_spsh2oct__ (@var{xls}, @var{wsh}, @var{range}, @var{spsh_opts}) ## Get cell contents in @var{range} in worksheet @var{wsh} in an Excel ## file pointed to in struct @var{xls} into the cell array @var{obj}. ## ## __COM_spsh2oct__ should not be invoked directly but rather through xls2oct. ## ## Examples: ## ## @example ## [Arr, status, xls] = __COM_spsh2oct__ (xls, 'Second_sheet', 'B3:AY41'); ## Arr = __COM_spsh2oct__ (xls, 'Second_sheet'); ## @end example ## ## @seealso {xls2oct, oct2xls, xlsopen, xlsclose, xlsread, xlswrite} ## ## @end deftypefn ## Author: Philip Nienhuis ## Based on mat2xls by Michael Goffioul (2007) ## Created: 2009-09-23 ## Last updates: ## 2009-12-11 ## 2010-10-07 Implemented limits (only reliable for empty input ranges) ## 2010-10-08 Resulting data array now cropped (also in case of specified range) ## 2010-10-10 More code cleanup (shuffled xls tests & wsh ptr code before range checks) ## 2010-10-20 Slight change to Excel range setup ## 2010-10-24 Added check for "live" ActiveX server ## 2010-11-12 Moved ptr struct check into main func ## 2010-11-13 Catch empty sheets when no range was specified ## 2012-01-26 Fixed "seealso" help string ## 2012-06-06 Implemented "formulas_as_text option" ## 2012-10-12 Renamed & moved into ./private ## 2012-10-24 Style fixes ## 2013-12-01 Copyright strings updates function [rawarr, xls, rstatus ] = __COM_spsh2oct__ (xls, wsh, crange, spsh_opts) rstatus = 0; rawarr = {}; ## Basic checks if (nargin < 2) error ("__COM_spsh2oct__ needs a minimum of 2 arguments."); endif if (size (wsh, 2) > 31) warning ("Worksheet name too long - truncated") wsh = wsh(1:31); endif app = xls.app; wb = xls.workbook; ## Check to see if ActiveX is still alive try wb_cnt = wb.Worksheets.count; catch error ("ActiveX invocation in file ptr struct seems non-functional"); end_try_catch ## Check & get handle to requested worksheet wb_cnt = wb.Worksheets.count; old_sh = 0; if (isnumeric (wsh)) if (wsh < 1 || wsh > wb_cnt) errstr = sprintf ("Worksheet number: %d out of range 1-%d", wsh, wb_cnt); error (errstr) rstatus = 1; return else old_sh = wsh; endif else ## Find worksheet number corresponding to name in wsh wb_cnt = wb.Worksheets.count; for ii =1:wb_cnt sh_name = wb.Worksheets(ii).name; if (strcmp (sh_name, wsh)) old_sh = ii; endif endfor if (~old_sh) errstr = sprintf ("Worksheet name \"%s\" not present", wsh); error (errstr) else wsh = old_sh; endif endif sh = wb.Worksheets (wsh); nrows = 0; if ((nargin == 2) || (isempty (crange))) allcells = sh.UsedRange; ## Get actually used range indices [trow, brow, lcol, rcol] = getusedrange (xls, old_sh); if (trow == 0 && brow == 0) ## Empty sheet rawarr = {}; printf ("Worksheet '%s' contains no data\n", sh.Name); return; else nrows = brow - trow + 1; ncols = rcol - lcol + 1; topleft = calccelladdress (trow, lcol); lowerright = calccelladdress (brow, rcol); crange = [topleft ":" lowerright]; endif else ## Extract top_left_cell from range [topleft, nrows, ncols, trow, lcol] = parse_sp_range (crange); brow = trow + nrows - 1; rcol = lcol + ncols - 1; endif; if (nrows >= 1) ## Get object from Excel sheet, starting at cell top_left_cell rr = sh.Range (crange); if (spsh_opts.formulas_as_text) rawarr = rr.Formula; else rawarr = rr.Value; endif delete (rr); ## Take care of actual singe cell range if (isnumeric (rawarr) || ischar (rawarr)) rawarr = {rawarr}; endif ## If we get here, all seems to have gone OK rstatus = 1; ## Keep track of data rectangle limits xls.limits = [lcol, rcol; trow, brow]; else error ("No data read from Excel file"); rstatus = 0; endif endfunction io/inst/private/__COM_spsh_close__.m0000644000076400010400000000531012246717232020741 0ustar PhilipAdministrators## Copyright (C) 2012,2013 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 Octave; see the file COPYING. If not, see ## . ## __COM_spsh_close__ - internal function: close a spreadsheet file using COM ## Author: Philip Nienhuis ## Created: 2012-10-12 ## Updates ## 2013-12-01 Style fixes, copyright string update function [ xls ] = __COM_spsh_close__ (xls) ## If file has been changed, write it out to disk. ## ## Note: COM / VB supports other Excel file formats as FileFormatNum: ## 4 = .wks - Lotus 1-2-3 / Microsoft Works ## 6 = .csv ## -4158 = .txt ## 36 = .prn ## 50 = .xlsb - xlExcel12 (Excel Binary Workbook in 2007 with or without macro's) ## 51 = .xlsx - xlOpenXMLWorkbook (without macro's in 2007) ## 52 = .xlsm - xlOpenXMLWorkbookMacroEnabled (with or without macro's in 2007) ## 56 = .xls - xlExcel8 (97-2003 format in Excel 2007) ## (see Excel Help, VB reference, Enumerations, xlFileType) ## xls.changed = 0: no changes: just close; ## 1: existing file with changes: save, close. ## 2: new file with data added: save, close ## 3: new file, no added added (empty): close & delete on disk xls.app.Application.DisplayAlerts = 0; try if (xls.changed > 0 && xls.changed < 3) if (isfield (xls, "nfilename")) fname = xls.nfilename; else fname = xls.filename; endif if (xls.changed == 2) ## Probably a newly created, or renamed, Excel file ## printf ("Saving file %s ...\n", fname); xls.workbook.SaveAs (canonicalize_file_name (fname)); elseif (xls.changed == 1) ## Just updated existing Excel file xls.workbook.Save (); endif xls.changed = 0; xls.workbook.Close (canonicalize_file_name (fname)); endif xls.app.Quit (); delete (xls.workbook); ## This statement actually closes the workbook delete (xls.app); ## This statement actually closes down Excel catch xls.app.Application.DisplayAlerts = 1; end_try_catch endfunction io/inst/private/__COM_spsh_info__.m0000644000076400010400000000330112246716616020572 0ustar PhilipAdministrators## Copyright (C) 2012,2013 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 Octave; see the file COPYING. If not, see ## . ## __COM_spsh_info__ ## Author: Philip Nienhuis ## Created: 2012-10-12 ## Updates: ## 2012-10-12 Moved into ./private ## 2012-10-24 Style fixes ## 2013-12-01 Copyright string update function [sh_names] = __COM_spsh_info__ (xls) xlWorksheet = -4167; xlChart = 4; ## See if desired worksheet number or name exists sh_cnt = xls.workbook.Sheets.count; sh_names = cell (sh_cnt, 2); ws_cnt = 0; ch_cnt = 0; o_cnt = 0; for ii=1:sh_cnt sh_names(ii, 1) = xls.workbook.Sheets(ii).Name; if (xls.workbook.Sheets(ii).Type == xlWorksheet) [tr, lr, lc, rc] = getusedrange (xls, ++ws_cnt); if (tr) sh_names(ii, 2) = sprintf ... ("%s:%s", calccelladdress (tr, lc), calccelladdress (lr, rc)); else sh_names(ii, 2) = "Empty"; endif elseif (xls.workbook.Sheets(ii).Type == xlChart) sh_names(ii, 2) = sprintf ("Chart"); ++ch_cnt; else sh_names(ii, 2) = "Other_type"; ++o_cnt; endif endfor endfunction io/inst/private/__COM_spsh_open__.m0000644000076400010400000000416712246716712020610 0ustar PhilipAdministrators## Copyright (C) 2012,2013 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 Octave; see the file COPYING. If not, see ## . ## __COM_xlsopen.m__ - Internal function for opening an xls(x) file using COM/ActiveX ## Author: Philip Nienhuis ## Created: 2012-10-07 ## Updates (possibly from xlsopen): ## 2010-11-01 Added .Application.DisplayAlerts=0 in COM section to avoid Excel pop-ups ## 2012-10-24 Style fixes ## 2012-12-01 Copyright string updates function [ xls, xlssupport, lastintf ] = __COM_spsh_open__ (xls, xwrite, filename, xlssupport) app = actxserver ("Excel.Application"); try ## Because Excel itself can still crash on file formats etc. app.Application.DisplayAlerts = 0; if (xwrite < 2) ## Open workbook wb = app.Workbooks.Open (canonicalize_file_name (filename)); elseif (xwrite > 2) ## Create a new workbook wb = app.Workbooks.Add (); ## Uncommenting the below statement can be useful in multi-user environments. ## Be sure to uncomment correspondig stanza in xlsclose to avoid zombie Excels ## wb.SaveAs (canonicalize_file_name (filename)) endif xls.app = app; xls.xtype = "COM"; xls.workbook = wb; xls.filename = filename; xlssupport += 1; lastintf = "COM"; catch warning ( sprintf ("ActiveX error trying to open or create file %s\n",... filename)); app.Application.DisplayAlerts = 1; app.Quit (); delete (app); end_try_catch endfunction io/inst/private/__get_ftype__.m0000644000076400010400000000654012261100442020057 0ustar PhilipAdministrators## 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 . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{ftype} =} __get_ftype__ (@var{fname}) ## Get file type index from a file name, based on the file extension. ## ## Supported file type indices: ## 1 = .xls (BIFF8, also BIFF5) ## 2 = .xlsx (OOXML) ## 3 = .ods (ODS 1.2) ## 4 = .sxc (old OpenOffice.org format) ## 5 = .gnumeric (Gnumeric XML) ## 6 = .csv (Comma Separated Values) ## 7 = .uof (Unified Office Format) ## 8 = .fods (ODS Flat XML) ## 9 = .dbf (Dbase) ## 10 = .dif (Digital InterchangeFormat) ## ## @var{ftype} is set to 0 (zero) for any other file type. ## @var{ftype} is set to empty for file names without extension. ## ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2014-01-01 function [ftype, filtnam] = __get_ftype__ (fname) persistent filtnams; filtnams = {"MS Excel 97", ## .xls "Calc MS Excel 2007 XML", ## .xlsx "calc8", ## .ods "StarOffice XML (Calc)", ## .sxc "---gnumeric---", ## .gnumeric "Text CSV", ## .csv "UOF spreadsheet", ## .uos "OpenDocument Spreadsheet Flat XML", ## .fods "dBase", ## .dbf "DIF"}; ## .dif [~, ~, ext] = fileparts (fname); if (! isempty (ext)) switch ext case ".xls" ## Regular (binary) BIFF ftype = 1; case {".xlsx", ".xlsm", ".xlsb"} ## Zipped XML / OOXML. Catches xlsx, xlsb, xlsm ftype = 2; case ".ods" ## ODS 1.2 (Excel 2007+ & OOo/LO can read ODS) ftype = 3; case ".sxc" ## old OpenOffice.org 1.0 Calc ftype = 4; case ".gnumeric" ## Zipped XML / gnumeric ftype = 5; case ".csv" ## csv. Detected for xlsread afficionados ftype = 6; case ".uof" ## Unified Office Format ftype = 7; case ".fods" ## ODS Flat HTML ftype = 8; case ".dbf" ## Dbase ftype = 9; case ".dif" ## Digital Interchange Format ftype = 10; otherwise ## Any other type = non-supported ftype = 0; endswitch else ftype = ''; endif if (ftype > 0) filtnam = filtnams{ftype}; endif endfunction io/inst/private/__JOD_getusedrange__.m0000644000076400010400000000535112246720556021262 0ustar PhilipAdministrators## Copyright (C) 2010,2011,2012,2013 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 . ## __JOD_getusedrange__ ## Author: Philip ## Created: 2010-05-25 ## Last updates: ## 2010-05-31 Fixed ignoring table-covered-cells; fixed count of sheets comprising just A1:A1 ## Added option for wsh being a string argument ## 2010-08-12 Little textual adaptations ## 2010-11-13 Catched jOpenDocument bug (1.2bx) where string cells have no office:value-type ## '' attrb set (by JOD). Somehow OTK is more robust as it catches these cells ## 2012-04-09 Fixed rowrepcnt (str2num not applied to tablerow) ## 2012-04-18 Added getUsedRange() method for JOD 1.3x and above ## 2012-10-12 Renamed & moved into ./private ## 2012-10-24 Style fixes ## 2013-01-20 Clarify internal code comments ## 2013-09-29 Split native Octave part into separate private/ function function [ trow, brow, lcol, rcol ] = __JOD_getusedrange__ (ods, wsh) ## This function works for older jOpendocument (<= 1.2) by virtue of sheets ## in JOD actually being a Java string. ## It works outside of the Java memory/heap space which is an added benefit... ## (Read: it is one big dirty hack... prone to crash Java on BIG spreadsheets) ## For newer jOpenDocument 1.3b1+ there's a newer and much faster method. if (isnumeric (wsh)) sh = char (ods.workbook.getSheet (wsh - 1)); else sh = char (ods.workbook.getSheet (wsh)); endif try ## Let's see if we have JOD v. 1.3x. If not, next call fails & we'll fall ## back to the old hack sh_rng = char (sh.getUsedRange ()); if (isempty (sh_rng)) ## Empty sheet trow = brow = lcol = rcol = 0; else ## Strip sheet name sh_rng = sh_rng(length (sh.getName) + 2 : end); ## Get rid of period sh_rng = strrep (sh_rng, ".", ""); [~, nr, nc, trow, lcol] = parse_sp_range (sh_rng); brow = trow + nr - 1; rcol = lcol + nc - 1; endif catch ## Fall back to the old hack :-( (now in private/ function) sh = char (sh); [trow, brow, lcol, rcol ] = __ods_get_sheet_dims__ (sh); end_try_catch endfunction io/inst/private/__JOD_oct2spsh__.m0000644000076400010400000001531112254666136020351 0ustar PhilipAdministrators## Copyright (C) 2009,2010,2011,2012,2013 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 . ## __JOD_oct2spsh__ - write data from octave to an ODS spreadsheet using the ## jOpenDocument interface. ## ## Author: Philip Nienhuis ## Created: 2009-12-13 ## First usable version: 2010-01-14 ## Updates: ## 2010-03-17 Adapted to simplified calccelladdress argument list ## 2010-04-24 Added ensureColumnCount & ensureRowCount ## Fixed a few bugs with top row & left column indexes ## Fixed a number of other stupid bugs ## Added check on NaN before assigning data value to sprdsh-cell ## 2010-06-01 Checked logic. AFAICS all should work with upcoming jOpenDocument 1.2b4; ## in 1.2b3 adding a newsheet always leaves an incomplete upper row; ## supposedly (hopefully) that will be fixed in 1.2b4. ## '' Added check for jOpenDocument version. Adding sheets only works for ## 1.2b3+ (barring bug above) ## 2010-06-02 Fixed first sheet remaining in new spreadsheets ## 2010-08-01 Added option for crange to be only topleft cell address ## '' Code cleanup ## 2010-08-13 Fixed bug of ignoring text sheet name in case of new spreadsheet ## 2010-08-15 Fixed bug with invalid first sheet in new spreadsheets ## 2010-10-27 Improved file change tracking tru ods.changed ## 2010-11-12 Improved file change tracking tru ods.changed ## 2012-02-26 Write logicals as doubles (bug in jOpenDocument, would write as text) ## 2012-10-12 Renamed & moved into ./private ## 2012-10-24 Style fixes ## 2013-12-01 Style fixes, copyright string updates ## 2013-12-19 More style fixes ## '' Work around jOpenDocument bug adding "A" to A1, "B" to B1 in new files function [ ods, rstatus ] = __JOD_oct2spsh__ (c_arr, ods, wsh, crange) rstatus = 0; sh = []; changed = 0; ## Get worksheet. Use first one if none given if (isempty (wsh)) wsh = 1; endif sh_cnt = ods.workbook.getSheetCount (); if (isnumeric (wsh)) if (wsh > 1024) error ("Sheet number out of range of ODS specification (>1024)"); elseif (wsh > sh_cnt) error ("Sheet number (%d) larger than number of sheets in file (%d)\n",... wsh, sh_cnt); else wsh = wsh - 1; sh = ods.workbook.getSheet (wsh); if (isempty (sh)) ## Sheet number wsh didn't exist yet wsh = sprintf ("Sheet%d", wsh+1); elseif (ods.changed > 2) sh.setName ("Sheet1"); changed = 1; endif endif endif ## wsh is now either a 0-based sheet no. or a string. In latter case: if (isempty (sh) && ischar (wsh)) sh = ods.workbook.getSheet (wsh); if (isempty (sh)) ## Still doesn't exist. Create sheet if (ods.odfvsn == 3) if (ods.changed > 2) ## 1st "new" -unnamed- sheet has already been made when creating the spreadsheet sh = ods.workbook.getSheet (0); sh.setName (wsh); changed = 1; else ## For existing spreadsheets ## printf ("Adding sheet '%s'\n", wsh); sh = ods.workbook.addSheet (sh_cnt, wsh); changed = 1; endif ## jOpenDocument bug: JOD seems to add "A" to A1 and "B" to B1 try if (! isempty (sh.getCellAt (0, 0).getValue)) sh.getCellAt (0, 0).clearValue(); sh.getCellAt (1, 0).clearValue(); endif catch end_try_catch else error (["jOpenDocument v. 1.2b2 does not support adding sheets" ... " - upgrade to v. 1.3\n"]); endif endif endif [nr, nc] = size (c_arr); if (isempty (crange)) trow = 0; lcol = 0; nrows = nr; ncols = nc; elseif (isempty (strfind (deblank (crange), ":"))) [~, ~, ~, trow, lcol] = parse_sp_range (crange); nrows = nr; ncols = nc; ## Row/col = 0 based in jOpenDocument trow = trow - 1; lcol = lcol - 1; else [~, nrows, ncols, trow, lcol] = parse_sp_range (crange); ## Row/col = 0 based in jOpenDocument trow = trow - 1; lcol = lcol - 1; endif if (trow > 65535 || lcol > 1023) error ("Topleft cell beyond spreadsheet limits (AMJ65536)."); endif ## Check spreadsheet capacity beyond requested topleft cell nrows = min (nrows, 65536 - trow); ## Remember, lcol & trow are zero-based ncols = min (ncols, 1024 - lcol); ## Check array size and requested range nrows = min (nrows, nr); ncols = min (ncols, nc); if (nrows < nr || ncols < nc) warning ("Array truncated to fit in range"); endif if (isnumeric (c_arr)) c_arr = num2cell (c_arr); endif ## Ensure sheet capacity is large enough to contain new data try ## try-catch needed to work around bug in jOpenDocument v 1.2b3 and earlier sh.ensureColumnCount (lcol + ncols); ## Remember, lcol & trow are zero-based catch ## catch is needed for new empty sheets (first ensureColCnt() hits null ptr) sh.ensureColumnCount (lcol + ncols); ## Kludge needed because upper row is defective (NPE jOpenDocument bug). ?Fixed in 1.2b4? if (trow == 0) ## Shift rows one down to avoid defective upper row ++trow; printf ("Info: empy upper row above data added to avoid JOD bug.\n"); endif end_try_catch sh.ensureRowCount (trow + nrows); ## Write data to worksheet for ii = 1 : nrows for jj = 1 : ncols val = c_arr {ii, jj}; if ((isnumeric (val) && ! isnan (val)) || ischar (val) || islogical (val)) ## FIXME: jOpenDocument doesn't really support writing booleans (doesn't set OffValAttr) if (islogical (val)) val = double (val); endif try sh.getCellAt (jj + lcol - 1, ii + trow - 1).clearValue(); jcell = sh.getCellAt (jj + lcol - 1, ii + trow - 1).setValue (val); changed = 1; catch ## No panic, probably a merged cell ## printf (sprintf ("Cell skipped at (%d, %d)\n", ii+lcol-1, jj+trow-1)); end_try_catch endif endfor endfor if (changed) ods.changed = max (min (ods.changed, 2), changed); # Preserve 2 (new file), 1 (existing) rstatus = 1; endif endfunction io/inst/private/__JOD_spsh2oct__.m0000644000076400010400000001735612246717772020370 0ustar PhilipAdministrators## Copyright (C) 2009,2010,2011,2012,2013 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 . ## __JOD_spsh2oct__ - get data out of an ODS spreadsheet into octave using jOpenDocument. ## Watch out, no error checks, and spreadsheet formula error results ## are conveyed as 0 (zero). ## ## Author: Philip Nienhuis ## Created: 2009-12-13 ## Last updates: ## 2010-12-31 Moved into subfunc of ods2oct ## 2010-08-12 Added separate stanzas for jOpenDocument v 1.2b3 and up. This version ## allows better cell type parsing and is therefore more reliable ## 2010-10-27 Moved cropping rawarr from empty outer rows & columns to here ## 2010-11-13 Added workaround for reading text cells in files made by jOpenDocument 1.2bx ## 2011-09-18 Comment out workaround for jOpenDocument bug (no OfficeValueAttr set) ## because this casts all numeric cells to string type for properly written ODS1.2 ## '' Remove rstatus var (now set in caller) ## 2012-02-25 Fix reading string values written by JOD itself (no text attribue!!). But ## the cntents could be BOOLEAN as well (JOD doesn't write OffVal attr either) ## 2012-02-26 Further workaround for reading strings (actually: cells w/o OfficeValueAttr) ## 2012-10-12 Renamed & moved into ./private ## 2012-10-24 Style fixes ## 2013-12-01 Style fixes, copyright string updates function [ rawarr, ods] = __JOD_spsh2oct__ (ods, wsh, crange) persistent months; months = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"}; ## Check jOpenDocument version sh = ods.workbook.getSheet (0); cl = sh.getCellAt (0, 0); if (ods.odfvsn == 3) ## 1.2b3+ has public getValueType () persistent ctype; if (isempty (ctype)) BOOLEAN = char (java_get ("org.jopendocument.dom.ODValueType", "BOOLEAN")); CURRENCY = char (java_get ("org.jopendocument.dom.ODValueType", "CURRENCY")); DATE = char (java_get ("org.jopendocument.dom.ODValueType", "DATE")); FLOAT = char (java_get ("org.jopendocument.dom.ODValueType", "FLOAT")); PERCENTAGE = char (java_get ("org.jopendocument.dom.ODValueType", "PERCENTAGE")); STRING = char (java_get ("org.jopendocument.dom.ODValueType", "STRING")); TIME = char (java_get ("org.jopendocument.dom.ODValueType", "TIME")); endif ## else ## ## 1.2b2 has not ## ver = 2; endif ## Sheet INDEX starts at 0 if (isnumeric (wsh)); --wsh; endif ## Check if sheet exists. If wsh = numeric, nonexistent sheets throw errors. try sh = ods.workbook.getSheet (wsh); catch error ("Illegal sheet number (%d) requested for file %s\n", wsh+1, ods.filename); end_try_catch ## If wsh = string, nonexistent sheets yield empty results if (isempty (sh)) error ("No sheet called '%s' present in file %s\n", wsh, ods.filename); endif ## Either parse (given cell range) or prepare (unknown range) help variables if (isempty (crange)) if (ods.odfvsn < 3) error ("No empty read range allowed in jOpenDocument version 1.2b2") else if (isnumeric (wsh)); wsh = wsh + 1; endif [ trow, brow, lcol, rcol ] = getusedrange (ods, wsh); nrows = brow - trow + 1; ## Number of rows to be read ncols = rcol - lcol + 1; ## Number of columns to be read endif else [dummy, nrows, ncols, trow, lcol] = parse_sp_range (crange); ## Check ODS column limits if (lcol > 1024 || trow > 65536) error ("ods2oct: invalid range; max 1024 columns & 65536 rows."); endif ## Truncate range silently if needed rcol = min (lcol + ncols - 1, 1024); ncols = min (ncols, 1024 - lcol + 1); nrows = min (nrows, 65536 - trow + 1); brow= trow + nrows - 1; endif ## Create storage for data content rawarr = cell (nrows, ncols); if (ods.odfvsn >= 3) ## Version 1.2b3+ for ii=1:nrows for jj = 1:ncols try scell = sh.getCellAt (lcol+jj-2, trow+ii-2); sctype = char (scell.getValueType ()); switch sctype case { FLOAT, CURRENCY, PERCENTAGE } rawarr{ii, jj} = scell.getValue (); case BOOLEAN rawarr {ii, jj} = scell.getValue () == 1; case STRING rawarr{ii, jj} = scell.getValue(); case DATE tmp = strsplit (char (scell.getValue ()), " "); yy = str2num (tmp{6}); mo = find (ismember (months, toupper (tmp{2})) == 1); dd = str2num (tmp{3}); hh = str2num (tmp{4}(1:2)); mi = str2num (tmp{4}(4:5)); ss = str2num (tmp{4}(7:8)); rawarr{ii, jj} = datenum (yy, mo, dd, hh, mi, ss); case TIME tmp = strsplit (char (scell.getValue ().getTime ()), " "); hh = str2num (tmp{4}(1:2)) / 24.0; mi = str2num (tmp{4}(4:5)) / 1440.0; ss = str2num (tmp{4}(7:8)) / 86600.0; rawarr {ii, jj} = hh + mi + ss; otherwise ## Workaround for sheets written by jOpenDocument (no value-type attrb): if (! isempty (scell.getValue) ) ## FIXME Assume cell contains string if there's a text attr. ## But it could be BOOLEAN too... if (findstr (". ## __JOD_spsh_close__ - internal function: close a spreadsheet file using JOD ## Author: Philip Nienhuis ## Created: 2012-10-12 ## Updates: ## 2012-10-23 Style fixes ## 2013-01-20 Adapted to ML-compatible Java calls ## 2013-12-01 Copyright string updates function [ ods ] = __JOD_spsh_close__ (ods) try if (ods.changed && ods.changed < 3) if (isfield (ods, "nfilename")) ofile = javaObject ("java.io.File", ods.nfilename); else ofile = javaObject ("java.io.File", ods.filename); endif ods.workbook.saveAs (ofile); ods.changed = 0; endif catch end_try_catch endfunction io/inst/private/__JOD_spsh_info__.m0000644000076400010400000000260412246720740020566 0ustar PhilipAdministrators## Copyright (C) 2012,2013 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 Octave; see the file COPYING. If not, see ## . ## __JOD_spsh_info__ ## Author: Philip Nienhuis ## Created: 2012-10-12 ## Updates: ## 2012-10-12 Moved into ./private ## Updates: ## 2012-10-24 Style fixes ## 2013-12-01 Copyright string updates function [sh_names] = __JOD_spsh_info__ (ods) nr_of_sheets = ods.workbook.getSheetCount (); sh_names = cell (nr_of_sheets, 2); for ii=1:nr_of_sheets sh_names(ii) = ods.workbook.getSheet (ii-1).getName (); [ tr, lr, lc, rc ] = getusedrange (ods, ii); if (tr) sh_names(ii, 2) = sprintf ("%s:%s", calccelladdress (tr, lc),... calccelladdress (lr, rc)); else sh_names(ii, 2) = "Empty"; endif endfor endfunction io/inst/private/__JOD_spsh_open__.m0000644000076400010400000000415612254404456020602 0ustar PhilipAdministrators## Copyright (C) 2012,2013 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 Octave; see the file COPYING. If not, see ## . ## __JOD_spsh_open ## Author: Philip Nienhuis ## Created: 2012-10-12 ## Updates: ## 2012-10-24 Style fixes ## 2013-01-20 Adapted to ML-compatible Java calls ## 2013-12-01 Copyright string updates function [ ods, odssupport, lastintf ] = __JOD_spsh_open__ (ods, rw, filename, odssupport) file = javaObject ("java.io.File", filename); jopendoc = "org.jopendocument.dom.spreadsheet.SpreadSheet"; try if (rw > 2) ## Create an empty 2 x 2 default TableModel template tmodel= javaObject ("javax.swing.table.DefaultTableModel", 2, 2); wb = javaMethod ("createEmpty", jopendoc, tmodel); else wb = javaMethod ("createFromFile", jopendoc, file); endif ods.workbook = wb; ods.filename = filename; ods.xtype = "JOD"; ods.app = "file"; ## Check jOpenDocument version. This can only work here when a ## workbook has been opened sh = ods.workbook.getSheet (0); cl = sh.getCellAt (0, 0); try # 1.2b3 has public getValueType () cl.getValueType (); ods.odfvsn = 3; catch # 1.2b2 has not ods.odfvsn = 2; printf ("NOTE: jOpenDocument v. 1.2b2 has limited functionality. Try upgrading to 1.2\n"); end_try_catch odssupport += 2; lastintf = "JOD"; catch error ("Couldn't open file %s using JOD", filename); end_try_catch endfunction io/inst/private/__JXL_getusedrange__.m0000644000076400010400000000363012246722150021271 0ustar PhilipAdministrators## Copyright (C) 2010,2011,2012,2013 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 . ## __JXL_getusedrange__ - get occupied data cell range from Excel sheet ## using java/JExcelAPI ## Author: Philip Nienhuis ## Created: 2010-03-20 ## Updates: ## 2012-10-12 Renamed & moved into ./private ## 2012-10-24 Style fixes ## 2013-12-01 Style fixes, copyright string updates function [ trow, brow, lcol, rcol ] = __JXL_getusedrange__ (xls, wsh) persistent emptycell = (java_get ("jxl.CellType", "EMPTY")).toString (); sh = xls.workbook.getSheet (wsh - 1); ## JXL sheet count 0-based brow = sh.getRows (); rcol = sh.getColumns (); if (brow == 0 || rcol == 0) ## Empty sheet trow = 0; lcol = 0; brow = 0; rcol = 0; else trow = brow + 1; lcol = rcol + 1; ## For loop coz we must check ALL rows for leftmost column for ii=0:brow-1 emptyrow = 1; jj = 0; ## While loop => only til first non-empty cell while (jj < rcol && emptyrow) cell = sh.getCell (jj, ii); if (! strcmp (char (cell.getType ()), emptycell)) lcol = min (lcol, jj + 1); emptyrow = 0; endif ++jj; endwhile if (! emptyrow) trow = min (trow, ii + 1); endif endfor endif endfunction io/inst/private/__JXL_oct2spsh__.m0000644000076400010400000001651112257326134020367 0ustar PhilipAdministrators## Copyright (C) 2009,2010,2011,2012,2013 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 . ## -*- texinfo -*- ## @deftypefn {Function File} [ @var{xlso}, @var{rstatus} ] = __JXL_oct2spsh__ ( @var{arr}, @var{xlsi}) ## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = __JXL_oct2spsh__ (@var{arr}, @var{xlsi}, @var{wsh}) ## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = __JXL_oct2spsh__ (@var{arr}, @var{xlsi}, @var{wsh}, @var{range}) ## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = __JXL_oct2spsh__ (@var{arr}, @var{xlsi}, @var{wsh}, @var{range}, @var{options}) ## ## Add data in 1D/2D CELL array @var{arr} into spreadsheet cell range @var{range} ## in worksheet @var{wsh} in an Excel spreadsheet file pointed to in structure ## @var{range}. ## Return argument @var{xlso} equals supplied argument @var{xlsi} and is ## updated by __JXL_oct2spsh__. ## ## __JXL_oct2spsh__ should not be invoked directly but rather through oct2xls. ## ## Example: ## ## @example ## [xlso, status] = __JXL_oct2spsh__ ('arr', xlsi, 'Third_sheet', 'AA31'); ## @end example ## ## @seealso {oct2xls, xls2oct, xlsopen, xlsclose, xlsread, xlswrite, xls2jxla2oct} ## ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2009-12-04 ## Updates: ## 2009-12-11 ## 2010-01-12 Fixed skipping empty array values (now Excel-conformant => cell cleared) ## Added xls.changed = 1 statement to signal successful write ## 2010-07-27 Added formula writing support (based on POI patch by Benjamin Lindner) ## Added check for valid file pointer struct ## 2010-08-01 Improved try-catch for formulas to enter wrong formulas as text strings ## 2010-08-01 Added range vs. array size vs. capacity checks ## '' Code cleanup ## '' Changed topleft arg into range arg (topleft version still recognized) ## 2010-08-03 Moved range checks and cell type parsing to separate routines ## 2010-08-11 Moved addcell() into try-catch as it is addCell which throws fatal errors ## 2010-10-20 Improved logic for tracking file changes (xls.changed 2 or 3); dropped ## '' internal variable 'changed' ## 2010-10-27 File change tracking again refined ## 2010-11-12 Moved ptr struct check into main func ## 2012-01-26 Fixed "seealso" help string ## 2012-02-27 Copyright strings updated ## 2012-05-21 "Double" cast added when writing numeric values ## 2012-05-21 "Double" cast moved into main func oct2xls ## 2012-10-12 Renamed & moved into ./private ## 2012-10-24 Style fixes ## 2013-01-20 Adapted to ML-compatible Java calls ## 2013-12-01 Style fixes, copyright string updates ## 2013-12-27 Style fixes function [ xls, rstatus ] = __JXL_oct2spsh__ (obj, xls, wsh, crange, spsh_opts) ## Preliminary sanity checks if (strcmpi (xls.filename(end-4:end-1), ".xls")) ## No OOXML in JXL error ("JXL interface can only process Excel .xls files") endif persistent ctype; if (isempty (ctype)) ctype = [1, 2, 3, 4, 5]; ## Number, Boolean, String, Formula, Empty endif ## scratch vars rstatus = 0; f_errs = 0; ## Prepare workbook pointer if needed if (xls.changed == 0) ## Only for 1st call of octxls after xlsopen ## Create writable copy of workbook. If >2 a writable wb was made in xlsopen xlsout = javaObject ("java.io.File", xls.filename); wb = javaMethod ("createWorkbook", "jxl.Workbook", xlsout, xls.workbook); ## Catch JExcelAPI bug/"feature": when switching to write mode, the file on disk ## is affected and the memory file MUST be written to disk to save earlier data xls.changed = 1; xls.workbook = wb; else wb = xls.workbook; endif ## Check if requested worksheet exists in the file & if so, get pointer nr_of_sheets = xls.workbook.getNumberOfSheets (); ## 1 based !! if (isnumeric (wsh)) if (wsh > nr_of_sheets) ## Watch out as a sheet called Sheet%d can exist with a lower index... strng = sprintf ("Sheet%d", wsh); ii = 1; while (~isempty (wb.getSheet (strng)) && (ii < 5)) strng = ["_" strng]; ++ii; endwhile if (ii >= 5) error (sprintf( " > 5 sheets named [_]Sheet%d already present!", wsh)); endif sh = wb.createSheet (strng, nr_of_sheets); ++nr_of_sheets; xls.changed = min (xls.changed, 2); ## Keep a 2 in case of new file else sh = wb.getSheet (wsh - 1); ## JXL sheet count 0-based endif shnames = char (wb.getSheetNames ()); printf ("(Writing to worksheet %s)\n", shnames {nr_of_sheets, 1}); else sh = wb.getSheet (wsh); if (isempty(sh)) ## Sheet not found, just create it sh = wb.createSheet (wsh, nr_of_sheets); ++nr_of_sheets; xls.changed = min (xls.changed, 2); ## Keep a 2 for new file endif endif ## Parse date ranges [nr, nc] = size (obj); [topleft, nrows, ncols, trow, lcol] = ... spsh_chkrange (crange, nr, nc, xls.xtype, xls.filename); if (nrows < nr || ncols < nc) warning ("Array truncated to fit in range"); obj = obj(1:nrows, 1:ncols); endif ## Prepare type array typearr = spsh_prstype (obj, nrows, ncols, ctype, spsh_opts); if (! spsh_opts.formulas_as_text) ## Remove leading '=' from formula strings fptr = ! (4 * (ones (size (typearr))) .- typearr); obj(fptr) = cellfun (@(x) x(2:end), obj(fptr), "Uniformoutput", false); endif clear fptr ## Write date to worksheet for ii=1:nrows ll = ii + trow - 2; ## Java JExcelAPI's row count = 0-based for jj=1:ncols kk = jj + lcol - 2; ## JExcelAPI's column count is also 0-based switch typearr(ii, jj) case 1 ## Numerical tmp = javaObject ("jxl.write.Number", kk, ll, obj{ii, jj}); sh.addCell (tmp); case 2 ## Boolean tmp = javaObject ("jxl.write.Boolean", kk, ll, obj{ii, jj}); sh.addCell (tmp); case 3 ## String tmp = javaObject ("jxl.write.Label", kk, ll, obj{ii, jj}); sh.addCell (tmp); case 4 ## Formula ## First make sure formula functions are all uppercase obj{ii, jj} = toupper (obj{ii, jj}); ## There's no guarantee for formula correctness, so.... try ## Actually JExcelAPI flags formula errors as mere warnings :-( tmp = javaObject ("jxl.write.Formula", kk, ll, obj{ii, jj}); ## ... while errors are actually detected in addCell(), so ## that should be within the try-catch sh.addCell (tmp); catch ++f_errs; ## Formula error. Enter formula as text string instead tmp = javaObject ("jxl.write.Label", kk, ll, obj{ii, jj}); sh.addCell (tmp); end_try_catch case 5 ## Empty or NaN tmp = javaObject ("jxl.write.Blank", kk, ll); sh.addCell (tmp); otherwise ## Just skip endswitch endfor endfor if (f_errs) printf ("%d formula errors encountered - please check input array\n", f_errs); endif xls.changed = max (xls.changed, 1); ## Preserve 2 for new files rstatus = 1; endfunction io/inst/private/__JXL_spsh2oct__.m0000644000076400010400000002173612246721562020376 0ustar PhilipAdministrators## Copyright (C) 2009,2010,2011,2012,2013 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 2 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 Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = __JXL_spsh2oct__ (@var{xls}) ## @deftypefnx {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = __JXL_spsh2oct__ (@var{xls}, @var{wsh}) ## @deftypefnx {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = __JXL_spsh2oct__ (@var{xls}, @var{wsh}, @var{range}) ## Get cell contents in @var{range} in worksheet @var{wsh} in an Excel ## file pointed to in struct @var{xls} into the cell array @var{obj}. ## @var{range} can be a range or just the top left cell of the range. ## ## __JXL_spsh2oct__ should not be invoked directly but rather through xls2oct. ## ## Examples: ## ## @example ## [Arr, status, xls] = __JXL_spsh2oct__ (xls, "Second_sheet", "B3:AY41"); ## B = __JXL_spsh2oct__ (xls, "Second_sheet"); ## @end example ## ## @seealso {xls2oct, oct2xls, xlsopen, xlsclose, xlsread, xlswrite, oct2jxla2xls} ## ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2009-12-04 ## Updates: ## 2009-12-11 ??? some bug fix ## 2010-07-28 Added option to read formulas as text strings rather than evaluated value ## Added check for proper xls structure ## 2010-07-29 Added check for too latge requested data rectangle ## 2010-10-10 Code cleanup: -getusedrange(); moved cropping result array to ## '' calling function ## 2010-11-12 Moved ptr struct check into main func ## 2010-11-13 Catch empty sheets when no range was specified ## 2011-04-11 (Ron Goldman ) Fixed missing months var, wrong arg ## '' order in strsplit, wrong isTime condition ## 2012-01-26 Fixed "seealso" help string ## 2012-10-12 Renamed & moved into ./private ## 2012-10-24 Style fixes ## 2013-12-01 Style fixes, copyright string updates function [ rawarr, xls, rstatus ] = __JXL_spsh2oct__ (xls, wsh, cellrange, spsh_opts) persistent ctype; persistent months; if (isempty (ctype)) ctype = cell (11, 1); ## Get enumerated cell types. Beware as they start at 0 not 1 ctype( 1) = (java_get ("jxl.CellType", "BOOLEAN")).toString (); ctype( 2) = (java_get ("jxl.CellType", "BOOLEAN_FORMULA")).toString (); ctype( 3) = (java_get ("jxl.CellType", "DATE")).toString (); ctype( 4) = (java_get ("jxl.CellType", "DATE_FORMULA")).toString (); ctype( 5) = (java_get ("jxl.CellType", "EMPTY")).toString (); ctype( 6) = (java_get ("jxl.CellType", "ERROR")).toString (); ctype( 7) = (java_get ("jxl.CellType", "FORMULA_ERROR")).toString (); ctype( 8) = (java_get ("jxl.CellType", "NUMBER")).toString (); ctype( 9) = (java_get ("jxl.CellType", "LABEL")).toString (); ctype(10) = (java_get ("jxl.CellType", "NUMBER_FORMULA")).toString (); ctype(11) = (java_get ("jxl.CellType", "STRING_FORMULA")).toString (); months = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"}; endif rstatus = 0; wb = xls.workbook; ## Check if requested worksheet exists in the file & if so, get pointer nr_of_sheets = wb.getNumberOfSheets (); shnames = char (wb.getSheetNames ()); if (isnumeric (wsh)) if (wsh > nr_of_sheets) error (sprintf ("Worksheet ## %d bigger than nr. of sheets (%d) in file %s",... wsh, nr_of_sheets, xls.filename)); endif sh = wb.getSheet (wsh - 1); ## JXL sheet count 0-based ## printf ("(Reading from worksheet %s)\n", shnames {wsh}); else sh = wb.getSheet (wsh); if (isempty (sh)) error (sprintf ("Worksheet %s not found in file %s", wsh, xls.filename)); endif end if (isempty (cellrange)) ## Get numeric sheet pointer (1-based) ii = 1; while (ii <= nr_of_sheets) if (strcmp (wsh, shnames{ii}) == 1) wsh = ii; ii = nr_of_sheets + 1; else ++ii; endif endwhile ## Get data rectangle row & column numbers (1-based) [firstrow, lastrow, lcol, rcol] = getusedrange (xls, wsh); if (firstrow == 0 && lastrow == 0) ## Empty sheet rawarr = {}; printf ("Worksheet '%s' contains no data\n", shnames {wsh}); rstatus = 1; return; else nrows = lastrow - firstrow + 1; ncols = rcol - lcol + 1; endif else ## Translate range to row & column numbers (1-based) [dummy, nrows, ncols, firstrow, lcol] = parse_sp_range (cellrange); ## Check for too large requested range against actually present range lastrow = min (firstrow + nrows - 1, sh.getRows ()); nrows = min (nrows, sh.getRows () - firstrow + 1); ncols = min (ncols, sh.getColumns () - lcol + 1); rcol = lcol + ncols - 1; endif ## Read contents into rawarr rawarr = cell (nrows, ncols); ## create placeholder for jj = lcol : rcol for ii = firstrow:lastrow scell = sh.getCell (jj-1, ii-1); switch char (scell.getType ()) case ctype{1} ## Boolean rawarr {ii+1-firstrow, jj+1-lcol} = scell.getValue (); case ctype{2} ## Boolean formula if (spsh_opts.formulas_as_text) tmp = scell.getFormula (); rawarr {ii+1-firstrow, jj+1-lcol} = ["=" tmp]; else rawarr {ii+1-firstrow, jj+1-lcol} = scell.getValue (); endif case ctype{3} ## Date try % Older JXL.JAR, returns float rawarr {ii+1-firstrow, jj+1-lcol} = scell.getValue (); catch % Newer JXL.JAR, returns date string w. epoch = 1-1-1900 :-( tmp = strsplit (char (scell.getDate ()), " "); yy = str2num (tmp{6}); mo = find (ismember (months, upper (tmp{2})) == 1); dd = str2num (tmp{3}); hh = str2num (tmp{4}(1:2)); mi = str2num (tmp{4}(4:5)); ss = str2num (tmp{4}(7:8)); if (scell.isTime ()) yy = mo = dd = 0; endif rawarr {ii+1-firstrow, jj+1-lcol} = datenum (yy, mo, dd, hh, mi, ss); end_try_catch case ctype{4} ## Date formula if (spsh_opts.formulas_as_text) tmp = scell.getFormula (); rawarr {ii+1-firstrow, jj+1-lcol} = ["=" tmp]; else unwind_protect % Older JXL.JAR, returns float tmp = scell.getValue (); % if we get here, we got a float (old JXL). % Check if it is time if (! scell.isTime ()) % Reset rawarr <> so it can be processed below as date string rawarr {ii+1-firstrow, jj+1-lcol} = []; else rawarr {ii+1-firstrow, jj+1-lcol} = tmp; end unwind_protect_cleanup if (isempty (rawarr {ii+1-firstrow, jj+1-lcol})) % Newer JXL.JAR, returns date string w. epoch = 1-1-1900 :-( tmp = strsplit (char (scell.getDate ()), " "); yy = str2num (tmp{6}); mo = find (ismember (months, upper (tmp{2})) == 1); dd = str2num (tmp{3}); hh = str2num (tmp{4}(1:2)); mi = str2num (tmp{4}(4:5)); ss = str2num (tmp{4}(7:8)); if (scell.isTime ()) yy = 0; mo = 0; dd = 0; end rawarr {ii+1-firstrow, jj+1-lcol} = datenum (yy, mo, dd, hh, mi, ss); endif end_unwind_protect endif case { ctype{5}, ctype{6}, ctype{7} } ## Empty, Error or Formula error. Nothing to do here case ctype{8} ## Number rawarr {ii+1-firstrow, jj+1-lcol} = scell.getValue (); case ctype{9} ## String rawarr {ii+1-firstrow, jj+1-lcol} = scell.getString (); case ctype{10} ## Numerical formula if (spsh_opts.formulas_as_text) tmp = scell.getFormula (); rawarr {ii+1-firstrow, jj+1-lcol} = ["=" tmp]; else rawarr {ii+1-firstrow, jj+1-lcol} = scell.getValue (); endif case ctype{11} ## String formula if (spsh_opts.formulas_as_text) tmp = scell.getFormula (); rawarr {ii+1-firstrow, jj+1-lcol} = ["=" tmp]; else rawarr {ii+1-firstrow, jj+1-lcol} = scell.getString (); endif otherwise ## Do nothing endswitch endfor endfor rstatus = 1; xls.limits = [lcol, rcol; firstrow, lastrow]; endfunction io/inst/private/__JXL_spsh_close__.m0000644000076400010400000000301012246721272020752 0ustar PhilipAdministrators## Copyright (C) 2012,2013 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 Octave; see the file COPYING. If not, see ## . ## __JXL_spsh_close__ - internal function: close a spreadsheet file using JXL ## Author: Philip Nienhuis ## Created: 2012-10-12 ## Updates: ## 2012-10-24 Style fixes ## 2013-12-01 Style fixes, copyright string updates function [ xls ] = __JXL_spsh_close__ (xls) if (xls.changed > 0 && xls.changed < 3) try ## if (xls.changed == 2); printf ("Saving file %s...\n", xls.filename); endif xls.workbook.write (); xls.workbook.close (); if (xls.changed == 3) ## Upon entering write mode, JExcelAPI always resets disk file. ## Incomplete new files (no data added) had better be deleted. xls.workbook.close (); delete (xls.filename); endif xls.changed = 0; catch end_try_catch endif endfunction io/inst/private/__JXL_spsh_info__.m0000644000076400010400000000274212246721204020606 0ustar PhilipAdministrators## Copyright (C) 2012,2013 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 Octave; see the file COPYING. If not, see ## . ## __JXL_spsh_info__ ## Author: Philip Nienhuis ## Created: 2012-10-12 ## Updates: ## 2012-10-12 Moved into ./private ## 2012-10-24 Style fixes ## 2013-12-01 Style fixes, copyright string updates function [sh_names, fformat] = __JXL_spsh_info__ (xls) sh_cnt = xls.workbook.getNumberOfSheets (); sh_names = cell (sh_cnt, 2); nsrows = zeros (sh_cnt, 1); sh_names(:,1) = char (xls.workbook.getSheetNames ()); for ii=1:sh_cnt [tr, lr, lc, rc] = getusedrange (xls, ii); if (tr) sh_names(ii, 2) = ... sprintf ("%s:%s", calccelladdress (tr, lc), calccelladdress (lr, rc)); else sh_names(ii, 2) = "Empty"; endif endfor if (sh_cnt > 0) fformat = "xlWorkbookNormal"; else fformat = ''; endif endfunction io/inst/private/__JXL_spsh_open__.m0000644000076400010400000000422012257324110020602 0ustar PhilipAdministrators## Copyright (C) 2012,2013 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 Octave; see the file COPYING. If not, see ## . ## __JXL_xlsopen__ - Internal function for opening an xls file using Java / JExcelAPI ## Author: Philip Nienhuis ## Created: 2012-10-07 ## Updates (possibly from xlsopen): ## 2010-11-05 Bug fix: JXL fallback from POI for BIFF5 is only useful for reading ## 2012-10-24 Style fixes ## 2013-01-20 Adapted to ML-compatible Java calls ## 2013-12-01 Style fixes, opyright string updates ## 2013-12-27 Use one variable for processed file type ## '' Clarify error message about unrecognized file type function [ xls, xlssupport, lastintf ] = __JXL_spsh_open__ (xls, xwrite, filename, xlssupport, ftype) if (ftype != 1) error ("xlsopen: JXL can only read .xls (BIFF5 - Excel95 or BIFF8 - Excel97-2003) files") endif try xlsin = javaObject ("java.io.File", filename); if (xwrite > 2) ## Get handle to new xls-file wb = javaMethod ("createWorkbook", "jxl.Workbook", xlsin); else ## Open existing file wb = javaMethod ("getWorkbook", "jxl.Workbook", xlsin); endif xls.xtype = "JXL"; xls.app = xlsin; xls.workbook = wb; xls.filename = filename; xlssupport += 4; lastintf = "JXL"; catch clear xlsin; if (xlsinterfaces.POI) ## Fall back to UNO only when that is stable (= closing soffice) printf ("... No luck with JXL either, unsupported file format.\n", filename); endif end_try_catch endfunction io/inst/private/__OCT_cc__.m0000644000076400010400000000653212260620012017163 0ustar PhilipAdministrators## Copyright (C) 2013 Markus Bergholz ## ## 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 . ## -*- texinfo -*- ## @deftypefn {Function File} [ var{output} ] = __OCT_cc__ (var{in}) ## Column calculator for OCT interface; transforms column number between 1 ## and 16384 to a letter column header, or a 1-3 letter column header into ## a column number. ## ## A <=> 1 ... XFD <=> 16384 ## ## Input argument has to be a positive integer between 1:18278. ## Result will be a string ## ## Input argument has to be a string (only uppercase letters from "A":"Z") with a length between 1:3. ## Result will be a positiv integer ## ## Created 2013-12-19 Markus Bergholz %% terminologie: %% length=3 :(x*26*26+y*26+z) %% length=2: y*26+z %% length=1: z function output = __OCT_cc__ (in) hstr = ["A":"Z"]; ## help string if (isnumeric (in)) ## Input check if (18278 < in) error ("__OCT_cc__ is limited to column number 18278!") return elseif (1 > in) error ("__OCT_cc__ supports positive integer values only!") return endif if (27 > in) output = hstr(in); elseif (in > 26 && in < 703) letter1 = fix (in / 26); if (! (in - (letter1 * 26))) output = [hstr(letter1 - 1) hstr(26)]; else a = hstr(letter1); output = [a hstr(in - (letter1 * 26))]; endif elseif (in > 702) ## It's at least (x*26*26+1*26+1) letter1 = round (in / (26 * 26 + 27)); if (in <= letter1 * 26 * 26) letter1 = letter1 - 1; elseif (27 < (in - letter1 * 26 * 26) / 26) letter1 = letter1 + 1; endif letter2 = fix (fix (in - letter1 * 26 * 26) / 26); if (! (in - (letter1 * 26 * 26) - (letter2 * 26))); letter2 = letter2 - 1; endif letter3 = in - (letter1 * 26 * 26) - (letter2 * 26); if (! letter3) letter3 = 26; endif output = [hstr(letter1) hstr(letter2) hstr(letter3)]; endif elseif (ischar (in)) strlength = length (in); ## Input check if (3 < strlength) error ("__OCT_cc__ supports maximum 3 letters!") return elseif (1 > strlength) error("__OCT_cc__ needs at least 1 uppercase letter!") return endif a = isstrprop (in, "upper"); ##if 0 ~=numel(a(a==0)) if (numel (a(a == 0))) error ('__OCT_cc__ supports only capital letters "A-Z"') return endif if (strlength == 1) output = [strfind(hstr, in)]; elseif (strlength == 2) output = [(strfind(hstr, in(1))) * 26 + (strfind (hstr, in(2)))]; elseif (strlength == 3) output = [(strfind(hstr, in(1))) * 26 * 26 + (strfind(hstr, in(2))) * 26 + (strfind(hstr, in(3)))]; else error ("String too long for __OCT_cc__ function. That should not happen") return endif else error ("Wrong usage of __OCT_cc__ function") return endif endfunction io/inst/private/__OCT_getusedrange__.m0000644000076400010400000001441112261110406021250 0ustar PhilipAdministrators## Copyright (C) 2013 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 Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{retval} =} __OCT_getusedrange__ (@var{x} @var{y}) ## Get leftmost & rightmost occupied column numbers, and topmost and ## lowermost occupied row numbers (base 1). ## ## @seealso{} ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2013-09-08 ## Updates: ## 2013-09-23 Prepared for adding in OOXML ## 2013-09-26 Improved code to skip last empty columns in column count ## 2013-09-27 Re-use old jOpenDocument code; may be slow but it is well-tested ## 2013-10-01 Gnumeric subfunction added ## 2013-11-03 Fix wrong variable name "xml"->"sheet" in __OCT_ods_getusedrange__ ## 2013-11-16 Replace fgetl calls by fread to cope with EOLs ## 2013-12-14 (OOXML) Insert scanning to circumvent faulty "A1" range from POI ## 2014-01-01 Beware of empty sheets in __OCT_xlsx_getusedrange__ range scanner function [ trow, brow, lcol, rcol ] = __OCT_getusedrange__ (spptr, ii) ## Check input nsheets = numel (spptr.sheets.sh_names); if (ii > nsheets) error ("getusedrange: sheet index (%d) out of range (1 - %d)", ii, nsheets); endif if (strcmpi (spptr.filename(end-3:end), ".ods")) [ trow, brow, lcol, rcol ] = __OCT_ods_getusedrange__ (spptr, ii); elseif (strcmpi (spptr.filename(end-4:end-1), ".xls")) [ trow, brow, lcol, rcol ] = __OCT_xlsx_getusedrange__ (spptr, ii); elseif (strcmpi (spptr.filename(end-8:end), ".gnumeric")) [ trow, brow, lcol, rcol ] = __OCT_gnm_getusedrange__ (spptr, ii); endif endfunction ##=============================OOXML======================== function [ trow, brow, lcol, rcol ] = __OCT_xlsx_getusedrange__ (spptr, ii); ## Approximation only! OOXML also counts empty cells (with only formatting) trow = brow = lcol = rcol = 0; ## Read first part of raw worksheet fid = fopen (sprintf ('%s/xl/worksheets/sheet%d.xml', spptr.workbook, ii)); if (fid > 0) xml = fread (fid, 512, "char=>char").'; ## Occupied range is in first 512 bytes fclose (fid); else ## We know the number must be good => apparently tmpdir is damaged or it has gone error ("getusedrange: sheet number nonexistent or corrupted file pointer struct"); endif node = getxmlnode (xml, "dimension"); crange = getxmlattv (node, "ref"); if (strcmpi (crange, "A1")) ## Looks like it has been written by POI OOXML or UNO. We need a better guess ## 1. Re-read entire worksheet fid = fopen (sprintf ('%s/xl/worksheets/sheet%d.xml', spptr.workbook, ii)); xml = fread (fid, Inf, "char=>char").'; fclose (fid); ## 2. Scan for cell addresses addr = cell2mat (regexp (xml, 'char").'; fclose (fid); endif ## Check if sheet contains any cell content at all ## FIXME: in far-fetched cases, cell string content may contain ' office:value' too if (isempty (strfind (sheet, " office:value"))) return endif [trow, brow, lcol, rcol ] = __ods_get_sheet_dims__ (sheet); endfunction ##===========================Gnumeric======================= function [ trow, brow, lcol, rcol ] = __OCT_gnm_getusedrange__ (spptr, ii); trow = brow = lcol = rcol = nrows = ncols = 0; if (isfield (spptr, "xml")) xml = spptr.xml; else ## Get requested sheet from info in ods struct pointer. Open file fid = fopen (spptr.workbook, 'r'); ## Go to start of requested sheet (real start, incl. xml id line) fseek (fid, spptr.sheets.shtidx(ii), 'bof'); ## Compute size of requested chunk nchars = spptr.sheets.shtidx(ii+1) - spptr.sheets.shtidx(ii); ## Get the sheet xml = fread (fid, nchars, "char=>char").'; fclose (fid); endif if (isempty (getxmlnode (xml, "gnm:Cell"))) ## No cell in sheet. We're done return endif ## Start processing cells. Although max row & column (0-based) are given in ## dedicated nodes in the xml, these don't seem exact, and no topleft limit ## is given anyway. cells = getxmlnode (xml, "gnm:Cells"); ## Min and max columns cols = regexp (cells, 'Col="\d*"', "match"); cols = regexprep (cols, 'Col="', ''); cols = regexprep (cols, '"', ''); cols = str2double (cols); lcol = min (cols) + 1; rcol = max (cols) + 1; ## Min and max rows rows = regexp (cells, 'Row="\d*"', "match"); rows = regexprep (rows, 'Row="', ''); rows = regexprep (rows, '"', ''); rows = str2double (rows); trow = min (rows) + 1; brow = max (rows) + 1; endfunction io/inst/private/__OCT_gnm2oct__.m0000644000076400010400000001254212241700300020143 0ustar PhilipAdministrators## Copyright (C) 2013 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 Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} [@var{raw}, @var{ods}, @var{rstatus} = __OCT_gnm2oct__ (@var{ods}, @var{wsh}, @var{range}, @var{opts}) ## Internal function for reading data from a Gnumeric worksheet ## ## @seealso{} ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2013-10-01 ## Updates: ## 2013-10-02 Drop return arg rstatus ## 2013-10-02 Significant speed-up using regexp and splitting xml in chunks ~4e5 chars ## 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 function [ rawarr, xls, rstatus] = __OCT_gnm2oct__ (xls, wsh, cellrange='', spsh_opts) rstatus = 0; ## Check if requested worksheet exists in the file & if so, get sheet if (isnumeric (wsh)) if (wsh > numel (xls.sheets.sh_names) || wsh < 1) error ("xls2oct: sheet number (%d) out of range (1 - %d)", wsh, numel (xls.sheets.sh_names)); endif elseif (ischar (wsh)) idx = strmatch (wsh, xls.sheets.sh_names); if (isempty (idx)) error ("xls2oct: sheet '%s' not found in file %s", wsh, xls.filename); endif wsh = idx; endif ## Get requested sheet from info in file struct pointer. Open file fid = fopen (xls.workbook, "r"); ## Go to start of requested sheet. This requires reading from start, not ## from after 1st xml id line fseek (fid, xls.sheets.shtidx(wsh), 'bof'); ## Compute size of requested chunk nchars = xls.sheets.shtidx(wsh+1) - xls.sheets.shtidx(wsh); ## Get the sheet xml = fread (fid, nchars, "char=>char").'; fclose (fid); ## Add xml to struct pointer to avoid __OCT_getusedrange__ to read it again xls.xml = xml; ## Check ranges [ firstrow, lastrow, leftcol, rightcol ] = getusedrange (xls, wsh); ## Remove xml field xls.xml = []; xls = rmfield (xls, "xml"); if (isempty (cellrange)) if (firstrow == 0 && lastrow == 0) ## Empty sheet rawarr = {}; printf ("Worksheet '%s' contains no data\n", xls.sheets.sh_names{wsh}); rstatus = 1; return; else nrows = lastrow - firstrow + 1; ncols = rightcol - leftcol + 1; endif else [~, nr, nc, tr, lc] = parse_sp_range (cellrange); ## Check if requested range exists if (tr > lastrow || lc > rightcol) ## Out of occupied range warning ("xls2oct: requested range outside occupied range"); rawarr = {}; xls.limits = []; return endif lastrow = min (lastrow, firstrow + nr - 1); rightcol = min (rightcol, leftcol + nc - 1); endif ## Get cell nodes cells = getxmlnode (xml, "gnm:Cells"); ## Pattern gets all required tokens in one fell swoop pattrn = '(.*?)'; allvals = cell2mat (regexp (cells, pattrn, "tokens")); ## Reshape into 4 x ... cell array allvals = reshape (allvals, 4, numel (allvals) / 4); ## Convert 0-based rw/column indices to 1-based numeric allvals(1:2, :) = num2cell (str2double (allvals(1:2, :)) + 1); ## Convert cell type values to double allvals(3, :) = num2cell (str2double (allvals(3, :))); ## Convert numeric cell values to double in = find ([allvals{3,:}] == 40); allvals(4, in) = num2cell (str2double(allvals(4, in))'); ## Convert boolean values to logical il = find ([allvals{3,:}] == 20); allvals(4, il) = num2cell (cellfun (@(x) strcmpi (x, "true"), allvals(4, il))); ## Get limits of data rectangle trow = min (cell2mat (allvals(1, :))); brow = max (cell2mat (allvals(1, :))); rcol = max (cell2mat (allvals(2, :))); lcol = min (cell2mat (allvals(2, :))); xls.limits = [lcol rcol; trow brow]; ## Create data array rawarr = cell (brow-trow+1, rcol-lcol+1); ## Compute linear indices into data array from 1-based row/col indices idx = sub2ind (size (rawarr), [allvals{1, :}] - trow + 1, [allvals{2,:}] - lcol + 1); ## And assign cell values to data array rawarr(idx) = allvals(4, :); ## FIXME maybe reading parts of the data can be done faster above by better regexps ## or sorting on row & truncating followed by sorting on columns and truncating if (! isempty (cellrange)) ## We'll do it the easy way: just read all data, then return only the requested part xls.limits = [max(lcol, lc), min(rcol, lc+nc-1); max(trow, tr), min(brow, tr+nr-1)]; ## Correct spreadsheet locations for lower right shift or raw rc = trow - 1; cc = lcol - 1; rawarr = rawarr(xls.limits(2, 1)-rc : xls.limits(2, 2)-rc, xls.limits(1, 1)-cc : xls.limits(1, 2)-cc); endif if (! isempty (allvals)) rstatus = 1; endif endfunction io/inst/private/__OCT_ods2oct__.m0000644000076400010400000002764512254674314020204 0ustar PhilipAdministrators## Copyright (C) 2013 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 Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} [@var{raw}, @var{ods}, @var{rstatus} = __OCT_ods2oct__ (@var{ods}, @var{wsh}, @var{range}, @var{opts}) ## Internal function for reading data from an ods worksheet ## ## @seealso{} ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2013-09-08 ## Updates: ## 2013-09-09 Fix getxmlnode call ## '' boolean, percentage & currency tags properly handled ## 2013-09-11 Properly skip empty upper table-rows ## '' Return dates as strings to avoid misinterpreting plethora of formats ## '' Try-catch construct for time values ## '' Formula reading support ## 2013-09-23 Renamed to __OCT_ods2oct__.m ## 2013-09-29 Use values between tags only for strings & dates/times ## '' Return date values as Octave datenums (doubles) ## '' Return requested range rather than entire sheet data ## 2013-10-01 Little adaptation in header ## 2013-10-01 Read sheets from disk rather than keep them in memory ## 2013-11-03 Fix bug with updating column ptr after repeated columns node ## 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) function [ rawarr, ods, rstatus] = __OCT_ods2oct__ (ods, wsh, cellrange='', spsh_opts) rstatus = 0; ## Check if requested worksheet exists in the file & if so, get sheet if (isnumeric (wsh)) if (wsh > numel (ods.sheets.sh_names) || wsh < 1) error ("ods2oct: sheet number (%d) out of range (1 - %d)", wsh, numel (ods.sheets.sh_names)); endif elseif (ischar (wsh)) idx = strmatch (wsh, ods.sheets.sh_names); if (isempty (idx)) error ("ods2oct: sheet '%s' not found in file %s", wsh, ods.filename); endif wsh = idx; endif ## Get requested sheet from info in ods struct pointer. Open file fid = fopen (sprintf ("%s/content.xml", ods.workbook), "r");; ## Go to start of requested sheet fseek (fid, ods.sheets.shtidx(wsh), 'bof'); ## Compute size of requested chunk nchars = ods.sheets.shtidx(wsh+1) - ods.sheets.shtidx(wsh); ## Get the sheet sheet = fread (fid, nchars, "char=>char").'; fclose (fid); ## Add xml to struct pointer to avoid __OCT_getusedrange__ to read it again ods.xml = sheet; ## Check ranges [ firstrow, lastrow, lcol, rcol ] = getusedrange (ods, wsh); ## Clear xml from file ptr struct ods.xml = []; ods = rmfield (ods, "xml"); if (isempty (cellrange)) if (firstrow == 0 && lastrow == 0) ## Empty sheet rawarr = {}; printf ("Worksheet '%s' contains no data\n", ods.sheets.sh_names{wsh}); rstatus = 1; return; else nrows = lastrow - firstrow + 1; ncols = rcol - lcol + 1; endif else [topleft, nrows, ncols, firstrow, lcol] = parse_sp_range (cellrange); ## Check if requested range exists if (firstrow > lastrow || lcol > rcol) ## Out of occupied range warning ("ods2oct: requested range outside occupied range"); rawarr = {}; ods.limits = []; return endif lastrow = min (lastrow, firstrow + nrows - 1); rcol = min (rcol, lcol + ncols - 1); endif ## FIXME Preallocation + data reading can be more efficient ## Preallocate output array; provisionally assign max nr. of rows & columns rawarr = cell (lastrow, rcol); ## Get data re = 1; # Start table-row search at first char of sheet irow = 0; # Counts "real" spreadsheet rows trow = " "; ## Row index ii below does not necessarily match table-rows! while (irow < lastrow && (! isempty (trow))) ## Get next table-row [trow, ~, re] = getxmlnode (sheet, "table:table-row", re); if (! isempty (trow)) ## Check if table-row has any data datrow = index (trow, " office:"); ## Check repeat status and update row counter reprow = str2double (getxmlattv (trow, "table:number-rows-repeated")); if (isfinite (reprow)) reprow = min (reprow, lastrow - irow) - 1; endif irow++; ## Only process table-row contents if it has any data. Skip upper ## empty table-rows (that's why we need an OR), only start counting ## with the first table-row containing data if (datrow || irow) ce = 0; # Char pointer on table-row tcell = " "; icol = 0; # Count spreadsheet column while (icol < rcol && (! isempty (tcell))) ## Get next table-cell. First see if it is covered (merged) [tcell1, ~, ce1] = getxmlnode (trow, "table:covered-table-cell", ce+1); [tcell2, ~, ce2] = getxmlnode (trow, "table:table-cell", ce+1); if (ce1 > 0 && ce2 > 0) ## Both table-cell and a table-covered-cell are present if (ce1 < ce2) ## table-covered cell before table-cell. Set pointer at its end ce = ce1; tcell = tcell1; ## Signal code below that content parsing must be skipped ce2 = 0; else ## table-cell before table-covered cell. Pointer to end of table-cell ce = ce2; tcell = tcell2; endif else if (ce1 > 0) ## Only table-covered-cell found ce = ce1; tcell = tcell1; else ## Only table-cell found ce = ce2; tcell = tcell2; endif endif ## First check its repeat status and update column counter repcol = str2double (getxmlattv (tcell, "table:number-columns-repeated")); if (isfinite (repcol)) repcol = min (repcol, rcol - icol); endif icol++; if (! isempty (tcell)) ## Try to get value type ctype = ''; if (ce2) ctype = getxmlattv (tcell, "office:value-type"); if (isempty (ctype) && spsh_opts.formulas_as_text) ## Work around OTK bug (doesn't write office:value-type for formulas) if (! isempty (strfind (tcell, "formula"))) ctype = "cformula"; endif endif endif if (! isempty (ctype)) if (spsh_opts.formulas_as_text) form = getxmlattv (tcell, "table:formula"); if (! isempty (form)) ctype = "cformula"; endif endif ## Get value ctvalue = getxmlnode (tcell, "text:p")(9:end-9); ## Put proper translation into rawarr switch ctype case "cformula" form = strrep (form, """, '"'); form = strrep (form, "<", "<"); form = strrep (form, ">", ">"); form = strrep (form, "&", "&"); ## Pimp ranges in formulas form = regexprep (form, '\[\.(\w+)\]', '$1'); form = regexprep (form, '\[\.(\w+):', '$1:'); form = regexprep (form, ':\.(\w+)\]', ':$1'); rawarr{irow, icol} = form; case "float" ## Watch out for error values. If so, has #VALUE and office:value = 0 if (isfinite (str2double (ctvalue))) rawarr{irow, icol} = str2double (getxmlattv (tcell, "office:value")); else rawarr{irow, icol} = NaN; endif case "percentage" ## Watch out for error values. If so, has #VALUE and office:value = 0 ctvalue = ctvalue (1:end-1); if (isfinite (str2double (ctvalue))) rawarr{irow, icol} = str2double (getxmlattv (tcell, "office:value")); else rawarr{irow, icol} = NaN; endif case "currency" ## Watch out for error values. If so, has #VALUE and office:value = 0 idx = regexp (ctvalue, '[\d.\d]'); if (isempty (idx)) rawarr{irow, icol} = NaN; else rawarr{irow, icol} = str2double (getxmlattv (tcell, "office:value")); endif case "string" ctvalue = strrep (ctvalue, "&", "&"); ctvalue = strrep (ctvalue, "<", "<"); ctvalue = strrep (ctvalue, ">", ">"); ctvalue = strrep (ctvalue, """, '"'); rawarr{irow, icol} = ctvalue; case "date" cvalue = getxmlattv (tcell, "office:date-value"); try cvalue = strsplit (cvalue, "T"); ## Date part cv = regexp (cvalue{1}, '[0-9]*', "match"); yr = str2double (cv(1)); mo = str2double (cv(2)); dy = str2double (cv(3)); rawarr{irow, icol} = datenum(yr, mo, dy) + 693960; ## Time part, if any (that's what the try-catch is for) cv = regexp (cvalue{2}, '[0-9]*', "match"); hh = str2double (cv(1)); mm = str2double (cv(2)); ss = str2double (cv(3)); rawarr{irow, icol} += datenum (0, 0, 0, hh, mm, ss); catch end_try_catch case "boolean" rawarr{irow, icol} = strcmpi (ctvalue, "true"); case "time" ## Time values usually have hours first, then minutes, optionally seconds hh = mi = ss = 0; ctvalue = regexp (getxmlattv (tcell, "office:time-value"), '[0-9]*', "match"); ## try-catch to catch missing seconds try hh = str2double (ctvalue(1)); mi = str2double (ctvalue(2)); ss = str2double (ctvalue(3)); catch end_try_catch rawarr{irow, icol} = datenum (0, 0, 0, hh, mi, ss); otherwise ## Do nothing endswitch endif ## Copy cell contents for repeated columns & bump column counter if (isfinite (repcol) && icol < rcol) rawarr(irow, icol+1:icol+repcol-1) = rawarr(irow, icol); icol += repcol - 1; repcol = ''; endif endif endwhile ## Copy row contents to repeated rows & bump row counter if (isfinite (reprow) && irow < lastrow) for kk=irow+1:min (nrows, irow+reprow-1) rawarr(kk, :) = rawarr(irow, :); endfor irow += reprow; reprow = ''; endif endif endif endwhile ## If required strip leftmost empty columns/topmost empty rows if (lcol > 1) rawarr(:, 1:ncols) = rawarr(:, lcol:rcol); rawarr(:, ncols+1:end) = []; endif if (firstrow > 1) rawarr(1:nrows, :) = rawarr(firstrow:lastrow, :); rawarr(nrows+1:end, :) = []; endif ## Keep track of data rectangle limits ods.limits = [lcol, rcol; firstrow, lastrow]; endfunction io/inst/private/__OCT_spsh_close__.m0000644000076400010400000000325212231031356020741 0ustar PhilipAdministrators## Copyright (C) 2013 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 Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{xls} =} __OCT_spsh_close__ (@var{xls}) ## Internal function! do not call directly; close spreadsheet pointer ## struct xls; for native OCT interface just set it to empty. ## ## @end deftypefn ## Author: Philip Nenhuis ## Created: 2013-09-09 ## Updates: ## 2013-09-23 Added in commented-out stanza for OOXML (.xlsx) ## 2013-10-20 OOXLM support function [xls] = __OCT_spsh_close__ (xls) ## Below order is vital - shortest extension first as you can have file 'a.' ## 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"); 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")) ## Delete temporary file unlink (xls.workbook); endif endfunction io/inst/private/__OCT_spsh_info__.m0000644000076400010400000000246112253140146020572 0ustar PhilipAdministrators## Copyright (C) 2013 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 Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{retval} =} __OCT_spsh_info__ (@var{x} @var{y}) ## ## @seealso{} ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2013-09-10 ## Updates: ## function [ sh_names ] = __OCT_spsh_info__ (ods) sh_names(:, 1) = ods.sheets.sh_names; for ii=1:numel (ods.sheets.sh_names) [ tr, lr, lc, rc ] = getusedrange (ods, ii); if (tr) sh_names(ii, 2) = sprintf ("%s:%s", calccelladdress (tr, lc),... calccelladdress (lr, rc)); else sh_names(ii, 2) = "Empty"; endif endfor endfunction io/inst/private/__OCT_spsh_open__.m0000644000076400010400000001400012261003314020562 0ustar PhilipAdministrators## Copyright (C) 2013 Philip Nienhuis ## Copyright (C) 2013 Markus Bergholz (.xlsx & archive unzip stuff) ## ## 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 Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{retval} =} __OCT_spsh_open__ (@var{x} @var{y}) ## ## @seealso{} ## @end deftypefn ## Author: Philip Nienhuis ## File open stuff by Markus Bergholz ## Created: 2013-09-08 ## Updates: ## 2013-09-09 Wipe temp dir after opening as all content is in memory ## FIXME this needs to be adapted for future OOXML support ## 2013-09-23 Fix copyright messages ## 2013-10-02 More comments ## 2013-10-20 Adapted parts of Markus' .xlxs code ## 2013-11-10 (MB) Compacted sheet names & rid code in xlsx section ## 2013-11-12 Rely on private/__unpack (patched unpack.m from core Octave) ## 2013-11-16 Replace fgetl calls by fread to cope with EOLs ## 2013-12-13 Fix sheet names parsing regexpr ## 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 function [ xls, xlssupport, lastintf] = __OCT_spsh_open__ (xls, xwrite, filename, xlssupport, ftype) ## Open and unzip file to temp location (code by Markus Bergholz) ## create current work folder tmpdir = tmpnam; if (ftype == 5) ## Gnumeric xml files are gzipped system (sprintf ("gzip -d -c -S=gnumeric %s > %s", filename, 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); try unpack (filename, tmpdir, "unzip"); catch printf ("file %s couldn't be unpacked. Is it the proper file format?\n", filename); xls = []; return end_try_catch endif ## Set up file pointer struct if (ftype == 2) ## ======================= XLSX =========================================== ## From xlsxread by Markus Bergholz ## https://github.com/markuman/xlsxread ## Get sheet names. Speeds up other functions a lot if we can do it here fid = fopen (sprintf ('%s/xl/workbook.xml', tmpdir)); if (fid < 0) ## File open error warning ("xls2oct: file %s couldn't be unzipped", filename); xls = []; return else ## Fill xlsx pointer xls.workbook = tmpdir; # subdir containing content.xml xls.xtype = "OCT"; # OCT is fall-back interface xls.app = 'xlsx'; # must NOT be an empty string! xls.filename = filename; # spreadsheet filename xls.changed = 0; # Dummy ## Get content.xml xml = fread (fid, "char=>char").'; ## Close file fclose (fid); ## Get sheet names and indices xls.sheets.sh_names = cell2mat (regexp (xml, 'char").'; ## Close file but keep it around, store file name in struct pointer fclose (fid); ## To speed things up later on, get sheet names and starting indices shtidx = strfind (xml, "") ]; xls.sheets.sh_names = cell (1, numel (shtidx)); sh_names = getxmlnode (xml, "gnm:SheetNameIndex"); jdx = 1; for ii=1:numel (shtidx) [xls.sheets.sh_names(ii), ~, jdx] = getxmlnode (sh_names, "gnm:SheetName", jdx, 1); endfor endif xlssupport += 1; lastintf = "OCT"; endfunction io/inst/private/__OCT_xlsx2oct__.m0000644000076400010400000003377412255041004020376 0ustar PhilipAdministrators## Copyright (C) 2013 Markus Bergholz ## Parts Copyright (C) 2013 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 Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} [ @var{raw}, @var{xls}, @var rstatus} ] = __OCT_xlsx2oct__ (@var{xlsx}, @var{wsh}, @var{range}, @spsh_opts) ## Internal function for reading data from an xlsx worksheet ## ## @seealso{} ## @end deftypefn ## Author: Markus Bergholz ## Created: 2013-10-04 ## Updates: ## 2010-10-20 Transplanted & adapted section for text string worksheet names (PRN) ## '' Much code restyled into Octave coding conventions ## 2013-10-28 More fixes by Markus ## 2013-11-02 (PRN) Added rstatus return arg (needed by xlsread.m) ## 2013-11-04 (PRN) Adapted regexp search strings to include (numeric) formulas and booleans ## '' (PRN) Commented out code for only numeric data until contiguousness is checked ## 2013-11-08 (PRN) Fix reading date/time ## '' Rework code to keep cell array, not a numeric matrix ## '' Add reading formulas ## 2013-11-09 (PRN) Add reading strings & formulas ## '' Rearrange code ## '' Prepare for fast reading (still uncommented) ## '' Implement selected range (still rough ATM but for devs the easiest) ## 2013-11-10 (PRN) Fix typo preventing reading named worksheets instead of indices ## 2013-11-13 (PRN) Pretty text output ## 2013-11-15 (PRN) Catch empty sharedString.xml (means no fixed strings) ## 2013-11-16 (PRN) Replace fgetl calls by fread to cope with EOLs ## 2013-12-12 (PRN) Adapted regular expressions for formulas_as_text to cope with POI ## '' Adapted regular expression for shared strings to cope with empty strings ## 2013-12-14 (PRN) Adapt regexpr for values (include "n" as value type) ## '' Fix regexpr for strings ( \d? => \d+ ) ## '' Add isfinite() check before attempt to process fixed strings ## 2013-12-19 (MB) Replace call to __col_str_to_number with __OCT_cc__ function [ raw, xls, rstatus ] = __OCT_xlsx2oct__ (xls, wsh, crange='', spsh_opts) ## spsh_opts is guaranteed to be filled by caller ## If a worksheet if given, check if it's given by a name (string) or a number if (ischar (wsh)) # fid = fopen (sprintf ('%s/xl/workbook.xml', xls.workbook)); # if (fid < 0) ## File open error # error ("xls2oct: file %s couldn't be opened for reading", filename); # else # xml = fread (fid, "char=>char").';; ## Close file # fclose (fid); ## Search for requested sheet name id = strmatch (wsh, xls.sheets.sh_names); if (isempty (id)) error ("xls2oct: cannot find sheet '%s' in file %s", wsh, xls.filename); else wsh = xls.sheets.rid(id); endif # endif elseif (wsh > numel (xls.sheets.sh_names)) error ("xls2oct: worksheet number %d > number of worksheets in file (%d)", wsh, numel (xls.sheets.sh_names)); elseif (wsh < 1) warning ("xls2oct: illegal worksheet number (%d) - worksheet #1 assumed", wsh); endif ## Prepare to open requested worksheet file in subdir xl/ . Note: Win accepts forward slashes rawsheet = fopen (sprintf ('%s/xl/worksheets/sheet%d.xml', xls.workbook, wsh)); if (rawsheet > 0) ## Get data rawdata = fread (rawsheet, "char=>char").'; fclose (rawsheet); ## Strings try fid = fopen (sprintf ("%s/xl/sharedStrings.xml", xls.workbook)); strings = fread (fid, "char=>char").'; fclose (fid); catch ## No sharedStrings.xml; implies no "fixed" strings (computed strings can still be there) strings = ""; end_try_catch endif rstatus = 0; ## Check if there are only numeric data (then no s="" or r="s") ## FIXME contiguous data rectangles check needed!! so corresponding else clause below ##if (! (numel (strfind (rawdata, ' s="')) > 0 || numel (strfind (rawdata, '')) > 0 || numel (strfind (rawdata, 't="s"')) > 0)) ## if no s="...", nor , nor t="s" is found. good luck - it could be awesome fast (like example.xlsx)! ## FIXME This will break on the reshape below if the data are non-contiguous. Numeric formula results are skipped too raw = {}; ##val = cell2mat (regexp (rawdata, '(.*?)', "tokens")); ##valraw = []; ##FIXME This reshape will break on non-contguous data ##try ## matrows = size (strfind (rawdata, ''), 2) ## raw = reshape (val, [], matrows)'; ## raw = num2cell (raw); ## ## Reshape didn't complain. Big chance we have contiguous data. ## topleft = cell2mat (regexp (rawdata, '.*?', "tokens", "once")); ## [~, ~, ~, trow, lcol] = parse_sp_range (topleft); ## [nrows, ncols] = size (raw); ## xls.limits = [lcol, lcol + ncols - 1; trow, trow + nrows - 1]; ## rstatus = 1; ## return ##catch ## raw = {}; ##end_try_catch ## 'val' are the actual values. 'valraw' are the corresponding(!) cell positions (e.g. B3). if (isempty (raw)) ## General note for tuning: '"([^"]*)"' (w/o single quotes) could be faster than '"(.*?)"' ## (http://stackoverflow.com/questions/2503413/regular-expression-to-stop-at-first-match comment #7) ## Below are loads of nested IFs. They're needed to catch empty previous results, even empty sheets ## 1. Get pure numbers, including booleans, double and boolean formula results, from cells w/o 's=""' tag val = cell2mat (regexp (rawdata, '(?:|/>))?(.*?)', "tokens")); if (! isempty (val)) valraw = cell2mat (regexp (rawdata, '(?:|/>))?.*?', "tokens")); endif ## If val is still empty, try another regexpression (PRN: will this ever work? haven't seen such cells) if (numel (val) == 0) val = cell2mat (regexp (rawdata, '(.*?)', "tokens")); if (! isempty (val)) valraw = cell2mat (regexp (rawdata, '.*?', "tokens")); endif endif ## If 'val' exist, check if there are tagged s="NUMBERS" values if (numel (regexp (rawdata, ' s="', "once")) > 0) ## Time/date values. Exclude formulas (having of tags), ## strings ('t="s"') and error results ('t="e"') valp = cell2mat (regexp (rawdata, '(.*?)', "tokens")); if (! isempty (valp)) valrawp = cell2mat(regexp (rawdata, '.*?', "tokens")); if (! isempty (val)) val = [val valp]; valraw = [valraw valrawp]; else val = valp; valraw = valrawp; clear valp valrawp ; endif endif endif ## Turn strings into numbers val = num2cell (str2double (val)); ## 2. String / text formulas (cached results are in this sheet; fixed strings in ) ## Formulas if (spsh_opts.formulas_as_text) ## Get formulas themselves as text strings. Formulas have no 't="s"' attribute. Keep starting '>' for next line valf1 = cell2mat (regexp (rawdata, '.*?)(?:.*?)?', "tokens")); if (! isempty (valf1)) valf1 = regexprep (valf1, '^>', '='); ## Pretty text output valf1 = strrep (valf1, """, '"'); valf1 = strrep (valf1, "<", "<"); valf1 = strrep (valf1, ">", ">"); valf1 = strrep (valf1, "&", "&"); valrawf1 = cell2mat(regexp (rawdata, '.*?(?:.*?)?', "tokens")); if (isempty (val)) val = valf1; else ## Formulas start with '=' so: val = [val valf1]; valraw = [valraw valrawf1]; endif endif clear valf1 valrawf1 ; else ## Get (cached) formula results. Watch out! as soon as a "t" attibute equals "b" or is missing it is a number ## First the non-numeric formula results valf2 = cell2mat (regexp (rawdata, '(?:|/>))(.*?)', "tokens")); if (! isempty (valf2)) ## Pretty text output valf2 = strrep (valf2, """, '"'); valf2 = strrep (valf2, "<", "<"); valf2 = strrep (valf2, ">", ">"); valf2 = strrep (valf2, "&", "&"); valrawf2 = cell2mat(regexp (rawdata, '(?:|/>)).*?', "tokens")); if (isempty (val)) val = valf2; valraw = valrawf2; else val = [val valf2]; valraw = [valraw valrawf2]; endif endif clear valf2 valrawf2 ; ## Next the numeric formula results. These need additional conversion valf3 = cell2mat (regexp (rawdata, '(?:|/>))(.*?)', "tokens")); if (! isempty (valf3)) valrawf3 = cell2mat(regexp (rawdata, '(?:|/>)).*?', "tokens")); if (isempty (val)) val = num2cell(str2double (valf3)); valraw = valrawf3; else val = [val num2cell(str2double (valf3))]; valraw = [valraw valrawf3]; endif endif clear valf3 valrawf3 ; endif ## 3. Strings if (! isempty (strings)) ## Extract string values. May be much more than present in current sheet ctext = cell2mat (regexp (strings, '(.+?)|(.*)/>)', "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, '(\d+)', "tokens"))) + 1; if (! isempty (vals) && isfinite (vals)) ## Get actual values vals = ctext(vals); ## Pretty text output vals = strrep (vals, """, '"'); vals = strrep (vals, "<", "<"); vals = strrep (vals, ">", ">"); vals = strrep (vals, "&", "&"); ## Cell addresses valraws = cell2mat (regexp (rawdata, '\d+', "tokens")); if (isempty (val)) val = vals; valraw = valraws; else val = [val vals]; valraw = [valraw valraws]; endif endif clear vals valraws ; endif ## If val is empty, sheet is empty if (isempty (val)) xls.limits = []; raw = {}; return endif ## 4. Prepare ## Get the row number (currently supported from 1 to 999999) vi.row = str2double (cell2mat (regexp (valraw, '(\d+|\d+\d+|\d+\d+\d+|\d+\d+\d+\d+|\d+\d+\d+\d+\+d|\d+\d+\d+\d+\d+\d+)?', "match"))')'; ## Get the column character (A to ZZZ) (that are more than 18k supported columns atm) vi.alph = cell2mat (regexp (valraw, '([A-Za-z]+|[A-Za-z]+[A-Za-z]+|[A-Za-z]+[A-Za-z]+[A-Za-z]+)?', "match")); ## Free memory; might be useful while reading huge files clear valraw ; ## If missed formular indices idx.all = cell2mat (regexp (rawdata, ']*> 1; C -> 3, AB -> 28 ... vi.col = double (cell2mat (cellfun (@__OCT_cc__, vi.alph, "UniformOutput", 0))); ## Find data rectangle limits idx.mincol = min ([idx.alph vi.col]); idx.minrow = min ([idx.num vi.row]); idx.maxrow = max ([idx.num vi.row]); idx.maxcol = max ([idx.alph vi.col]); ## Convey limits of data rectangle to xls2oct. Must be done here xls.limits = [idx.mincol, idx.maxcol; idx.minrow, idx.maxrow]; ## column adjustment when first number or formula don't begin in the first column if (1 < idx.mincol) vi.col = vi.col - (idx.mincol - 1); endif ## row adjustment when first number or formular don't begin in the first row if (1 < idx.minrow) vi.row = vi.row - (idx.minrow - 1); endif ## Initialize output cell array raw = cell (idx.maxrow - idx.minrow + 1, idx.maxcol - idx.mincol + 1); ## get logical indices for 'val' from 'valraw' positions in NaN matrix vi.idx = sub2ind (size (raw), (vi.row), (vi.col)); ## set values to the corresponding indizes in final cell matrix raw(vi.idx) = val; endif ## FIXME maybe reading parts of the data can be done faster above by better regexps if (! isempty (crange)) ## We'll do it the easy way: just read all data, then return only the requested part [~, nr, nc, tr, lc] = parse_sp_range (crange); xls.limits = [max(idx.mincol, lc), min(idx.maxcol, lc+nc-1); max(idx.minrow, tr), min(idx.maxrow, tr+nr-1)]; ## Correct spreadsheet locations for lower right shift or raw rc = idx.minrow - 1; cc = idx.mincol - 1; raw = raw(xls.limits(2, 1)-rc : xls.limits(2, 2)-rc, xls.limits(1, 1)-cc : xls.limits(1, 2)-cc); endif if (! isempty (val)) rstatus = 1; endif endfunction io/inst/private/__ods_get_sheet_dims__.m0000644000076400010400000001321712240763610021731 0ustar PhilipAdministrators## Copyright (C) 2013 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 Octave; see the file COPYING. If not, see ## . ## __ods_get_sheet_dims__ ## Internal function - get dimensions of occupied cell range in an ODS sheet. ## Author: Philip Nienhuis ## Created: 2013-09-29 (split off from __JOD_getusedrange__.m) ## Updates: ## 2013-11-13 Fix table-row counter bug function [trow, brow, lcol, rcol ] = __ods_get_sheet_dims__ (sh) ## 1. Get table-row pointers id_trow = strfind (sh, "") - 1; id_trow = [id_trow id]; trow = rcol = 0; lcol = 1024; brow = 0; if (~isempty (id)) ## 2. Loop over all table-rows rowrepcnt = 0; for irow = 1:length (id_trow)-1 ## Isolate single table-row tablerow = sh(id_trow(irow):id_trow(irow+1)-1); ## Search table-cells. table-c covers both table-cell & table-covered-cell id_tcell = strfind (tablerow, ". ## __OTK_getusedrange__ - get used range from ODS spreadsheet using ODF Toolkit ## Author: Philip Nienhuis ## Created: 2010-03-18 (First usable version) ## Updates: ## 2010-08-24 Support for odfdom (ODF Toolkit) 0.8.6 checked; we still need ## => TableTable API because 0.8.6 is fooled by empty lowermost ## filler rows comprising number-rows-repeated table attribute :-( ## '' Indentation changed from tab to double space ## 2010-11-13 Catched jOpenDocument bug (1.2bx) where string cells have no office:value-type ## attrib set (by JOD). Somehow OTK is more robust as it catches these cells; ## Currently this fix is just commented. ## 2011-06-06 Fixed wrong if clause for finding last filler cells (L.160 & L.176) ## 2011-09-12 Support for odfdom-0.8.7 added (API change for XPATH) ## 2012-06-08 Support for odsfdom-0.8.8-incubator ## 2012-10-12 Renamed & moved into ./private ## 2012-10-24 Style fixes ## 2013-12-01 Style fixes, copyright string updates ## 2013-12-27 Style fixes function [ trow, lrow, lcol, rcol ] = __OTK_getusedrange__ (ods, ii) odfcont = ods.workbook; ## Local copy just in case if (isfield (ods, "odfvsn")) if (strcmp (ods.odfvsn, "0.8.6") || strcmp (ods.odfvsn, "0.7.5")) xpath = ods.app.getXPath; else ## API changed in odfdom-0.8.7 xpath = ods.workbook.getXPath; endif else error ("ODS file ptr struct for OTK interface seems broken."); endif ## Create an instance of type NODESET for use in subsequent statement NODESET = java_get ("javax.xml.xpath.XPathConstants", "NODESET"); ## Get table-rows in sheet no. wsh. Sheet count = 1-based (!) str = sprintf ("//table:table[%d]/table:table-row", ii); sh = xpath.evaluate (str, odfcont, NODESET); nr_of_trows = sh.getLength(); jj = 0; ## Table row counter trow = 0; drows = 0; ## Top data row, actual data row range nrows = 0; reprows = 0; ## Scratch counter rcol = 0; lcol = 1024; ## Rightmost and leftmost data column while jj < nr_of_trows row = sh.item(jj); ## Check for data rows rw_char = char (row) (1:min(500, length (char (row)))); if (findstr ("office:value-type", rw_char) || findstr (" attribute when writing strings ##if (isempty (findstr ("office:value-type", cl_char)) ... ## || isempty (findstr (". ## __OTK_oct2ods__ ## write data array to an ODS spreadsheet using Java & ODFtoolkit 0.7.5 ## Note: __OTK_oct2spsh__ uses more recent odfdom that operates at higher level ## I'm truly sorry that oct2jotk2ods is so ridiculously complex, ## and therefore so slow; but there's a good reason for that: ## Writing to ODS is already fairly complicated when just making a ## new sheet ("table"); but it really becomes a headache when ## writing to an existing sheet. In that case one should beware of ## table-number-columns-repeated, table-number-rows-repeated, ## covered (merged) cells, incomplete tables and rows, etc. ## ODF toolkit v. 0.7.5 does nothing to hide this from the user; ## you may sort it out all by yourself. ## Author: Philip Nienhuis ## Created: 2010-01-07 ## Updates: ## 2010-01-14 (finally seems to work OK) ## 2010-03-08 Some comment lines adapted ## 2010-03-25 Try-catch added f. unpatched-for-booleans java-1.2.6 / 1.2.7 package ## 2010-04-11 Changed all references to "cell" to "scell" to avoid reserved keyword ## '' Small bugfix for cases with empty left columns (wrong cell reference) ## 2010-04-13 Fixed bug with stray cell copies beyond added data rectangle ## 2010-07-29 Added formula input support (based on xls patch by Benjamin Lindner) ## 2010-08-01 Added try-catch around formula input ## '' Changed range arg to also allow just topleft cell ## 2010-08-03 Moved range checks and type array parsing to separate functions ## 2010-08-13 Fixed empty Sheet1 in case of new spreadsheets, fix input text sheet name ## 2010-10-27 Improved file change tracking tru ods.changed ## 2010-11-12 Improved file change tracking tru ods.changed ## 2012-10-12 Renamed & moved into ./private ## 2012-10-24 Style fixes ## 2013-01-20 Adapted to ML-compatible Java calls ## 2013-12-01 Style fixes, copyright string updates function [ ods, rstatus ] = __OTK_oct2ods__ (c_arr, ods, wsh, crange, spsh_opts) persistent ctype; if (isempty (ctype)) ## Number, Boolean, String, Formula, Empty, Date, Time (last 2 are ignored) ctype = [1, 2, 3, 4, 5, 6, 7]; endif rstatus = 0; f_errs = 0; ## Get some basic spreadsheet data from the pointer using ODFtoolkit odfcont = ods.workbook; xpath = ods.app.getXPath (); offsprdsh = ods.app.getContentRoot(); autostyles = odfcont.getOrCreateAutomaticStyles(); officestyles = ods.app.getOrCreateDocumentStyles(); ## Create an instance of type NODESET for use in subsequent statements NODESET = java_get ("javax.xml.xpath.XPathConstants", "NODESET"); ## Parse sheets ("tables") from ODS file sheets = xpath.evaluate ("//table:table", odfcont, NODESET); nr_of_sheets = sheets.getLength (); newsh = 0; ## Assume existing sheet if (isempty (wsh)) wsh = 1; endif if (! isnumeric (wsh)) ## Sheet name specified ## Search in sheet names, match sheet name to sheet number. ## Beware, 0-based index, 1-based count! ii = 0; while (++ii <= nr_of_sheets && ischar (wsh)) ## Look in first part of the sheet nodeset sh_name = sheets.item(ii-1).getTableNameAttribute (); if (strcmp (sh_name, wsh)) ## Convert local copy of wsh into a number (pointer) wsh = ii - 1; endif endwhile if (ischar (wsh) && nr_of_sheets < 256) newsh = 1; endif else ## Sheet index specified if ((ods.changed > 2) || (wsh > nr_of_sheets && wsh < 256)) ## Max nr of sheets = 256 ## Create a new sheet newsh = 1; elseif (wsh <=nr_of_sheets && wsh > 0) ## Existing sheet. Count = 1-based, index = 0-based --wsh; sh = sheets.item(wsh); printf ("Writing to sheet %s\n", sh.getTableNameAttribute()); else error ("oct2ods: illegal sheet number."); endif endif ## Check size of data array & range / capacity of worksheet & prepare vars [nr, nc] = size (c_arr); [topleft, nrows, ncols, trow, lcol] = ... spsh_chkrange (crange, nr, nc, ods.xtype, ods.filename); --trow; --lcol; ## Zero-based row ## & col ## if (nrows < nr || ncols < nc) warning ("Array truncated to fit in range"); c_arr = c_arr(1:nrows, 1:ncols); endif ## 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 ")") fptr = cellfun (@(x) ischar (x) && strncmp (x, "=", 1) ... && strncmp (x(end:end), ")", 1), c_arr); typearr(fptr) = ctype(4); ## FORMULA endif ## Prepare worksheet for writing. If needed create new sheet if (newsh) if (ods.changed > 2) ## New spreadsheet. Prepare to use the default 1x1 first sheet. sh = sheets.item(0); else ## Other sheets exist, create a new sheet. First the basics sh = javaObject ("org.odftoolkit.odfdom.doc.table.OdfTable", odfcont); ## Append sheet to spreadsheet ( contentRoot) offsprdsh.appendChild (sh); ## Rebuild sheets nodes sheets = xpath.evaluate ("//table:table", odfcont, NODESET); endif ## Sheet name if (isnumeric (wsh)) ## Give sheet a name str = sprintf ("Sheet%d", wsh); sh.setTableNameAttribute (str); else ## Assign name to sheet and change wsh into numeric pointer sh.setTableNameAttribute (wsh); wsh = sheets.getLength () - 1; endif ## Fixup wsh pointer in case of new spreadsheet if (ods.changed > 2) wsh = 0; endif ## Add table-column entry for style etc col = sh.addTableColumn (); col.setTableDefaultCellStyleNameAttribute ("Default"); col.setTableNumberColumnsRepeatedAttribute (lcol + ncols + 1); col.setTableStyleNameAttribute ("co1"); ## Build up the complete row & cell structure to cover the data array. ## This will speed up processing later ## 1. Build empty table row template row = javaObject ("org.odftoolkit.odfdom.doc.table.OdfTableRow", odfcont); ## Create an empty tablecell & append it to the row scell = javaObject ("org.odftoolkit.odfdom.doc.table.OdfTableCell", odfcont); scell = row.appendCell (scell); scell.setTableNumberColumnsRepeatedAttribute (1024); ## 2. If needed add empty filler row above the data rows & if needed add repeat count if (trow > 0) sh.appendRow (row); if (trow > 1) row.setTableNumberRowsRepeatedAttribute (trow); endif endif ## 3. Add data rows; first one serves as a template drow = javaObject ("org.odftoolkit.odfdom.doc.table.OdfTableRow", odfcont); if (lcol > 0) scell = javaObject ("org.odftoolkit.odfdom.doc.table.OdfTableCell", odfcont); drow.appendCell (scell); if (lcol > 1) scell.setTableNumberColumnsRepeatedAttribute (lcol); endif endif ## 4. Add data cell placeholders scell = javaObject ("org.odftoolkit.odfdom.doc.table.OdfTableCell", odfcont); drow.appendCell (scell); for jj=2:ncols dcell = scell.cloneNode (1); ## Deep copy drow.appendCell (dcell); endfor ## 5. Last cell is remaining column counter rest = max (1024 - lcol - ncols); if (rest) dcell = scell.cloneNode (1); ## Deep copy drow.appendCell (dcell); if (rest > 1) dcell.setTableNumberColumnsRepeatedAttribute (rest); endif endif ## Only now add drow as otherwise for each cell an empty table-column is ## inserted above the rows (odftoolkit bug?) sh.appendRow (drow); if (ods.changed > 2) ## In case of a completely new spreadsheet, delete the first initial 1-cell row ## But check if it *is* a row... try sh.removeChild (drow.getPreviousRow ()); catch ## Nothing. Apparently there was only the just appended row. end_try_catch endif ## 6. Row template ready. Copy row template down to cover future array for ii=2:nrows nrow = drow.cloneNode (1); ## Deep copy sh.appendRow (nrow); endfor ods.changed = min (ods.changed, 2); ## Keep 2 for new spshsht, 1 for existing + changed else ## Existing sheet. We must be prepared for all situations, incomplete rows, ## number-rows/columns-repeated, merged (spanning) cells, you name it. ## First explore row buildup of existing sheet using an XPath sh = sheets.item(wsh); ## 0 - based str = sprintf ("//table:table[%d]/table:table-row", wsh + 1); ## 1 - based trows = xpath.evaluate (str, odfcont, NODESET); nr_of_trows = trows.getLength(); ## Nr. of existing table-rows, not data rows! ## For the first rows we do some preprocessing here. Similar stuff for cells ## i.e. table-cells (columns) is done in the loops below. ## Make sure the upper data array row doesn't end up in a nr-rows-repeated row ## Provisionally! set start table-row in case "while" & "if" (split) are skipped drow = trows.item(0); rowcnt = 0; trowcnt = 0; ## Spreadsheet/ table-rows, resp; while (rowcnt < trow && trowcnt < nr_of_trows) ## Count rows & table-rows UNTIL we reach trow ++trowcnt; ## Nr of table-rows row = drow; drow = row.getNextSibling (); repcnt = row.getTableNumberRowsRepeatedAttribute(); rowcnt = rowcnt + repcnt; ## Nr of spreadsheet rows endwhile rsplit = rowcnt - trow; if (rsplit > 0) ## Apparently a nr-rows-repeated top table-row must be split, as the ## first data row seems to be projected in it (1st while condition above!) row.removeAttribute ("table:number-rows-repeated"); row.getCellAt (0).removeAttribute ("table:number-columns-repeated"); nrow = row.cloneNode (1); drow = nrow; ## Future upper data array row if (repcnt > 1) row.setTableNumberRowsRepeatedAttribute (repcnt - rsplit); else row.removeAttribute ("table:number-rows-repeated"); endif rrow = row.getNextSibling (); sh.insertBefore (nrow, rrow); for jj=2:rsplit nrow = nrow.cloneNode (1); sh.insertBefore (nrow, rrow); endfor elseif (rsplit < 0) ## New data rows to be added below existing data & table(!) rows, i.e. ## beyond lower end of the current sheet. Add filler row and 1st data row row = javaObject ("org.odftoolkit.odfdom.doc.table.OdfTableRow", odfcont); drow = row.cloneNode (1); ## First data row row.setTableNumberRowsRepeatedAttribute (-rsplit); ## Filler row scell = javaObject ("org.odftoolkit.odfdom.doc.table.OdfTableCell", odfcont); dcell = scell.cloneNode (1); scell.setTableNumberColumnsRepeatedAttribute (COL_CAP); ## Filler cell row.appendCell (scell); sh.appendRow (row); drow.appendCell (dcell); sh.appendRow (drow); endif endif ## For each row, for each cell, add the data. Expand row/column-repeated nodes row = drow; ## Start row; pointer still exists from above stanzas for ii=1:nrows if (! newsh) ## Only for existing sheets the next checks should be made ## While processing next data rows, fix table-rows if needed if (isempty (row) || (row.getLength () < 1)) ## Append an empty row with just one empty cell row = javaObject ("org.odftoolkit.odfdom.doc.table.OdfTableRow", odfcont); scell = javaObject ("org.odftoolkit.odfdom.doc.table.OdfTableCell", odfcont); scell.setTableNumberColumnsRepeatedAttribute (lcol + 1); row.appendCell (scell); sh.appendRow (row); else ## If needed expand nr-rows-repeated repcnt = row.getTableNumberRowsRepeatedAttribute (); if (repcnt > 1) row.removeAttribute ("table:number-rows-repeated"); ## Insert new table-rows above row until our new data space is complete. ## Keep handle of upper new table-row as that's where data are added 1st drow = row.cloneNode (1); sh.insertBefore (drow, row); for kk=1:min (repcnt, nrows-ii) nrow = row.cloneNode (1); sh.insertBefore (nrow, row); endfor if (repcnt > nrows-ii+1) row.setTableNumberRowsRepeatedAttribute (repcnt - nrows +ii - 1); endif row = drow; endif endif ## Check if leftmost cell ends up in nr-cols-repeated cell colcnt = 0; tcellcnt = 0; rcellcnt = row.getLength(); dcell = row.getCellAt (0); while (colcnt < lcol && tcellcnt < rcellcnt) ## Count columns UNTIL we hit lcol ++tcellcnt; ## Nr of table-cells counted scell = dcell; dcell = scell.getNextSibling (); repcnt = scell.getTableNumberColumnsRepeatedAttribute (); colcnt = colcnt + repcnt; ## Nr of spreadsheet cell counted endwhile csplit = colcnt - lcol; if (csplit > 0) ## Apparently a nr-columns-repeated cell must be split scell.removeAttribute ("table:number-columns-repeated"); ncell = scell.cloneNode (1); if (repcnt > 1) scell.setTableNumberColumnsRepeatedAttribute (repcnt - csplit); else scell.removeAttribute ("table:number-columns-repeated"); endif rcell = scell.getNextSibling (); row.insertBefore (ncell, rcell); for jj=2:csplit ncell = ncell.cloneNode (1); row.insertBefore (ncell, rcell); endfor elseif (csplit < 0) ## New cells to be added beyond current last cell & table-cell in row dcell = javaObject ("org.odftoolkit.odfdom.doc.table.OdfTableCell", odfcont); scell = dcell.cloneNode (1); dcell.setTableNumberColumnsRepeatedAttribute (-csplit); row.appendCell (dcell); row.appendCell (scell); endif endif ## Write a row of data from data array, column by column for jj=1:ncols scell = row.getCellAt (lcol + jj - 1); if (! newsh) if (isempty (scell)) ## Apparently end of row encountered. Add cell scell = javaObject ("org.odftoolkit.odfdom.doc.table.OdfTableCell", odfcont); scell = row.appendCell (scell); else ## If needed expand nr-cols-repeated repcnt = scell.getTableNumberColumnsRepeatedAttribute (); if (repcnt > 1) scell.removeAttribute ("table:number-columns-repeated"); for kk=2:repcnt ncell = scell.cloneNode (1); row.insertBefore (ncell, scell.getNextSibling ()); endfor endif endif ## Clear text contents while (scell.hasChildNodes ()) tmp = scell.getFirstChild (); scell.removeChild (tmp); endwhile scell.removeAttribute ("table:formula"); endif ## Empty cell count stuff done. At last we can add the data switch (typearr (ii, jj)) case 1 ## float scell.setOfficeValueTypeAttribute ("float"); scell.setOfficeValueAttribute (c_arr{ii, jj}); case 2 ## boolean ## Beware, for unpatched-for-booleans java-1.2.7- we must resort to floats try ## First try the preferred java-boolean way scell.setOfficeValueTypeAttribute ("boolean"); scell.removeAttribute ("office:value"); if (c_arr{ii, jj}) scell.setOfficeBooleanValueAttribute (1); else scell.setOfficeBooleanValueAttribute (0); endif catch ## Unpatched java package. Fall back to transferring a float scell.setOfficeValueTypeAttribute ("float"); if (c_arr{ii, jj}) scell.setOfficeValueAttribute (1); else scell.setOfficeValueAttribute (0); endif end_try_catch case 3 ## string scell.setOfficeValueTypeAttribute ("string"); pe = javaObject ("org.odftoolkit.odfdom.doc.text.OdfTextParagraph",... odfcont,"", c_arr{ii, jj}); scell.appendChild (pe); case 4 ## Formula. ## As we don't know the result type, simply remove previous type info. ## Once OOo Calc reads it, it'll add the missing attributes scell.removeAttribute ("office:value"); scell.removeAttribute ("office:value-type"); ## Try-catch not strictly needed, there's no formula validator yet try scell.setTableFormulaAttribute (c_arr{ii, jj}); scell.setOfficeValueTypeAttribute ("string"); pe = javaObject ("org.odftoolkit.odfdom.doc.text.OdfTextParagraph",... odfcont,"", "##Recalc Formula##"); scell.appendChild (pe); catch ++f_errs; scell.setOfficeValueTypeAttribute ("string"); pe = javaObject ("org.odftoolkit.odfdom.doc.text.OdfTextParagraph",... odfcont,"", c_arr{ii, jj}); scell.appendChild (pe); end_try_catch case {0 5} ## Empty. Clear value attributes if (! newsh) scell.removeAttribute ("office:value-type"); scell.removeAttribute ("office:value"); endif case 6 ## Date (implemented but Octave has no "date" data type - yet?) scell.setOfficeValueTypeAttribute ("date"); [hh mo dd hh mi ss] = datevec (c_arr{ii,jj}); str = sprintf ("%4d-%2d-%2dT%2d:%2d:%2d", yy, mo, dd, hh, mi, ss); scell.setOfficeDateValueAttribute (str); case 7 ## Time (implemented but Octave has no "time" data type) scell.setOfficeValueTypeAttribute ("time"); [hh mo dd hh mi ss] = datevec (c_arr{ii,jj}); str = sprintf ("PT%2d:%2d:%2d", hh, mi, ss); scell.setOfficeTimeValuettribute (str); otherwise ## Nothing endswitch scell = scell.getNextSibling (); endfor row = row.getNextSibling (); endfor if (f_errs) printf ("%d formula errors encountered - please check input array\n", f_errs); endif ods.changed = max (min (ods.changed, 2), changed); ## Preserve 2 (new file), 1 (existing) rstatus = 1; endfunction io/inst/private/__OTK_oct2spsh__.m0000644000076400010400000001667512246725250020402 0ustar PhilipAdministrators## Copyright (C) 2010,2011,2012,2013 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 . ## __OTK_oct2spsh__ - read ODS spreadsheet data using Java & odftoolkit v 0.8.6+. ## You need proper java-for-octave & odfdom.jar 0.8.6+ & xercesImpl.jar 2.9.1 ## in your javaclasspath. ## ## Author: Philip Nenhuis ## Created: 2010-03-16, after oct2jotk2ods() ## Updates: ## 2010-03-17 Rebuild for odfdom-0.8 ## 2010-03-19 Showstopper bug in odfdom-0.8 - getCellByPosition(
    ) ## crashes on rows > #10 !!! Rest seems to work OK, however ## 2010-03-22 First somewhat usable version for odfdom 0.8 ## 2010-03-29 Gave up. Writing a new empty sheet works, appending ## data to an existing one can crash virtually anywhere. ## The wait is for odfdom-0.8.+ .... ## 2010-06-05 odfdom 0.8.5 is there, next try.... ## 2010-06-## odfdom 0.8.5 dropped, too buggy ## 2010-08-22 odfdom 0.8.6 is there... seems to work with just one bug, easily worked around ## 2010-10-27 Improved file change tracking tru ods.changed ## 2010-11-12 Improved file change tracking tru ods.changed ## 2010-12-08 Bugfixes (obj -> arg L.715; removed stray arg in call to spsh_prstype L.719) ## 2011-03-23 First try of odfdom 0.8.7 ## 2012-06-08 Support for odfdom-incubator-0.8.8 ## 2012-10-12 Renamed & moved into ./private ## 2013-12-01 Style fixes, copyright string updates function [ ods, rstatus ] = __OTK_oct2spsh__ (c_arr, ods, wsh, crange, spsh_opts) persistent ctype; if (isempty (ctype)) ## Number, Boolean, String, Formula, Empty; Date, Time - last two aren't used ctype = [1, 2, 3, 4, 5, 6, 7]; endif rstatus = 0; changed = 0; newsh = 0; ## Get contents and table stuff from the workbook odfcont = ods.workbook; ## Use a local copy just to be sure. octave ## makes physical copies only when needed (?) odfroot = odfcont.getRootElement (); offsprdsh = ods.app.getContentRoot(); if (strcmp (ods.odfvsn, "0.8.7") || strfind (ods.odfvsn, "0.8.8")) spsh = odfcont.getDocument (); else spsh = odfcont.getOdfDocument (); endif ## Get some basic spreadsheet data from the pointer using ODFtoolkit autostyles = odfcont.getOrCreateAutomaticStyles(); officestyles = ods.app.getOrCreateDocumentStyles(); ## Parse sheets ("tables") from ODS file sheets = ods.app.getTableList(); nr_of_sheets = sheets.size (); ## Check user input & find sheet pointer if (! isnumeric (wsh)) try sh = ods.app.getTableByName (wsh); ## We do need a sheet index number... ii = 0; while (ischar (wsh) && ii < nr_of_sheets) sh_nm = sh.getTableName (); if (strcmp (sh_nm, wsh)) wsh = ii + 1; else ++ii; endif endwhile catch newsh = 1; end_try_catch if (isempty (sh)) newsh = 1; endif elseif (wsh < 1) ## Negative sheet number: error (sprintf ("Illegal worksheet nr. %d\n", wsh)); elseif (wsh > nr_of_sheets) newsh = 1; else sh = sheets.get (wsh - 1); endif ## Check size of data array & range / capacity of worksheet & prepare vars [nr, nc] = size (c_arr); [topleft, nrows, ncols, trow, lcol] = ... spsh_chkrange (crange, nr, nc, ods.xtype, ods.filename); --trow; --lcol; ## Zero-based row ## & col ## if (nrows < nr || ncols < nc) warning ("Array truncated to fit in range"); c_arr = c_arr(1:nrows, 1:ncols); endif ## Parse data array, setup typarr and throw out NaNs to speed up writing; typearr = spsh_prstype (c_arr, nrows, ncols, ctype, spsh_opts); if (! spsh_opts.formulas_as_text) ## Find formulas (designated by a string starting with "=" and ending in ")") fptr = cellfun (@(x) ischar (x) && strncmp (x, "=", 1) ... && strncmp (x(end:end), ")", 1), c_arr); typearr(fptr) = ctype(4); ## FORMULA endif ## Prepare spreadsheet for writing (size, etc.). If needed create new sheet if (newsh) if (ods.changed > 2) ## New spreadsheet, use default first sheet sh = sheets.get (0); else ## Create a new sheet using DOM API. This part works OK. sh = sheets.get (nr_of_sheets - 1).newTable (spsh, nrows, ncols); endif changed = 1; if (isnumeric (wsh)) ## Give sheet a name str = sprintf ("Sheet%d", wsh); sh.setTableName (str); wsh = str; else ## Assign name to sheet and change wsh into numeric pointer sh.setTableName (wsh); endif ## printf ("Sheet %s added to spreadsheet.\n", wsh); else ## Add "physical" rows & columns. Spreadsheet max. capacity checks have been done above ## Add spreadsheet data columns if needed. Compute nr of extra columns & rows. curr_ncols = sh.getColumnCount (); ii = max (0, lcol + ncols - curr_ncols); if (ii == 1) nwcols = sh.appendColumn (); else nwcols = sh.appendColumns (ii); endif ## Add spreadsheet rows if needed curr_nrows = sh.getRowCount (); ii = max (0, trow + nrows - curr_nrows); if (ii == 1) nwrows = sh.appendRow (); else nwrows = sh.appendRows (ii); endif endif ## Transfer array data to sheet for ii=1:nrows for jj=1:ncols ocell = sh.getCellByPosition (jj+lcol-1, ii+trow-1); if (! isempty (ocell )) ## Might be spanned (merged), hidden, .... ## Number, String, Boolean, Date, Time try switch typearr (ii, jj) case {1, 6, 7} ## Numeric, Date, Time ocell.setDoubleValue (c_arr{ii, jj}); case 2 ## Logical / Boolean ## ocell.setBooleanValue (c_arr{ii, jj}); ## Doesn't work, bug in odfdom 0.8.6 ## Bug workaround: 1. Remove all cell contents ocell.removeContent (); ## 2. Switch to TableTableElement API tocell = ocell.getOdfElement (); tocell.setAttributeNS ("office", "office:value-type", "boolean"); ## 3. Add boolean-value attribute. ## This is only accepted in TTE API with a NS tag (actual bug, IMO) if (c_arr {ii,jj}) tocell.setAttributeNS ("office", "office:boolean-value", "true"); else tocell.setAttributeNS ("office", "office:boolean-value", "false"); endif case 3 ## String ocell.setStringValue (c_arr{ii, jj}); case 4 ## Formula ocell.setFormula (c_arr{ii, jj}); otherwise ## 5, empty and catch-all ## The above is all octave has to offer & java can accept... endswitch changed = 1; catch printf ("\n"); end_try_catch endif endfor endfor if (changed) ods.changed = max (min (ods.changed, 2), changed); ## Preserve 2 (new file), 1 (existing) rstatus = 1; endif endfunction io/inst/private/__OTK_ods2oct__.m0000644000076400010400000002145712246723016020202 0ustar PhilipAdministrators## Copyright (C) 2009,2010,2011,2012,2013 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 . ## __OTK_ods2oct__ - read ODS spreadsheet data using Java & odftoolkit 0.7.5 ## You need proper java-for-octave & odfdom.jar + xercesImpl.jar 2.9.1 ## in your javaclasspath. ## Author: Philip Nenhuis ## Created: 2009-12-24 ## Updates: ## 2010-01-08 First working version ## 2010-03-18 Fixed many bugs with wrong row references in case of empty upper rows ## "" Fixed reference to upper row in case of nr-rows-repeated top tablerow ## "" Tamed down memory usage for rawarr when desired data range is given ## "" Added call to getusedrange() for cases when no range was specified ## 2010-03-19 More code cleanup & fixes for bugs introduced 18/3/2010 8-() ## 2010-08-03 Added preliminary support for reading back formulas as text strings ## 2010-10-27 Moved cropping rawarr from empty outer rows & columns to caller ## 2011-09-18 Remove rstatus var (now set in caller) ## 2012-10-12 Renamed & moved 2 ./private; soon te be dropped as OTK 0.7.5 is too old ## 2012-10-24 Style fixes ## 2013-12-01 Style fixes, str2num->str2double, copyright string updates function [ rawarr, ods ] = __OTK_ods2oct__ (ods, wsh, crange, spsh_opts) ## Parts after user gfterry in ## http://www.oooforum.org/forum/viewtopic.phtml?t=69060 ## Get contents and table stuff from the workbook odfcont = ods.workbook; ## Use a local copy just to be sure. octave ## makes physical copies only when needed (?) xpath = ods.app.getXPath; ## AFAICS ODS spreadsheets have the following hierarchy (after Xpath processing): ## - table nodes, the actual worksheets; ## - row nodes, the rows in a worksheet; ## - cell nodes, the cells in a row; ## Styles (formatting) are defined in a section "settings" outside the ## contents proper but are referenced in the nodes. ## Create an instance of type NODESET for use in subsequent statement NODESET = java_get ("javax.xml.xpath.XPathConstants", "NODESET"); ## Parse sheets ("tables") from ODS file sheets = xpath.evaluate ("//table:table", odfcont, NODESET); nr_of_sheets = sheets.getLength (); ## Check user input & find sheet pointer (1-based), using ugly hacks if (! isnumeric (wsh)) ## Search in sheet names, match sheet name to sheet number ii = 0; while (++ii <= nr_of_sheets && ischar (wsh)) ## Look in first part of the sheet nodeset sh_name = sheets.item(ii-1).getTableNameAttribute (); if (strcmp (sh_name, wsh)) ## Convert local copy of wsh into a number (pointer) wsh = ii; endif endwhile if (ischar (wsh)) error (sprintf ("No worksheet '%s' found in file %s", wsh, ods.filename)); endif elseif (wsh > nr_of_sheets || wsh < 1) ## We already have a numeric sheet pointer. If it's not in range: error (sprintf ("Worksheet no. %d out of range (1 - %d)", wsh, nr_of_sheets)); endif ## Get table-rows in sheet no. wsh. Sheet count = 1-based (!) str = sprintf ("//table:table[%d]/table:table-row", wsh); sh = xpath.evaluate (str, odfcont, NODESET); nr_of_rows = sh.getLength (); ## Either parse (given cell range) or prepare (unknown range) help variables if (isempty (crange)) [ trow, brow, lcol, rcol ] = getusedrange (ods, wsh); nrows = brow - trow + 1; ## Number of rows to be read ncols = rcol - lcol + 1; ## Number of columns to be read else [dummy, nrows, ncols, trow, lcol] = parse_sp_range (crange); brow = min (trow + nrows - 1, nr_of_rows); ## Check ODS column limits if (lcol > 1024 || trow > 65536) error ("ods2oct: invalid range; max 1024 columns & 65536 rows."); endif ## Truncate range silently if needed rcol = min (lcol + ncols - 1, 1024); ncols = min (ncols, 1024 - lcol + 1); nrows = min (nrows, 65536 - trow + 1); endif ## Create storage for data content rawarr = cell (nrows, ncols); ## Prepare reading sheet row by row rightmcol = 0; ## Used to find actual rightmost column ii = trow - 1; ## Spreadsheet row counter rowcnt = 0; ## Find uppermost requested *tablerow*. It may be influenced by nr-rows-repeated if (ii >= 1) tfillrows = 0; while (tfillrows < ii) row = sh.item(tfillrows); extrarows = row.getTableNumberRowsRepeatedAttribute (); tfillrows = tfillrows + extrarows; ++rowcnt; endwhile ## Desired top row may be in a nr-rows-repeated tablerow.... if (tfillrows > ii) ii = tfillrows; endif endif ## Read from worksheet row by row. Row numbers are 0-based while (ii < brow) row = sh.item(rowcnt++); nr_of_cells = min (row.getLength (), rcol); rightmcol = max (rightmcol, nr_of_cells); ## Keep track of max row length ## Read column (cell, "table-cell" in ODS speak) by column jj = lcol; while (jj <= rcol) tcell = row.getCellAt(jj-1); form = 0; if (! isempty (tcell)) ## If empty it's possibly in columns-repeated/spanned if (spsh_opts.formulas_as_text) ## Get spreadsheet formula rather than value ## Check for formula attribute tmp = tcell.getTableFormulaAttribute (); if isempty (tmp) form = 0; else if (strcmp (tolower (tmp(1:3)), "of:")) tmp (1:end-3) = tmp(4:end); endif rawarr(ii-trow+2, jj-lcol+1) = tmp; form = 1; endif endif if (! (form || index (char(tcell), "text:p>Err:") ... || index (char(tcell), "text:p>##DIV"))) ## Get data from cell ctype = tcell.getOfficeValueTypeAttribute (); cvalue = tcell.getOfficeValueAttribute (); switch deblank (ctype) case {"float", "currency", "percentage"} rawarr(ii-trow+2, jj-lcol+1) = cvalue; case "date" cvalue = tcell.getOfficeDateValueAttribute (); ## Dates are returned as octave datenums, i.e. 0-0-0000 based yr = str2double (cvalue(1:4)); mo = str2double (cvalue(6:7)); dy = str2double (cvalue(9:10)); if (index (cvalue, "T")) hh = str2double (cvalue(12:13)); mm = str2double (cvalue(15:16)); ss = str2double (cvalue(18:19)); rawarr(ii-trow+2, jj-lcol+1) = datenum (yr, mo, dy, hh, mm, ss); else rawarr(ii-trow+2, jj-lcol+1) = datenum (yr, mo, dy); endif case "time" cvalue = tcell.getOfficeTimeValueAttribute (); if (index (cvalue, "PT")) hh = str2double (cvalue(3:4)); mm = str2double (cvalue(6:7)); ss = str2double (cvalue(9:10)); rawarr(ii-trow+2, jj-lcol+1) = datenum (0, 0, 0, hh, mm, ss); endif case "boolean" cvalue = tcell.getOfficeBooleanValueAttribute (); rawarr(ii-trow+2, jj-lcol+1) = cvalue; case "string" cvalue = tcell.getOfficeStringValueAttribute (); if (isempty (cvalue)) ## Happens with e.g., hyperlinks tmp = char (tcell); ## Hack string value from between tags ist = findstr (tmp, " 0 && (ii + extrarows) < 65535) ## Expand rawarr cf. table-row nr_of_rows = nr_of_rows + extrarows; ii = ii + extrarows; endif ++ii; endwhile ## Keep track of data rectangle limits ods.limits = [lcol, rcol; trow, brow]; endfunction io/inst/private/__OTK_spsh2oct__.m0000644000076400010400000001546712246723520020376 0ustar PhilipAdministrators## Copyright (C) 2010,2011,2012,2013 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 . ## __OTK_spsh2oct__: internal function for reading odf files using odfdom-0.8.6+ ## Author: Philip Nienhuis ## Created: 2010-08-24. First workable version Aug 27, 2010 ## Updates: ## 2010-10-27 Moved cropping rawarr from empty outer rows & columns to caller ## 2010-11-13 Added workaround for reading text cells in files made by jOpenDocument 1.2bx ## 2011-09-18 Comment out workaround for jOpenDocument bug (no OfficeValueAttr set) ## because this casts all numeric cells to string type for properly written ODS1.2 ## '' Remove rstatus var (now set in caller) ## 2012-10-12 Renamed & moved into ./private ## 2012-10-24 Style fixes ## 2013-09-11 rstatus return arg added (nowhere used, but all other routines have it) ## '' Returned formulas cleaned up ## 2013-12-01 Style fixes, copyright string updates function [ rawarr, ods, rstatus ] = __OTK_spsh2oct__ (ods, wsh, crange, spsh_opts) rstatus = 0; ## Get contents and table stuff from the workbook odfcont = ods.workbook; ## Use a local copy just to be sure. octave ## makes physical copies only when needed (?) ## Parse sheets ("tables") from ODS file sheets = ods.app.getTableList(); nr_of_sheets = sheets.size (); ## Check user input & find sheet pointer (1-based) if (! isnumeric (wsh)) try sh = ods.app.getTableByName (wsh); sh_err = isempty (sh); catch sh_err = 1; end_try_catch if (sh_err) error (sprintf ("Sheet %s not found in file %s\n", wsh, ods.filename)); endif elseif (wsh > nr_of_sheets || wsh < 1) ## We already have a numeric sheet pointer. If it's not in range: error (sprintf ("Worksheet no. %d out of range (1 - %d)", wsh, nr_of_sheets)); else sh = sheets.get (wsh - 1); endif ## Either parse (given cell range) or prepare (unknown range) help variables if (isempty (crange)) if (! isnumeric (wsh)) ## Get sheet index jj = nr_of_sheets; while (jj-- >= 0) if (strcmp (wsh, sheets.get(jj).getTableName()) == 1) wsh = jj +1; jj = -1; endif endwhile endif [ trow, brow, lcol, rcol ] = getusedrange (ods, wsh); nrows = brow - trow + 1; ## Number of rows to be read ncols = rcol - lcol + 1; ## Number of columns to be read else [dummy, nrows, ncols, trow, lcol] = parse_sp_range (crange); ## Check ODS row/column limits if (lcol > 1024 || trow > 65536) error ("ods2oct: invalid range; max 1024 columns & 65536 rows."); endif ## Truncate range silently if needed rcol = min (lcol + ncols - 1, 1024); ncols = min (ncols, 1024 - lcol + 1); nrows = min (nrows, 65536 - trow + 1); brow = trow + nrows - 1; endif ## Create storage for data content rawarr = cell (nrows, ncols); ## Read from worksheet row by row. Row numbers are 0-based for ii=trow:nrows+trow-1 row = sh.getRowByIndex (ii-1); for jj=lcol:ncols+lcol-1; ocell = row.getCellByIndex (jj-1); if (! isempty (ocell)) otype = deblank (tolower (ocell.getValueType ())); if (spsh_opts.formulas_as_text) if (! isempty (ocell.getFormula ())) otype = "formula"; endif endif ## ## Provisions for catching jOpenDocument 1.2b bug where text cells ## ## haven't been assigned an attribute ## if (! isempty (ocell)) ## if (findstr (" tags ## ist = findstr (tmp, ". ## __OTK_spsh_close__ - internal function: close a spreadsheet file using OTK ## Author: Philip Nienhuis ## Created: 2012-10-12 ## Updates: ## 2012-10-23 Style fixes (none) ## 2013-12-01 Copyright string updates function [ ods ] = __OTK_spsh_close__ (ods, force) try if (ods.changed && ods.changed < 3) if (isfield (ods, "nfilename")) ods.app.save (ods.nfilename); else ods.app.save (ods.filename); endif endif ods.changed = 0; ods.app.close (); catch if (force) ods.app.close (); endif end_try_catch endfunction io/inst/private/__OTK_spsh_info__.m0000644000076400010400000000360512246723724020616 0ustar PhilipAdministrators## Copyright (C) 2012,2013 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 Octave; see the file COPYING. If not, see ## . ## __OTK_spsh_info__ ## Author: Philip Nienhuis ## Created: 2012-10-12 ## Updates: ## 2012-10-12 Moved into ./private ## 2012-10-24 Style fixes ## 2013-12-01 Copyright string updates function [sh_names] = __OTK_spsh_info__ (ods) ## Get contents and table (= sheet) stuff from the workbook if (strcmp (ods.odfvsn, "0.8.7") || strfind (ods.odfvsn, "0.8.8")) xpath = ods.workbook.getXPath; else xpath = ods.app.getXPath; endif ## Create an instance of type NODESET for use in subsequent statement NODESET = java_get ("javax.xml.xpath.XPathConstants", "NODESET"); ## Parse sheets ("tables") from ODS file sheets = xpath.evaluate ("//table:table", ods.workbook, NODESET); nr_of_sheets = sheets.getLength(); sh_names = cell (nr_of_sheets, 2); ## Get sheet names (& optionally data row count estimate) for ii=1:nr_of_sheets ## Check in first part of the sheet nodeset sh_names (ii) = sheets.item(ii-1).getTableNameAttribute (); [ tr, lr, lc, rc ] = getusedrange (ods, ii); if (tr) sh_names(ii, 2) = sprintf ("%s:%s", calccelladdress (tr, lc),... calccelladdress (lr, rc)); endif endfor endfunction io/inst/private/__OTK_spsh_open__.m0000644000076400010400000000434212246724020020611 0ustar PhilipAdministrators## Copyright (C) 2012,2013 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 Octave; see the file COPYING. If not, see ## . ## __OTK_SPSH_open ## Author: Philip Nienhuis ## Created: 2012-10-12 ## Updates: ## 2012-10-24 Style fixes ## 2013-01-20 Adapted to ML-compatible Java calls ## 2013-12-01 Copyright string updates function [ ods, odssupport, lastintf ] = __OTK_spsh_open__ (ods, rw, filename, odssupport) ## Parts after user gfterry in ## http://www.oooforum.org/forum/viewtopic.phtml?t=69060 ## Get odfdom version persistent odfvsn; odfvsn = []; if (isempty (odfvsn)) try odfvsn = " "; ## New in 0.8.6 odfvsn = ... javaMethod ("getOdfdomVersion", "org.odftoolkit.odfdom.JarManifest"); catch odfvsn = ... javaMethod ("getApplicationVersion", "org.odftoolkit.odfdom.Version"); end_try_catch ## For odfdom-incubator (= 0.8.8+), strip extra info odfvsn = regexp (odfvsn, '\d\.\d\.\d', "match"){1}; endif odftk = "org.odftoolkit.odfdom.doc"; try if (rw > 2) ## New spreadsheet wb = javaMethod ("newSpreadsheetDocument", [odftk ".OdfSpreadsheetDocument"]); else ## Existing spreadsheet wb = javaMethod ("loadDocument", [odftk ".OdfDocument"], filename); endif ods.workbook = wb.getContentDom (); # Reads the entire spreadsheet ods.xtype = "OTK"; ods.app = wb; ods.filename = filename; ods.odfvsn = odfvsn; odssupport += 1; lastintf = "OTK"; catch error ("Couldn't open file %s using OTK", filename); end_try_catch endfunction io/inst/private/__OXS_getusedrange__.m0000644000076400010400000000275112250367502021311 0ustar PhilipAdministrators## Copyright (C) 2010,2011,20123 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 . ## __OXS_getusedrange__ ## Author: Philip ## Created: 2011-06-13 ## Updates: ## 2011-06-29 try-catch to be able to skip non-data (e.g., graph) sheets ## 2012-10-12 Renamed & moved into ./private ## 2012-10-24 Style fixes ## 2013-12-06 Updated copyright strings function [ trow, brow, lcol, rcol ] = __OXS_getusedrange__ (xls, wsh) sh = xls.workbook.getWorkSheet (wsh - 1); try ## Intriguing: sh.getFirst<> is off by one, sh.getLast<> = OK.... 8-Z trow = sh.getFirstRow () + 1; brow = sh.getLastRow (); lcol = sh.getFirstCol () + 1; rcol = sh.getLastCol (); catch ## Might be an empty sheet trow = brow = lcol = rcol = 0; end_try_catch ## Check for empty sheet if ((trow > brow) || (lcol > rcol)) trow = brow = lcol = rcol = 0; endif endfunction io/inst/private/__OXS_oct2spsh__.m0000644000076400010400000001337312260122350020372 0ustar PhilipAdministrators## Copyright (C) 2011,2012,2013 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 . ## -*- texinfo -*- ## @deftypefn {Function File} [ @var{xlso}, @var{rstatus} ] = __OXS_oct2spsh__ ( @var{arr}, @var{xlsi}) ## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = __OXS_oct2spsh__ (@var{arr}, @var{xlsi}, @var{wsh}) ## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = __OXS_oct2spsh__ (@var{arr}, @var{xlsi}, @var{wsh}, @var{range}) ## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = __OXS_oct2spsh__ (@var{arr}, @var{xlsi}, @var{wsh}, @var{range}, @var{options}) ## ## Add data in 1D/2D CELL array @var{arr} into spreadsheet cell range @var{range} ## in worksheet @var{wsh} in an Excel spreadsheet file pointed to in structure ## @var{range}. ## Return argument @var{xlso} equals supplied argument @var{xlsi} and is ## updated by __OXS_oct2spsh__. ## ## __OXS_oct2spsh__ should not be invoked directly but rather through oct2xls. ## ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2011-03-29 ## Updates: ## 2012-10-12 Renamed & moved into ./private ## 2012-10-24 Style fixes ## 2013-12-06 Updated copyright strings; style fixes ## 2013-12-27 Style fixes ## 2013-12-29 Commented out formula formatting line function [ xls, rstatus ] = __OXS_oct2spsh__ (obj, xls, wsh, crange, spsh_opts) changed = 0; persistent ctype; if (isempty (ctype)) ## Number, Boolean, String, Formula, Empty ctype = [1, 2, 3, 4, 5]; endif ## scratch vars rstatus = 0; f_errs = 0; ## Prepare workbook pointer if needed wb = xls.workbook; ## Check if requested worksheet exists in the file & if so, get pointer nr_of_sheets = wb.getNumWorkSheets (); ## 1 based !! if (isnumeric (wsh)) if (wsh > nr_of_sheets) ## Watch out as a sheet called Sheet%d can exist with a lower index... strng = sprintf ("Sheet%d", wsh); ii = 1; try ## While loop should be inside try-catch while (ii < 5) sh = wb.getWorkSheet (strng) strng = ['_' strng]; ++ii; endwhile catch ## No worksheet named found => we can proceed end_try_catch if (ii >= 5) error (sprintf( " > 5 sheets named [_]Sheet%d already present!", wsh)); endif ## OpenXLS v.10 has some idiosyncrasies. Might be related to the empty workbook... try sh = wb.createWorkSheet (strng); ++nr_of_sheets; catch if (wb.getNumWorkSheets () > nr_of_sheets) ## Adding a sheet did work out, in spite of Java exception ## lasterr should be something like "org/json/JSONException" ++nr_of_sheets; else error ("Couldn't add worksheet. Error message =\n%s", lasterr); endif end_try_catch xls.changed = min (xls.changed, 2); ## Keep a 2 in case of new file else sh = wb.getWorkSheet (wsh - 1); ## OXS sheet index 0-based endif printf ("(Writing to worksheet %s)\n", sh.getSheetName ()); else try sh = wb.getWorkSheet (wsh); catch ## Sheet not found, just create it. Mind OpenXLS v.10 idiosyncrasies if (xls.changed == 3 || strcmpi (wb.getWorkSheet (0).getSheetName, ")_]_}_ Dummy sheet made by Octave_{_[_(")) ## Workbook was just created, still has one empty worksheet. Rename it sh = wb.getWorkSheet (0); ## Index = 0-based sh.setSheetName (wsh); else try sh = wb.createWorkSheet (wsh); ++nr_of_sheets; catch if (wb.getNumWorkSheets () > nr_of_sheets) ## Adding a sheet did work out, in spite of Java exception ## lasterr should be something like "org/json/JSONException" ++nr_of_sheets; else error ("Couldn't add worksheet. Error message =\n%s", lasterr); endif end_try_catch endif xls.changed = min (xls.changed, 2); ## Keep a 2 for new file end_try_catch endif ## Parse date ranges [nr, nc] = size (obj); [topleft, nrows, ncols, trow, lcol] = ... spsh_chkrange (crange, nr, nc, xls.xtype, xls.filename); if (nrows < nr || ncols < nc) warning ("Array truncated to fit in range"); obj = obj(1:nrows, 1:ncols); endif ## Prepare type array typearr = spsh_prstype (obj, nrows, ncols, ctype, spsh_opts); if (! spsh_opts.formulas_as_text) ## Remove leading '=' from formula strings //FIXME needs updating fptr = (! (4 * (ones (size (typearr))) .- typearr)); # obj(fptr) = cellfun (@(x) x(2:end), obj(fptr), "Uniformoutput", false); endif clear fptr for ii=1:ncols for jj=1:nrows try ## Set value sh.getCell(jj+trow-2, ii+lcol-2).setVal (obj{jj, ii}); ## Addr.cnt = 0-based changed = 1; catch ## Cell not existent. Add cell if (typearr(jj, ii) != 5) sh.add (obj{jj, ii}, jj+trow-2, ii+lcol-2); changed = 1; endif end_try_catch endfor endfor if (changed) ## Preserve 2 for new files xls.changed = max (xls.changed, 1); endif rstatus = 1; endfunction io/inst/private/__OXS_spsh2oct__.m0000644000076400010400000001234612260122440020371 0ustar PhilipAdministrators## Copyright (C) 2011,2012,2013 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 . ## -*- texinfo -*- ## @deftypefn {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = __OXS_spsh2oct__ (@var{xls}) ## @deftypefnx {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = __OXS_spsh2oct__ (@var{xls}, @var{wsh}) ## @deftypefnx {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = __OXS_spsh2oct__ (@var{xls}, @var{wsh}, @var{range}) ## Get cell contents in @var{range} in worksheet @var{wsh} in an Excel ## file pointed to in struct @var{xls} into the cell array @var{obj}. ## @var{range} can be a range or just the top left cell of the range. ## ## __OXS_spsh2oct__ should not be invoked directly but rather through xls2oct. ## ## Author: Philip Nienhuis ## Created: 2011-03-26 ## Updates: ## 2012-02-25 Changed ctype into num array rather than cell array ## 2012-10-12 Renamed & moved into ./private ## 2012-10-24 Style fixes ## 2013-12-06 Updated copyright strings ## 2013-12-29 Overhauled actual worksheet reading section. Now does formulas too function [ rawarr, xls, rstatus ] = __OXS_spsh2oct__ (xls, wsh, cellrange, spsh_opts) persistent ctype; if (isempty (ctype)) ctype = zeros (6, 1); ## Get enumerated cell types. Beware as they start at 0 not 1 ctype( 1) = (java_get ("com.extentech.ExtenXLS.CellHandle", "TYPE_STRING")); ## 0 ctype( 2) = (java_get ("com.extentech.ExtenXLS.CellHandle", "TYPE_FP")); ## 1 ctype( 3) = (java_get ("com.extentech.ExtenXLS.CellHandle", "TYPE_INT")); ## 2 ctype( 4) = (java_get ("com.extentech.ExtenXLS.CellHandle", "TYPE_FORMULA")); ## 3 ctype( 5) = (java_get ("com.extentech.ExtenXLS.CellHandle", "TYPE_BOOLEAN")); ## 4 ctype( 6) = (java_get ("com.extentech.ExtenXLS.CellHandle", "TYPE_DOUBLE")); ## 5 endif rstatus = 0; wb = xls.workbook; ## Check if requested worksheet exists in the file & if so, get pointer nr_of_sheets = wb.getNumWorkSheets (); if (isnumeric (wsh)) if (wsh > nr_of_sheets) error (sprintf ... ("Worksheet ## %d bigger than nr. of sheets (%d) in file %s",... wsh, nr_of_sheets, xls.filename)); endif sh = wb.getWorkSheet (wsh - 1); ## OXS sheet count 0-based printf ("(Reading from worksheet %s)\n", sh.getSheetName ()); else try sh = wb.getWorkSheet (wsh); catch error (sprintf ("Worksheet %s not found in file %s", wsh, xls.filename)); end_try_catch end if (isempty (cellrange)) ## Get numeric sheet pointer (0-based) wsh = sh.getTabIndex (); ## Get data rectangle row & column numbers (1-based) [firstrow, lastrow, lcol, rcol] = getusedrange (xls, wsh+1); if (firstrow == 0 && lastrow == 0) ## Empty sheet rawarr = {}; printf ("Worksheet '%s' contains no data\n", shnames {wsh}); rstatus = 1; return; else nrows = lastrow - firstrow + 1; ncols = rcol - lcol + 1; endif else ## Translate range to row & column numbers (1-based) [dummy, nrows, ncols, firstrow, lcol] = parse_sp_range (cellrange); ## Check for too large requested range against actually present range lastrow = min (firstrow + nrows - 1, sh.getLastRow + 1 ()); nrows = min (nrows, sh.getLastRow () - firstrow + 1); ncols = min (ncols, sh.getLastCol () - lcol + 1); rcol = lcol + ncols - 1; endif ## Read contents into rawarr rawarr = cell (nrows, ncols); ## create placeholder for jj = lcol:rcol for ii = firstrow:lastrow try scell = sh.getCell (ii-1, jj-1); sctype = scell.getCellType (); switch sctype case {ctype(2), ctype(3), ctype(6)} ## Float / double rawarr{ii+1-firstrow, jj+1-lcol} = scell.getDoubleVal (); case ctype(4) ## Formula cell if (spsh_opts.formulas_as_text) tmp = char (sh.getFormula (scell.getCellAddress)); rawarr{ii+1-firstrow, jj+1-lcol} = tmp(index (tmp, ":=") + 1 : end); else ## FIXME - may still be a string; usually OpenXLS gets it right rawarr{ii+1-firstrow, jj+1-lcol} = scell.getVal (); endif case ctype(5) rawarr{ii+1-firstrow, jj+1-lcol} = scell.getVal () == 1; case ctype(1) rawarr{ii+1-firstrow, jj+1-lcol} = scell.getVal (); otherwise # rawarr{ii+1-firstrow, jj+1-lcol} = scell.getVal (); endswitch catch ## Empty or non-existing cell end_try_catch endfor endfor rstatus = 1; xls.limits = [lcol, rcol; firstrow, lastrow]; endfunction io/inst/private/__OXS_spsh_close__.m0000644000076400010400000000332412260073262020771 0ustar PhilipAdministrators## Copyright (C) 2012,2013 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 Octave; see the file COPYING. If not, see ## . ## __OXS_spsh_close__ - internal function: close a spreadsheet file using JXL ## Author: Philip Nienhuis ## Created: 2012-10-12 ## Updates: ## 2012-10-24 Style fixes ## 2013-01-20 Adapted to ML-compatible Java calls ## 2013-12-06 Updated copyright string ## 2013-12-28 Style fixes ## '' Moved wb close statement down to always unlock file function [ xls ] = __OXS_spsh_close__ (xls) if (xls.changed > 0 && xls.changed < 3) if (isfield (xls, "nfilename")) fname = xls.nfilename; else fname = xls.filename; endif try if (xls.changed == 2) printf ("Saving file %s...\n", fname); endif xlsout = javaObject ("java.io.FileOutputStream", fname); xls.workbook.write (xlsout); xlsout.close (); xls.changed = 0; catch warning ("__OXS_spsh_close__: error trying to close OXS file ptr"); end_try_catch endif xls.workbook.close (); endfunction io/inst/private/__OXS_spsh_info__.m0000644000076400010400000000311012260122240020577 0ustar PhilipAdministrators## Copyright (C) 2013 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 Octave; see the file COPYING. If not, see ## . ## __OXS_spsh_info__ ## Author: Philip Nienhuis ## Created: 2012-10-12 ## Updates: ## 2012-10-12 Moved into ./private ## 2012-10-24 Style fixes ## 2013-12-06 Updated copyright strings ## 2012-12-29 Typo in comment line fixed function [sh_names] = __OXS_spsh_info__ (xls) sh_cnt = xls.workbook.getNumWorkSheets (); sh_names = cell (sh_cnt, 2); nsrows = zeros (sh_cnt, 1); for ii=1:sh_cnt sh = xls.workbook.getWorkSheet (ii-1); ## OpenXLS starts counting at 0 sh_names(ii, 1) = char (sh.getSheetName()); ## OpenXLS doesn't offer methods to distinguish between worksheets ## and graph sheets [tr, lr, lc, rc] = getusedrange (xls, ii); if (tr) sh_names(ii, 2) = ... sprintf ("%s:%s", calccelladdress (tr, lc), calccelladdress (lr, rc)); else sh_names(ii, 2) = "Empty or Chart"; endif endfor endfunction io/inst/private/__OXS_spsh_open__.m0000644000076400010400000000504112260122136020616 0ustar PhilipAdministrators## Copyright (C) 2012,2013 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 Octave; see the file COPYING. If not, see ## . ## __OXS_xlsopen__ - internal function for opening an xls file using Java / OpenXLS ## Author: Philip Nienhuis ## Created: 2012-10-07 ## Updates: ## 2012-10-24 Style fixes ## 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 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") endif try if (xwrite > 2) if (ftype == 1) ## Create BIFF 8 file (.xls) wb = javaObject ("com.extentech.ExtenXLS.WorkBookHandle", false); else ## Create OOXML file (.xlsx) wb = javaObject ("com.extentech.ExtenXLS.WorkBookHandle", true); endif ## This new workbook has 3 empty sheets - get rid of the last two. ## Renaming, if needed, of Sheet1 is handled in __OXS_oct2spsh__.m for ii=2:wb.getNumWorkSheets ## Remarkable = sheet index = 0-based! wb.getWorkSheet (1).remove; endfor ## Workbook now has only one sheet ("Sheet1"). Rename it wb.getWorkSheet(0).setSheetName (")_]_}_ Dummy sheet made by Octave_{_[_("); else xlsin = javaObject ("java.io.FileInputStream", filename); wb = javaObject ("com.extentech.ExtenXLS.WorkBookHandle", xlsin); xlsin.close (); endif xls.xtype = "OXS"; xls.app = "void - OpenXLS"; xls.workbook = wb; xls.filename = filename; xlssupport += 8; lastintf = "OXS"; catch printf ("Unsupported file format for OpenXLS - %s\n"); end_try_catch endfunction io/inst/private/__POI_getusedrange__.m0000644000076400010400000000440412250644456021272 0ustar PhilipAdministrators## Copyright (C) 2010,2011,2012,2013 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 . ## __POI_getusedrange__ - get range of occupied data cells from Excel using java/POI ## Author: Philip Nienhuis ## Created: 2010-03-20 ## Updates: ## 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 function [ trow, brow, lcol, rcol ] = __POI_getusedrange__ (xls, ii) persistent cblnk; cblnk = java_get ("org.apache.poi.ss.usermodel.Cell", "CELL_TYPE_BLANK"); sh = xls.workbook.getSheetAt (ii-1); ## Java POI starts counting at 0 trow = sh.getFirstRowNum (); ## 0-based brow = sh.getLastRowNum (); ## 0-based ## Get column range lcol = 1048577; ## OOXML (xlsx) max. + 1 rcol = 0; botrow = brow; for jj=trow:brow irow = sh.getRow (jj); if (! isempty (irow)) scol = irow.getFirstCellNum; ## If getFirstCellNum < 0, row is empty if (scol >= 1) lcol = min (lcol, scol); ecol = irow.getLastCellNum - 1; rcol = max (rcol, ecol); ## Keep track of lowermost non-empty row as getLastRowNum() is unreliable if (! (irow.getCell(scol).getCellType () == cblnk ... && irow.getCell(ecol).getCellType () == cblnk)) botrow = jj; endif endif endif endfor if (lcol > 1048576) ## Empty sheet trow = 0; brow = 0; lcol = 0; rcol = 0; else ## 1-based retvals brow = min (brow, botrow) + 1; ++trow; ++lcol; ++rcol; endif endfunction io/inst/private/__POI_oct2spsh__.m0000644000076400010400000001614412250644156020363 0ustar PhilipAdministrators## Copyright (C) 2009,2010,2011,2012,2013 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 . ## -*- texinfo -*- ## @deftypefn {Function File} [ @var{xlso}, @var{rstatus} ] = __POI_oct2spsh__ ( @var{arr}, @var{xlsi}) ## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = __POI_oct2spsh__ (@var{arr}, @var{xlsi}, @var{wsh}) ## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = __POI_oct2spsh__ (@var{arr}, @var{xlsi}, @var{wsh}, @var{range}) ## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = __POI_oct2spsh__ (@var{arr}, @var{xlsi}, @var{wsh}, @var{range}, @var{options}) ## ## Add data in 1D/2D CELL array @var{arr} into a range with upper left ## cell equal to @var{topleft} in worksheet @var{wsh} in an Excel ## spreadsheet file pointed to in structure @var{range}. ## Return argument @var{xlso} equals supplied argument @var{xlsi} and is ## updated by __POI_oct2spsh__. ## ## __POI_oct2spsh__ should not be invoked directly but rather through oct2xls. ## ## Example: ## ## @example ## [xlso, status] = __POI_oct2spsh__ ("arr", xlsi, "Third_sheet", "AA31"); ## @end example ## ## @seealso {oct2xls, xls2oct, xlsopen, xlsclose, xlsread, xlswrite} ## ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2009-11-26 ## Updates: ## 2010-01-03 Bugfixes ## 2010-01-12 Added xls.changed = 1 statement to signal successful write ## 2010-03-08 Dumped formula evaluator for booleans. Not being able to ## write booleans was due to a __java__.oct deficiency (see ## http://sourceforge.net/mailarchive/forum.php?thread_name=4B59A333.5060302%40net.in.tum.de&forum_name=octave-dev ) ## 2010-07-27 Added formula writing support (based on patch by Benjamin Lindner) ## 2010-08-01 Improved try-catch for formulas to enter wrong formulas as text strings ## 2010-08-01 Added range vs. array size vs. capacity checks ## 2010-08-03 Moved range checks and type array parsingto separate functions ## 2010-10-21 Improved logic for tracking file changes ## 2010-10-27 File change tracking again refined, internal var "changed" dropped ## 2010-11-12 Moved ptr struct check into main func ## 2011-11-19 Try-catch added to allow for changed method name for nr of worksheets ## 2012-01-26 Fixed "seealso" help string ## 2012-02-27 Copyright strings updated ## 2012-05-21 "Double" cast added when writing numeric values ## 2012-05-21 "Double" cast moved into main func oct2xls ## 2012-10-12 Renamed & moved into ./private ## 2012-10-24 Style fixes ## 2013-12-06 Updated copyright strings; style fixes ## 2013-12-07 Fixed .xls extension check; style fixes function [ xls, rstatus ] = __POI_oct2spsh__ (obj, xls, wsh, crange, spsh_opts) ## Preliminary sanity checks if (isempty (strcmpi (xls.filename(end-3:end), ".xls"))) error ("POI interface can only write to Excel .xls or .xlsx files") endif persistent ctype; if (isempty (ctype)) ## Get cell types. Beware as they start at 0 not 1 ctype(1) = java_get ("org.apache.poi.ss.usermodel.Cell", "CELL_TYPE_NUMERIC"); ## 0 ctype(2) = java_get ("org.apache.poi.ss.usermodel.Cell", "CELL_TYPE_BOOLEAN"); ## 4 ctype(3) = java_get ("org.apache.poi.ss.usermodel.Cell", "CELL_TYPE_STRING"); ## 1 ctype(4) = java_get ("org.apache.poi.ss.usermodel.Cell", "CELL_TYPE_FORMULA"); ## 2 ctype(5) = java_get ("org.apache.poi.ss.usermodel.Cell", "CELL_TYPE_BLANK"); ## 3 endif ## scratch vars rstatus = 0; f_errs = 0; ## Check if requested worksheet exists in the file & if so, get pointer try nr_of_sheets = xls.workbook.getNumWorkSheets (); catch nr_of_sheets = xls.workbook.getNumberOfSheets (); end_try_catch if (isnumeric (wsh)) if (wsh > nr_of_sheets) ## Watch out as a sheet called Sheet%d can exist with a lower index... strng = sprintf ("Sheet%d", wsh); ii = 1; while (! isempty (xls.workbook.getSheet (strng)) && (ii < 5)) strng = ["_" strng]; ++ii; endwhile if (ii >= 5) error (sprintf( " > 5 sheets named [_]Sheet%d already present!", wsh)); endif sh = xls.workbook.createSheet (strng); xls.changed = min (xls.changed, 2); ## Keep 2 for new files else sh = xls.workbook.getSheetAt (wsh - 1); ## POI sheet count 0-based endif printf ("(Writing to worksheet %s)\n", sh.getSheetName ()); else sh = xls.workbook.getSheet (wsh); if (isempty (sh)) ## Sheet not found, just create it sh = xls.workbook.createSheet (wsh); xls.changed = min (xls.changed, 2); ## Keep 2 or 3 f. new files endif endif ## Parse date ranges [nr, nc] = size (obj); [topleft, nrows, ncols, trow, lcol] = ... spsh_chkrange (crange, nr, nc, xls.xtype, xls.filename); if (nrows < nr || ncols < nc) warning ("Array truncated to fit in range"); obj = obj(1:nrows, 1:ncols); endif ## Prepare type array typearr = spsh_prstype (obj, nrows, ncols, ctype, spsh_opts); if (! spsh_opts.formulas_as_text) ## Remove leading "=" from formula strings ## FIXME should be easier using typearr<4> info fptr = (! (2 * (ones (size (typearr))) .- typearr)); obj(fptr) = cellfun (@(x) x(2:end), obj(fptr), "Uniformoutput", false); endif ## Create formula evaluator frm_eval = xls.workbook.getCreationHelper ().createFormulaEvaluator (); for ii=1:nrows ll = ii + trow - 2; ## Java POI's row count 0-based row = sh.getRow (ll); if (isempty (row)) row = sh.createRow (ll); endif for jj=1:ncols kk = jj + lcol - 2; ## POI's column count is 0-based if (typearr(ii, jj) == ctype(5)) ## Empty cells cell = row.createCell (kk, ctype(5)); elseif (typearr(ii, jj) == ctype(4)) ## Formulas ## Try-catch needed as there's no guarantee for formula correctness try cell = row.createCell (kk, ctype(4)); cell.setCellFormula (obj{ii,jj}); catch ++f_errs; cell.setCellType (ctype (3)); ## Enter formula as text cell.setCellValue (obj{ii, jj}); end_try_catch else cell = row.createCell (kk, typearr(ii,jj)); if (isnumeric (obj{ii, jj})) cell.setCellValue (obj{ii, jj}); else cell.setCellValue (obj{ii, jj}); endif endif endfor endfor if (f_errs) printf ("%d formula errors encountered - please check input array\n", f_errs); endif xls.changed = max (xls.changed, 1); ## Preserve a "2" rstatus = 1; endfunction io/inst/private/__POI_spsh2oct__.m0000644000076400010400000001750312250373466020366 0ustar PhilipAdministrators## Copyright (C) 2009,2010,2011,2012,2013 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 . ## -*- texinfo -*- ## @deftypefn {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = __POI_spsh2oct__ (@var{xls}) ## @deftypefnx {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = __POI_spsh2oct__ (@var{xls}, @var{wsh}) ## @deftypefnx {Function File} [@var{obj}, @var{rstatus}, @var{xls} ] = __POI_spsh2oct__ (@var{xls}, @var{wsh}, @var{range}) ## Get cell contents in @var{range} in worksheet @var{wsh} in an Excel ## file pointed to in struct @var{xls} into the cell array @var{obj}. ## @var{range} can be a range or just the top left cell of the range. ## ## __POI_spsh2oct__ should not be invoked directly but rather through xls2oct. ## ## Examples: ## ## @example ## [Arr, status, xls] = __POI_spsh2oct__ (xls, 'Second_sheet', 'B3:AY41'); ## B = __POI_spsh2oct__ (xls, 'Second_sheet', 'B3'); ## @end example ## ## @seealso {xls2oct, oct2xls, xlsopen, xlsclose, xlsread, xlswrite, oct2jpoi2xls} ## ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2009-11-23 ## Updates: ## 2010-01-11 Fall back to cached values when formula evaluator fails ## 2010-03-14 Fixed max column nr for OOXML for empty given range ## 2010-07-28 Added option to read formulas as text strings rather than evaluated value ## 2010-08-01 Some bug fixes for formula reading (cvalue rather than scell) ## 2010-10-10 Code cleanup: -getusedrange called; - fixed typo in formula evaluation msg; ## '' moved cropping output array to calling function. ## 2010-11-12 Moved ptr struct check into main func ## 2010-11-13 Catch empty sheets when no range was specified ## 2010-11-14 Fixed sheet # index (was offset by -1) in call to getusedrange() in case ## of text sheet name arg ## 2012-01-26 Fixed "seealso" help string ## 2012-10-12 Renamed & moved into ./private ## 2012-10-24 Style fixes ## 2013-12-06 Updated copyright strings; style fixes function [ rawarr, xls, rstatus ] = __POI_spsh2oct__ (xls, wsh, cellrange, spsh_opts) persistent ctype; if (isempty (ctype)) ## Get enumerated cell types. Beware as they start at 0 not 1 ctype(1) = java_get ("org.apache.poi.ss.usermodel.Cell", "CELL_TYPE_NUMERIC"); ctype(2) = java_get ("org.apache.poi.ss.usermodel.Cell", "CELL_TYPE_STRING"); ctype(3) = java_get ("org.apache.poi.ss.usermodel.Cell", "CELL_TYPE_FORMULA"); ctype(4) = java_get ("org.apache.poi.ss.usermodel.Cell", "CELL_TYPE_BLANK"); ctype(5) = java_get ("org.apache.poi.ss.usermodel.Cell", "CELL_TYPE_BOOLEAN"); ctype(6) = java_get ("org.apache.poi.ss.usermodel.Cell", "CELL_TYPE_ERROR"); endif rstatus = 0; jerror = 0; wb = xls.workbook; ## Check if requested worksheet exists in the file & if so, get pointer nr_of_sheets = wb.getNumberOfSheets (); if (isnumeric (wsh)) if (wsh > nr_of_sheets) error (sprintf ("Worksheet ## %d bigger than nr. of sheets (%d) in file %s",... wsh, nr_of_sheets, xls.filename)); endif sh = wb.getSheetAt (wsh - 1); ## POI sheet count 0-based ## printf ("(Reading from worksheet %s)\n", sh.getSheetName ()); else sh = wb.getSheet (wsh); if (isempty (sh)) error (sprintf ("Worksheet %s not found in file %s", wsh, xls.filename)); endif end ## Check ranges firstrow = sh.getFirstRowNum (); ## 0-based lastrow = sh.getLastRowNum (); ## 0-based if (isempty (cellrange)) if (ischar (wsh)) ## get numeric sheet index ii = wb.getSheetIndex (sh) + 1; else ii = wsh; endif [ firstrow, lastrow, lcol, rcol ] = getusedrange (xls, ii); if (firstrow == 0 && lastrow == 0) ## Empty sheet rawarr = {}; printf ("Worksheet '%s' contains no data\n", sh.getSheetName ()); rstatus = 1; return; else nrows = lastrow - firstrow + 1; ncols = rcol - lcol + 1; endif else ## Translate range to HSSF POI row & column numbers [topleft, nrows, ncols, firstrow, lcol] = parse_sp_range (cellrange); lastrow = firstrow + nrows - 1; rcol = lcol + ncols - 1; endif ## Create formula evaluator (needed to infer proper cell type into rawarr) frm_eval = wb.getCreationHelper().createFormulaEvaluator (); ## Read contents into rawarr rawarr = cell (nrows, ncols); ## create placeholder for ii = firstrow:lastrow irow = sh.getRow (ii-1); if (! isempty (irow)) scol = irow.getFirstCellNum; ecol = irow.getLastCellNum - 1; for jj = lcol:rcol scell = irow.getCell (jj-1); if (! isempty (scell)) ## Explore cell contents type_of_cell = scell.getCellType (); if (type_of_cell == ctype(3)) ## Formula if (! spsh_opts.formulas_as_text) try ## Because not al Excel formulas have been implemented in POI cvalue = frm_eval.evaluate (scell); type_of_cell = cvalue.getCellType(); ## Separate switch because form.eval. yields different type switch type_of_cell case ctype (1) ## Numeric rawarr {ii+1-firstrow, jj+1-lcol} = cvalue.getNumberValue (); case ctype(2) ## String rawarr {ii+1-firstrow, jj+1-lcol} = ... char (cvalue.getStringValue ()); case ctype (5) ## Boolean rawarr {ii+1-firstrow, jj+1-lcol} = cvalue.BooleanValue (); otherwise ## Nothing to do here endswitch ## Set cell type to blank to skip switch below type_of_cell = ctype(4); catch ## In case of formula errors we take the cached results type_of_cell = scell.getCachedFormulaResultType (); ## We only need one warning even for multiple errors ++jerror; end_try_catch endif endif ## Preparations done, get data values into data array switch type_of_cell case ctype(1) ## 0 Numeric rawarr {ii+1-firstrow, jj+1-lcol} = scell.getNumericCellValue (); case ctype(2) ## 1 String rawarr {ii+1-firstrow, jj+1-lcol} = ... char (scell.getRichStringCellValue ()); case ctype(3) if (spsh_opts.formulas_as_text) tmp = char (scell.getCellFormula ()); rawarr {ii+1-firstrow, jj+1-lcol} = ["=" tmp]; endif case ctype(4) ## 3 Blank ## Blank; ignore until further notice case ctype(5) ## 4 Boolean rawarr {ii+1-firstrow, jj+1-lcol} = scell.getBooleanCellValue (); otherwise ## 5 Error ## Ignore endswitch endif endfor endif endfor if (jerror > 0) warning (sprintf ("%d cached values instead of formula evaluations read.\n",... jerror)); endif rstatus = 1; xls.limits = [lcol, rcol; firstrow, lastrow]; endfunction io/inst/private/__POI_spsh_close__.m0000644000076400010400000000316312250374276020760 0ustar PhilipAdministrators## Copyright (C) 2012,2013 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 Octave; see the file COPYING. If not, see ## . ## __POI_spsh_close__ - internal function: close a spreadsheet file using POI ## Author: Philip Nienhuis ## Created: 2012-10-12 ## Updates: ## 2012-10-24 Style fixes ## 2013-01-20 Adapted to ML-compatible Java calls ## 2013-12-06 Updated copyright strings function [ xls ] = __POI_spsh_close__ (xls) if (xls.changed > 0 && xls.changed < 3) if (isfield (xls, "nfilename")) fname = xls.nfilename; else fname = xls.filename; endif try xlsout = javaObject ("java.io.FileOutputStream", fname); bufout = javaObject ("java.io.BufferedOutputStream", xlsout); ## if (xls.changed == 2); printf ("Saving file %s...\n", fname); endif xls.workbook.write (bufout); bufout.flush (); bufout.close (); xlsout.close (); xls.changed = 0; catch ## xlsout.close (); end_try_catch endif endfunction io/inst/private/__POI_spsh_info__.m0000644000076400010400000000314112250374356020601 0ustar PhilipAdministrators## Copyright (C) 2012,2013 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 Octave; see the file COPYING. If not, see ## . ## __POI_spsh_info__ ## Author: Philip Nienhuis ## Created: 2012-10-12 ## Updates: ## 2012-10-12 Moved into ./private ## 2012-10-24 Style fixes ## 2013-12-06 Updated copyright strings function [sh_names] = __POI_spsh_info__ (xls) persistent cblnk; cblnk = java_get ("org.apache.poi.ss.usermodel.Cell", "CELL_TYPE_BLANK"); sh_cnt = xls.workbook.getNumberOfSheets(); sh_names = cell (sh_cnt, 2); nsrows = zeros (sh_cnt, 1); for ii=1:sh_cnt sh = xls.workbook.getSheetAt (ii-1); # Java POI starts counting at 0 sh_names(ii, 1) = char (sh.getSheetName()); ## Java POI doesn't distinguish between worksheets and graph sheets [tr, lr, lc, rc] = getusedrange (xls, ii); if (tr) sh_names(ii, 2) = ... sprintf ("%s:%s", calccelladdress (tr, lc), calccelladdress (lr, rc)); else sh_names(ii, 2) = "Empty"; endif endfor endfunction io/inst/private/__POI_spsh_open__.m0000644000076400010400000000472112257315242020610 0ustar PhilipAdministrators## Copyright (C) 2012,2013 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 Octave; see the file COPYING. If not, see ## . ## __POI_xlsopen__ - Internal function for opening an xls(x) file using Java/Apache POI ## Author: Philip Nienhuis ## Created: 2012-10-07 ## ## Updates (possibly earlier in xlsopen): ## 2010-01-03 Added OOXML support ## 2010-01-16 Removed echoeing debug info in POI stanza ## 2010-09-27 Improved POI help message for unrecognized .xls format to hint for BIFF5/JXL ## 2010-11-08 Tested with POI 3.7 (OK) ## 2012-06-07 Fixed mixed-up lastintf assignments for POI and JXL ## 2012-10-24 Style fixes; added UNO to fall-back for BIFF5 formats ## 2013-01-20 Adapted to ML-compatible Java calls ## 2013-12-06 Updated copyright strings ## 2013-12-27 Use one variable for processed file type function [ xls, xlssupport, lastintf ] = __POI_spsh_open__ (xls, xwrite, filename, xlssupport, ftype, xlsinterfaces) ## Get handle to workbook try if (xwrite > 2) if (ftype == 1) wb = javaObject ("org.apache.poi.hssf.usermodel.HSSFWorkbook"); elseif (ftype == 2) wb = javaObject ("org.apache.poi.xssf.usermodel.XSSFWorkbook"); endif xls.app = "new_POI"; else xlsin = javaObject ("java.io.FileInputStream", filename); wb = javaMethod ("create", ... "org.apache.poi.ss.usermodel.WorkbookFactory",... xlsin); xls.app = xlsin; endif xls.xtype = "POI"; xls.workbook = wb; xls.filename = filename; xlssupport += 2; lastintf = "POI"; catch clear xlsin; if (ftype == 1 && (xlsinterfaces.JXL || xlsinterfaces.UNO)) printf ... (["Couldn't open file %s using POI;\n" ... "trying Excel'95 format with JXL or UNO...\n"], filename); endif end_try_catch endfunction io/inst/private/__UNO_getusedrange__.m0000644000076400010400000000605612250375046021305 0ustar PhilipAdministrators## Copyright (C) 2011,2012,2013 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 . ## __UNO_getusedrange__ ## Author: Philip Nienhuis ## Created: 2011-05-06 ## Updates: ## 2011-06-29 Fixed wrong address range inference in case of sheet names ## containing period(s) ## 2012-03-02 Adapted code to assess nr of range blocks to ';' separator for LO3.5+ ## 2012-10-12 Renamed & moved into ./private ## 2012-10-24 Style fixes ## 2013-01-20 Adapted to ML-compatible Java calls ## 2013-12-06 Updated copyright strings function [ srow, erow, scol, ecol ] = __UNO_getusedrange__ (ods, ii) # Get desired sheet sheets = ods.workbook.getSheets (); sh_names = sheets.getElementNames (); unotmp = javaObject ("com.sun.star.uno.Type", "com.sun.star.sheet.XSpreadsheet"); sh = sheets.getByName (sh_names(ii)).getObject.queryInterface (unotmp); ## Prepare cell range query unotmp = javaObject ("com.sun.star.uno.Type", "com.sun.star.sheet.XCellRangesQuery"); xRQ = sh.queryInterface (unotmp); Cellflgs = javaObject ("java.lang.Short", "23"); ccells = xRQ.queryContentCells (Cellflgs); ## Get addresses of all blocks containing data addrs = ccells.getRangeAddressesAsString (); ## Strip sheet name from addresses. Watch out, in LO3.5 they changed ## the separator from ',' to ';' (without telling me 8-Z) ## 1. Get nr of range blocks nblks = numel (strfind (addrs, sh_names(ii))); ## 2. First try with "," separator... adrblks = strsplit (addrs, ","); if (numel (adrblks) < nblks) ## Apparently we have a ';' separator, so try with semicolon adrblks = strsplit (addrs, ";"); endif if (isempty (adrblks) || isempty (adrblks{1})) srow = erow = scol = ecol = 0; return endif ## Find leftmost & rightmost columns, and highest and lowest row with data srow = scol = 1e10; erow = ecol = 0; for ii=1:numel (adrblks) ## Check if address contains a sheet name in quotes (happens if name contains a period) if (int8 (adrblks{ii}(1)) == 39) ## Strip sheet name part idx = findstr (adrblks{ii}, "'."); range = adrblks{ii}(idx+2 : end); else ## Same, but tru strsplit() range = strsplit (adrblks{ii}, "."){2}; endif [dummy, nrows, ncols, trow, lcol] = parse_sp_range (range); brow = trow + nrows - 1; rcol = lcol + ncols - 1; srow = min (srow, trow); scol = min (scol, lcol); erow = max (erow, brow); ecol = max (ecol, rcol); endfor endfunction io/inst/private/__UNO_oct2spsh__.m0000644000076400010400000001473312250424436020374 0ustar PhilipAdministrators## Copyright (C) 2011,2012,2013 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 . ## oct2uno2xls - Internal function: write to spreadsheet file using UNO-Java bridge ## Author: Philip Nienhuis ## Created: 2011-05-18 ## 2011-09-18 Adapted sh_names type to LO 3.4.1 ## 2011-09-23 Removed stray debug statements ## 2012-02-25 Fixed wrong var name in L.933 ## 2012-02-25 Catch stray Java RuntimeException when deleting sheets ## 2012-02-26 Bug fix when adding sheets near L.994 (wrong if-else-end construct). ## 2012-02-27 Copyright strings updated ## 2012-05-21 "Double" cast added when writing numeric values ## 2012-05-21 "Double" cast moved into main func oct2xls ## 2012-10-12 Renamed & moved into ./private ## 2012-10-24 Style fixes ## 2012-12-21 Search for exact match when searching sheet names ## 2013-01-20 Adapted to ML-compatible Java calls ## 2013-12-06 Updated copyright string; function [ xls, rstatus ] = __UNO_oct2spsh__ (c_arr, xls, wsh, crange, spsh_opts) changed = 0; newsh = 0; ctype = [1, 2, 3, 4, 5]; ## Float, Logical, String, Formula, Empty ## Get handle to sheet, create a new one if needed sheets = xls.workbook.getSheets (); sh_names = sheets.getElementNames (); if (! iscell (sh_names)) ## Java array (LibreOffice 3.4.+); convert to cellstr sh_names = char (sh_names); else sh_names = {sh_names}; endif ## Clear default 2 last sheets in case of a new spreadsheet file if (xls.changed > 2) ii = numel (sh_names); while (ii > 1) shnm = sh_names{ii}; try ## Catch harmless Java RuntimeException "out of range" in LibreOffice 3.5rc1 sheets.removeByName (shnm); end_try_catch --ii; endwhile ## Give remaining sheet a name unotmp = javaObject ("com.sun.star.uno.Type", "com.sun.star.sheet.XSpreadsheet"); sh = sheets.getByName (sh_names{1}).getObject.queryInterface (unotmp); if (isnumeric (wsh)); wsh = sprintf ("Sheet%d", wsh); endif unotmp = javaObject ("com.sun.star.uno.Type", "com.sun.star.container.XNamed"); sh.queryInterface (unotmp).setName (wsh); else ## Check sheet pointer ## FIXME sheet capacity check needed if (isnumeric (wsh)) if (wsh < 1) error ("Illegal sheet index: %d", wsh); elseif (wsh > numel (sh_names)) ## New sheet to be added. First create sheet name but check if it already exists shname = sprintf ("Sheet%d", numel (sh_names) + 1); jj = strmatch (shname, sh_names, "exact"); if (~isempty (jj)) ## New sheet name already in file, try to create a unique & reasonable one ii = 1; filler = ""; maxtry = 5; while (ii <= maxtry) shname = sprintf ("Sheet%s%d", [filler "_"], numel (sh_names + 1)); if (isempty (strmatch (shname, sh_names, "exact"))) ii = 10; else ++ii; endif endwhile if (ii > maxtry + 1) error ("Could not add sheet with a unique name to file %s"); endif endif wsh = shname; newsh = 1; else ## turn wsh index into the associated sheet name wsh = sh_names (wsh); endif else ## wsh is a sheet name. See if it exists already if (isempty (strmatch (wsh, sh_names, "exact"))) ## Not found. New sheet to be added newsh = 1; endif endif if (newsh) ## Add a new sheet. Sheet index MUST be a Java Short object shptr = javaObject ("java.lang.Short", sprintf ("%d", numel (sh_names) + 1)); sh = sheets.insertNewByName (wsh, shptr); endif ## At this point we have a valid sheet name. Use it to get a sheet handle unotmp = javaObject ("com.sun.star.uno.Type", "com.sun.star.sheet.XSpreadsheet"); sh = sheets.getByName (wsh).getObject.queryInterface (unotmp); endif ## Check size of data array & range / capacity of worksheet & prepare vars [nr, nc] = size (c_arr); [topleft, nrows, ncols, trow, lcol] = ... spsh_chkrange (crange, nr, nc, xls.xtype, xls.filename); --trow; --lcol; ## Zero-based row ## & col ## if (nrows < nr || ncols < nc) warning ("Array truncated to fit in range"); c_arr = c_arr(1:nrows, 1:ncols); endif ## 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 ")") fptr = cellfun (@(x) ischar (x) && strncmp (x, "=", 1), c_arr); typearr(fptr) = ctype(4); ## FORMULA endif ## Transfer data to sheet for ii=1:nrows for jj=1:ncols try XCell = sh.getCellByPosition (lcol+jj-1, trow+ii-1); switch typearr(ii, jj) case 1 ## Float XCell.setValue (c_arr{ii, jj}); case 2 ## Logical. Convert to float as OOo has no Boolean type XCell.setValue (double (c_arr{ii, jj})); case 3 ## String unotmp = javaObject ("com.sun.star.uno.Type", "com.sun.star.text.XText"); XCell.queryInterface (unotmp).setString (c_arr{ii, jj}); case 4 ## Formula if (spsh_opts.formulas_as_text) unotmp = javaObject ("com.sun.star.uno.Type", "com.sun.star.text.XText"); XCell.queryInterface (unotmp).setString (c_arr{ii, jj}); else XCell.setFormula (c_arr{ii, jj}); endif otherwise ## Empty cell endswitch changed = 1; catch printf ("Error writing cell %s (typearr() = %d)\n",... calccelladdress(trow+ii, lcol+jj), typearr(ii, jj)); end_try_catch endfor endfor if (changed) ## Preserve 2 (new file), 1 (existing) xls.changed = max (min (xls.changed, 2), changed); rstatus = 1; endif endfunction io/inst/private/__UNO_spsh2oct__.m0000644000076400010400000001203512250422614020361 0ustar PhilipAdministrators## Copyright (C) 2011,2012,2013 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 . ## __UNO_spsh2oct__ - Inernal function for reading from spreadsheets using UNO/Java ## Author: Philip Nienhuis ## Created: 2011-05-05 ## Updates: ## 2011-09-18 Adapted sh_names type to LO 3.4.1 ## 2011-09-19 Try to decipher if formulas return numeric or string values ## 2012-10-12 Renamed & moved into ./private ## 2012-10-24 Style fixes ## 2012-12-21 Search for exact match when searching sheet names ## 2013-01-20 Adapted to ML-compatible Java calls ## 2013-12-06 Updated copyright strings; style fixes function [rawarr, xls, rstatus] = __UNO_spsh2oct__ (xls, wsh, datrange, spsh_opts) sheets = xls.workbook.getSheets (); sh_names = sheets.getElementNames (); if (! iscell (sh_names)) ## Java array (LibreOffice 3.4.+), convert to cellstr sh_names = char (sh_names); else sh_names = {sh_names}; endif ## Check sheet pointer if (isnumeric (wsh)) if (wsh < 1 || wsh > numel (sh_names)) error ("Sheet index %d out of range 1-%d", wsh, numel (sh_names)); endif else ii = strmatch (wsh, sh_names, "exact"); if (isempty (ii)) error ("Sheet '%s' not found", wsh); endif wsh = ii; endif unotmp = javaObject ("com.sun.star.uno.Type", "com.sun.star.sheet.XSpreadsheet"); sh = sheets.getByName(sh_names{wsh}).getObject.queryInterface (unotmp); unotmp = javaObject ("com.sun.star.uno.Type", "com.sun.star.sheet.XCellRangesQuery"); xRQ = sh.queryInterface (unotmp); ## Get cell ranges of all rectangles containing data. Type values: ##java_get ("com.sun.star.sheet.CellFlags", "VALUE") ans = 1 ##java_get ("com.sun.star.sheet.CellFlags", "DATETIME") ans = 2 ##java_get ("com.sun.star.sheet.CellFlags", "STRING") ans = 4 ##java_get ("com.sun.star.sheet.CellFlags", "FORMULA") ans = 16 + ## Yep, boolean is lacking... sum = 23 Cellflgs = javaObject ("java.lang.Short", "23"); ccells = xRQ.queryContentCells (Cellflgs); addrs = ccells.getRangeAddressesAsString (); ## Strip sheet name from addresses adrblks = strsplit (addrs, ","); if (isempty (adrblks)) warning ("Sheet %s contains no data", sh_names{wsh}); return endif ## Either parse (given cell range) or prepare (unknown range) help variables. ## As OpenOffice knows the occupied range, we need the limits anyway to avoid ## out-of-range errors [ trow, brow, lcol, rcol ] = getusedrange (xls, wsh); if (isempty (datrange)) nrows = brow - trow + 1; ## Number of rows to be read ncols = rcol - lcol + 1; ## Number of columns to be read else [dummy, nrows, ncols, srow, scol] = parse_sp_range (datrange); ## Truncate range silently if needed brow = min (srow + nrows - 1, brow); rcol = min (scol + ncols - 1, rcol); trow = max (trow, srow); lcol = max (lcol, scol); nrows = min (brow - trow + 1, nrows); ## Number of rows to be read ncols = min (rcol - lcol + 1, ncols); ## Number of columns to be read endif ## Create storage for data at Octave side rawarr = cell (nrows, ncols); ## Get data. Apparently row & column indices are 0-based in UNO for ii=trow-1:brow-1 for jj=lcol-1:rcol-1 XCell = sh.getCellByPosition (jj, ii); cType = XCell.getType ().getValue (); switch cType case 1 ## Value rawarr{ii-trow+2, jj-lcol+2} = XCell.getValue (); case 2 ## String unotmp = javaObject ("com.sun.star.uno.Type", "com.sun.star.text.XText"); rawarr{ii-trow+2, jj-lcol+2} = XCell.queryInterface (unotmp).getString (); case 3 ## Formula if (spsh_opts.formulas_as_text) rawarr{ii-trow+2, jj-lcol+2} = XCell.getFormula (); else ## Unfortunately OOo gives no clue as to the type of formula result unotmp = javaObject ("com.sun.star.uno.Type", "com.sun.star.text.XText"); rawarr{ii-trow+2, jj-lcol+2} = XCell.queryInterface (unotmp).getString (); tmp = str2double (rawarr{ii-trow+2, jj-lcol+2}); ## If the string happens to contain just a number we'll assume it is numeric if (! isnan (tmp)) rawarr{ii-trow+2, jj-lcol+2} = tmp; endif endif otherwise ## Empty cell endswitch endfor endfor ## Keep track of data rectangle limits xls.limits = [lcol, rcol; trow, brow]; rstatus = ! isempty (rawarr); endfunction io/inst/private/__UNO_spsh_close__.m0000644000076400010400000001145412261107164020764 0ustar PhilipAdministrators## Copyright (C) 2012,2013 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 Octave; see the file COPYING. If not, see ## . ## __UNO_spsh_close__ - internal function: close a spreadsheet file using UNO ## Author: Philip Nienhuis ## Created: 2012-10-12 ## Updates: ## 2012-10-23 Style fixes ## 2013-01-20 Adapted to ML-compatible Java calls ## 2013-12-06 Updated copyright strings ## 2014-01-01 Fixed bug ignoring xls.nfilename ## '' Simplified filename/nfilename code ## '' First throw at output file type filters ## '' Add ";" to suppress debug output function [ xls ] = __UNO_spsh_close__ (xls, force) if (isfield (xls, "nfilename")) ## New filename specified if (strcmp (xls.xtype, 'UNO')) ## For UNO, turn filename into URL nfilename = xls.nfilename; if (! isempty (strmatch ("file:///", nfilename))... || ! isempty (strmatch ("http://", nfilename))... || ! isempty (strmatch ("ftp://", nfilename))... || ! isempty (strmatch ("www://", nfilename))) ## Seems in proper shape for OOo (at first sight) else ## Transform into URL form if (ispc) fname = canonicalize_file_name (strsplit (nfilename, filesep){end}); else fname = make_absolute_filename (strsplit (nfilename, filesep){end}); endif ## On Windows, change backslash file separator into forward slash if (strcmp (filesep, "\\")) tmp = strsplit (fname, filesep); flen = numel (tmp); tmp(2:2:2*flen) = tmp; tmp(1:2:2*flen) = "/"; filename = [ "file://" tmp{:} ]; endif endif endif else filename = xls.filename; endif try if (xls.changed > 0 && xls.changed < 3) ## Workaround: unotmp = javaObject ("com.sun.star.uno.Type", "com.sun.star.frame.XModel"); xModel = xls.workbook.queryInterface (unotmp); unotmp = javaObject ("com.sun.star.uno.Type", "com.sun.star.util.XModifiable"); xModified = xModel.queryInterface (unotmp); if (xModified.isModified ()) unotmp = ... javaObject ("com.sun.star.uno.Type", "com.sun.star.frame.XStorable"); # isReadonly() ? xStore = xls.app.xComp.queryInterface (unotmp); if (xls.changed == 2) ## Some trickery as Octave Java cannot create non-numeric arrays lProps = javaArray ("com.sun.star.beans.PropertyValue", 2); ## Set file type property [ftype, filtnam] = __get_ftype__ (filename); if (isempty (filtnam)) filtnam = "calc8"; endif lProp = javaObject ... ("com.sun.star.beans.PropertyValue", "FilterName", 0, filtnam, []); lProps(1) = lProp; ## Set "Overwrite" property lProp = ... javaObject ("com.sun.star.beans.PropertyValue", "Overwrite", 0, true, []); lProps(2) = lProp; ## OK, store file # if (isfield (xls, "nfilename")) ## Store in another file ## FIXME check if we need to close the old file # xStore.storeAsURL (xls.nfilename, lProps); # else # xStore.storeAsURL (xls.filename, lProps); xStore.storeAsURL (filename, lProps); # endif else xStore.store (); endif endif endif xls.changed = -1; ## Needed for check on properly shutting down OOo ## Workaround: unotmp = javaObject ("com.sun.star.uno.Type", "com.sun.star.frame.XModel"); xModel = xls.app.xComp.queryInterface (unotmp); unotmp = javaObject ("com.sun.star.uno.Type", "com.sun.star.util.XCloseable"); xClosbl = xModel.queryInterface (unotmp); xClosbl.close (true); unotmp = javaObject ("com.sun.star.uno.Type", "com.sun.star.frame.XDesktop"); xDesk = xls.app.aLoader.queryInterface (unotmp); xDesk.terminate(); xls.changed = 0; catch if (force) ## Force closing OOo unotmp = javaObject ("com.sun.star.uno.Type", "com.sun.star.frame.XDesktop"); xDesk = xls.app.aLoader.queryInterface (unotmp); xDesk.terminate(); else warning ("Error closing xls pointer (UNO)"); endif return end_try_catch endfunction io/inst/private/__UNO_spsh_info__.m0000644000076400010400000000267012250424672020616 0ustar PhilipAdministrators## Copyright (C) 2012,2013 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 Octave; see the file COPYING. If not, see ## . ## __UNO_spsh_info__ ## Author: Philip Nienhuis ## Created: 2012-10-12 ## Updates: ## 2012-10-12 Moved into ./private ## 2012-10-24 Style fixes ## 2013-12-06 Updated copyright strings function [sh_names] = __UNO_spsh_info__ (xls) sheets = xls.workbook.getSheets (); sheetnames = sheets.getElementNames (); ## A Java object, NOT a cell array sh_cnt = numel (sheetnames); sh_names = cell (sh_cnt, 2); for ii=1:sh_cnt sh_names(ii, 1) = sheetnames(ii); [ tr, lr, lc, rc ] = getusedrange (xls, ii); if (tr) sh_names(ii, 2) = ... sprintf ("%s:%s", calccelladdress (tr, lc), calccelladdress (lr, rc)); else sh_names(ii, 2) = "Empty or Chart"; endif endfor endfunction io/inst/private/__UNO_spsh_open__.m0000644000076400010400000001060312261077160020615 0ustar PhilipAdministrators## Copyright (C) 2012,2013 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 Octave; see the file COPYING. If not, see ## . ## __UNO_xlsopen__ - Internal function for opening a spreadsheet file using Java / OOo/LO UNO ## Author: Philip Nienhuis ## Created: 2012-10-07 ## Updates (possibly from xlsopen): ## 2011-05-18 Experimental UNO support added, incl. creating new spreadsheets ## 2012-09-02 (in UNO section) web adresses need only two consecutive slashes ## 2012-09-03 (in UNO section) replace canonicalize_file_name on non-Windows to ## make_absolute_filename (see bug #36677) ## 2012-10-24 Style fixes ## 2013-01-20 Adapted to ML-compatible Java calls ## 2013-12-06 Updated copyright strings ## 2014-01-01 First throw at input/output type filters function [ xls, xlssupport, lastintf ] = __UNO_spsh_open__ (xls, xwrite, filename, xlssupport) ## First, the file name must be transformed into a URL if (! isempty (strmatch ("file:///", filename)) || ! isempty (strmatch ("http://", filename))... || ! isempty (strmatch ("ftp://", filename)) || ! isempty (strmatch ("www://", filename))) ## Seems in proper shape for OOo (at first sight) else ## Transform into URL form. ## FIXME make_absolute_filename() doesn't work across drive(-letters) so ## until it is fixed we'll fall back on canonicalize_file_name() there if (ispc) fname = canonicalize_file_name (strsplit (filename, filesep){end}); else fname = make_absolute_filename (strsplit (filename, filesep){end}); endif ## On Windows, change backslash file separator into forward slash if (strcmp (filesep, "\\")) tmp = strsplit (fname, filesep); flen = numel (tmp); tmp(2:2:2*flen) = tmp; tmp(1:2:2*flen) = '/'; fname = [ tmp{:} ]; endif filename = [ "file://" fname ]; endif try xContext = javaMethod ("bootstrap", "com.sun.star.comp.helper.Bootstrap"); xMCF = xContext.getServiceManager (); oDesktop = xMCF.createInstanceWithContext ("com.sun.star.frame.Desktop", xContext); ## Workaround for .queryInterface(): unotmp = javaObject ("com.sun.star.uno.Type", "com.sun.star.frame.XComponentLoader"); aLoader = oDesktop.queryInterface (unotmp); ## Some trickery as Octave Java cannot create initialized arrays lProps = javaArray ("com.sun.star.beans.PropertyValue", 2); ## Set file type property [ftype, filtnam] = __get_ftype__ (filename); if (isempty (filtnam)) filtnam = "calc8"; endif lProp = javaObject ... ("com.sun.star.beans.PropertyValue", "FilterName", 0, filtnam, []); lProps(1) = lProp; ## Set hidden property lProp = javaObject ("com.sun.star.beans.PropertyValue", "Hidden", 0, true, []); lProps(2) = lProp; flags = 0; if (xwrite > 2) xComp = aLoader.loadComponentFromURL ("private:factory/scalc", "_blank", flags, lProps); else xComp = aLoader.loadComponentFromURL (filename, "_blank", flags, lProps); endif ## Workaround for .queryInterface(): unotmp = javaObject ("com.sun.star.uno.Type", "com.sun.star.sheet.XSpreadsheetDocument"); xSpdoc = xComp.queryInterface (unotmp); ## save in ods struct: xls.xtype = "UNO"; xls.workbook = xSpdoc; ## Needed to be able to close soffice in odsclose() xls.filename = filename; xls.app.xComp = xComp; ## Needed to be able to close soffice in odsclose() xls.app.aLoader = aLoader;## Needed to be able to close soffice in odsclose() xls.odfvsn = "UNO"; xlssupport += 16; lastintf = "UNO"; catch error ("Couldn't open file %s using UNO", filename); end_try_catch endfunction io/inst/read_namelist.m0000644000076400010400000002001312217071420016425 0ustar PhilipAdministrators## Copyright (C) Darien Pardinas Diaz ## ## 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 . ## S = READ_NAMELIST (FILENAME) returns the struct S containing namelists and ## variables in the file FILENAME organised in hierachical way: ## ## |--VAR1 ## |--VAR2 ## |-- NMLST_A--|... ## | |--VARNa ## | ## | |--VAR1 ## |-- NMLST_B--|--VAR2 ## | |... ## S --| ... |--VARNb ## | ## | |--VAR1 ## |-- NMLST_M--|--VAR2 ## |... ## |--VARNm ## ## Note: The function can read multidimensional variables as well. The ## function assumes that there is no more than one namelist section per ## line. At this time there is no syntax checking functionality so the ## function will crash in case of errors. ## ## Example: ## NMLST = read_namelist ("OPTIONS.nam"); ## NMLST.NAM_FRAC.XUNIF_NATURE = 0.1; ## write_namelist(NMlST, "MOD_OPTIONS.nam"); ## Written by: Darien Pardinas Diaz (darien.pardinas-diaz@monash.edu) ## Version: 1.0 ## Date: 16 Dec 2011 ## ## Released under GPL License 30/3/2013 ## ## Notes Re: Use in Octave. ## -Line 83 causes a problem. Seems to work OK if commented out.FIXED ## -Cannot find end of namelist if marker (/) is preceded by space. ## -Copes with Fortran comment (!) e.g. ## &data1 ## a = 100.0 ! length metres ## b = 25.0 ! mass kg ## / ## is read OK ## Terry Duell 31 mar 2013 function S = read_namelist (filename) S = struct (); ## Open and read the text file containing the namelists fid = fopen (filename, "r"); c = 0; lines = cell(1); ## Read all the text lines in namelist file while (! feof (fid)) line = fgetl (fid); ## Remove comments if any on the line idx = find (line == "!"); if ~isempty (idx), line = line (1:idx(1) - 1); end if (! isempty (line)), ++c; lines{c} = line; ## FIXME each time appending to a cell array is slow end end fclose(fid); ii = 0; while (ii < c); ## Find a record ++ii; line = lines{ii}; idx = find (line == "&"); if (! isempty (idx)) ## i.e. a namelist start line = line(idx(1) + 1:end); ## find next space idx = find (line == " "); if (! isempty (idx)) namelst = line(1:idx(1) - 1); line = line(idx(1) + 1:end); else namelst = line; line = []; ##TDuell 31/03/2013 Provisional fix L.102 PRN 1apr2013 endif nmlst_bdy = []; if (! isempty (line)); idx = strfind (line, "/"); endif ## Get the variable specification section while (isempty (idx) && ii < c) nmlst_bdy = [ nmlst_bdy " " line ]; ++ii; line = lines{ii}; idx = strfind (line, "/"); endwhile if (! isempty (idx) && idx(1) > 1) nmlst_bdy = [ nmlst_bdy " " line ]; endif ## Parse current namelist (set of variables) S.(namelst) = parse_namelist (nmlst_bdy); endif endwhile endfunction ## Internal function to parse the body text of a namelist section. ## Limitations: the following patterns are prohibited inside the literal ## strings: ".t." ".f." ".true." ".false." "(:)" function S = parse_namelist (strng) ## Get all .true., .t. and .false., .f. to T and F strng = regexprep (strng, '\.true\.' , "T", "ignorecase"); strng = regexprep (strng, '\.false\.', "F", "ignorecase"); strng = regexprep (strng, '\.t\.', "T", "ignorecase"); strng = regexprep (strng, '\.f\.', "F", "ignorecase"); ## Make evaluable the (:) expression in MATLAB if any strng = regexprep (strng, '\(:\)', "(1,:)"); [strng, islit] = parse_literal_strings ([strng " "]); ## Find the position of all the "=" eq_idx = find (strng == "="); nvars = length (eq_idx); arg_start = eq_idx + 1; arg_end = zeros (size (eq_idx)); vars = cell (nvars, 1); S = struct; ## Loop through every variable for kk = 1:nvars, ii = eq_idx(kk) - 1; ## Move to the left and discard blank spaces while (strng(ii) == " "); --ii; endwhile ## Now we are over the variable name or closing parentesis jj = ii; if (strng(ii) == ")"), while (strng(ii) ~= "("); --ii; endwhile --ii; ## Move to the left and discard any possible blank spaces while (strng(ii) == " "); --ii; endwhile endif ## Now we are over the last character of the variable name while (strng(ii) ~= " "); --ii; endwhile if (kk > 1); arg_end(kk - 1) = ii; endif vars{kk} = [ "S." strng(ii + 1: jj) ]; endfor arg_end(end) = length (strng); ## This variables are used in the eval function to evaluate True/False, ## so don't remove it! T = ".true."; F = ".false."; ## Loop through every variable guess variable type for kk = 1:nvars arg = strng(arg_start(kk):arg_end(kk)); arglit = islit(arg_start(kk):arg_end(kk))'; ## Remove commas in non literal string... commas = (! arglit && arg == ','); if (any (commas)) arg(commas) = " "; endif if (any (arglit)) ## We are parsing a variable that is literal string arg = [ "{" arg "};"]; elseif (! isempty (find (arg == "T" || arg == "F", 1))), ## We are parsing a boolean variable arg = [ "{" arg "};" ]; else ## We are parsing a numerical array arg = [ "[" arg "];"]; endif ## Eval the modified syntax in Matlab eval ([vars{kk} " = " arg]); endfor endfunction ## Parse the literal declarations of strings and change to Matlab syntax function [strng, is_lit] = parse_literal_strings (strng) len = length (strng); add_squote = []; ## Positions to add a scape single quote on syntax rem_dquote = []; ## Positions to remove a double quote scape on syntax ii = 1; while (ii < len) if strng(ii) == "'", ## Opening string with single quote... ++ii; while ((ii < len && strng(ii) ~= "'") || strcmp (strng(ii:ii+1), '''''')) ++ii; if strcmp (strng(ii-1:ii), ''''''), ++ii; endif endwhile endif if (strng(ii) == '"') ## Opening string with double quote... strng(ii) = "'"; ## Change to single quote ++ii; while (strng(ii) ~= '"' || strcmp (strng(ii:i+1),'""') && ii < len) ## Check for a possible single quote here if strng(ii) == "'", add_squote = [ add_squote ii ]; endif ++ii; if (strcmp (strng(ii-1:ii), '""')) rem_dquote = [ rem_dquote ii-1 ]; ++ii; endif endwhile strng(ii) = "'"; ## Change to single quote endif ++ii; endwhile for ii = 1:length (add_squote); strng = [ strng(1:add_squote(ii)) strng(add_squote(ii):end) ]; endfor for ii = 1:length(rem_dquote); strng = [ strng(1:rem_dquote(ii)-1) strng(rem_squote(ii)+1:end) ]; endfor ## Now everything should be in Matlab string syntax ## Classify syntax as literal or regular expression ii = 1; len = length (strng); is_lit = zeros(len, 1); while (ii < len) if (strng(ii) == "'") ## Opening string with single quote... is_lit(ii) = 1; ++ii; while ((ii < len && strng(ii) ~= "'") || strcmp(strng(ii:ii+1), "''")) is_lit(ii) = 1; ii = ii + 1; if (strcmp (strng(ii-1:ii), '''''')), is_lit(ii) = 1; ++ii; endif endwhile is_lit(ii) = 1; endif ++ii; endwhile endfunction io/inst/rfsearch.m0000644000076400010400000001116512261512626015432 0ustar PhilipAdministrators## Copyright (C) 2013 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 2 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 Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} @var{filename} = rsearchfile (@var{dname}, @var{fname}) ## @deftypefnx {Function File} @var{filename} = rsearchfile (@var{dname}, @var{fname}, @var{maxdepth}) ## Recursively search for file or filename pattern FNAME starting in directory ## DNAME and return the first match. ## ## @var{dname} and @var{fname} must be character strings and should conform ## to the directory name and filename requirements of your operating system. ## Optional argument @var{maxdepth} can be specified to limit the maximum search ## depth; the default value is 1 (search only in @var{dname} and subdirs of ## @var{dname}). Setting maxdepth to 0 limits the search to @var{dname}. ## Be careful with setting @var{maxdepth} to values > 3 or 4 as this can ## provoke excessive search times in densely populated directory trees. ## Keep in mind that rfsearch is a recursive function itself. ## ## Output argument @var{filename} returns the relative file path of the ## first match, relative to @var{DNAME}, or an empty character string if ## no match was found. ## ## Examples: ## ## @example ## filename = rfsearch ("/home/guest/octave", "test.fil") ## Look for file test.fil and start the search in /home/guest/octave ## @end example ## ## @example ## filename = rfsearch ("/home", "test.fil", 2) ## Look for file test.fil, start the search in /home, and if needed ## search subdirs of subdirs of /home ## @end example ## ## @seealso {dir, glob} ## ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2013-08-20 ## Updates: ## 2013-08-30 Texinfo header ## '' Input validation ## '' Change name from find_in_subdir to rsearchfile ## 2013-09-01 Input validation of purposely undocumented arg #4 ## '' Name changed to rfseach ## 2013-12-14 Texinfo header adaptations (recursion noted) ## 2014-01-03 Check for empty subdir before exploring it (L.95) function [ fpath ] = rfsearch (dname, fname, mxdpth=1, depth=0) ## Input validation if (nargin < 2) print_usage () elseif ((! ischar (dname)) || (! ischar (fname))) error ("rsearchfile: character arguments expected for DNAME and FNAME"); elseif (! isnumeric (mxdpth)) error ("Numeric value >= 0 expected for MAXDEPTH"); elseif (mxdpth < 0) warning ("rsearchfile: negative value for MAXDEPTH (%d) set to 0\n", mxdpth); mxdpth = 0; elseif (! isnumeric (depth)) print_usage ("too many or illegal arguments"); endif ## If present strip trailing filesep of dname (doesn't hurt though). ## Preserve root / if (length (dname) > 1 && strcmp (dname(min(2, end)), filesep)) dname(end:end) = ''; endif sbdir = ''; fpath = dir ([dname filesep fname '*']); if (isempty (fpath) && depth < mxdpth) ## Bump search depth ++depth; ## Get list of subdirs in current level dirlist = dir (dname); if (! isempty (dirlist)) dirlist = dirlist(find ([dirlist.isdir])); ii = 0; if (strcmp (dirlist(1).name, '.')) ## Not a root dir; discard entries '.' & '..' ii = 2; endif fpath = ''; ## Search all subdirs in current level while (++ii <= numel (dirlist) && isempty (fpath)) sbdir = [filesep dirlist(ii).name]; fpath = dir ([dname sbdir filesep fname '*']); if (isempty (fpath) && depth < mxdpth) ## Try a level deeper, if allowed. Be sure to convey current depth ## as 'find_in_subdir' is called recursively here fpath = rfsearch ([dname sbdir], fname, mxdpth, depth); endif endwhile endif endif ## Final parts if (isempty (fpath)) fpath = ''; else if (isstruct (fpath)) fpath = fpath.name; endif ## Combine and strip leading filesep fpath = [sbdir filesep fpath](2:end); endif endfunction ## rfsearch io/inst/test_spsh.m0000644000076400010400000001216312261023036015640 0ustar PhilipAdministrators## Copyright (C) 2013 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 Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} [ @var{void} ] = test_sprdsh () ## Test functionality of supported spreadsheet interfaces. ## ## test_spsh tests simply tests all interfaces that are found to be ## supported by chk_spreadsheet_support() function, one by one. ## It invokes the functions io_xls_testscript.m and io_ods_testscript.m ## for the actual testing. ## ## As it is meant to be used interactively, no output arguments ## are returned. ## ## @seealso {io_xls_testscript, io_ods_testscript} ## ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2013-04-21 ## Updates: ## 2013-12-20 Updated texinfo header & copyright strings ## '' Added OCT interface tests conditional of writing interfaces ## 2013-12-31 Extended texinfo help text function [] = test_spsh (numb = []) persistent xls_intf = {'com', 'poi', 'oox', 'jxl', 'oxs', ' - ', ' - ', 'uno'}; persistent ods_intf = {' - ', ' - ', ' - ', ' - ', ' - ', 'otk', 'jod', 'uno'}; ## Get available interfaces avail_intf = uint16 (chk_spreadsheet_support ()); ## FIXME Sort out below code so that arbitrary bit patterns can be tested ## resembling the one returned by uint16 (chk_spreadsheet_support) ##if (! isempty (numb)) ## ## Check if numb makes sense ## if (ischar (numb)) ## numb = lower (numb); ## ## First check if it is recognized in the list ofinterfaces ## if (ismember (numb, xls_intf) || ismember (numb, ods_intf)) ## idx = strmatch (numb, [xls_intf ods_intf]); ## ## It is known; now check if it's actually supported at the moment ## if (bitget (avail_intf, idx)) ## ## It is, set just that bit of avail_intf that's related to intf 'numb' ## avail_intf = bitset (uint16 (0), idx, 1); ## else ## ## It isn't, notify user ## error ("Requested interface \"%s\" presently not available\n", numb); ## endif ## else ## error ("Unknown interface - %s\n", numb); ## endif ## endif ##endif ## First all Excel xls/xlsx interfaces intf2 = ''; for ii = 1:numel (xls_intf) intfpatt = bitset (uint16 (0), ii, 1);## uint16 so more intfs can be added intfchk = bitand (intfpatt, avail_intf); intf = []; fname = 'io-test.xls'; switch intfchk case 1 ## COM (ActiveX / hidden MS-Excel) intf = intf2 = 'com'; case 2 ## POI (Apache POI) intf = 'poi'; tst_oct = 1; case 4 ## POI/OOXML (Apache POI) intf = intf2 = 'poi'; fname = 'io-test.xlsx'; case 8 ## JXL (JExcelAPI) intf = 'jxl'; case 16 ## OXS (OpenXLS/ Extentech) intf = 'oxs'; case 128 ## UNO (LibreOffice Java-UNO bridge) intf = intf2 = 'uno'; otherwise endswitch ## If present, test selected interfaces if (! isempty (intf)) printf ("\nInterface \"%s\" found.\n", upper (intf)); io_xls_testscript (intf, fname); endif ## Allow the OS some time for cleaning up sleep (0.25); endfor ## Test OCT interface if possible. Intf2 = last used in above for loop if (! isempty (intf2)) printf ("\nInterface \"OCT\"....\n"); io_xls_testscript ("OCT", 'io-test.xlsx', intf2); endif ## Next, all (OOo/LO) ods interfaces intf2 = ''; for ii = 1:numel (ods_intf) intfpatt = bitset (uint16 (0), ii, 1);## uint16 so more intfs can be added intfchk = bitand (intfpatt, avail_intf); intf = []; switch intfchk case 32 ## OTK (ODF Toolkit) intf = intf2 = 'otk' case 64 ## JOD (jOpenDocument) intf = intf2 = 'jod'; case 128 ## UNO (LibreOffice Java-UNO bridge) intf = intf2 = 'uno'; otherwise endswitch ## If present, test selected interfaces if (! isempty (intf)) printf ("\nInterface \"%s\" found.\n", upper (intf)); io_ods_testscript (intf, 'io-test.ods'); endif ## Allow the OS some time for cleaning up sleep (0.25); endfor ## Test OCT interface if possible. Intf2 = last used in above for loop if (! isempty (intf2)) printf ("\nInterface \"OCT\"....\n"); io_ods_testscript ("OCT", 'io-test.ods', intf2); endif printf ("End of test_spsh\n"); endfunction io/inst/write_namelist.m0000644000076400010400000000626312217071420016657 0ustar PhilipAdministrators## Copyright (C) Darien Pardinas Diaz ## ## 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 . ## WRITE_NAMELIST(S, FILENAME) writes a namelist data structure S to a ## file FILENAME. S should follow the following structure: ## ## |--VAR1 ## |--VAR2 ## |-- NMLST_A--|... ## | |--VARNa ## | ## | |--VAR1 ## |-- NMLST_B--|--VAR2 ## | |... ## S --| ... |--VARNb ## | ## | |--VAR1 ## |-- NMLST_M--|--VAR2 ## |... ## |--VARNm ## ## Notes: Only supports variables of type: ## Scalars, vectors and 2D numeric arrays (integers and floating points) ## Scalars and 1D boolean arrays specified as '.true.' and '.false.' strings ## Single and 1D arrays of strings ## ## Example: ## NMLST = read_namelist ("OPTIONS.nam"); ## NMLST.NAM_FRAC.XUNIF_NATURE = 0.1; ## write_namelist(NMlST, "MOD_OPTIONS.nam"); ## Written by: Darien Pardinas Diaz (darien.pardinas-diaz@monash.edu) ## Version: 1.0 ## Date: 16 Dec 2011 ## ## Released under GPL License 30/3/2013 function [ ret ] = write_namelist (S, filename) fid = fopen (filename, "w"); name_lists = fieldnames (S); n_name_lists = length(name_lists); for ii = 1:n_name_lists, ## Write individual namelist records fprintf (fid, "&%s\n", name_lists{ii}); rcrds = S.(name_lists{ii}); rcrds_name = fieldnames(rcrds); n_rcrds = length(rcrds_name); for jj = 1:n_rcrds, var = rcrds.(rcrds_name{jj}); ## Find variable type... if (iscell (var)), fprintf (fid, " %s =", rcrds_name{jj}); if (strcmp (var{1}, ".true.") || strcmp (var{1},"'.false.")), for kk = 1:length (var), fprintf (fid, " %s,", var{kk}); endfor else for kk = 1:length (var), fprintf (fid, " %s,", [ "'" var{kk} "'" ]); endfor endif fprintf (fid, "%s\n", ""); else [r, c] = size (var); if (r == 1 || c == 1) ## Variable is a scalar or vector fprintf (fid, " %s =", rcrds_name{jj}); fprintf (fid, " %g,", var); fprintf (fid, "%s\n", ""); else ## Varible is a two dimensional array for kk = 1:r, fprintf (fid, " %s(%i,:) =", rcrds_name{jj}, kk); fprintf (fid, " %g,", var(kk,:)); fprintf (fid, "%s\n", ""); endfor endif endif endfor fprintf (fid, "%s\n", "/"); endfor fclose (fid); endfunction io/inst/xls2oct.m0000644000076400010400000002400212246624514015230 0ustar PhilipAdministrators## Copyright (C) 2009,2010,2011,2012,2013 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 . ## -*- texinfo -*- ## @deftypefn {Function File} [ @var{rawarr}, @var{xls}, @var{rstatus} ] = xls2oct (@var{xls}) ## @deftypefnx {Function File} [ @var{rawarr}, @var{xls}, @var{rstatus} ] = xls2oct (@var{xls}, @var{wsh}) ## @deftypefnx {Function File} [ @var{rawarr}, @var{xls}, @var{rstatus} ] = xls2oct (@var{xls}, @var{wsh}, @var{range}) ## @deftypefnx {Function File} [ @var{rawarr}, @var{xls}, @var{rstatus} ] = xls2oct (@var{xls}, @var{wsh}, @var{range}, @var{options}) ## ## Read data contained within cell range @var{range} from worksheet @var{wsh} ## in an Excel spreadsheet file pointed to in struct @var{xls}. Gnumeric ## files can be read as well. ## ## @var{xls} is supposed to have been created earlier by xlsopen in the ## same octave session. ## ## @var{wsh} is either numerical or text, in the latter case it is ## case-sensitive and it may be max. 31 characters long. ## Note that in case of a numerical @var{wsh} this number refers to the ## position in the worksheet stack, counted from the left in an Excel ## window. The default is numerical 1, i.e. the leftmost worksheet ## in the Excel file. ## ## @var{range} is expected to be a regular spreadsheet range format, ## or "" (empty string, indicating all data in a worksheet). ## If no range is specified the occupied cell range will have to be ## determined behind the scenes first; this can take some time for the ## Java-based interfaces. Be aware that in COM/ActiveX interface the ## used range can be outdated. The Java-based interfaces are more ## reliable in this respect albeit much slower. ## ## Optional argument @var{options}, a structure, can be used to ## specify various read modes by setting option fields in the struct ## to true (1) or false (0). Currently recognized option fields are: ## ## @table @asis ## @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. The default value is 0 (FALSE). ## ## @item 'strip_array' ## Set the value of this field set to TRUE or 1 to strip the returned ## output array @var{rawarr} from empty outer columns and rows. The ## spreadsheet cell rectangle limits from where the data actually ## came will be updated. The default value is FALSE or 0 (no cropping). ## When using the COM interface, the output array is always cropped. ## @end table ## ## If only the first argument @var{xls} is specified, xls2oct will try ## to read all contents from the first = leftmost (or the only) ## worksheet (as if a range of @'' (empty string) was specified). ## ## If only two arguments are specified, xls2oct assumes the second ## argument to be @var{wsh}. In that case xls2oct will try to read ## all data contained in that worksheet. ## ## Return argument @var{rawarr} contains the raw spreadsheet cell data. ## Use parsecell() to separate numeric and text values from @var{rawarr}. ## ## Optional return argument @var{xls} contains the pointer struct, ## If any data have been read, field @var{xls}.limits contains the ## outermost column and row numbers of the actually returned cell range. ## ## Optional return argument @var{rstatus} will be set to 1 if the ## requested data have been read successfully, 0 otherwise. ## ## Erroneous data and empty cells turn up empty in @var{rawarr}. ## Date/time values in Excel are returned as numerical values. ## Note that Excel and Octave have different date base values (1/1/1900 & ## 1/1/0000, resp.) ## Be aware that Excel trims @var{rawarr} from empty outer rows & columns, ## so any returned cell array may turn out to be smaller than requested ## in @var{range}, independent of field 'formulas_as_text' in @var{options}. ## When using COM, POI, or UNO interface, formulas in cells are evaluated; if ## that fails cached values are retrieved. These may be outdated depending ## on Excel's "Automatic calculation" settings when the spreadsheet was saved. ## ## When reading from merged cells, all array elements NOT corresponding ## to the leftmost or upper Excel cell will be treated as if the ## "corresponding" Excel cells are empty. ## ## Beware: when the COM interface is used, hidden Excel invocations may be ## kept running silently in case of COM errors. ## ## Examples: ## ## @example ## A = xls2oct (xls1, '2nd_sheet', 'C3:AB40'); ## (which returns the numeric contents in range C3:AB40 in worksheet ## '2nd_sheet' from a spreadsheet file pointed to in pointer struct xls1, ## into numeric array A) ## @end example ## ## @example ## [An, xls2, status] = xls2oct (xls2, 'Third_sheet'); ## @end example ## ## @seealso {oct2xls, xlsopen, xlsclose, parsecell, xlsread, xlsfinfo, xlswrite } ## ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2010-10-16 ## Updates: ## 2009-01-03 (added OOXML support & cleaned up code. Excel ## ADDRESS function still not implemented in Apache POI) ## 2010-03-14 Updated help text ## 2010-05-31 Updated help text (delay i.c.o. empty range due to getusedrange call) ## 2010-07-28 Added option to read formulas as text strings rather than evaluated value ## 2010-08-25 Small typo in help text ## 2010-10-20 Added option fornot stripping output arrays ## 2010-11-07 More rigorous input checks. ## 2010-11-12 Moved pointer check into main func ## 2010-11-13 Catch empty sheets when no range was specified ## 2011-03-26 OpenXLS support added ## 2011-03-29 Test for proper input xls struct extended ## 2011-05-18 Experimental UNO support added ## 2011-09-08 Minor code layout ## 2012-01-26 Fixed "seealso" help string ## 2012-02-25 Fixed missing quotes in struct check L.149-153 ## 2012-02-26 Updated texinfo header help text ## 2012-06-06 Implemented "formulas_as_text" option for COM ## 2012-06-07 Replaced all tabs by double space ## 2012-10-12 Moved all interface-specific subfubcs into ./private ## 2012-10-24 Style fixes ## 2013-09-30 Native Octave (OCT) added ## 2013-10-01 Some adaptations for gnumeric ## 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 ## ## Latest subfunc update: 2012-10-12 function [ rawarr, xls, rstatus ] = xls2oct (xls, wsh=1, datrange="", spsh_opts=[]) ## Check if xls struct pointer seems valid if (~isstruct (xls)) error ("File ptr struct expected for arg @ 1"); endif test1 = ~isfield (xls, "xtype"); test1 = test1 || ~isfield (xls, "workbook"); test1 = test1 || isempty (xls.workbook); test1 = test1 || isempty (xls.app); test1 = test1 || ~ischar (xls.xtype); if test1 error ("Invalid xls file pointer struct"); endif ## Check worksheet ptr if (~(ischar (wsh) || isnumeric (wsh))) error ("Integer (index) or text (wsh name) expected for arg # 2"); endif ## Check range if (~(isempty (datrange) || ischar (datrange))) error ("Character string expected for arg # 3 (range)"); endif ## Check & setup options struct if (nargin < 4 || isempty (spsh_opts)) spsh_opts.formulas_as_text = 0; spsh_opts.strip_array = 1; ## Future options: elseif (isstruct (spsh_opts)) if (~isfield (spsh_opts, "formulas_as_text")) spsh_opts.formulas_as_text = 0; endif if (~isfield (spsh_opts, "strip_array")) spsh_opts.strip_array = 1; endif ## Future options: else error ("Structure expected for arg # 4 (options)"); endif ## Select the proper interfaces if (strcmp (xls.xtype, "COM")) ## Call Excel tru COM / ActiveX server [rawarr, xls, rstatus] = __COM_spsh2oct__ (xls, wsh, datrange, spsh_opts); elseif (strcmp (xls.xtype, "POI")) ## Read xls file tru Java POI [rawarr, xls, rstatus] = __POI_spsh2oct__ (xls, wsh, datrange, spsh_opts); elseif (strcmp (xls.xtype, "JXL")) ## Read xls file tru JExcelAPI [rawarr, xls, rstatus] = __JXL_spsh2oct__ (xls, wsh, datrange, spsh_opts); elseif (strcmp (xls.xtype, "OXS")) ## Read xls file tru OpenXLS [rawarr, xls, rstatus] = __OXS_spsh2oct__ (xls, wsh, datrange, spsh_opts); elseif (strcmp (xls.xtype, "UNO")) ## Read xls file tru OpenOffice.org UNO (Java) bridge [rawarr, xls, rstatus] = __UNO_spsh2oct__ (xls, wsh, datrange, spsh_opts); elseif (strcmp (xls.xtype, "OCT")) ## Read xls file tru native Octave if (strcmpi (xls.app, 'xlsx')) [rawarr, xls, rstatus] = __OCT_xlsx2oct__ (xls, wsh, datrange, spsh_opts); elseif (strcmpi (xls.app, 'gnumeric')) [rawarr, xls, rstatus] = __OCT_gnm2oct__ (xls, wsh, datrange); endif ##elseif ---- ## Call to next interface else error (sprintf ("xls2oct: unknown Excel .xls interface - %s.", xls.xtype)); endif ## Optionally strip empty outer rows and columns & keep track of original data location if (spsh_opts.strip_array) emptr = cellfun ('isempty', rawarr); if (all (all (emptr))) rawarr = {}; xls.limits = []; else nrows = size (rawarr, 1); ncols = size (rawarr, 2); irowt = 1; while (all (emptr(irowt, :))), irowt++; endwhile irowb = nrows; while (all (emptr(irowb, :))), irowb--; endwhile icoll = 1; while (all (emptr(:, icoll))), icoll++; endwhile icolr = ncols; while (all (emptr(:, icolr))), icolr--; endwhile ## Crop output cell array and update limits rawarr = rawarr(irowt:irowb, icoll:icolr); xls.limits = xls.limits + [icoll-1, icolr-ncols; irowt-1, irowb-nrows]; endif endif endfunction io/inst/xlsclose.m0000644000076400010400000001466712261032720015473 0ustar PhilipAdministrators## Copyright (C) 2009,2010,2011,2012,2013 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 . ## -*- texinfo -*- ## @deftypefn {Function File} [@var{xls}] = xlsclose (@var{xls}) ## @deftypefnx {Function File} [@var{xls}] = xlsclose (@var{xls}, @var{filename}) ## @deftypefnx {Function File} [@var{xls}] = xlsclose (@var{xls}, "FORCE") ## Close the Excel spreadsheet pointed to in struct @var{xls}, if needed ## write the file to disk. Based on information contained in @var{xls}, ## xlsclose will determine if the file should be written to disk. ## ## If no errors occured during writing, the xls file pointer struct will be ## reset and -if COM interface was used- ActiveX/Excel will be closed. ## However if errors occurred, the file pinter will be untouched so you can ## clean up before a next try with xlsclose(). ## Be warned that until xlsopen is called again with the same @var{xls} pointer ## struct, hidden Excel or Java applications with associated (possibly large) ## memory chunks are kept in memory, taking up resources. ## If (string) argument "FORCE" is supplied, the file pointer will be reset ## regardless, whether the possibly modified file has been saved successfully ## or not. Hidden Excel (COM) or OpenOffice.org (UNO) invocations may live on, ## possibly even impeding proper shutdown of Octave. ## ## @var{filename} can be used to write changed spreadsheet files to ## 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. ## ## @var{xls} must be a valid pointer struct made by xlsopen() in the same ## octave session. ## ## Examples: ## ## @example ## xls1 = xlsclose (xls1); ## (Close spreadsheet file pointed to in pointer struct xls1; xls1 is reset) ## @end example ## ## @seealso {xlsopen, xlsread, xlswrite, xls2oct, oct2xls, xlsfinfo} ## ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2009-11-29 ## Updates: ## 2010-01-03 (checked OOXML support) ## 2010-08-25 See also: xlsopen (instead of xlsclose) ## 2010-10-20 Improved tracking of file changes and need to write it to disk ## 2010-10-27 Various changes to catch errors when writing to disk; ## " Added input arg "keepxls" for use with xlswrite.m to save the ## " untouched file ptr struct in case of errors rather than wipe it ## 2010-11-12 Replaced 'keepxls' by new filename arg; catch write errors and ## always keep file pointer in case of write errors ## 2011-03-26 Added OpenXLS support ## 2011-05-18 Added experimental UNO support, incl. saving newly created files ## 2011-09-08 Bug fix in check for filename input arg ## 2012-01-26 Fixed "seealso" help string ## 2012-09-03 (in UNO sections) replace canonicalize_file_name on non-Windows to ## make_absolute_filename (see bug #36677) ## '' (in UNO section) web adresses need only two consecutive slashes ## 2012-10-12 Move most interface-specific code to ./private subfuncs ## '' Move "file ptr preserved" message to proper else clause ## 2012-10-24 Style fixes ## 2012-12-18 Improved error/warning messages ## 2013-09-30 OCT interface added ## 2013-10-01 Warn for empty struct input ## 2013-12-29 Style fixes ## 2014-01-01 Style fixes function [ xls ] = xlsclose (xls, varargs) if (isempty (xls)) warning ("xlsclose: file pointer struct was already closed"); return endif force = 0; if (nargin > 1) for ii=2:nargin if (strcmpi (varargin{ii}, "force")) ## Close .xls anyway even if write errors occur force = 1; ## Interface-specific clauses here: elseif (! isempty (strfind (tolower (varargin{ii}), "."))) ## Apparently a file name. First some checks.... if (xls.changed == 0 || xls.changed > 2) warning ("xlsclose: file %s wasn't changed, new filename ignored.", xls.filename); elseif (strcmp (xls.xtype, "JXL")) error ("xlsclose: JXL doesn't support changing filename, new filename ignored."); elseif (! ((strcmp (xls.xtype, "COM") || strcmp (xls.xtype, "UNO")) ... && isempty (strfind ( lower (filename), ".xls")))) # Excel/ActiveX && OOo (UNO bridge) will write any valid filetype; POI/JXL/OXS need .xls[x] error ("xlsclose: .xls or .xlsx suffix lacking in filename %s", filename); else ## For multi-user environments, uncomment below AND relevant stanza in xlsopen ## In case of COM, be sure to first close the open workbook ##if (strcmp (xls.xtype, 'COM')) ## xls.app.Application.DisplayAlerts = 0; ## xls.workbook.close(); ## xls.app.Application.DisplayAlerts = 0; ##endif ## Preprocessing / -checking ready. Assign filename arg to file ptr struct xls.nfilename = filename; endif endif endfor endif if (strcmp (xls.xtype, "COM")) xls = __COM_spsh_close__ (xls); elseif (strcmp (xls.xtype, "POI")) xls = __POI_spsh_close__ (xls); elseif (strcmp (xls.xtype, "JXL")) xls = __JXL_spsh_close__ (xls); elseif (strcmp (xls.xtype, "OXS")) xls = __OXS_spsh_close__ (xls); elseif (strcmp (xls.xtype, "UNO")) xls = __UNO_spsh_close__ (xls, force); elseif (strcmp (xls.xtype, "OCT")) xls = __OCT_spsh_close__ (xls); ## elseif endif if (xls.changed && xls.changed < 3) warning (sprintf ("xlsclose: file %s could not be saved. Read-only or in use elsewhere?", ... xls.filename)); if (force) xls = []; else printf ("(File pointer preserved. Try saving again later...)\n"); endif else xls = []; endif endfunction io/inst/xlsfinfo.m0000644000076400010400000001517412260076204015465 0ustar PhilipAdministrators## Copyright (C) 2009,2010,2011,2012,2013 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 . ## -*- texinfo -*- ## @deftypefn {Function File} [@var{filetype}] = xlsfinfo (@var{filename} [, @var{reqintf}]) ## @deftypefnx {Function File} [@var{filetype}, @var{sh_names}] = xlsfinfo (@var{filename} [, @var{reqintf}]) ## @deftypefnx {Function File} [@var{filetype}, @var{sh_names}, @var{fformat}] = xlsfinfo (@var{filename} [, @var{reqintf}]) ## Query Excel spreadsheet file @var{filename} for some info about its ## contents. ## ## If @var{filename} is a recognizable Excel spreadsheet file, ## @var{filetype} returns the string "Microsoft Excel Spreadsheet", or ## @'' (empty string) otherwise. ## ## If @var{filename} is a recognizable Excel spreadsheet file, optional ## argument @var{sh_names} contains a list (cell array) of sheet ## names (and in case Excel is installed: sheet types) contained in ## @var{filename}, in the order (from left to right) in which they occur ## in the sheet stack. ## ## Optional return value @var{fformat} currently returns @'' (empty ## string) unless @var{filename} is a readable Excel 97-2003 .xls file or ## an Excel 2007 .xlsx / .xlsb file in which case @var{fformat} is set to ## "xlWorkbookNormal". Excel 95 .xls files can only be read through the JXL ## (JExcelAPI) or UNO (OpenOffice.org) Java-based interfaces. ## ## If no return arguments are specified the sheet names are echoed to the ## terminal screen; in case of Java interfaces for each sheet the actual ## occupied data range is echoed as well. The occupied cell range will have ## to be determined behind the scenes first; this can take some time for the ## Java-based interfaces. ## ## If multiple xls interfaces have been installed, @var{reqintf} can be ## specified. This can sometimes be handy, e.g. to get an idea of occupied ## cell ranges in each worksheet using different interfaces (due to cached ## 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'. ## ## Examples: ## ## @example ## exist = xlsfinfo ('test4.xls'); ## (Just checks if file test4.xls is a readable Excel file) ## @end example ## ## @example ## [exist, names] = xlsfinfo ('test4.xls'); ## (Checks if file test4.xls is a readable Excel file and return a ## list of sheet names and -types) ## @end example ## ## @seealso {oct2xls, xlsread, xls2oct, xlswrite} ## ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2009-10-27 ## Updates: ## 2009-01-01 Echo sheet names to screen, request interface type) ## 2010-03-21 Better tabulated output; occupied date range per sheet echoed ## for Java interfaces (though it may be a bit off in case of JXL) ## 2010-05-31 Added remark about delays when determining occupied data range ## 2010-08-25 Improved help text (Excel file types) ## 2010-10-06 Added ";" to str2 declaration ## '' Added occupied range echo for COM interface (may be a bit off too) ## 2010-10-10 Made output arg2 contain only address ranges (or other sheet type names) ## 2010-11-01 Added other file type strings for return arg #3 (fformat) ## 2011-03-26 Added OpenXLS support ## 2011-05-18 Experimental UNO support ## 2011-09-08 Some code simplifications ## 2012-01-26 Fixed "seealso" help string ## 2012-02-25 Added info on occupied ranges to sh_names outarg for all interfaces ## 2012-10-12 Moved all interface-specific code into ./private subfuncs ## 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 function [ filetype, sh_names, fformat ] = xlsfinfo (filename, reqintf=[]) persistent str2; str2 = " "; ## 33 spaces persistent lstr2; lstr2 = length (str2); xls = xlsopen (filename, 0, reqintf); if (isempty (xls)) return; endif toscreen = nargout < 1; ## If any valid xls-pointer struct has been returned, it must be a valid ## spreadsheet. Find out what format [~, ~, ext] = fileparts (xls.filename); switch ext case {"xls", "xlsx", "xlsm", "xlsb"} filetype = "Microsoft Excel Spreadsheet"; case "ods" filetype = "OpenOffice.org Calc spreadsheet"; case "gnumeric" filetype = "Gnumeric spreadsheet"; otherwise endswitch fformat = ""; if (strcmp (xls.xtype, "COM")) [sh_names] = __COM_spsh_info__ (xls); elseif (strcmp (xls.xtype, "POI")) [sh_names] = __POI_spsh_info__ (xls); elseif (strcmp (xls.xtype, "JXL")) [sh_names] = __JXL_spsh_info__ (xls); elseif (strcmp (xls.xtype, "OXS")) [sh_names] = __OXS_spsh_info__ (xls); elseif (strcmp (xls.xtype, "UNO")) [sh_names] = __UNO_spsh_info__ (xls); elseif (strcmp (xls.xtype, "OCT")) [sh_names] = __OCT_spsh_info__ (xls); ##elseif else error (sprintf ("xlsfinfo: unknown Excel .xls interface - %s.", xls.xtype)); endif sh_cnt = size (sh_names, 1); if (toscreen) ## Echo sheet names to screen for ii=1:sh_cnt str1 = sprintf ("%3d: %s", ii, sh_names{ii, 1}); if (index (sh_names{ii, 2}, ":")) str3 = [ "(Used range ~ " sh_names{ii, 2} ")" ]; else str3 = sh_names{ii, 2}; endif printf ("%s%s%s\n", str1, str2(1:lstr2-length (sh_names{ii, 1})), str3); endfor else if (sh_cnt > 0) if (strcmpi (xls.filename(end-2:end), "xls")) fformat = "xlWorkbookNormal"; elseif (strcmpi (xls.filename(end-2:end), "csv")) fformat = "xlCSV"; ## Works only with COM elseif (strcmpi (xls.filename(end-3:end-1), "xls")) fformat = "xlOpenXMLWorkbook"; elseif (strmatch ('htm', lower (xls.filename(end-3:end)))) fformat = "xlHtml"; ## Works only with COM else fformat = ""; endif endif endif xlsclose (xls); endfunction io/inst/xlsopen.m0000644000076400010400000004154012261102350015312 0ustar PhilipAdministrators## Copyright (C) 2009,2010,2011,2012,2013 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 2 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 Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} @var{xls} = xlsopen (@var{filename}) ## @deftypefnx {Function File} @var{xls} = xlsopen (@var{filename}, @var{readwrite}) ## @deftypefnx {Function File} @var{xls} = xlsopen (@var{filename}, @var{readwrite}, @var{reqintf}) ## Get a pointer to an Excel spreadsheet in the form of return argument ## (file pointer struct) @var{xls}. After processing the spreadsheet, ## the file pointer must be explicitly closed by calling xlsclose(). ## ## 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 ## 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. ## ## @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 ## that your installed Excel version can read AND write; the same goes for UNO ## (OpenOffice.org). Using the other Java interfaces, only .xls or .xlsx are ## 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. ## ## Optional input argument @var{reqintf} can be used to override the Excel ## interface that otherwise is automatically selected by xlsopen. Currently ## implemented interfaces (in order of preference) are 'COM' (Excel/COM), ## 'POI' (Java/Apache POI), 'JXL' (Java/JExcelAPI), 'OXS' (Java/OpenXLS), ## 'UNO' (Java/OpenOffice.org - EXPERIMENTAL!), or 'OCT' (native Octave). ## In most situations this parameter is unneeded as xlsopen automatically ## selects the most useful interface present. ## ## Beware: Excel invocations may be left running invisibly in case of COM ## errors or forgetting to close the file pointer. Similarly for OpenOffice.org ## which may even prevent Octave from being closed. ## ## Examples: ## ## @example ## xls = xlsopen ('test1.xls'); ## (get a pointer for reading from spreadsheet test1.xls) ## ## xls = xlsopen ('test2.xls', 1, 'POI'); ## (as above, indicate test2.xls will be written to; in this case using Java ## and the Apache POI interface are requested) ## @end example ## ## @seealso {xlsclose, xlsread, xlswrite, xls2oct, oct2xls, xlsfinfo} ## ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2009-11-29 ## Updates: ## 2010-01-03 Added OOXML support ## 2010-01-10 Changed (java) interface preference order to COM->POI->JXL ## 2010-01-16 Removed echoeing debug info in POI stanza ## 2010-03-01 Removed javaclasspath check for rt.jar ## 2010-03-14 Fixed check on xwrite flag lines 204+, if xlsopen fails xls ptr ## should be [] ## 2010-08-25 Improved help text ## 2010-09-27 Improved POI help message for unrecognized .xls format to hint for BIFF5/JXL ## 2010-10-20 Improved code for tracking changes to new/existing files ## '' Lots of code cleanup, improved error checking and catching ## '' Implemented fallback to JXL if POI can't read a file. ## 2010-10-30 More fine-grained file existence/writable checks ## 2010-11-01 Added .Application.DisplayAlerts=0 in COM section to avoid Excel pop-ups ## 2010-11-05 Option for multiple requested interface types (cell array) ## '' Bug fix: JXL fallback from POI for BIFF5 is only useful for reading ## 2010-11-05 Slight change to reporting to screen ## 2010-11-08 Tested with POI 3.7 (OK) ## 2010-11-10 Texinfo header updated ## 2010-12-01 Small bugfix - reset xlssupport in l. 102 ## 2010-12-06 Textual changes to info header ## 2011-03-26 OpenXLS support added ## 2011-05-18 Experimental UNO support added, incl. creating new spreadsheets ## 2011-05-22 Textual changes in header ## 2011-05-29 Cleanup of comments & messages ## 2011-09-03 Reset chkintf to [] if no xls support was discovered (to allow ## rediscovery of interfaces between xlsopen calls, e.g. javaclasspath changes) ## 2011-09-08 Minor code cleanup ## 2012-01-26 Fixed "seealso" help string ## 2012-06-06 Improved interface detection logic. No more messages if same interface is ## requested & used consecutively ## 2012-06-07 Fixed mixed-up lastintf assignments for POI and JXL ## 2012-09-02 (in UNO section) web adresses need only two consecutive slashes ## 2012-09-03 (in UNO section) replace canonicalize_file_name on non-Windows to ## make_absolute_filename (see bug #36677) ## 2012-10-07 Moved subfunc getxlsinterfaces to ./private ## '' Moved all interface-specific file open stanzas to separate ./private funcs ## 2012-10-24 Style fixes ## 2012-12-18 Improved warning/error messages ## 2013-02-24 Temporarily disabled OXS and UNO ## 2013-05-16 Fix fallback to JXL for OOXML files ## 2013-06-18 Re-enabled OXS and UNO ## 2013-09-01 Allow input of filename w/o suffix for Excel files ## 2013-09-02 Better fix for undue fallback to JXL for OOXML files ## '' Fixed wrong error message about OXS and UNO not being supported ## 2013-09-30 Native Octave interface ("OCT") for reading .xlsx ## '' Adapted header to OCT (also Excel 2013 is supported) ## 2013-10-01 Some adaptations for gnumeric ## 2013-10-20 Overhauled file extension detection logic ## 2013-11-03 Improved interface selection (fix a.o., fallback to JXL for xlsx) ## 2013-11-04 Catch attempts to write with only OCT interface ## 2013-12-01 Add support for ODS (Excel 2007+ and OpenOffice.org/LibreOffice support it) ## 2013-12-27 Use one variable for processed file type ## '' Style fixes ## 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 function [ xls ] = xlsopen (filename, xwrite=0, reqinterface=[]) persistent xlsinterfaces; persistent chkintf; persistent lastintf; ## xlsinterfaces. = [] (not yet checked), 0 (found to be unsupported) or 1 (OK) if (isempty (chkintf)); chkintf = 1; xlsinterfaces = struct ('COM', [], 'POI', [], 'JXL', [], 'OXS', [], 'UNO', [], "OCT", 1); endif if (isempty (lastintf)) lastintf = "---"; endif xlsintf_cnt = 1; xlssupport = 0; if (nargout < 1) usage ("XLS = xlsopen (Xlfile [, Rw] [, reqintf]). But no return argument specified!"); endif if (! (islogical (xwrite) || isnumeric (xwrite))) usage ("xlsopen.m: numerical or logical value expected for arg ## 2 (readwrite)") endif if (! isempty (reqinterface)) if (! (ischar (reqinterface) || iscell (reqinterface))) usage ("Arg ## 3 (interface) not recognized - character value required"); endif ## Turn arg3 into cell array if needed if (! iscell (reqinterface)) reqinterface = {reqinterface}; endif ## Check if previously used interface matches a requested interface if (isempty (regexpi (reqinterface, lastintf, 'once'){1}) || ! xlsinterfaces.(upper (reqinterface{1}))) ## New interface requested xlsinterfaces.COM = 0; xlsinterfaces.POI = 0; xlsinterfaces.JXL = 0; xlsinterfaces.OXS = 0; xlsinterfaces.UNO = 0; xlsinterfaces.OCT = 0; for ii=1:numel (reqinterface) reqintf = toupper (reqinterface {ii}); ## Try to invoke requested interface(s) for this call. Check if it ## is supported anyway by emptying the corresponding var. if (strcmpi (reqintf, 'COM')) xlsinterfaces.COM = []; elseif (strcmpi (reqintf, 'POI')) xlsinterfaces.POI = []; elseif (strcmpi (reqintf, 'JXL')) xlsinterfaces.JXL = []; elseif (strcmpi (reqintf, 'OXS')) xlsinterfaces.OXS = []; elseif (strcmpi (reqintf, 'UNO')) xlsinterfaces.UNO = []; elseif (strcmpi (reqintf, 'OCT')) xlsinterfaces.OCT = []; else usage (sprintf (["xlsopen.m: unknown .xls interface \"%s\" requested.\n" "Only COM, POI, JXL, OXS, UNO, or OCT) supported\n"], reqinterface{})); endif endfor printf ("Checking requested interface(s):\n"); xlsinterfaces = getxlsinterfaces (xlsinterfaces); ## Well, is/are the requested interface(s) supported on the system? xlsintf_cnt = 0; for ii=1:numel (reqinterface) if (! xlsinterfaces.(toupper (reqinterface{ii}))) ## No it aint printf ("%s is not supported.\n", upper (reqinterface{ii})); else ++xlsintf_cnt; endif endfor ## Reset interface check indicator if no requested support found if (! xlsintf_cnt) chkintf = []; xls = []; return endif endif endif ## Check if Excel file exists. First check for (supported) file name suffix: ftype = 0; has_suffix = 1; [sfxpos, ~, ~, ext] = regexpi (filename, '(\.xlsx?|\.gnumeric|\.ods|\.csv)'); if (! isempty (sfxpos)) ext = lower (ext{end}); ## .xls or .xls[x,m,b] or .gnumeric is there, but at the right(most) position? if (sfxpos(end) <= length (filename) - length (ext)) ## Apparently not, or it is an unrecognized extension ## If xwrite = 0, check file suffix, else add .xls has_suffix = 0; else switch ext case ".xls" ## Regular (binary) BIFF ftype = 1; case {".xlsx", ".xlsm", ".xlsb"} ## Zipped XML / OOXML. Catches xlsx, xlsb, xlsm ftype = 2; case "ods" ## ODS 1.2 (Excel 2007+ & OOo/LO can read ODS) ftype = 3; case ".gnumeric" ## Zipped XML / gnumeric ftype = 5; case ".csv" ## csv. Detected for xlsread afficionados ftype = 6; otherwise warning ("xlsopen: file type ('%s' extension) not supported", ext); endswitch endif else has_suffix = 0; endif ## Var readwrite 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. ## Adapt file open mode for readwrite argument if (xwrite) ## Catch attempts to write gnumeric 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) filename = [filename ".xls"]; endif else fmode = 'rb'; if (! has_suffix) ## Try to find find existing file name. We ignore .gnumeric filnm = dir ([filename ".xls*"]); if (! isempty (filnm)) ## Simply choose the first one if (isstruct (filnm)) filename = filnm(1).name; else filename = filnm; endif endif endif endif fid = fopen (filename, fmode); if (fid < 0) ## File doesn't exist... if (! xwrite) ## ...which obviously is fatal for reading... error ( sprintf ("xlsopen.m: file %s not found\n", filename)); else ## ...but for writing, we need more info: fid = fopen (filename, 'rb'); ## Check if it exists at all... if (fid < 0) ## File didn't exist yet. Simply create it printf ("Creating file %s\n", filename); xwrite = 3; else ## File exists, but isn't writable => Error fclose (fid); ## Do not forget to close the handle neatly error (sprintf ("xlsopen.m: write mode requested but file %s is not writable\n", filename)) endif endif else ## Close file anyway to avoid COM or Java errors fclose (fid); endif ## Check for the various Excel interfaces. No problem if they've already ## been checked, getxlsinterfaces (far below) just returns immediately then. xlsinterfaces = getxlsinterfaces (xlsinterfaces); ## Initialize file ptr struct xls = struct ("xtype", 'NONE', "app", [], "filename", [], "workbook", [], "changed", 0, "limits", []); ## Keep track of which interface is selected xlssupport = 0; ## Interface preference order is defined below: currently COM -> POI -> JXL -> OXS -> UNO -> OCT ## ftype (file type) is conveyed depending on interface capabilities if ((! xlssupport) && xlsinterfaces.COM && (ftype != 5)) ## Excel functioning has been tested above & file exists, so we just invoke it. [ xls, xlssupport, lastintf ] = __COM_spsh_open__ (xls, xwrite, filename, xlssupport); endif if ((! xlssupport) && xlsinterfaces.POI && (ftype <= 2)) [ xls, xlssupport, lastintf ] = __POI_spsh_open__ (xls, xwrite, filename, xlssupport, ftype, xlsinterfaces); endif if ((! xlssupport) && xlsinterfaces.JXL && ftype == 1) [ xls, xlssupport, lastintf ] = __JXL_spsh_open__ (xls, xwrite, filename, xlssupport, ftype); endif if ((! xlssupport) && xlsinterfaces.OXS && ftype <= 2) [ xls, xlssupport, lastintf ] = __OXS_spsh_open__ (xls, xwrite, filename, xlssupport, ftype); endif if ((! xlssupport) && xlsinterfaces.UNO && (ftype != 5)) ## Warn for LO / OOo stubbornness if (ftype == 0 || ftype == 5 || ftype == 6) warning ("UNO interface will write ODS format for unsupported file extensions") endif [ xls, xlssupport, lastintf ] = __UNO_spsh_open__ (xls, xwrite, filename, xlssupport); endif if ((! xlssupport) && xlsinterfaces.OCT && ... (ftype == 2 || ftype == 3 || ftype == 5)) [ xls, xlssupport, lastintf ] = __OCT_spsh_open__ (xls, xwrite, filename, xlssupport, ftype); endif ## if ## ---- other interfaces ## endif ## Rounding up. If none of the xlsinterfaces is supported we're out of luck. if (! xlssupport) if (isempty (reqinterface)) ## If no suitable interface was detected (COM or UNO can read .csv), handle ## .csv in xlsread (as that's where Matlab n00bs would expect .csv support) if (ftype != 6) ## This message is appended after message from getxlsinterfaces() printf ("None.\n"); warning ("xlsopen.m: no support for spreadsheet I/O"); endif else ## No match between filte type & interface found warning ("xlsopen.m: file type not supported by %s %s %s %s %s %s", reqinterface{:}); endif xls = []; ## Reset found interfaces for re-testing in the next call. Add interfaces if needed. chkintf = []; else ## From here on xwrite is tracked via xls.changed in the various lower ## level r/w routines xls.changed = xwrite; ## xls.changed = 0 (existing/only read from), 1 (existing/data added), 2 (new, ## data added) or 3 (pristine, no data added). ## Until something was written to existing files we keep status "unchanged". if (xls.changed == 1) xls.changed = 0; endif endif endfunction io/inst/xlsread.m0000644000076400010400000002363412257317560015310 0ustar PhilipAdministrators## Copyright (C) 2009,2010,2011,2012,2013 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 ## 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 . ## -*- texinfo -*- ## @deftypefn {Function File} [@var{numarr}, @var{txtarr}, @var{rawarr}, @var{limits}] = xlsread (@var{filename}) ## @deftypefnx {Function File} [@var{numarr}, @var{txtarr}, @var{rawarr}, @var{limits}] = xlsread (@var{filename}, @var{wsh}) ## @deftypefnx {Function File} [@var{numarr}, @var{txtarr}, @var{rawarr}, @var{limits}] = xlsread (@var{filename}, @var{range}) ## @deftypefnx {Function File} [@var{numarr}, @var{txtarr}, @var{rawarr}, @var{limits}] = xlsread (@var{filename}, @var{wsh}, @var{range}) ## @deftypefnx {Function File} [@var{numarr}, @var{txtarr}, @var{rawarr}, @var{limits}] = xlsread (@var{filename}, @var{wsh}, @var{range}, @var{reqintf}) ## ## Read data contained in range @var{range} from worksheet @var{wsh} ## in Excel spreadsheet file @var{filename}. ## Return argument @var{numarr} contains the numeric data, optional ## return arguments @var{txtarr} and @var{rawarr} contain text strings ## and the raw spreadsheet cell data, respectively. Return argument ## @var{limits} contains the outer column/row numbers of the read ## spreadsheet range where @var{numarr}, @var{txtarr} and @var{rawarr} ## have come from (remember, xlsread trims outer rows and columns). ## ## If @var{filename} does not contain any directory, the file is ## 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.). ## ## @var{range} is expected to be a regular spreadsheet range format, ## or "" (empty string, indicating all data in a worksheet). ## If no range is specified the occupied cell range will have to be ## determined behind the scenes first; this can take some time for the ## Java-based interfaces (but the results may be more reliable than ## that of ActiveX/COM). ## ## @var{wsh} is either numerical or text; in the latter case it is ## case-sensitive and it may be max. 31 characters long. ## Note that in case of a numerical @var{wsh} this number refers to the ## position in the worksheet stack, counted from the left in an Excel ## window. The default is numerical 1, i.e. the leftmost worksheet ## in the Excel file. ## ## If only the first argument is specified, xlsread will try to read ## all contents (as if a range of @'' (empty string) was specified) ## from the first = leftmost (or the only) worksheet ## ## If only two arguments are specified, xlsread assumes the second ## argument to be @var{range} if it is a string argument and contains ## a ":" or if it is @'' (empty string), and in those cases assumes ## the data must be read from the first worksheet (not necessarily ## Sheet1! but the leftmost sheet). ## ## However, if only two arguments are specified and the second argument ## is numeric or a text string that does not contain a ":", it is ## assumed to be @var{wsh} and to refer to a worksheet. In that case ## xlsread tries to read all data contained in that worksheet. ## ## 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 ## 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. ## ## 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. ## @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}. ## ## When reading from merged cells, all array elements NOT corresponding ## to the leftmost or upper Excel cell will be treated as if the ## "corresponding" Excel cells are empty. ## ## xlsread is just a wrapper for a collection of scripts that find out ## the interface to be used (COM, Java/POI, Java/JXL Java/OXS, Java/UNO, ## OCT) and do the actual reading. For each call to xlsread the interface ## must be started and the Excel file read into memory. When reading ## multiple ranges (in optionally multiple worksheets) a significant speed ## boost can be obtained by invoking those scripts directly as in: ## xlsopen / xls2oct [/ parsecell] / ... / xlsclose ## ## Beware: when using the COM interface, hidden Excel invocations may be ## kept running silently if not closed explicitly. ## ## Examples: ## ## @example ## A = xlsread ('test4.xls', '2nd_sheet', 'C3:AB40'); ## (which returns the numeric contents in range C3:AB40 in worksheet ## '2nd_sheet' from file test4.xls into numeric array A) ## @end example ## ## @example ## [An, Tn, Ra, limits] = xlsread ('Sales2009.xls', 'Third_sheet'); ## (which returns all data in worksheet 'Third_sheet' in file 'Sales2009.xls' ## into array An, the text data into array Tn, the raw cell data into ## cell array Ra and the ranges from where the actual data came in limits) ## @end example ## ## @example ## numarr = xlsread ('Sales2010.xls', 4, [], @{'JXL', 'COM'@}); ## (Read all data from 4th worksheet in file Sales2010.xls using either JXL ## or COM interface (i.e, exclude POI interface). ## @end example ## ## @seealso {xlswrite, xlsopen, xls2oct, xlsclose, xlsfinfo, oct2xls} ## ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2009-10-16 ## Updates: ## 2009-12-29 bug fixes ## 2010-01-12 added unwind_protect to get rid of stray Excel invocations i.c.o. COM errors ## 2010-05-31 Updated help text (delays i.c.o. empty range due to getusedrange call) ## 2010-08-18 Added check for existence of xls after call to xlsopen to ## '' avoid unneeded error message clutter ## 2010-08-25 Improved help text, esp. sections Excel file types and interfaces ## 2010-10-20 Dropped wiping xls.limits for COM (nowadays COM can return those) ## 2010-10-21 Formally added 'BASIC' option as synonym for 'JXL' ## 2010-11-05 Updated help text ## 2010-11-13 Added some input checks ## 2011-04-11 Return upon empty xls struct from xlsopen() ## 2011-04-17 Suppress xlsopen messages (";" was missing) ## 2011-09-08 Minor code cleanup; included UNO & OXS support in test ## 2012-01-26 Fixed "seealso" help string ## 2012-03-07 Updated texinfo help header ## 2012-10-24 Style fixes ## 2013-09-24 Drop requirement of having at least one output arg ## 2013-09-27 Check for proper filename in input ## 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 function [ numarr, txtarr, rawarr, lims ] = xlsread (fn, wsh, datrange, reqintf=[]) rstatus = 0; if (nargin < 1) error ("xlsread: no input arguments specified") numarr = []; txtarr={}; rawarr = {}; return elseif (! ischar (fn)) error ("filename (text string) expected for argument #1, not a %s", class (fn)); elseif (nargin == 1) wsh = 1; datrange = ""; elseif (nargin == 2) ## Find out whether 2nd argument = worksheet or range if (isnumeric (wsh) || (isempty (findstr (wsh, ":" )) && ~isempty (wsh))) ## Apparently a worksheet specified datrange = ""; else ## Range specified datrange = wsh; wsh = 1; endif endif ## A small gesture for Matlab compatibility. JExcelAPI supports BIFF5. if (! isempty (reqintf) && ischar (reqintf) && strcmpi (reqintf, "BASIC")) reqintf = {"JXL"}; printf ("(BASIC (BIFF5) support request translated to JXL)\n"); endif ## Checks done. Get raw data into cell array "rawarr". xlsopen finds out ## what interface to use. If none found, just return as xlsopen will complain enough unwind_protect # Needed to catch COM errors & able to close stray Excel invocations ## Get pointer array to Excel file xls_ok = 0; xls = xlsopen (fn, 0, reqintf); if (! isempty (xls)) xls_ok = 1; else ## Convenience for scripts from lazy Matlab users (see bug #40993): [~, ~, ext] = fileparts (fn); if strcmpi (fn, ".csv") numarr = csvread (fn, 1, datrange); endif return endif ## Get data from Excel file & return handle [rawarr, xls, rstatus] = xls2oct (xls, wsh, datrange); ## Save some results before xls is wiped rawlimits = xls.limits; xtype = xls.xtype; if (rstatus) [numarr, txtarr, lims] = parsecell (rawarr, rawlimits); else rawarr = {}; numarr = []; txtarr = {}; endif unwind_protect_cleanup ## Close Excel file if (xls_ok) xls = xlsclose (xls); endif end_unwind_protect endfunction io/inst/xlswrite.m0000644000076400010400000001727012250646222015517 0ustar PhilipAdministrators## Copyright (C) 2009,2010,2011,2012,2013 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 . ## -*- texinfo -*- ## @deftypefn {Function File} @var{rstatus} = xlswrite (@var{filename}, @var{arr}) ## @deftypefnx {Function File} @var{rstatus} = xlswrite (@var{filename}, @var{arr}, @var{wsh}) ## @deftypefnx {Function File} @var{rstatus} = xlswrite (@var{filename}, @var{arr}, @var{wsh}, @var{range}) ## @deftypefnx {Function File} @var{rstatus} = xlswrite (@var{filename}, @var{arr}, @var{wsh}, @var{range}, @var{reqintf}) ## Add data in 1D/2D array @var{arr} to worksheet @var{wsh} in Excel ## spreadsheet file @var{filename} in cell range @var{range}. ## ## @var{rstatus} returns 1 if write succeeded, 0 otherwise. ## ## @var{filename} must be a valid .xls Excel file name (including file ## name extension). If @var{filename} does not contain any directory path, ## the file is saved in the current directory. ## ## @var{arr} can be any 1D or 2D array containing numerical or character ## data (cellstr) except complex. Mixed numeric/text arrays can only be ## cell arrays. ## ## If only 3 arguments are given, the 3rd is assumed to be a spreadsheet ## range if it contains a ":" or is a completely empty string (corresponding ## to A1:IV65336 for regular .xls or A1:XFD1048576 for OOXML .xlsx). The ## 3rd argument is assumed to refer to a worksheet if it is a numeric value ## or a non-empty text string not containing ":" ## ## @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. ## 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). ## When new worksheets are to be added to the Excel file, they are ## inserted to the right of all existing worksheets. The pointer to the ## "active" sheet (shown when Excel opens the file) remains untouched. ## ## @var{range} is expected to be a regular spreadsheet range. ## Data is added to the worksheet; existing data in the requested ## range will be overwritten. ## Array @var{arr} will be clipped at the right and/or bottom if its size ## is bigger than can be accommodated in @var{range}. ## If @var{arr} is smaller than the @var{range} allows, it is placed ## in the top left rectangle of @var{range} and remaining cell values ## outside the rectangle will be retained. ## ## If @var{range} contains merged cells, only the elements of @var{arr} ## corresponding to the top or left Excel cells of those merged cells ## will be written, other array cells corresponding to that cell will be ## ignored. ## ## 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 ## 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. ## ## xlswrite is a mere wrapper for various scripts which find out what ## Excel interface to use (COM, POI, etc) plus code to mimic the other ## brand's syntax. For each call to xlswrite such an interface must be ## started and possibly an Excel file loaded. When writing to multiple ## ranges and/or worksheets in the same Excel file, a speed bonus can be ## obtained by invoking those scripts directly with multiple calls to ## oct2xls (one for each sheet or range) surrounded by one call to ## xlsopen and xlsclose: ## (xlsopen / octxls / oct2xls / .... / xlsclose) ## ## Examples: ## ## @example ## status = xlswrite ('test4.xls', 'arr', 'Third_sheet', 'C3:AB40'); ## (which adds the contents of array arr (any type) to range C3:AB40 ## in worksheet 'Third_sheet' in file test4.xls and returns a logical ## True (= numerical 1) in status if al went well) ## @end example ## ## @seealso {xlsread, oct2xls, xls2oct, xlsopen, xlsclose, xlsfinfo} ## ## @end deftypefn ## Author: Philip Nienhuis ## Created: 2009-10-16 ## Updates: ## 2010-01-04 (Adapted range capacity checks to OOXML) ## 2010-01-12 (Bug fix; added unwind_protect to xlsopen...xlsclose calls) ## 2010-01-15 Fixed typos in texinfo ## 2010-08-18 Added check for existence of xls after call to xlsopen to ## avoid unneeded error message clutter ## 2010-10-27 Changed range -> crange to unhide other range functions ## 2011-09-08 Minor code syntax updates ## 2012-01-26 Fixed "seealso" help string ## 2012-06-07 Replaced all tabs by double space ## 2012-10-24 Style fixes ## 2012-12-23 Fix rare occasion of xlsclose error in unwind_protect block ## 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 function [ rstatus ] = xlswrite (filename, arr, arg3, arg4, arg5) rstatus = 0; ## Sanity checks if (nargin < 2) usage ("Insufficient arguments - see 'help xlswrite'"); elseif (! ischar (filename)) error ("First argument must be a filename (incl. suffix)"); elseif (nargin == 2) ## Assume first worksheet and full worksheet starting at A1 wsh = 1; if (strcmpi (filename(end-4:end-1), ".xls")) crange = "A1:XFD1048576"; ## OOXML has ridiculously large limits else crange = "A1:IV65536"; ## Regular xls limits endif elseif (nargin == 3) ## Find out whether 3rd argument = worksheet or range if (isnumeric (arg3) || (isempty (findstr (arg3, ":")) && ~isempty (arg3))) ## Apparently a worksheet specified wsh = arg3; if (strcmpi (filename(end-4:end-1), ".xls")) crange = "A1:XFD1048576"; ## OOXML has ridiculously large limits else crange = "A1:IV65536"; ## Regular xls limits endif else ## Range specified wsh = 1; crange = arg3; endif elseif (nargin >= 4) wsh = arg3; crange = arg4; endif if (nargin == 5) reqintf = arg5; else reqintf = []; endif ## Parse range [topleft, nrows, ncols, trow, lcol] = parse_sp_range (crange); ## Check if arr fits in range [nr, nc] = size (arr); if ((nr > nrows) || (nc > ncols)) # Array too big; truncate nr = min (nrows, nr); nc = min (ncols, nc); warning ("xlswrite - array truncated to %d by %d to fit in range %s", ... nrows, ncols, crange); endif unwind_protect ## Needed to be sure Excel can be closed i.c.o. errors xls_ok = 0; xls = xlsopen (filename, 1, reqintf); if (! isempty (xls)) xls_ok = 1; [xls, rstatus] = oct2xls (arr(1:nr, 1:nc), xls, wsh, topleft); endif unwind_protect_cleanup if (xls_ok && ! isempty (xls)) xls = xlsclose (xls); endif end_unwind_protect endfunction io/inst/xmlwrite.m0000644000076400010400000001321712217071420015501 0ustar PhilipAdministrators## Copyright (C) 2004 Laurent Mazet ## ## 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 . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{nb} =} xmlwrite (@var{filename}, @var{value}) ## @deftypefnx {Function File} {@var{nb} =} xmlwrite (@var{fd}, @var{value}, [@var{name}]) ## ## Write a @var{value} into @var{filename} (@var{fd}) as an XML file. ## ##The number of elements (@var{nb}) or 0 is returned. ## @end deftypefn function nb = xmlwrite (filename, value, name) persistent indent = ""; persistent separator = "\n"; ## Check argument number nb = 0; if (nargin < 2) || (nargin > 3) print_usage; endif ## Get the file identificator isopen = false; if ischar(filename) ## Check file name sn = char (strsplit (filename, ".")); if !strcmp(tolower(deblank(sn(end,:))), "xml") filename = [filename, ".xml"]; endif ## Open file fd = fopen (filename, "w"); if fd <= 0 error("xmlwrite: error opening file \"%s\"\n", filename); endif ## XML header fprintf (fd, "\n"); fprintf (fd, "\n"); fprintf (fd, "\n"); indent = " "; else isopen = true; fd = filename; endif ## Store name in optional argument opt = ""; if nargin == 3 opt = sprintf(" name=\"%s\"", name); endif ## Process by type if ischar(value) && (rows(value) <= 1) ## String type fprintf (fd, "%s%s%s", indent, opt, length(value), value, separator); elseif ischar(value) ## String array type fprintf (fd, "%s\n", indent, opt, rows(value)); _indent = indent; indent = [indent, " "]; for k=1:rows(value), nb += xmlwrite (fd, deblank(value(k, :))); endfor indent = _indent; fprintf (fd, "%s\n", indent); elseif isscalar(value) ## Scalar type if iscomplex(value) ## Complex type fprintf (fd, "%s", indent, opt); _indent = indent; indent = ""; _separator = separator; separator = ""; nb += xmlwrite (fd, real(value)); nb += xmlwrite (fd, imag(value)); indent = _indent; separator = _separator; fprintf (fd, "%s", separator); elseif isbool(value) ## Boolean type if value fprintf (fd, "%s%s", indent, opt, separator); else fprintf (fd, "%s%s", indent, opt, separator); endif elseif isinf(value) ## Infinite type if value > 0 fprintf (fd, "%s%s", indent, opt, separator); else fprintf (fd, "%s%s", indent, opt, separator); endif elseif isnan(value) ## Not-A-Number type fprintf (fd, "%s%s", indent, opt, separator); elseif isna(value) ## Not-Avaliable fprintf (fd, "%s%s", indent, opt, separator); else sc = sprintf(sprintf("%%.%dg", save_precision), value); fprintf (fd, "%s%s%s", indent, opt, sc, ... separator); endif elseif ismatrix(value) && isnumeric(value) && (length(size(value)) <= 2) ## Matrix type fprintf (fd, "%s\n", indent, opt, rows(value), columns(value)); _indent = indent; indent = ""; separator = ""; for k=1:rows(value), fprintf (fd, "%s ", _indent); for l=1:columns(value)-1, nb += xmlwrite (fd, value(k, l)); fprintf (fd, " "); endfor nb += xmlwrite (fd, value(k, end)); fprintf (fd, "\n"); endfor indent = _indent; separator = "\n"; fprintf (fd, "%s\n", indent); elseif isstruct(value) ## Structure type st = fieldnames(value); fprintf (fd, "%s\n", indent, opt); _indent = indent; indent = [indent, " "]; for k=1:length(st), eval(sprintf("nb += xmlwrite (fd, value.%s, \"%s\");", st{k}, st{k})); endfor indent = _indent; fprintf (fd, "%s\n", indent); elseif iscell(value) ## Cell type fprintf (fd, "%s\n", indent, opt, rows(value), columns(value)); _indent = indent; indent = [indent, " "]; for k=1:rows(value), for l=1:columns(value), nb += xmlwrite (fd, value{k, l}); endfor endfor indent = _indent; fprintf (fd, "%s\n", indent); elseif islist(value) ## List type fprintf (fd, "%s\n", indent, opt, length(value)); _indent = indent; indent = [indent, " "]; for k=1:length(value), nb += xmlwrite (fd, value{k}); endfor indent = _indent; fprintf (fd, "%s\n", indent); else ## Unknown type error("xmlwrite: unknown type\n"); endif nb++; if !isopen fprintf (fd, "\n"); fclose(fd); endif endfunction io/NEWS0000644000076400010400000005556312263334122013206 0ustar PhilipAdministratorsSummary of important user-visible changes for releases of the io package =============================================================================== io-2.0.2 Release Date: 2014-01-09 Release Manager: Philip Nienhuis =============================================================================== Another bug fix release *** Bug fixes: - PKG_ADD, PKG_DEL: move into script dir to be sure they can be invoked while loading / unloading io package *** New features: - chk_spreadsheet_support: Remembers which javaclasspath entries it loaded, can remove them too - PKG_DEL: Removes all javaclasspath entries added by chk_spreadsheet-support when unloading the io package - PKG_ADD: Searches for OpenOffice.org / LibreOffice in some conventional places to allow silent automatic loading of Java class libs & directories required for OOo / LO =============================================================================== io-2.0.1 Release Date: 2014-01-01 Release Manager: Philip Nienhuis =============================================================================== Bug fix release *** Bug fixes: - Fixed rfsearch error (empty subdirs) when loading package *** PKG_ADD: Also search user (%USERPROFILE%\Java or ~/Java) for Java spreadsheet support .jar files; also add conventional Linux place in search (usually /usr/share/java) =============================================================================== io-2.0.0 Release Date: 2014-01-01 Release Manager: Philip Nienhuis =============================================================================== *** Some code simplifications & style fixes An updated overview of which interface can be used for what types of files (extension): ~ = 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 R .xlsb, .xlsm ~ ? R .wk1 + R .wks + R .dbf + + .ods ~ + + + R .sxc + + .fods + .uos + .dif + .csv + R .gnumeric R -------------------------------------------------------------- For unsupported file types, UNO will write .ods whatever the actual file extension. *** Bug fixes: - Fixed texinfo headers for the test scripts - The UNO interface no longer writes ODS for all file extensions. An updated list is shown above. *** Known issues: - OOXML write/read support in OpenXLS (OXS) is a bit wonky. Doesn't pass Octave OF-io's test script. Upstream has been informed of one example bug. - OpenXLS' OOXML depends on another .jar file (gwt-servlet-deps.jar). Rip it from this archive (108+ MB download): gwt-2.5.1.zip, available at: http://www.gwtproject.org/download.html ("Download GWT SDK") - LibreOffice/OpenOffice.org (UNO interface) doesn't write .csv - OTK interface (.ods) sometimes writes ridiculously wide columns. =============================================================================== io-1.3.6 Release Date: 2013-TBA Release Manager: Philip Nienhuis =============================================================================== *** OXS (OpenXLS) now has read/write support. AFAICS it is the fastest Java- based interface. Provisionally .xls (BIFF8, Excel'97-2003) works fairly reliably. OOXML works too but is unstable (see below, "Known issues"). *** Some code simplifications & style fixes *** xlsread may fall back to csvread for .csv files when no Excel (COM) or LibreOffice/OOo (UNO) interface is supported (bug #40993) An updated overview of which interface can be used for what types of files (extension): ( ~ = dependent on Excel 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) + + + + + + .xlxx/xlsm + + (+) + R .wk1 + + .wks + + .dbf + + .ods ~ + + + R .sxc + + .fods + .uos + .dif + .csv + + .gnumeric R -------------------------------------------------------------- *** Bug fixes: - post_install.m: seems unneeded, provisionally commented out all commands - PKG_ADD: dropped all references to Java package, now just checks octave_config_info("features").JAVA *** Known issues: - OOXML write/read support in OpenXLS (OXS) is a bit wonky. Doesn't pass Octave OF-io's test script. Upstream has been informed of one example bug. - OpenXLS' OOXML depends on another .jar file (gwt-servlet-deps.jar). Rip it from this archive (108+ MB download): gwt-2.5.1.zip, available at: http://www.gwtproject.org/download.html ("Download GWT SDK") =============================================================================== io-1.3.5 Release Date: 2013-TBA Release Manager: Philip Nienhuis =============================================================================== *** Merged in changes from io-1.2.5 (OCT interface) *** New spreadsheet test routine; improved existing routines to write with one and read with some other interface (helped to uncover many concealed bugs) *** (pending) Cleaning up chk_spreadsheet_support.m *** Bug fixes: - OCT: Replace fgetl calls by fread Improved regexp's - JOD: Wipe "A" and "B" in A1/B1 in new empty spreadsheets (a very old bug) - POI: File extension checks improved =============================================================================== io-1.3.4 Release Date: None (internal) =============================================================================== *** chk_spreadsheet_support restyled from Matlab into Octave style " , introduced recursive subdir search for Java class libs (nice for Fedora) Added rfsearch.m, function to find files in subdirs =============================================================================== io-1.3.3 Release Date: 2013-08-15 Release Manager: Philip Nienhuis =============================================================================== Intermediate unofficial development version for Octave 3.7.x. Only released on patch tracker Changes: see section for version 1.2.3 =============================================================================== io-1.3.2 Release Date: 2013-06-18 Release Manager: Philip Nienhuis =============================================================================== Intermediate unofficial development version for Octave 3.7.x. Only released on patch tracker ** Bug fixes --- chk_spredsheet_support: better Java detection (bug #38725) --- xlsopen.m: .xlsx files are properly recognized --- Re-enabled OXS (only reading) and UNO ** Created test_spsh.m test script --- This will find all supported spreadsheet interfaces and tests them one by one =============================================================================== io-1.3.0, io-1.3.1 Release Date: -internal- Release Manager: Philip Nienhuis =============================================================================== Version 1.3.0 - 1.3.1 are intermediate development versions for Octave > 3.7.1 with built-in Java support. They are largely untested; the built-in test scripts work for all tested interfaces except UNO and OXS (which consequently are disabled). =============================================================================== io-1.2.5 Release Date: 2013-11-14 Release Manager: Philip Nienhuis =============================================================================== *** - Added string/formula read support to xlsx/OCT. There's now full read support for .xlsx (OOXML) files w/o requiring Java or COM - Added requested range for .xlsx/OCT reading *** Bug fixes: - Better filetype / file extension detection (bug #40490) - Added unpack.m from dev core Octave as private/__unpack.m to avoid unzip errors for .xlsx and .gnumeric - Removed harmless but annoying error messages from Java detection - Fix tablerow repeat counter bugs (affected reading ODS w. OCT interface) =============================================================================== io-1.2.4 Release Date: 2013-11-05 Release Manager: Philip Nienhuis =============================================================================== *** Added !experimental! OCT (native Octave) interface for reading .ods, gnumeric, and xlsx. OCT doesn't need Java or COM/ActiveX; it works without any support software. That independence does come at a price however: - reading .ods is fully flexible like the other interfaces but a bit slow - reading .xlsx is FAST but it only gives numeric data (no strings yet) - reading gnumeric only reads "hard" data, no formula results. I'm afraid this isn't gonna change (it's a gnumeric developer issue) Markus Bergholz supplied the code for very fast reading of OOXML (at present only numeric data) - Thanks very much Markus! An overview of what interface can be used for which types of files (extension) ( ~ = dependent on Excel 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) + + + + R + .xlxx/xlsm + + + R .wk1 + + .wks + + .dbf + + .ods ~ + + + R .sxc + + .fods + .uos + .dif + .csv + + .gnumeric R -------------------------------------------------------------- *** getxmlattv.m, getxmlnode.m: new functions (for support of OCT interface) *** xlsopen.m: suffixes for Excel filenames (.xls, .xlsx) need not be specified. (But the files on disk do need these suffixes!) *** odsread.m, xlsread.m: No output arg required (output is sent to terminal if not output args specified) '' '' Check if filename is a text string *** odsopen: Relax requirement of lower case filename extension ** Bug fixes: --- xlsopen.m: Undue fallback to JXL for OOXML files hopefully fixed now '' Misinformation in error message about unsupported OXS & UNO fixed --- private/__POI_getusedrange__.m: Check return value of XSSF getFirstCellNum method =============================================================================== io-1.2.3 Release Date: 2013-08-15 Release Manager: Philip Nienhuis =============================================================================== ** Bug fixes: --- private/chk_jar_entries.m: trim multiple entries to avoid padded spaces *** private/getxlsinterfaces.m: add multiple jar entries for POI cf. Fedora naming (actually a Fedora packaging complication) *** chk_spreadsheet_support.m: same as getxlsinterfaces.m *** Added logical types to object2json (by Keith Sheppard, bug #39429) *** Tested odfdom-0.6-incubator (odfdom-0.8.9): too buggy to support :-( Updated doc/READ-ODS.html and added checks to chk_spreadsheet_support.m and private/getodsinterfaces.m =============================================================================== io-1.2.2 Release Date: 2013-05-21 Release Manager: Philip Nienhuis =============================================================================== ** Bug fixes: --- xlsopen.m: avoid fallback to JXL for OOXML files in some cases --- xlsopen.m, odsopen.m (actually silently fixed in 1.2.1): always re-read javaclasspath when a Java spreadsheet interface is requested explicitly (because between calls to xls-/odsopen new classes could be added to the javaclasspath, this wasn't picked up properly) --- csv2cell(): Fix hanging when it encountered EOF w/o preceding EOL (#143 in former OctDev bug tracker) csv2cell(): Fix inconsistent behavior when first field on a line is a string protected by "" (see http://octave.1599824.n4.nabble.com/csv2cell-inconsistent-tc4635817.html) --- __UNO_oct2spsh__.m: wrong assignment in code finding existing sheetnames --- Fix checks on xls or xls? suffix (due to Vermylen) --- Temporarily commented out tests in private subdir (bug #38755) ** csv2cell(): Tests added for above bugs and proper SEP and PROT args ** cell2csv(): Tests added incl. for proper SEP and PROT args ** Added read_namelist.m and write_namelist.m, kindly contributed by Darien Pardinas Diaz and Terry Duel =============================================================================== io-1.2.1 Release Date: 2013-03-01 Release Manager: Philip Nienhuis =============================================================================== ** Bug fixes: --- post_install.m: fixed wrong format specifier in error message --- chk_spreadsheet_support: Java call to return JVM memory size returns varying type dependent on Java version. Made this part of code more robust. Also prepared for Octave-3.8 built-in Java support --- xlsopen.m, odsopen.m: improved matching file type to specific interfaces (e.g., .sxc can only be read by JOD and UNO; .xlsx only by COM, POI-OOXML and UNO) ** moved common Java detection code from getods/getxlsinterfaces to separate function ** post_install: if PKG_ADD couldn't be removed from .oct file dir, inform user to add spreadsheet Java class libs manually to the javaclasspath ** Replaced all calls to to-be-deprecated java_new & java_invoke calls by javaObject and javaMethod =============================================================================== io-1.2.0 Release Date: 2012-12-27 Release Manager: Philip Nienhuis =============================================================================== This will be the last major version that is "depending" on the separate Java package for most of the spreadsheet I/O. In a next major version this will be based on Octave's built-in Java support. Some of the spreadsheet support files in io-1.2.0 are expected not to work anymore in Octave-3.8+ ** Bug fixes: --- xls2oct(POI)/__POI_spsh2oct__: now correctly evaluates formulas (as far as POI can handle cell formulas) --- Fixed sheet selection code for UNO and COM interfaces ** Moved all interface-specific subfunctions and code into ./private subdir. This allowed for elimination of a lot of duplicate code. ** Moved functions parse_sp_range.m, spsh_chkrange.m & spsh_prstype.m into ./private subdir ** Support for POI 3.9 added =============================================================================== io-1.0.20 Release Date: 2012-09-07 Release Manager: Philip Nienhuis =============================================================================== ** Bug fixes: --- xlsopen, xlsclose, odsopen, odsclose: replaced canonicalize_file_name call with make_absolute_filename for non-windows systems (canonicalize_file_name doesn't work with non-existent (new) files on *nix) (bug #36677); Web addresses (URLs) only need two rather than three slashes; --- xlsopen: matching .jar names to javaclasspath entries worked the wrong way --- io_xls_testscript / io_ods_testscript: added small delay for UNO calls to avoid lock-ups with recent LibreOffice (3.6.x) ** The annoying flashing LibreOffice splash screens have been fixed upstream; with LibreOffice 3.6.1 I didn't see them anymore ** Extended file rename section in odsclose similar to that in xlsclose =============================================================================== io-1.0.19 Release Date: 2012-06-08 Release Manager: Philip Nienhuis =============================================================================== ** Bug fixes: --- getusedrange subfunc getusedrange_jod: str2num applied to indices rather than the substring. Must have been there for > 2 years, only surfaced with jopendocument v 1.3b1 --- oct2xls, oct2ods: cast all numeric types in input array to double as spreadsheets have only double, boolean or character string type. This bug has been there from the very beginning of the spreadsheet functions >8-O --- Support for reading back formulas from .xls spreadsheets using ActiveX/COM ** Compatible with jOpenDocument version 1.3b1 getUsedRange() method added (MUCH faster than the old hack) ** Compatible with odfdom-java-0.8.8-incubator.jar (ODF Toolkit 0.5-incubating) ** Compatible with Apache POI 3.8 final =============================================================================== io-1.0.18 Release Date: 2012-03-22 Release Manager: Philip Nienhuis =============================================================================== ** The following functions have been imported from the miscellaneous package: cell2csv csvconcat xmlread csv2cell csvexplode xmlwrite Their error messages and help messages have been cleaned up a bit. ** Bug fixes: --- odsfinfo: fixed "wrong type argument `cell'" bug when run interactively. --- xlsopen, odsopen: fixed messed up screen output due to UNO usage warning. --- csv2cell: checks if file is empty and if so, return an empty cell. --- xlsopen: better Java detection logic, more informative error messages ** Adapted to internal LibreOffice-3.5-final changes. Some bugs (flashing LO screens) still have to be fixed upstream - see here: https://bugs.freedesktop.org/show_bug.cgi?id=42470 ** Tried OpenXLS-6.0.7.jar. Reads OK, still unusable for writing .xls files. =============================================================================== io-1.0.17 Release Date: 2012-02-27 Release Manager: Philip Nienhuis =============================================================================== ** Bug fixes: --- oct2ods, oct2xls, odswrite default range input arg. These functions may not have worked properly for two years (!) ** Fixed support for odfdom v.0.8.7 (ODS). Note: the OTK interface only works well with xercesImpl.jar 2.9.1 (Sep 14, 2009) ** Many small bug fixes & documentation updated to actual functionality. ** Fixed "seealso" texinfo header string in almost all functions. ** Added formal test scripts to "internal functions" section. =============================================================================== io-1.0.16 Release Date: 2012-01-19 Release Manager: Philip Nienhuis =============================================================================== ** Bug fixing release ** PKG_ADD now expects Java spreadsheet class libs (.jars) in /lib/java (for MinGW) =============================================================================== io-1.0.15 Release Date: 2011-10-02 Release Manager: Philip Nienhuis =============================================================================== io-1.0.15 is primarily a bug fix release and a snapshot / wrap-up of current development status (some still a bit experimental). It mainly comprises: ** A number of bug fixes (incl. some serious ones, notably with .ods/OOo Calc); ** Some mainly cosmetic improvements to existing code; less verbosity; ** pch2mat (reading & transforming Nastran PCH files, contributed by B. Oytun Peksel); ** object2json.m (creating a json description string of objects, contributed by Daniel Torre). This was already silently introduced in io-1.0.14; ** A scripted troubleshooting / classpath setup tool for spreadsheet I/O support (chk_spreadsheet_support.m); ** Experimental OXS support (OpenXLS) for reading Excel xls (BIFF8). OpenXLS is -let's say- a little bit lacking: For reading it is faster than JXL. However, while OXS write support has been coded (and works) I had to disable it as the OXS Java classes won't release the file handle so Octave will hang upon closing :-( I'm stuck with this so I just release it as-is; ** Experimental UNO support, i.e. invoking OpenOffice.org (or clones like LibreOffice) behind the scenes to read spreadsheet files, much like ActiveX/COM for MS-Excel. This is also based on Java. The first time you use UNO, OOo has to be loaded and you'll have to be patient, but once loaded (and in the OS cache) you'll see the pros: --* Very fast; --* Much lower Java memory usage as OOo loads the spreadsheet in its own memory chunk (not Octave's) => much bigger spreadsheet capacity; --* You can read *all* formats supported by OOo: .ods, .xls, .csv, .xlsx, .sxc, .dbf, Lotus wk1, Quattro Pro, ......; and it doesn't really matter whether xlsopen of odsopen is used. Of course all this wonderful stuff comes at a prize: --* After closing the spreadsheet file (odsclose, xlsclose) ALL OOo invocations will be closed, also those started outside Octave. This is due to "the way OpenOffice works" (quoted from OOo dev forum), especially through Java. There are other ways to close OOo but they'll hang Octave; --* The Java UNO classes supplied with e.g. LibreOffice aren't kept quite up-to-date with the main program. As a consequence, with e.g., LibreOffice 3.4 the main LO window will pop up (it can't be hidden). I filed a bug report for this (https://bugs.freedesktop.org/show_bug.cgi?id=40991) but I haven't seen it being picked up yet. Another example: while LO 3.3.1's row capacity was already > 10^6, it took until LO 3.4 before this capacity was implemented in the Java UNO classes. Like with OXS, I'm a bit stuck here - all this has to be fixed upstream. Hint: for older Octave versions (< 3.4.0) you can install io-1.0.15 using the -nodeps flag. You'll then loose the old and buggy textread and csv/dlm-read/write functions but I'd consider that as no big loss. io/PKG_ADD0000644000076400010400000000520412263350056013512 0ustar PhilipAdministrators## PKG_ADD ## add paths of io pkg java jars. ## First check if Java support was built in anyway if (octave_config_info ("features").JAVA) ## OK, Java built-in / supported. Check environment var userdir = getenv ("OCTAVE_IO_JAVALIBS"); if (ispc) homedir = getenv ("USERPROFILE"); # (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... elseif (isunix) homedir = tilde_expand ("~"); ## On linux spreadsheet .jars are often found somewhere in /usr/share/java libdir = "/usr/share"; else ## Set libdir to "." to avoid searching in a root dir libdir = "."; endif ## Find LibreOffice or OpenOffice.org ooopath = ''; ii = 0; ## Possible locations for OOo or LO. bnam = {"C:/Program Files (X86)", ... "C:/Program Files", ... "C:/Programs", ... "/opt", ... "/usr/lib"}; while (isempty (ooopath) && ii < numel (bnam)) ooopath = glob ([ bnam{++ii} filesep "LibreOffice*"]); endwhile while (isempty (ooopath) && ii < numel (bnam)) ooopath = glob ([ bnam{++ii} filesep "OpenOffice.org*"]); endwhile while (isempty (ooopath) && ii < numel (bnam)) ooopath = glob ([ bnam{++ii} filesep "ooo*"]); endwhile if (! isempty (ooopath)) ooopath = ooopath{:}; else ooopath = ''; endif ## One big try-catch to circumvent possible problems on Linux 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 clear libdir spr_status userdir homedir ; return endif ## First allow some time for io package to be fully loaded pause (0.25); ## Check first for user-, then system supplied jars if (exist (userdir) == 7) ## Userdir is a subdir spr_status = chk_spreadsheet_support (userdir, 0, ooopath); endif ## Also try user's home directory else ## Allow some time for io package to be fully loaded pause (0.25); endif ## Try /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); catch warning ("(Automatic loading of spreadsheet I/O Java classlibs failed)\n"); end_try_catch endif ## Clean up clear libdir spr_status userdir homedir bnam ooopath ii; io/PKG_DEL0000644000076400010400000000046512263600612013526 0ustar PhilipAdministrators## PKG_DEL ## ## All we need to do is try to remove all Java spreadsheet class libs loaded ## by chk_spreadsheet_support.m from the javaclasspath try chk_spreadsheet_support ("", -1); catch warning ("Couldn't remove spreadsheet I/O javaclasspath entries while unloading io pkg"); end_try_catch io/post_install.m0000644000076400010400000000203212263343322015361 0ustar PhilipAdministrators## (C) 2011,2012 Nitzan Arani ## (C) 2014 Philip Nienhuis ## This function moves the PKG_ADD & PKG_DEL scripts from the .oct directory of the io ## package to the function script file after installation. The reason is that PKG_ADD ## calls chk_spreadsheet_support before the function subdir has been added to Octave's ## search path. ## Changes: ## 2014-01-08 Changed to move, rather than remove, PKG_ADD & PKG_DEL function post_install (desc) ## Try to move PKG_ADD & PKG_DEL to the io function script subdir to avoid ## PKG_ADD invoking chk_spreadsheet_support before the function dir is in ## the load path during loading of io pkg (esp. during installation). files = cstrcat (desc.archprefix, filesep, octave_config_info ("canonical_host_type"), "-", octave_config_info ("api_version"), filesep, "PKG_???"); [status, msg] = movefile (files, desc.dir, 'f'); if (! status) warning ("post_install.m: unable to move PKG_ADD & PKG_DEL to script dir: %s", msg); endif endfunction io/src/0000755000076400010400000000000012263601446013266 5ustar PhilipAdministratorsio/src/cell2csv.cc0000644000076400010400000001077012217071416015314 0ustar PhilipAdministrators// Copyright (C) 2004 Laurent Mazet // // 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 . /* %% Straightforward performance %!test %! arr = arr1 = num2cell (randn (3, 3)); %! for ii=1:size (arr, 1) %! arr1(ii, ii) = sprintf ("\"Val = %f\"", arr{ii, ii}); %! endfor %! f = tmpnam(); %! cell2csv (f, arr1); %! arr2 = csv2cell (f); %! unlink (f); %! idx = find (cellfun ("ischar", arr2)); %! arr2(idx) = cellfun (@(x) str2double(strrep(x, "Val = ", "")), arr2(idx), "Uni", false); %! assert (arr, arr2, 1e-5); %% Test with SEP and PROT args %!test %! arr = arr1 = num2cell (randn (3, 3)); %! for ii=1:size (arr, 1) %! arr1(ii, ii) = sprintf ("Val = %f", arr{ii, ii}); %! endfor %! arr1(2, 2) = [arr1{2, 2} ";"]; %! f = tmpnam(); %! cell2csv (f, arr1, ";", "&"); %! arr2 = csv2cell (f, ";", "&"); %! unlink (f); %! assert (arr2{2, 2}(end), ";"); %! arr2(2, 2) = strrep (arr2{2, 2}, ";", ""); %! idx = find (cellfun ("ischar", arr2)); %! arr2(idx) = cellfun (@(x) str2double(strrep(x, "Val = ", "")), arr2(idx), "Uni", false); %! assert (arr, arr2, 1e-5); */ #include #include #include DEFUN_DLD (cell2csv, args, nargout, "-*- texinfo -*-\n" "@deftypefn {Loadable Function} {} cell2csv (@var{file}, @var{c})\n" "@deftypefnx {Loadable Function} {} cell2csv (@var{file}, @var{c}, @var{sep})\n" "@deftypefnx {Loadable Function} {} cell2csv (@var{file}, @var{c}, @var{sep}, @var{prot})\n" "\n" "Create a CSV file from a cell array. " "@var{sep} (character value) changes the character used to separate two fields. " "The default value is a comma " "(@code{,}). @var{prot} (character value) changes the character used to protect a string. " "Default value is a double quote (@code{\"}).\n" "@end deftypefn") { /* Check argument */ if ((args.length() < 2) || (args.length() > 4)) { print_usage (); return octave_value(); } /* Get arguments */ std::string file = args(0).string_value(); Cell c = args(1).cell_value(); std::string sep = (args.length() > 2) ? args(2).string_value() : ","; if (sep.length() != 1) { error("cell2csv: separator can only be one character\n"); return octave_value(); } std::string prot = (args.length() > 3) ? args(3).string_value() : "\""; if (prot.length() != 1) { error("cell2csv: protector can only be one character\n"); return octave_value(); } /* Open file */ std::ofstream fd(file.c_str()); if (!fd.is_open()) { error("cell2csv: cannot open file %s for writing\n", file.c_str()); return octave_value(); } /* Concat a cell into a string */ std::string word; /* For each element */ for (int i=0, il=c.rows(); i // // 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 . /* %% Check EOF w/o preceding EOL & text fields in 1st column disguised as numeric str %!test %! f = tmpnam (); %! fid = fopen (f, 'w+'); %! fprintf (fid, "\"1\""); %! fclose (fid); %! s = csv2cell (f){1}; %! unlink (f); %! assert (s, "1"); %!test %! f = tmpnam (); %! csvwrite(f, "\"1\",2", "DELIMITER", ""); %! s = csv2cell(f); %! unlink (f); %! assert (s{1}, "1"); %! assert (s{2}, 2); %!test %! f = tmpnam (); %! csvwrite(f, "3,\"1\"", "DELIMITER", ""); %! s = csv2cell(f); %! unlink (f); %! assert (s{1}, 3); %! assert (s{2}, "1"); %% Check proper string protection %!test %! f = tmpnam (); %! fid = fopen (f, 'w+'); %! str = ['01/03/2012,"H (Mar, 12)",26.750000,2584' "\n"]; %! str = [str '"01/04/2012",H (Mar, 12),2330' "\n"]; %! str = [str '"01/05/2012","H (Mar 12)",26.000000,3198' "\n"]; %! str = [str '01/06/2012,H (Mar 12),25.500000,3045' "\n"]; %! fprintf (fid, str); %! fclose (fid); %! s = csv2cell (f); %! unlink (f); %! assert (isnumeric ([s{1:4, 4}]), true); %! ddd = datenum (s{2,1}, "dd/mm/yyyy") - datenum (s{1,1}, "dd/mm/yyyy"); %! assert (ddd, 31.0, 1e-5); %! assert (iscellstr (s(1:4, 2)), true); %! assert (isnumeric ([s{1, 3} s{3:4, 3}]), true); %1 assert (ischar (s{2, 3}), true); %% Check separator and string protection arguments %!test %! f = tmpnam (); %! fid = fopen (f, 'w+'); %! str = ['01/03/2012;$H (Mar; 12)$;26.750000;2584' "\n"]; %! str = [str '$01/04/2012$;H (Mar; 12);2330' "\n"]; %! str = [str '$01/05/2012$;$H (Mar 12)$;26.000000;3198' "\n"]; %! str = [str '01/06/2012;H (Mar 12);25.500000;3045' "\n"]; %! fprintf (fid, str); %! fclose (fid); %! s = csv2cell (f, ";", "$"); %! unlink (f); %! assert (isnumeric ([s{1:4, 4}]), true); %! ddd = datenum (s{2,1}, "dd/mm/yyyy") - datenum (s{1,1}, "dd/mm/yyyy"); %! assert (ddd, 31.0, 1e-5); %! assert (iscellstr (s(1:4, 2)), true); %! assert (isnumeric ([s{1, 3} s{3:4, 3}]), true); %1 assert (ischar (s{2, 3}), true); */ #include #include #include #define MAXSTRINGLENGTH 4096 DEFUN_DLD (csv2cell, args, nargout, "-*- texinfo -*-\n" "@deftypefn {Loadable Function} {@var{c} = } csv2cell (@var{file})\n" "@deftypefnx {Loadable Function} {@var{c} = } csv2cell (@var{file}, @var{sep})\n" "@deftypefnx {Loadable Function} {@var{c} = } csv2cell (@var{file}, @var{sep}, @var{prot})\n" "\n" "Read a CSV (Comma Separated Values) file and convert it into a cell array. " "@var{sep} (a character value) changes the character used to separate two fields. " "The default value is a comma " "(@code{,}). @var{prot} (character value) changes the character used to protect a string. " "The default is a double quote (@code{\"}).\n" "The maximum line width of the csv file is 4092 characters.\n" "@end deftypefn") { /* Get arguments */ const int nargin = args.length (); octave_value_list retval; if (nargin == 0) { error ("csv2cell: not enough input arguments"); return retval; } const std::string file = args (0).string_value (); const std::string _sep = (nargin > 1) ? args(1).string_value () : ","; if (_sep.length() != 1) { error ("csv2cell: separator value can only be one character\n"); return retval; } char sep = _sep[0]; const std::string _prot = (nargin > 2) ? args(2).string_value () : "\""; if (_prot.length() != 1) { error ("csv2cell: protector value can be only one character\n"); return retval; } char prot = _prot[0]; /* Open file */ std::ifstream fd (file.c_str ()); if (!fd.is_open ()) { error ("csv2cell: cannot open file %s for reading\n", file.c_str()); return retval; } fd.seekg (0, std::ios::end); long fdend = fd.tellg (); fd.seekg (0, std::ios::beg); if (fd.tellg () >= fdend) return octave_value (Cell (0, 0)); /* Buffers */ char line [MAXSTRINGLENGTH]; std::string str, word; bool inside = false; /* Read a line */ str = ""; fd.getline (line, MAXSTRINGLENGTH); while (fd.fail ()) { fd.clear (); str += line; fd.getline (line, MAXSTRINGLENGTH); } str += line; /* Parse first to get number of columns */ int nbcolumns = 0; for (int i = 0, len = str.length (); i <= len; i++) if ((i==len) || ((str[i] == sep) || (str[i] == 10)) && (!inside)) nbcolumns++; else if ((inside) && (str[i] == prot) && ((i < len) && (str[i+1] == prot))) ++i; else if (str[i] == prot) inside = !inside; /* Read all the file to get number of rows */ int nbrows = 1; while (fd.tellg () <= fdend && fd.peek () != EOF) { fd.getline (line, MAXSTRINGLENGTH); while (fd.fail () && fd.peek() != EOF) { fd.clear (); fd.getline (line, MAXSTRINGLENGTH); } nbrows++; } fd.clear(); /* Rewind */ fd.seekg (0, std::ios::beg); if (!fd.good ()) { error ("csv2cell: cannot reread %s\n", file.c_str ()); return retval; } /* Read all the file until the end */ Cell c (nbrows, nbcolumns); for (int i = 0; i < nbrows; i++) { /* Read a line */ str = ""; fd.getline (line, MAXSTRINGLENGTH); while (fd.fail ()) { fd.clear (); str += line; fd.getline (line, MAXSTRINGLENGTH); } str += line; /* Explode a line into a sub cell */ word = ""; // inside = (str[0] == prot); inside = false; int j = 0; // Keep track of when just read, but not yet copied field, was inside (text) bool oinside = false; for (int k = 0, len = str.length (); k <= len; k++) { if (((k == len) || (str[k] == sep)) && (!inside)) { /* Check number of columns */ if (j == nbcolumns) { fd.close (); error ("csv2cell: incorrect CSV file, line %d too long\n", i+1); return retval; } /* Check if scalar */ const char *word_str = word.c_str (); char *err; double val = strtod (word_str, &err); /* Store into the cell */ c(i, j++) = ((word == "") || oinside || (err != word_str+word.length())) ? octave_value (word) : octave_value (val); word = ""; oinside = false; } else if ((inside) && (str[k] == prot) && ((k < len) && (str[k+1] == prot))) { /* Inside a string */ word += prot; ++k; } else if (str[k] == prot) { /* Changing */ oinside = inside; inside = !inside; } else word += str[k]; } /* Check number of columns */ if (j != nbcolumns) { fd.close (); error ("csv2cell: incorrect CSV file, line %d too short\n", i+1); return retval; } } /* Close file */ fd.close (); retval (0) = c; return retval; } io/src/csvconcat.cc0000644000076400010400000000604312217071416015560 0ustar PhilipAdministrators// Copyright (C) 2004 Laurent Mazet // // 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 . #include #include DEFUN_DLD (csvconcat, args, nargout, "-*- texinfo -*-\n" "@deftypefn {Loadable Function} {@var{str} = } csvconcat (@var{c})\n" "@deftypefnx {Loadable Function} {@var{str} = } csvconcat (@var{c}, @var{sep})\n" "@deftypefnx {Loadable Function} {@var{str} = } csvconcat (@var{c}, @var{sep}, @var{prot})\n" "\n" "Concatenate a cell into a CSV string or array of strings. " "@var{sep} (character value) changes the character used to separate two fields. " "The default value is a comma " "(@code{,}). @var{prot} (character value) changes the character used to protect a string. " "The default is a double quote (@code{\"}).\n" "@end deftypefn") { /* Check argument */ if ((args.length() < 1) || (args.length() > 3)) { print_usage (); return octave_value(); } /* Get arguments */ Cell c = args(0).cell_value(); std::string sep = (args.length() > 1) ? args(1).string_value() : ","; if (sep.length() != 1) { error("csvconcat: separator can only be one character\n"); return octave_value(); } std::string prot = (args.length() > 2) ? args(2).string_value() : "\""; if (prot.length() != 1) { error("csvconcat: protector can only be one character\n"); return octave_value(); } /* Concat a cell into a string */ string_vector vec(c.rows()); std::string word; /* For each element */ for (int i=0, il=c.rows(); i // // 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 . #include #include DEFUN_DLD (csvexplode, args, nargout, "-*- texinfo -*-\n" "@deftypefn {Loadable Function} {@var{c} =} csvexplode (@var{str})\n" "@deftypefnx {Loadable Function} {@var{c} =} csvexplode (@var{str}, @var{sep})\n" "@deftypefnx {Loadable Function} {@var{c} =} csvexplode (@var{str}, @var{sep}, @var{prot})\n" "\n" "Explode a CSV string into a cell. " "@var{sep} (character value) changes the character used to separate two fields. " "The default value is a comma (@code{,}). @var{prot} (character value) changes " "the character used to protect a string. The default is a double quote (@code{\"}).\n" "@end deftypefn") { /* Check argument */ if ((args.length() < 1) || (args.length() > 3)) { print_usage (); return octave_value(); } /* Get arguments */ if (!args(0).is_string()) { if (args(0).is_cell()) return octave_value(args(0)); else return octave_value(Cell(args(0))); } std::string str = args(0).string_value(); std::string _sep = (args.length() > 1) ? args(1).string_value() : ","; if (_sep.length() != 1) { error("csvexplode: separator can only be one character\n"); return octave_value(); } char sep = _sep[0]; std::string _prot = (args.length() > 2) ? args(2).string_value() : "\""; if (_prot.length() != 1) { error("csvexplode: protector can only be one character\n"); return octave_value(); } char prot = _prot[0]; /* Explode a line into a cell */ Cell retval; std::string word; bool inside = false; for (int i=0, len=str.length(); i<=len; i++) { if (((i==len) || (str[i] == sep)) && (!inside)) { /* Extand cell */ retval.resize(dim_vector(1, retval.columns()+1)); /* Check if scalar */ const char *word_str=word.c_str(); char *err; double val = strtod (word_str, &err); /* Store into the cell */ retval(0, retval.columns()-1) = ((word == "") || (err != word_str+word.length())) ? octave_value(word) : octave_value(val); word = ""; } else if ((inside) && (str[i]==prot) && ((i io/src/xmlread.cc0000644000076400010400000001102312217071416015223 0ustar PhilipAdministrators// Copyright (C) 2004 Laurent Mazet // // 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 . #include #include #include #include extern "C" { #include "xmltree.h" #include "xmltree_read.h" } octave_value get_element (element *root) { int length, rows, columns; string_vector tmp_array; ComplexMatrix tmp_matrix; octave_scalar_map tmp_structure; Cell tmp_cell; octave_value_list tmp_list; octave_value retval; if (!root) return retval; switch (root->def_value) { case value_scalar: switch (root->const_value) { case const_true: retval = octave_value(true); break; case const_false: retval = octave_value(false); break; case const_inf: retval = octave_value(octave_Inf); break; case const_neginf: retval = octave_value(-octave_Inf); break; case const_nan: retval = octave_value(octave_NaN); break; case const_na: retval = octave_value(octave_NA); break; case const_undef: retval = octave_value(root->scalar_value); break; } break; case value_complex: retval = octave_value(Complex(get_element(root->child).double_value(), get_element(root->child->next).double_value())); break; case value_string: retval = octave_value(root->string_value); break; case value_array: rows = root->rows; root = root->child; tmp_array = string_vector(rows); for (int k=0; (knext) tmp_array(k) = get_element(root).string_value(); retval = octave_value(tmp_array); break; case value_matrix: rows = root->rows; columns = root->columns; root = root->child; tmp_matrix = ComplexMatrix(rows, columns); for (int k=0; (knext) tmp_matrix(k, l) = get_element(root).complex_value(); if (tmp_matrix.all_elements_are_real()) retval = octave_value(real(tmp_matrix)); else retval = octave_value(tmp_matrix); break; case value_structure: root = root->child; for (int k=0; root; root = root->next) if (root->name) tmp_structure.assign(root->name, get_element(root)); else { char *name = new char[7]; sprintf (name, "__%04d", k++); warning ("no field name in structure."); tmp_structure.assign(name, get_element(root)); delete[] name; } retval = octave_value(tmp_structure); break; case value_list: length = root->length; root = root->child; //tmp_list = octave_value_list(length); for (int k=0; (knext) tmp_list(k) = get_element(root); retval = octave_value(tmp_list); break; case value_cell: rows = root->rows; columns = root->columns; root = root->child; tmp_cell = Cell(rows, columns); for (int k=0; (knext) tmp_cell(k, l) = get_element(root); retval = octave_value(tmp_cell); break; default: warning ("unknown type.\n"); } return retval; } DEFUN_DLD (xmlread, args, nargout, "-*- texinfo -*-\n" "@deftypefn {Loadable Function} {@var{value} =} xmlread(@var{filename})\n" "Read a @var{value} from @var{filename} as an XML file\n" "@end deftypefn") { /* Check argument */ if (args.length() != 1) { print_usage (); return octave_value_list(); } /* Read file */ std::string filename = args(0).string_value(); element *root = read_xmltree(filename.c_str()); if (!root) return octave_value_list(); /* step down into the element tree */ octave_value retval = get_element (root->child); free_element (root); return retval; } io/src/xmltree.c0000644000076400010400000000733312217071416015115 0ustar PhilipAdministrators// Copyright (C) 2004 Laurent Mazet // // 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 . #include #include #include "xmltree.h" element *new_element () { element *new; new = (element *) malloc (sizeof(element)); if (!new) perror("xmltree: not enough memory for new_element()\n"); new->next = new->child = NULL; new->def_value = value_undef; new->const_value = const_undef; new->scalar_value = 0; new->string_value = NULL; new->name = NULL; new->length = new->rows = new->columns = new->nb_elements = 0; return new; } element *new_next (element *pred) { element *new = new_element(); if (pred) pred->next = new; return new; } element *new_child (element *father) { element *new = new_element(); if (father) father->child = new; return new; } void free_element (element *root) { if (!root) return; if (root->next) free_element (root->next); if (root->child) free_element (root->child); if (root->string_value) free (root->string_value); if (root->name) free (root->name); free (root); } void print_level(int l) { int i; for (i=0; iname) { print_level(l); printf ("name: %s\n", root->name); } print_level(l); switch (root->def_value) { case value_scalar: printf ("scalar: "); switch (root->const_value) { case const_true: printf ("true\n"); break; case const_false: printf ("false\n"); break; case const_inf: printf ("inf\n"); break; case const_neginf: printf ("neginf\n"); break; case const_nan: printf ("nan\n"); break; case const_na: printf ("na\n"); break; case const_undef: printf ("%f\n", root->scalar_value); break; } break; case value_data: printf ("data:\n"); break; case value_complex: printf ("complex:\n"); break; case value_string: printf ("string (%d): %s\n", root->length, root->string_value); break; case value_array: printf ("array (%d):\n", root->rows); break; case value_matrix: printf ("matrix (%d, %d):\n", root->rows, root->columns); break; case value_structure: printf ("structure:\n"); break; case value_list: printf ("list (%d):\n", root->length); break; case value_cell: printf ("cell (%d, %d):\n", root->rows, root->columns); break; default: printf ("???:\n"); } if (root->child) { print_level(l); printf ("child:\n"); print_element (root->child, l+1); } if (root->next) { print_level(l); printf ("next:\n"); print_element (root->next, l); } } list *new_list(list *father) { list *new; new = (list *) malloc (sizeof(list)); if (!new) perror("xmltree: not enough memory for new_list()\n"); new->prev = father; new->root = NULL; return new; } list *pop_list(list *child) { list *father; father = child->prev; free (child); return father; } io/src/xmltree.h0000644000076400010400000000343412217071416015120 0ustar PhilipAdministrators// Copyright (C) 2004 Laurent Mazet // // 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 . /* xmltree structure */ #if !defined(__XMLTREE_H__) #define __XMLTREE_H__ typedef enum { value_undef = 0, value_scalar, value_complex, value_string, value_array, value_matrix, value_structure, value_list, value_cell, value_data } t_value; typedef enum { const_undef = 0, const_true, const_false, const_inf, const_neginf, const_na, const_nan } t_const; typedef struct _element { struct _element *next; struct _element *child; /* values */ t_value def_value; t_const const_value; double scalar_value; char *string_value; /* parameters */ char *name; int length; int rows; int columns; /* check */ int nb_elements; } element; typedef struct _list { struct _list *prev; element **root; } list; element *new_element (); element *new_next (element *pred); element *new_child (element *father); void free_element (element *root); void print_element (element *root, int l); list *new_list(list *father); list *pop_list(list *child); #endif /* __XMLTREE_H__ */ io/src/xmltree_read.act0000644000076400010400000001701212217071416016430 0ustar PhilipAdministrators #endif #include "xmltree.h" #define warning perror element **current; element *root; list *lastlist; ]]> def_value = value_data; current = &(root->child); lastlist = new_list(lastlist); lastlist->root = current; ]]> root; lastlist = pop_list(lastlist); current = &((*current)->next); ]]> name = (char *) malloc(strlen({name})+1); strcpy ((*current)->name, {name}); } (*current)->def_value = value_scalar; switch ({value}) { case {value=true}: (*current)->const_value = const_true; break; case {value=false}: (*current)->const_value = const_false; break; case {value=inf}: (*current)->const_value = const_inf; break; case {value=neginf}: (*current)->const_value = const_neginf; break; case {value=nan}: (*current)->const_value = const_nan; break; case {value=na}: (*current)->const_value = const_na; break; default: (*current)->const_value = const_undef; } ]]> const_value == const_undef) && ({#PCDATA})) (*current)->scalar_value = strtod ({#PCDATA}, NULL); (*(lastlist->root))->nb_elements++; current = &((*current)->next); ]]> name = (char *) malloc(strlen({name})+1); strcpy ((*current)->name, {name}); } if ({length}) (*current)->length = strtol ({length}, NULL, 10); (*current)->def_value = value_string; ]]> length != len) { warning("incorrect length parameter for string\n"); (*current)->length = len; } (*current)->string_value = (char *) malloc ((len+1) * sizeof(char)); strcpy((*current)->string_value, {#PCDATA}); } (*(lastlist->root))->nb_elements++; current = &((*current)->next); ]]> name = (char *) malloc(strlen({name})+1); strcpy ((*current)->name, {name}); } (*current)->def_value = value_complex; lastlist = new_list(lastlist); lastlist->root = current; current = &((*current)->child); ]]> root; lastlist = pop_list(lastlist); (*(lastlist->root))->nb_elements++; current = &((*current)->next); ]]> name = (char *) malloc(strlen({name})+1); strcpy ((*current)->name, {name}); } if ({rows}) (*current)->rows = strtol ({rows}, NULL, 10); (*current)->def_value = value_array; lastlist = new_list(lastlist); lastlist->root = current; current = &((*current)->child); ]]> root))->rows != (*(lastlist->root))->nb_elements) { warning("incorrect length parameter for array\n"); (*(lastlist->root))->rows = (*(lastlist->root))->nb_elements; } current = lastlist->root; lastlist = pop_list(lastlist); (*(lastlist->root))->nb_elements++; current = &((*current)->next); ]]> name = (char *) malloc(strlen({name})+1); strcpy ((*current)->name, {name}); } if ({rows}) (*current)->rows = strtol ({rows}, NULL, 10); if ({columns}) (*current)->columns = strtol ({columns}, NULL, 10); (*current)->def_value = value_matrix; lastlist = new_list(lastlist); lastlist->root = current; current = &((*current)->child); ]]> root))->rows * (*(lastlist->root))->columns != (*(lastlist->root))->nb_elements) { warning("incorrect (rows, columns) parameters for matrix: reshaping matrix into vector\n"); (*(lastlist->root))->rows = 1; (*(lastlist->root))->columns = (*(lastlist->root))->nb_elements; } current = lastlist->root; lastlist = pop_list(lastlist); (*(lastlist->root))->nb_elements++; current = &((*current)->next); ]]> name = (char *) malloc(strlen({name})+1); strcpy ((*current)->name, {name}); } (*current)->def_value = value_structure; lastlist = new_list(lastlist); lastlist->root = current; current = &((*current)->child); ]]> root; lastlist = pop_list(lastlist); (*(lastlist->root))->nb_elements++; current = &((*current)->next); ]]> name = (char *) malloc(strlen({name})+1); strcpy ((*current)->name, {name}); } if ({length}) (*current)->length = strtol ({length}, NULL, 10); (*current)->def_value = value_list; lastlist = new_list(lastlist); lastlist->root = current; current = &((*current)->child); ]]> root))->length != (*(lastlist->root))->nb_elements) { warning("incorrect length parameter for list\n"); (*(lastlist->root))->length = (*(lastlist->root))->nb_elements; } current = lastlist->root; lastlist = pop_list(lastlist); (*(lastlist->root))->nb_elements++; current = &((*current)->next); ]]> name = (char *) malloc(strlen({name})+1); strcpy ((*current)->name, {name}); } if ({rows}) (*current)->rows = strtol ({rows}, NULL, 10); if ({columns}) (*current)->columns = strtol ({columns}, NULL, 10); (*current)->def_value = value_cell; lastlist = new_list(lastlist); lastlist->root = current; current = &((*current)->child); ]]> root))->rows * (*(lastlist->root))->columns != (*(lastlist->root))->nb_elements) { warning("incorrect (rows, columns) parameters for cell: reshaping cell into list\n"); (*(lastlist->root))->def_value = value_list; (*(lastlist->root))->length = (*(lastlist->root))->nb_elements; } current = lastlist->root; lastlist = pop_list(lastlist); (*(lastlist->root))->nb_elements++; current = &((*current)->next); ]]>
    element *read_xmltree (const char *file) { current = NULL; root = NULL; lastlist = NULL; xml_in = fopen(file, "r"); if (!xml_in) perror("can't open file\n"); xml_lex(); fclose(xml_in); return root; }
    io/src/xmltree_read.c0000644000076400010400000043643712217071416016123 0ustar PhilipAdministrators/* A lexical scanner generated by flex */ /* Scanner skeleton version: * $Header$ */ #define FLEX_SCANNER #define XML__FLEX_MAJOR_VERSION 2 #define XML__FLEX_MINOR_VERSION 5 #include #include /* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ #ifdef c_plusplus #ifndef __cplusplus #define __cplusplus #endif #endif #ifdef __cplusplus #include #ifndef _WIN32 #include #endif /* Use prototypes in function declarations. */ #define XML__USE_PROTOS /* The "const" storage-class-modifier is valid. */ #define XML__USE_CONST #else /* ! __cplusplus */ #if __STDC__ #define XML__USE_PROTOS #define XML__USE_CONST #endif /* __STDC__ */ #endif /* ! __cplusplus */ #ifdef __TURBOC__ #pragma warn -rch #pragma warn -use #include #include #define XML__USE_CONST #define XML__USE_PROTOS #endif #ifdef XML__USE_CONST #define xml_const const #else #define xml_const #endif #ifdef XML__USE_PROTOS #define XML__PROTO(proto) proto #else #define XML__PROTO(proto) () #endif /* Returned upon end-of-file. */ #define XML__NULL 0 /* Promotes a possibly negative, possibly signed char to an unsigned * integer for use as an array index. If the signed char is negative, * we want to instead treat it as an 8-bit unsigned char, hence the * double cast. */ #define XML__SC_TO_UI(c) ((unsigned int) (unsigned char) c) /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN xml__start = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The XML_STATE alias is for lex * compatibility. */ #define XML__START ((xml__start - 1) / 2) #define XML_STATE XML__START /* Action number for EOF rule of a given start state. */ #define XML__STATE_EOF(state) (XML__END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define XML__NEW_FILE xml_restart( xml_in ) #define XML__END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #define XML__BUF_SIZE 16384 typedef struct xml__buffer_state *XML__BUFFER_STATE; extern int xml_leng; extern FILE *xml_in, *xml_out; #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 /* The funky do-while in the following #define is used to turn the definition * int a single C statement (which needs a semi-colon terminator). This * avoids problems with code like: * * if ( condition_holds ) * xml_less( 5 ); * else * do_something_else(); * * Prior to using the do-while the compiler would get upset at the * "else" because it interpreted the "if" statement as being all * done when it reached the ';' after the xml_less() call. */ /* Return all but the first 'n' matched characters back to the input stream. */ #define xml_less(n) \ do \ { \ /* Undo effects of setting up xml_text. */ \ *xml__cp = xml__hold_char; \ XML__RESTORE_XML__MORE_OFFSET \ xml__c_buf_p = xml__cp = xml__bp + n - XML__MORE_ADJ; \ XML__DO_BEFORE_ACTION; /* set up xml_text again */ \ } \ while ( 0 ) #define unput(c) xml_unput( c, xml_text_ptr ) /* The following is because we cannot portably get our hands on size_t * (without autoconf's help, which isn't available because we want * flex-generated scanners to compile on their own). */ typedef unsigned int xml__size_t; struct xml__buffer_state { FILE *xml__input_file; char *xml__ch_buf; /* input buffer */ char *xml__buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ xml__size_t xml__buf_size; /* Number of characters read into xml__ch_buf, not including EOB * characters. */ int xml__n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int xml__is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int xml__is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int xml__at_bol; /* Whether to try to fill the input buffer when we reach the * end of it. */ int xml__fill_buffer; int xml__buffer_status; #define XML__BUFFER_NEW 0 #define XML__BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as XML__EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via xml_restart()), so that the user can continue scanning by * just pointing xml_in at a new input file. */ #define XML__BUFFER_EOF_PENDING 2 }; static XML__BUFFER_STATE xml__current_buffer = 0; /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". */ #define XML__CURRENT_BUFFER xml__current_buffer /* xml__hold_char holds the character lost when xml_text is formed. */ static char xml__hold_char; static int xml__n_chars; /* number of characters read into xml__ch_buf */ int xml_leng; /* Points to current character in buffer. */ static char *xml__c_buf_p = (char *) 0; static int xml__init = 1; /* whether we need to initialize */ static int xml__start = 0; /* start state number */ /* Flag which is used to allow xml_wrap()'s to do buffer switches * instead of setting up a fresh xml_in. A bit of a hack ... */ static int xml__did_buffer_switch_on_eof; void xml_restart XML__PROTO(( FILE *input_file )); void xml__switch_to_buffer XML__PROTO(( XML__BUFFER_STATE new_buffer )); void xml__load_buffer_state XML__PROTO(( void )); XML__BUFFER_STATE xml__create_buffer XML__PROTO(( FILE *file, int size )); void xml__delete_buffer XML__PROTO(( XML__BUFFER_STATE b )); void xml__init_buffer XML__PROTO(( XML__BUFFER_STATE b, FILE *file )); void xml__flush_buffer XML__PROTO(( XML__BUFFER_STATE b )); #define XML__FLUSH_BUFFER xml__flush_buffer( xml__current_buffer ) XML__BUFFER_STATE xml__scan_buffer XML__PROTO(( char *base, xml__size_t size )); XML__BUFFER_STATE xml__scan_string XML__PROTO(( xml_const char *xml__str )); XML__BUFFER_STATE xml__scan_bytes XML__PROTO(( xml_const char *bytes, int len )); static void *xml__flex_alloc XML__PROTO(( xml__size_t )); static void *xml__flex_realloc XML__PROTO(( void *, xml__size_t )); static void xml__flex_free XML__PROTO(( void * )); #define xml__new_buffer xml__create_buffer #define xml__set_interactive(is_interactive) \ { \ if ( ! xml__current_buffer ) \ xml__current_buffer = xml__create_buffer( xml_in, XML__BUF_SIZE ); \ xml__current_buffer->xml__is_interactive = is_interactive; \ } #define xml__set_bol(at_bol) \ { \ if ( ! xml__current_buffer ) \ xml__current_buffer = xml__create_buffer( xml_in, XML__BUF_SIZE ); \ xml__current_buffer->xml__at_bol = at_bol; \ } #define XML__AT_BOL() (xml__current_buffer->xml__at_bol) #define xml_wrap() 1 #define XML__SKIP_XML_WRAP typedef unsigned char XML__CHAR; FILE *xml_in = (FILE *) 0, *xml_out = (FILE *) 0; typedef int xml__state_type; extern char *xml_text; #define xml_text_ptr xml_text static xml__state_type xml__get_previous_state XML__PROTO(( void )); static xml__state_type xml__try_NUL_trans XML__PROTO(( xml__state_type current_state )); static int xml__get_next_buffer XML__PROTO(( void )); static void xml__fatal_error XML__PROTO(( xml_const char msg[] )); /* Done after the current pattern has been matched and before the * corresponding action - sets up xml_text. */ #define XML__DO_BEFORE_ACTION \ xml_text_ptr = xml__bp; \ xml_leng = (int) (xml__cp - xml__bp); \ xml__hold_char = *xml__cp; \ *xml__cp = '\0'; \ xml__c_buf_p = xml__cp; #define XML__NUM_RULES 157 #define XML__END_OF_BUFFER 158 static xml_const short int xml__accept[1064] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 158, 156, 23, 10, 10, 23, 23, 135, 10, 135, 5, 6, 5, 8, 9, 8, 151, 143, 144, 152, 149, 152, 150, 155, 143, 144, 155, 157, 157, 27, 10, 27, 27, 27, 25, 157, 31, 10, 31, 157, 51, 10, 51, 51, 51, 49, 51, 51, 152, 151, 157, 60, 10, 60, 60, 60, 58, 60, 64, 10, 64, 157, 72, 10, 72, 72, 72, 70, 72, 72, 152, 157, 83, 10, 83, 83, 83, 81, 83, 83, 87, 10, 87, 87, 157, 97, 10, 97, 97, 97, 95, 97, 97, 97, 101, 10, 101, 157, 101, 157, 107, 10, 107, 107, 107, 105, 107, 152, 157, 118, 10, 118, 118, 118, 116, 118, 118, 152, 157, 131, 10, 131, 131, 131, 129, 131, 131, 131, 152, 10, 0, 2, 2, 0, 4, 7, 146, 145, 0, 0, 0, 0, 0, 154, 0, 26, 28, 0, 0, 0, 0, 0, 0, 50, 52, 52, 52, 0, 0, 0, 0, 59, 61, 61, 0, 0, 71, 73, 73, 73, 0, 82, 84, 84, 84, 0, 0, 96, 98, 98, 98, 98, 0, 0, 106, 108, 108, 0, 117, 119, 119, 119, 0, 0, 130, 132, 132, 132, 132, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 52, 0, 0, 0, 148, 61, 0, 0, 0, 73, 73, 0, 0, 84, 84, 0, 0, 0, 98, 98, 98, 0, 0, 0, 108, 0, 0, 119, 119, 0, 0, 132, 132, 132, 0, 0, 0, 22, 1, 0, 0, 141, 0, 0, 0, 138, 137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 52, 52, 0, 0, 0, 54, 0, 61, 0, 0, 63, 0, 0, 73, 73, 0, 0, 75, 0, 84, 84, 0, 0, 86, 0, 0, 98, 98, 98, 0, 0, 100, 0, 0, 108, 0, 0, 110, 0, 119, 119, 0, 0, 121, 0, 132, 132, 132, 0, 0, 134, 0, 0, 0, 142, 136, 0, 0, 0, 0, 122, 0, 111, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 119, 0, 0, 0, 132, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 139, 140, 0, 76, 122, 0, 111, 0, 0, 0, 0, 0, 48, 47, 0, 0, 0, 0, 0, 57, 56, 0, 73, 0, 69, 68, 0, 0, 80, 79, 0, 78, 77, 0, 0, 98, 0, 94, 93, 0, 90, 89, 0, 0, 104, 103, 0, 119, 0, 115, 114, 0, 132, 0, 128, 127, 0, 124, 123, 0, 0, 0, 11, 24, 76, 0, 32, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 88, 98, 0, 0, 0, 0, 0, 120, 132, 0, 133, 0, 0, 24, 55, 32, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 66, 0, 0, 85, 88, 0, 0, 0, 0, 0, 113, 112, 0, 0, 0, 0, 55, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 0, 53, 0, 0, 74, 0, 92, 91, 0, 99, 0, 0, 126, 125, 0, 0, 102, 0, 0, 44, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 102, 0, 40, 46, 0, 0, 0, 0, 39, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, 35, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 14, 0, 13, 0, 16, 0, 0, 0, 15, 0, 0, 0, 0, 19, 0 } ; static xml_const int xml__ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 2, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 5, 6, 7, 1, 1, 8, 9, 1, 1, 1, 1, 1, 10, 11, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 15, 16, 17, 18, 19, 1, 20, 21, 22, 23, 24, 21, 14, 14, 14, 14, 14, 14, 25, 14, 26, 27, 14, 14, 28, 29, 14, 14, 14, 14, 30, 14, 31, 1, 32, 1, 14, 1, 33, 21, 34, 35, 36, 37, 38, 39, 40, 14, 14, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 14, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static xml_const int xml__meta[55] = { 0, 1, 2, 2, 2, 1, 1, 1, 1, 1, 3, 3, 1, 4, 5, 1, 1, 1, 6, 1, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 1, 1, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 } ; static xml_const short int xml__base[1112] = { 0, 0, 0, 0, 3, 6, 9, 24, 27, 11, 14, 15, 17, 29, 38, 45, 52, 59, 61, 67, 70, 93, 125, 73, 76, 143, 146, 149, 164, 180, 0, 232, 234, 241, 249, 266, 309, 284, 287, 290, 327, 330, 333, 351, 354, 370, 0, 422, 424, 431, 439, 456, 0, 509, 512, 515, 518, 533, 536, 539, 542, 557, 560, 563, 566, 582, 0, 635, 638, 641, 644, 659, 662, 665, 668, 683, 686, 702, 745, 727, 762, 720, 723, 794, 0, 846, 848, 765, 769, 880, 0, 932, 934, 0, 0, 3088, 3089, 3089, 111, 114, 47, 62, 3089, 117, 150, 3089, 3089, 3077, 3089, 3089, 3068, 3089, 3081, 3081, 932, 3089, 3089, 3089, 3089, 3079, 3079, 3049, 3089, 236, 3089, 168, 3062, 0, 155, 3089, 938, 3089, 173, 242, 936, 3089, 256, 3061, 0, 159, 3089, 3045, 3044, 244, 3044, 940, 3089, 357, 3057, 0, 343, 3089, 3041, 3089, 361, 432, 939, 3089, 446, 3055, 0, 426, 3089, 3036, 3038, 434, 942, 3089, 689, 3052, 0, 528, 3089, 3036, 3024, 3089, 692, 941, 770, 949, 3089, 738, 3049, 0, 552, 3089, 3022, 3032, 3020, 3089, 788, 964, 958, 774, 962, 3089, 855, 3045, 0, 654, 3089, 3029, 1008, 975, 3089, 863, 3043, 0, 678, 3089, 3024, 3026, 3046, 977, 3089, 866, 3039, 0, 855, 3089, 3012, 3022, 3010, 3041, 869, 34, 2999, 3089, 3041, 3032, 3089, 3089, 3089, 37, 40, 3000, 2999, 2997, 3028, 3011, 3089, 0, 2997, 260, 3003, 73, 2998, 3007, 3089, 0, 2998, 2998, 148, 2990, 3019, 2992, 3089, 0, 2993, 3000, 2984, 3089, 0, 2989, 2989, 2982, 3089, 0, 2987, 2976, 2994, 2993, 3089, 0, 2984, 2982, 2971, 2980, 2972, 3089, 0, 2978, 2971, 3089, 0, 2975, 2975, 2975, 2979, 3089, 0, 2973, 2971, 2960, 2977, 2992, 2999, 281, 2966, 3089, 148, 0, 2962, 2962, 2990, 2989, 2959, 3089, 2953, 2954, 2959, 2957, 2950, 2964, 2949, 997, 1000, 2959, 2944, 2971, 1005, 1026, 3089, 2956, 1022, 1029, 2944, 2952, 2953, 1033, 1051, 2952, 2939, 1059, 1062, 2937, 2935, 2948, 2935, 1068, 1072, 2935, 2945, 1079, 1085, 2942, 2943, 1089, 1092, 2928, 2941, 2928, 1109, 1112, 2957, 3089, 3089, 17, 2933, 3089, 2958, 2957, 2923, 3089, 3089, 2921, 2936, 2935, 2926, 2921, 2840, 2847, 255, 1115, 1118, 3089, 1121, 1138, 2842, 2852, 1141, 1147, 3089, 1150, 1154, 1158, 1170, 3089, 1175, 2832, 2820, 1178, 1182, 1187, 3089, 1194, 1199, 1204, 1207, 1211, 3089, 1216, 2819, 2821, 1220, 1228, 1224, 1236, 3089, 1244, 2810, 1247, 1253, 1256, 3089, 1263, 2808, 1266, 1273, 1276, 3089, 1282, 2812, 1285, 1294, 1301, 1304, 3089, 1310, 321, 1313, 3089, 3089, 2836, 2829, 2788, 2780, 873, 2788, 1055, 2791, 2776, 2780, 1321, 1331, 1334, 1342, 2789, 1353, 1358, 1361, 1370, 2765, 1374, 1377, 1393, 1396, 1399, 1414, 1417, 1425, 2654, 2650, 1432, 1435, 1443, 1448, 1459, 1462, 1465, 1478, 2653, 1481, 1484, 1497, 2648, 1500, 1505, 1516, 1520, 1532, 698, 2672, 1535, 3089, 2670, 3089, 3089, 2651, 1528, 1538, 2650, 1541, 2638, 2646, 2634, 1545, 1552, 3089, 3089, 1562, 1565, 2653, 1573, 1578, 3089, 3089, 1586, 1590, 1596, 3089, 3089, 1606, 1609, 3089, 3089, 1617, 3089, 3089, 1626, 2624, 2628, 1629, 3089, 3089, 1637, 3089, 3089, 1648, 1651, 3089, 3089, 1659, 1665, 1669, 3089, 3089, 1681, 2623, 1688, 3089, 3089, 1698, 3089, 3089, 1706, 320, 333, 3089, 1709, 1712, 2617, 1715, 1718, 2617, 1723, 1726, 1694, 1696, 2645, 1745, 1748, 1751, 1758, 1767, 1754, 1771, 1774, 1777, 1784, 1794, 1797, 1805, 3089, 1810, 1813, 3089, 284, 41, 1816, 1822, 1832, 1835, 2596, 1838, 2606, 2594, 51, 2573, 2569, 2539, 2518, 309, 2482, 2213, 2201, 1841, 1844, 1848, 3089, 3089, 1861, 1864, 3089, 1867, 1870, 1874, 1882, 1886, 1889, 3089, 3089, 1899, 1903, 1911, 505, 1915, 2137, 1919, 3089, 2096, 2062, 694, 2026, 2010, 1985, 1920, 1874, 130, 1872, 1858, 1825, 3089, 1922, 3089, 1928, 1931, 3089, 1939, 3089, 3089, 1948, 3089, 1951, 1954, 3089, 3089, 1997, 283, 1968, 1756, 1787, 3089, 1736, 1700, 1670, 1659, 1622, 1650, 3089, 1588, 1519, 1436, 1417, 1971, 3089, 1974, 509, 536, 326, 711, 228, 1050, 506, 1977, 1373, 3089, 3089, 1344, 1346, 1312, 1284, 3089, 3089, 1256, 1286, 1157, 1984, 530, 411, 533, 631, 105, 683, 972, 635, 634, 1141, 1089, 3089, 953, 943, 914, 3089, 813, 1991, 3089, 1113, 944, 977, 970, 996, 1308, 1060, 1088, 2001, 3089, 778, 740, 3089, 689, 612, 720, 2004, 1061, 2009, 640, 1086, 1309, 1003, 845, 2030, 2040, 3089, 542, 3089, 400, 2022, 2033, 638, 2050, 1111, 1049, 1145, 979, 1117, 2053, 2078, 2110, 333, 204, 2070, 1157, 1151, 1243, 2073, 2102, 2128, 2131, 1149, 2149, 2181, 17, 6, 1291, 1020, 2141, 1080, 2173, 2200, 2203, 2206, 1225, 511, 3089, 3089, 1264, 1215, 2212, 1272, 1374, 1392, 1394, 1412, 1217, 1300, 508, 1495, 837, 1340, 1477, 1534, 1542, 2223, 1021, 556, 1567, 762, 1364, 1396, 1430, 1460, 2233, 931, 2240, 1492, 2244, 1329, 1366, 1452, 1473, 1604, 2250, 2261, 1533, 2269, 1640, 1656, 1661, 1671, 1619, 2279, 632, 1388, 1680, 1598, 1811, 2287, 2290, 2296, 2299, 1498, 1814, 1831, 1218, 1332, 2307, 1351, 1422, 2317, 2325, 2335, 2343, 1554, 1583, 1630, 1565, 1607, 2353, 1627, 1772, 1876, 1920, 1921, 1941, 1972, 1973, 1979, 2045, 1764, 1804, 1878, 1705, 1929, 2048, 2103, 1949, 1950, 1669, 1776, 1910, 2089, 2090, 2144, 2145, 2177, 2361, 1996, 2032, 1585, 1810, 2199, 2204, 2049, 2051, 2052, 2120, 2121, 2122, 2174, 2201, 2211, 2227, 2364, 2085, 2256, 1371, 1437, 2231, 2237, 1476, 1747, 2251, 2297, 2300, 2318, 2336, 2342, 2354, 2356, 2130, 2176, 1863, 2221, 2010, 2248, 2358, 2359, 2295, 2367, 2330, 2332, 2362, 2366, 2368, 2370, 2372, 2375, 2278, 2298, 2383, 2384, 1457, 2379, 2378, 2380, 2381, 2385, 2259, 2286, 2306, 2322, 2382, 2386, 2388, 2389, 2387, 2390, 2392, 2393, 2391, 2394, 2397, 2412, 2414, 2416, 2424, 2426, 2427, 2435, 2436, 2438, 2439, 2440, 2434, 2437, 2423, 2441, 2442, 2443, 2451, 2453, 2448, 2450, 2456, 2457, 2458, 2461, 2462, 2463, 2464, 2466, 2455, 2468, 2469, 2470, 1978, 2485, 2477, 2482, 2154, 2493, 2471, 2489, 2490, 2491, 2492, 2495, 2496, 2497, 2498, 2500, 2515, 2513, 2524, 2505, 2506, 2545, 2517, 2525, 2532, 2533, 2535, 2538, 2539, 2540, 2514, 2519, 2562, 2574, 3089, 2544, 2551, 2579, 3089, 2553, 2575, 2581, 2576, 2582, 2580, 2584, 2586, 2573, 2578, 2603, 3089, 2597, 2592, 2614, 2620, 2623, 2626, 2591, 2593, 2631, 2643, 3089, 2648, 3089, 2651, 3089, 2654, 3089, 2596, 2601, 2660, 3089, 2642, 2650, 2671, 2677, 3089, 3089, 2695, 2702, 2709, 2716, 2723, 2730, 2737, 2744, 2751, 2758, 2765, 2772, 2779, 2786, 2793, 2798, 2803, 2808, 2813, 2818, 2823, 2828, 2833, 2838, 2845, 2848, 2851, 2854, 2857, 2860, 2863, 2866, 2869, 2872, 2879, 2883, 2889, 2895, 2901, 2907, 2913, 2919, 2925, 2931, 2937, 2944, 2951, 2958 } ; static xml_const short int xml__def[1112] = { 0, 1064, 1064, 1065, 1065, 1065, 1065, 1066, 1066, 1067, 1067, 1068, 1068, 1069, 1069, 1069, 1069, 1070, 1070, 1071, 1071, 1072, 1072, 1071, 1071, 1073, 1073, 1071, 1071, 1063, 29, 1069, 1069, 1071, 1071, 1074, 1074, 1071, 1071, 1071, 1071, 1075, 1075, 1071, 1071, 1063, 45, 1069, 1069, 1071, 1071, 1063, 51, 1071, 1071, 1071, 1071, 1071, 1071, 1076, 1076, 1076, 1076, 1071, 1071, 1063, 65, 1077, 1077, 1071, 1071, 1077, 1077, 1077, 1077, 1071, 1071, 1078, 1078, 1069, 1069, 1071, 1071, 1063, 83, 1069, 1069, 1071, 1071, 1063, 89, 1069, 1069, 1064, 1064, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1079, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1080, 1063, 1063, 1080, 1080, 1063, 1063, 1063, 1063, 1063, 1063, 1081, 1063, 1063, 1081, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1082, 1063, 1063, 1082, 1082, 1063, 1063, 1063, 1063, 1063, 1083, 1063, 1063, 1083, 1083, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1084, 1063, 1063, 1084, 1084, 1084, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1085, 1063, 1063, 1085, 1063, 1063, 1063, 1063, 1063, 1086, 1063, 1063, 1086, 1086, 202, 1063, 1063, 1063, 1063, 1087, 1063, 1063, 1087, 1087, 1087, 202, 1063, 1088, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1079, 1063, 1063, 1063, 1063, 1089, 1063, 1063, 1080, 1080, 1080, 1063, 1090, 1063, 1063, 1063, 1081, 1081, 1091, 1063, 1063, 1082, 1082, 1082, 1092, 1063, 1083, 1083, 1083, 1093, 1063, 1063, 1084, 1084, 1084, 1084, 1094, 1063, 1063, 1085, 1085, 1095, 1063, 1086, 1086, 1086, 1096, 1063, 1063, 1087, 1087, 1087, 1087, 1097, 1098, 1063, 1098, 1063, 1063, 1063, 1099, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1100, 1100, 1080, 1080, 1063, 1101, 1101, 1063, 1081, 1102, 1102, 1063, 1082, 1082, 1103, 1103, 1083, 1083, 1104, 1104, 1063, 1084, 1084, 1084, 1105, 1105, 1063, 1085, 1106, 1106, 1086, 1086, 1107, 1107, 1087, 1087, 1087, 1108, 1108, 1098, 1063, 1063, 1098, 1063, 1063, 1099, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1100, 1063, 1100, 1080, 1080, 1063, 1063, 1101, 1063, 1101, 1081, 1063, 1102, 1063, 1102, 1063, 1082, 1082, 1063, 1103, 1063, 1103, 1083, 1083, 1063, 1104, 1063, 1104, 1063, 1084, 1084, 1084, 1063, 1105, 1063, 1105, 1063, 1085, 1063, 1106, 1063, 1106, 1086, 1086, 1063, 1107, 1063, 1107, 1087, 1087, 1087, 1063, 1108, 1063, 1108, 1098, 1109, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1100, 1063, 1063, 1080, 1063, 1101, 1063, 1063, 1102, 1082, 1063, 1063, 1103, 1063, 1063, 1063, 1063, 1104, 1063, 1084, 1063, 1063, 1063, 1063, 1105, 1063, 1063, 1106, 1086, 1063, 1063, 1107, 1087, 1063, 1063, 1063, 1063, 1108, 1098, 1109, 1109, 1063, 1109, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1100, 1063, 1063, 1063, 1063, 1063, 1063, 1101, 1063, 1063, 1063, 1102, 1082, 1063, 1063, 1063, 1103, 1063, 1063, 1063, 1063, 1063, 1063, 1104, 1063, 1084, 1063, 1063, 1063, 1063, 1063, 1063, 1105, 1063, 1063, 1063, 1106, 1086, 1063, 1063, 1063, 1107, 1087, 1063, 1063, 1063, 1063, 1063, 1063, 1108, 1098, 1109, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1100, 1063, 1063, 1063, 1063, 1101, 1102, 1063, 1063, 1103, 1104, 1063, 1084, 1105, 1106, 1063, 1063, 1063, 1063, 1087, 1063, 1063, 1098, 1109, 1063, 1063, 1063, 1063, 1063, 1100, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1101, 1102, 1063, 1063, 1063, 1103, 1063, 1063, 1063, 1063, 1063, 1105, 1106, 1063, 1063, 1063, 1063, 1063, 1098, 1109, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1102, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1106, 1063, 1063, 1063, 1098, 1109, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1106, 1098, 1098, 1098, 1098, 1098, 1098, 1109, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1106, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1109, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1109, 1063, 1063, 1063, 1063, 1063, 1063, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1109, 1109, 1063, 1063, 1063, 1063, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1109, 1110, 1111, 1063, 1063, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1110, 1111, 1063, 1063, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1109, 1063, 1063, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1063, 1098, 1098, 1098, 1063, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1063, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1063, 1098, 1063, 1098, 1063, 1098, 1063, 1098, 1098, 1098, 1063, 1098, 1098, 1098, 1098, 1063, 0, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063 } ; static xml_const short int xml__nxt[3144] = { 0, 1063, 98, 99, 98, 98, 99, 98, 98, 99, 98, 98, 99, 98, 106, 775, 100, 106, 109, 100, 109, 107, 101, 774, 107, 101, 103, 99, 103, 103, 99, 103, 112, 113, 110, 355, 110, 114, 115, 429, 104, 112, 113, 104, 296, 116, 114, 115, 112, 113, 300, 117, 225, 114, 116, 112, 113, 297, 117, 484, 114, 116, 119, 120, 119, 120, 226, 225, 116, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 227, 302, 123, 622, 303, 123, 623, 615, 130, 301, 121, 130, 121, 124, 125, 99, 125, 124, 124, 124, 124, 124, 124, 124, 126, 124, 313, 124, 128, 124, 129, 124, 224, 224, 224, 224, 224, 224, 224, 224, 224, 314, 355, 124, 124, 124, 125, 99, 125, 124, 124, 124, 124, 124, 124, 124, 126, 124, 659, 124, 128, 124, 129, 124, 132, 99, 132, 132, 99, 132, 99, 99, 99, 711, 228, 124, 124, 296, 133, 228, 300, 133, 359, 228, 134, 99, 99, 99, 227, 224, 224, 224, 660, 227, 224, 224, 224, 227, 319, 134, 135, 136, 99, 136, 135, 135, 135, 135, 135, 135, 135, 137, 135, 138, 135, 139, 135, 140, 135, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 135, 135, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 141, 138, 138, 138, 138, 138, 138, 138, 142, 138, 138, 138, 112, 113, 112, 113, 763, 114, 228, 114, 99, 99, 99, 355, 228, 143, 252, 143, 99, 99, 99, 246, 227, 253, 145, 224, 224, 224, 227, 693, 227, 144, 145, 144, 146, 147, 99, 147, 146, 146, 146, 146, 146, 146, 146, 148, 146, 239, 146, 150, 146, 151, 146, 99, 99, 99, 99, 99, 99, 99, 99, 99, 441, 310, 146, 146, 355, 134, 484, 355, 134, 311, 442, 134, 357, 614, 152, 146, 147, 99, 147, 146, 146, 146, 146, 146, 146, 146, 148, 146, 673, 146, 150, 146, 151, 146, 99, 99, 99, 154, 99, 154, 154, 99, 154, 355, 355, 146, 146, 628, 134, 355, 629, 155, 577, 228, 155, 481, 484, 152, 99, 99, 99, 99, 99, 99, 224, 224, 224, 227, 224, 224, 224, 691, 156, 762, 578, 156, 157, 158, 99, 158, 157, 157, 157, 157, 157, 157, 157, 159, 157, 160, 157, 161, 157, 162, 157, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 157, 157, 160, 160, 160, 160, 160, 160, 160, 160, 163, 160, 164, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 112, 113, 112, 113, 355, 114, 228, 114, 99, 99, 99, 750, 228, 165, 252, 165, 99, 99, 99, 259, 227, 265, 166, 224, 224, 224, 227, 708, 227, 144, 166, 144, 167, 168, 99, 168, 167, 167, 167, 167, 167, 167, 167, 169, 167, 170, 167, 171, 167, 172, 167, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 167, 167, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 173, 170, 170, 170, 174, 170, 170, 170, 170, 170, 170, 170, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 484, 484, 156, 355, 355, 156, 484, 485, 156, 795, 228, 156, 99, 99, 99, 99, 99, 99, 176, 99, 176, 176, 99, 176, 227, 355, 156, 696, 355, 156, 648, 355, 177, 688, 228, 177, 176, 99, 176, 176, 99, 176, 99, 99, 99, 99, 99, 99, 227, 689, 178, 355, 709, 178, 707, 749, 179, 690, 804, 179, 180, 181, 99, 181, 180, 180, 180, 180, 180, 180, 180, 182, 180, 183, 180, 184, 180, 185, 180, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 180, 180, 183, 186, 183, 183, 183, 183, 183, 183, 183, 183, 187, 183, 183, 183, 188, 183, 183, 183, 183, 183, 183, 183, 190, 99, 190, 190, 99, 190, 99, 99, 99, 99, 99, 99, 355, 355, 191, 484, 355, 191, 736, 355, 192, 355, 228, 192, 190, 99, 190, 190, 99, 190, 190, 99, 190, 190, 99, 190, 227, 753, 191, 834, 715, 191, 710, 741, 193, 714, 228, 193, 99, 99, 99, 99, 99, 99, 224, 224, 224, 224, 224, 224, 227, 735, 194, 652, 355, 194, 195, 196, 99, 196, 195, 195, 195, 195, 195, 195, 195, 197, 195, 355, 195, 199, 195, 200, 195, 99, 99, 99, 99, 99, 99, 546, 355, 112, 113, 712, 195, 195, 114, 203, 653, 355, 203, 224, 224, 224, 202, 692, 201, 195, 196, 99, 196, 195, 195, 195, 195, 195, 195, 195, 197, 195, 144, 195, 199, 195, 200, 195, 112, 113, 99, 99, 99, 114, 99, 99, 99, 737, 228, 195, 195, 202, 228, 355, 213, 270, 734, 733, 213, 277, 806, 201, 227, 224, 224, 224, 227, 144, 204, 205, 99, 205, 204, 204, 204, 204, 204, 204, 204, 206, 204, 207, 204, 208, 204, 209, 204, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 204, 204, 207, 207, 207, 207, 207, 207, 207, 207, 210, 207, 211, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 112, 113, 112, 113, 721, 114, 355, 114, 224, 224, 224, 228, 797, 212, 355, 212, 224, 224, 224, 224, 224, 224, 224, 224, 224, 227, 490, 490, 490, 144, 745, 144, 214, 215, 99, 215, 214, 214, 214, 214, 214, 214, 214, 216, 214, 217, 214, 218, 214, 219, 214, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 214, 214, 217, 220, 217, 217, 217, 217, 217, 217, 217, 217, 221, 217, 217, 217, 222, 217, 217, 217, 217, 217, 217, 217, 112, 113, 112, 113, 233, 114, 228, 114, 228, 228, 228, 228, 228, 223, 355, 223, 720, 719, 270, 228, 227, 812, 227, 227, 227, 227, 227, 355, 228, 144, 234, 144, 228, 227, 228, 235, 242, 243, 236, 255, 242, 277, 227, 237, 244, 228, 227, 228, 227, 247, 723, 245, 260, 355, 260, 355, 271, 255, 718, 227, 355, 227, 355, 255, 373, 373, 373, 373, 373, 373, 713, 247, 380, 380, 380, 278, 288, 247, 252, 355, 375, 244, 758, 375, 725, 282, 355, 724, 382, 385, 385, 385, 227, 380, 380, 380, 385, 385, 385, 376, 392, 392, 392, 355, 355, 387, 242, 243, 726, 382, 803, 744, 387, 777, 244, 271, 394, 239, 392, 392, 392, 245, 492, 492, 492, 383, 398, 398, 398, 398, 398, 398, 355, 355, 394, 406, 406, 406, 388, 406, 406, 406, 400, 355, 355, 400, 412, 412, 412, 694, 756, 408, 412, 412, 412, 408, 418, 418, 418, 418, 418, 418, 414, 355, 695, 395, 728, 739, 414, 355, 409, 355, 420, 779, 401, 420, 425, 425, 425, 425, 425, 425, 373, 373, 373, 373, 373, 373, 373, 373, 373, 717, 427, 729, 355, 427, 355, 421, 375, 415, 355, 375, 742, 730, 375, 444, 444, 444, 380, 380, 380, 722, 716, 428, 380, 380, 380, 380, 380, 380, 445, 449, 449, 449, 382, 385, 385, 385, 355, 755, 382, 759, 355, 382, 355, 443, 450, 385, 385, 385, 355, 387, 385, 385, 385, 453, 453, 453, 448, 392, 392, 392, 765, 387, 392, 392, 392, 757, 387, 704, 454, 392, 392, 392, 772, 394, 456, 456, 456, 766, 394, 458, 458, 458, 398, 398, 398, 394, 398, 398, 398, 457, 451, 398, 398, 398, 459, 463, 463, 463, 400, 406, 406, 406, 400, 465, 465, 465, 355, 400, 355, 355, 464, 406, 406, 406, 455, 408, 355, 786, 466, 406, 406, 406, 468, 468, 468, 846, 793, 408, 412, 412, 412, 412, 412, 412, 355, 408, 460, 469, 412, 412, 412, 472, 472, 472, 414, 784, 767, 414, 418, 418, 418, 418, 418, 418, 414, 355, 473, 418, 418, 418, 476, 476, 476, 355, 420, 785, 467, 420, 703, 478, 478, 478, 702, 420, 788, 477, 425, 425, 425, 425, 425, 425, 355, 470, 479, 425, 425, 425, 483, 483, 483, 355, 427, 701, 776, 427, 373, 373, 373, 355, 355, 427, 794, 474, 484, 485, 444, 444, 444, 497, 497, 497, 375, 498, 727, 743, 499, 500, 500, 500, 355, 445, 700, 355, 480, 699, 816, 496, 380, 380, 380, 355, 501, 449, 449, 449, 504, 504, 504, 847, 505, 798, 355, 506, 382, 385, 385, 385, 450, 453, 453, 453, 509, 509, 509, 355, 510, 355, 849, 511, 698, 387, 355, 817, 454, 355, 807, 503, 392, 392, 392, 456, 456, 456, 513, 513, 513, 789, 514, 355, 914, 515, 697, 355, 394, 355, 457, 355, 507, 458, 458, 458, 516, 516, 516, 790, 517, 791, 808, 518, 398, 398, 398, 355, 459, 835, 512, 463, 463, 463, 522, 522, 522, 355, 523, 792, 400, 524, 465, 465, 465, 355, 464, 525, 525, 525, 686, 526, 355, 850, 527, 519, 809, 466, 406, 406, 406, 468, 468, 468, 529, 529, 529, 355, 530, 685, 915, 531, 355, 818, 408, 355, 469, 412, 412, 412, 472, 472, 472, 534, 534, 534, 810, 535, 355, 950, 536, 355, 355, 414, 819, 473, 418, 418, 418, 476, 476, 476, 799, 528, 539, 539, 539, 355, 540, 918, 355, 541, 420, 355, 477, 478, 478, 478, 814, 542, 542, 542, 796, 543, 843, 532, 544, 550, 550, 550, 479, 425, 425, 425, 483, 483, 483, 490, 490, 490, 492, 492, 492, 537, 373, 373, 373, 427, 355, 355, 484, 497, 497, 497, 824, 498, 684, 355, 499, 800, 375, 500, 500, 500, 556, 556, 556, 801, 557, 355, 545, 558, 380, 380, 380, 859, 501, 504, 504, 504, 355, 505, 355, 547, 506, 385, 385, 385, 382, 562, 562, 562, 805, 555, 683, 509, 509, 509, 355, 510, 355, 387, 511, 560, 563, 392, 392, 392, 513, 513, 513, 862, 514, 355, 860, 515, 516, 516, 516, 355, 517, 394, 355, 518, 561, 398, 398, 398, 522, 522, 522, 820, 523, 896, 355, 524, 525, 525, 525, 837, 526, 400, 355, 527, 831, 355, 564, 406, 406, 406, 529, 529, 529, 863, 530, 355, 682, 531, 412, 412, 412, 861, 827, 408, 570, 570, 570, 681, 534, 534, 534, 355, 535, 866, 414, 536, 355, 565, 828, 571, 572, 572, 572, 829, 355, 568, 355, 539, 539, 539, 569, 540, 680, 830, 541, 355, 573, 542, 542, 542, 885, 543, 836, 679, 544, 575, 575, 575, 579, 579, 579, 550, 550, 550, 581, 581, 581, 582, 582, 582, 355, 576, 373, 373, 373, 556, 556, 556, 585, 557, 590, 586, 558, 591, 587, 879, 592, 678, 375, 677, 588, 589, 593, 594, 380, 380, 380, 385, 385, 385, 562, 562, 562, 602, 602, 602, 584, 598, 598, 598, 382, 599, 355, 387, 600, 563, 392, 392, 392, 603, 604, 604, 604, 605, 605, 605, 406, 406, 406, 355, 919, 597, 394, 412, 412, 412, 876, 355, 606, 596, 676, 355, 408, 570, 570, 570, 609, 609, 609, 414, 610, 675, 601, 611, 572, 572, 572, 886, 571, 612, 612, 612, 575, 575, 575, 579, 579, 579, 867, 355, 573, 616, 616, 616, 613, 355, 355, 607, 576, 355, 608, 581, 581, 581, 582, 582, 582, 618, 618, 618, 633, 633, 633, 385, 385, 385, 355, 598, 598, 598, 877, 599, 838, 619, 600, 844, 634, 663, 897, 387, 636, 636, 636, 602, 602, 602, 604, 604, 604, 605, 605, 605, 845, 638, 638, 638, 637, 639, 355, 603, 640, 641, 641, 641, 606, 412, 412, 412, 609, 609, 609, 355, 610, 355, 635, 611, 930, 642, 612, 612, 612, 414, 644, 644, 644, 662, 645, 661, 658, 646, 647, 647, 647, 613, 616, 616, 616, 868, 618, 618, 618, 633, 633, 633, 878, 355, 355, 664, 664, 664, 636, 636, 636, 643, 619, 355, 355, 634, 638, 638, 638, 887, 639, 665, 355, 640, 637, 641, 641, 641, 412, 412, 412, 644, 644, 644, 355, 645, 657, 880, 646, 869, 870, 642, 355, 355, 414, 674, 674, 674, 664, 664, 664, 412, 412, 412, 674, 674, 674, 883, 884, 1004, 871, 705, 705, 705, 665, 355, 355, 414, 705, 705, 705, 355, 355, 666, 647, 647, 647, 706, 731, 731, 731, 738, 738, 738, 706, 687, 740, 740, 740, 355, 355, 872, 873, 732, 484, 656, 932, 355, 874, 751, 751, 751, 355, 355, 894, 667, 668, 731, 731, 731, 738, 738, 738, 669, 670, 355, 671, 746, 746, 746, 672, 747, 732, 484, 748, 355, 355, 740, 740, 740, 746, 746, 746, 484, 747, 655, 752, 748, 355, 654, 895, 355, 355, 355, 355, 355, 484, 751, 751, 751, 768, 768, 768, 754, 482, 482, 482, 482, 482, 482, 482, 482, 482, 355, 875, 482, 355, 881, 482, 482, 482, 484, 482, 764, 651, 900, 902, 901, 355, 769, 769, 769, 355, 355, 482, 482, 482, 482, 482, 482, 482, 482, 482, 482, 482, 355, 355, 482, 888, 889, 482, 482, 482, 484, 482, 770, 770, 770, 771, 771, 771, 912, 650, 355, 355, 355, 482, 482, 778, 778, 778, 355, 882, 355, 355, 482, 482, 482, 482, 482, 773, 482, 482, 482, 355, 1007, 482, 355, 355, 482, 482, 482, 484, 482, 903, 904, 905, 355, 649, 928, 768, 768, 768, 890, 891, 482, 482, 482, 482, 482, 482, 482, 482, 482, 482, 773, 355, 355, 482, 355, 355, 482, 482, 482, 484, 482, 780, 769, 769, 769, 770, 770, 770, 771, 771, 771, 892, 482, 482, 778, 778, 778, 355, 355, 355, 929, 355, 355, 906, 355, 802, 802, 802, 781, 355, 355, 782, 632, 898, 783, 802, 802, 802, 899, 355, 787, 355, 813, 813, 813, 355, 815, 815, 815, 355, 907, 355, 821, 821, 821, 355, 631, 931, 355, 933, 908, 811, 355, 813, 813, 813, 355, 822, 355, 355, 823, 815, 815, 815, 355, 825, 909, 355, 826, 355, 916, 821, 821, 821, 920, 832, 917, 355, 833, 839, 839, 839, 840, 840, 840, 956, 355, 355, 841, 841, 841, 842, 842, 842, 355, 355, 936, 913, 355, 848, 848, 848, 946, 355, 355, 355, 355, 355, 355, 839, 839, 839, 957, 851, 355, 355, 852, 840, 840, 840, 921, 853, 947, 922, 854, 355, 355, 841, 841, 841, 355, 855, 958, 355, 856, 842, 842, 842, 355, 857, 355, 923, 858, 355, 355, 848, 848, 848, 959, 864, 355, 355, 865, 893, 893, 893, 893, 893, 893, 924, 910, 355, 355, 911, 355, 925, 355, 355, 937, 355, 355, 938, 355, 939, 355, 355, 355, 926, 355, 927, 355, 934, 935, 355, 948, 949, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 940, 951, 355, 954, 941, 960, 942, 955, 943, 961, 944, 962, 963, 945, 966, 967, 952, 355, 953, 355, 970, 355, 974, 964, 975, 976, 965, 968, 355, 355, 969, 355, 355, 977, 978, 971, 979, 980, 981, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 988, 972, 989, 973, 355, 982, 355, 355, 983, 355, 984, 355, 355, 355, 355, 986, 987, 355, 355, 355, 355, 990, 355, 991, 355, 355, 355, 355, 985, 992, 993, 994, 1004, 355, 995, 996, 997, 998, 355, 999, 1007, 355, 1002, 1003, 1000, 355, 355, 355, 355, 355, 1005, 355, 355, 355, 355, 1006, 355, 1001, 1008, 1018, 1018, 355, 355, 1033, 1019, 1019, 1019, 630, 1034, 355, 355, 355, 1016, 355, 1017, 355, 1009, 1010, 1011, 1012, 1020, 355, 1013, 1014, 1015, 1023, 1023, 1023, 355, 355, 1025, 355, 1021, 1022, 355, 355, 355, 1039, 1026, 627, 355, 1024, 1035, 1035, 1035, 1027, 1028, 355, 1029, 355, 626, 1030, 1031, 1032, 1019, 1019, 1019, 1037, 1036, 1023, 1023, 1023, 1039, 1040, 1038, 1040, 1041, 1041, 1042, 355, 1020, 355, 355, 1042, 355, 1024, 355, 355, 355, 1045, 355, 1045, 355, 1035, 1035, 1035, 1043, 355, 355, 355, 625, 1044, 355, 355, 1046, 1046, 1046, 355, 624, 1036, 1048, 1048, 1048, 1050, 1050, 1050, 1052, 1052, 1052, 1058, 1047, 1056, 1056, 1056, 1059, 621, 1049, 620, 1054, 1051, 1055, 617, 1053, 1046, 1046, 1046, 1060, 1057, 1048, 1048, 1048, 1050, 1050, 1050, 1052, 1052, 1052, 1060, 355, 1047, 1056, 1056, 1056, 595, 1049, 583, 355, 1051, 580, 574, 1053, 1061, 1061, 1061, 567, 566, 1057, 1061, 1061, 1061, 559, 554, 553, 552, 551, 549, 548, 1062, 484, 538, 533, 521, 520, 1062, 96, 96, 96, 96, 96, 96, 96, 97, 97, 97, 97, 97, 97, 97, 102, 102, 102, 102, 102, 102, 102, 105, 105, 105, 105, 105, 105, 105, 108, 108, 108, 108, 108, 108, 108, 111, 111, 111, 111, 111, 111, 111, 118, 118, 118, 118, 118, 118, 118, 122, 122, 122, 122, 122, 122, 122, 127, 127, 127, 127, 127, 127, 127, 131, 131, 131, 131, 131, 131, 131, 149, 149, 149, 149, 149, 149, 149, 153, 153, 153, 153, 153, 153, 153, 175, 175, 175, 175, 175, 175, 175, 189, 189, 189, 189, 189, 189, 189, 198, 198, 198, 198, 198, 198, 198, 241, 241, 241, 508, 241, 249, 249, 249, 502, 249, 257, 257, 257, 495, 257, 262, 262, 262, 494, 262, 267, 267, 267, 493, 267, 273, 273, 273, 491, 273, 280, 280, 280, 489, 280, 284, 284, 284, 488, 284, 290, 290, 290, 487, 290, 295, 295, 295, 295, 295, 486, 295, 315, 475, 315, 320, 471, 320, 324, 442, 324, 329, 462, 329, 333, 461, 333, 339, 452, 339, 343, 441, 343, 347, 447, 347, 352, 446, 352, 354, 354, 354, 354, 354, 354, 354, 360, 440, 439, 360, 374, 374, 374, 374, 374, 374, 381, 381, 381, 381, 381, 381, 386, 386, 386, 386, 386, 386, 393, 393, 393, 393, 393, 393, 399, 399, 399, 399, 399, 399, 407, 407, 407, 407, 407, 407, 413, 413, 413, 413, 413, 413, 419, 419, 419, 419, 419, 419, 426, 426, 426, 426, 426, 426, 482, 482, 482, 482, 482, 482, 482, 760, 760, 760, 760, 760, 760, 760, 761, 761, 761, 761, 761, 761, 761, 438, 437, 436, 435, 434, 433, 432, 431, 430, 355, 424, 423, 422, 417, 416, 411, 410, 405, 404, 403, 402, 397, 396, 391, 390, 389, 384, 379, 378, 377, 372, 371, 370, 369, 368, 367, 366, 365, 364, 363, 362, 361, 358, 356, 355, 353, 351, 350, 349, 310, 348, 346, 345, 344, 342, 341, 340, 338, 337, 336, 335, 334, 332, 331, 330, 328, 327, 326, 325, 323, 311, 322, 321, 318, 317, 313, 316, 312, 309, 308, 307, 306, 305, 304, 299, 296, 298, 294, 293, 292, 291, 289, 287, 286, 285, 283, 281, 279, 276, 275, 274, 272, 269, 268, 266, 264, 263, 261, 258, 256, 254, 251, 250, 248, 240, 238, 232, 231, 232, 231, 230, 229, 1063, 95, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063 } ; static xml_const short int xml__chk[3144] = { 0, 0, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 9, 763, 3, 10, 11, 4, 12, 9, 5, 762, 10, 6, 7, 7, 7, 8, 8, 8, 13, 13, 11, 357, 12, 13, 13, 357, 7, 14, 14, 8, 225, 13, 14, 14, 15, 15, 233, 15, 100, 15, 14, 16, 16, 225, 16, 578, 16, 15, 17, 17, 18, 18, 100, 101, 16, 19, 19, 19, 20, 20, 20, 23, 23, 23, 24, 24, 24, 101, 234, 19, 587, 234, 20, 587, 578, 23, 233, 17, 24, 18, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 245, 21, 21, 21, 21, 21, 98, 98, 98, 99, 99, 99, 103, 103, 103, 245, 692, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 628, 22, 22, 22, 22, 22, 25, 25, 25, 26, 26, 26, 27, 27, 27, 692, 104, 22, 22, 252, 25, 128, 300, 26, 300, 139, 27, 28, 28, 28, 104, 125, 125, 125, 628, 128, 132, 132, 132, 139, 252, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 31, 31, 32, 32, 750, 31, 123, 32, 33, 33, 33, 671, 133, 31, 143, 32, 34, 34, 34, 133, 123, 143, 33, 136, 136, 136, 133, 671, 143, 31, 34, 32, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 123, 35, 35, 35, 35, 35, 37, 37, 37, 38, 38, 38, 39, 39, 39, 372, 243, 35, 35, 297, 37, 648, 577, 38, 243, 372, 39, 297, 577, 35, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 648, 36, 36, 36, 36, 36, 40, 40, 40, 41, 41, 41, 42, 42, 42, 546, 429, 36, 36, 592, 40, 669, 592, 41, 546, 150, 42, 429, 547, 36, 43, 43, 43, 44, 44, 44, 147, 147, 147, 150, 154, 154, 154, 669, 43, 749, 547, 44, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 47, 47, 48, 48, 689, 47, 161, 48, 49, 49, 49, 736, 155, 47, 165, 48, 50, 50, 50, 155, 161, 165, 49, 158, 158, 158, 155, 689, 165, 47, 50, 48, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 53, 53, 53, 54, 54, 54, 55, 55, 55, 56, 56, 56, 615, 673, 53, 786, 667, 54, 773, 773, 55, 786, 171, 56, 57, 57, 57, 58, 58, 58, 59, 59, 59, 60, 60, 60, 171, 688, 57, 673, 690, 58, 615, 668, 59, 667, 184, 60, 61, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 64, 184, 668, 61, 795, 690, 62, 688, 734, 63, 668, 795, 64, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 67, 67, 67, 68, 68, 68, 69, 69, 69, 70, 70, 70, 691, 822, 67, 696, 695, 68, 721, 739, 69, 726, 199, 70, 71, 71, 71, 72, 72, 72, 73, 73, 73, 74, 74, 74, 199, 739, 71, 822, 696, 72, 691, 726, 73, 695, 208, 74, 75, 75, 75, 76, 76, 76, 168, 168, 168, 176, 176, 176, 208, 720, 75, 622, 693, 76, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 481, 77, 77, 77, 77, 77, 81, 81, 81, 82, 82, 82, 481, 670, 79, 79, 693, 77, 77, 79, 81, 622, 722, 82, 181, 181, 181, 79, 670, 77, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 79, 78, 78, 78, 78, 78, 80, 80, 87, 87, 87, 80, 88, 88, 88, 722, 178, 78, 78, 80, 193, 797, 87, 178, 718, 717, 88, 193, 797, 78, 178, 190, 190, 190, 193, 80, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 85, 85, 86, 86, 704, 85, 788, 86, 196, 196, 196, 218, 788, 85, 730, 86, 205, 205, 205, 215, 215, 215, 224, 224, 224, 218, 437, 437, 437, 85, 730, 86, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 91, 91, 92, 92, 114, 91, 134, 92, 130, 156, 145, 177, 166, 91, 803, 92, 702, 701, 177, 179, 134, 803, 130, 156, 145, 177, 166, 708, 192, 91, 114, 92, 194, 179, 191, 114, 130, 130, 114, 145, 166, 191, 192, 114, 130, 203, 194, 213, 191, 134, 708, 130, 156, 710, 177, 694, 179, 192, 700, 203, 709, 213, 744, 191, 315, 315, 315, 316, 316, 316, 694, 192, 320, 320, 320, 194, 213, 191, 202, 711, 315, 203, 744, 316, 710, 202, 729, 709, 320, 324, 324, 324, 202, 321, 321, 321, 325, 325, 325, 316, 329, 329, 329, 765, 794, 324, 202, 202, 711, 321, 794, 729, 325, 765, 202, 202, 329, 202, 330, 330, 330, 202, 439, 439, 439, 321, 333, 333, 333, 334, 334, 334, 742, 672, 330, 339, 339, 339, 325, 340, 340, 340, 333, 713, 724, 334, 343, 343, 343, 672, 742, 339, 344, 344, 344, 340, 347, 347, 347, 348, 348, 348, 343, 767, 672, 330, 713, 724, 344, 727, 340, 714, 347, 767, 334, 348, 352, 352, 352, 353, 353, 353, 373, 373, 373, 374, 374, 374, 376, 376, 376, 698, 352, 714, 741, 353, 707, 348, 373, 344, 745, 374, 727, 714, 376, 377, 377, 377, 380, 380, 380, 707, 697, 353, 381, 381, 381, 383, 383, 383, 377, 384, 384, 384, 380, 385, 385, 385, 743, 741, 381, 745, 759, 383, 753, 376, 384, 386, 386, 386, 752, 385, 388, 388, 388, 391, 391, 391, 383, 392, 392, 392, 752, 386, 393, 393, 393, 743, 388, 686, 391, 395, 395, 395, 759, 392, 396, 396, 396, 753, 393, 397, 397, 397, 398, 398, 398, 395, 399, 399, 399, 396, 388, 401, 401, 401, 397, 404, 404, 404, 398, 406, 406, 406, 399, 405, 405, 405, 777, 401, 784, 834, 404, 407, 407, 407, 395, 406, 772, 777, 405, 409, 409, 409, 411, 411, 411, 834, 784, 407, 412, 412, 412, 413, 413, 413, 754, 409, 401, 411, 415, 415, 415, 417, 417, 417, 412, 772, 754, 413, 418, 418, 418, 419, 419, 419, 415, 776, 417, 421, 421, 421, 423, 423, 423, 779, 418, 776, 409, 419, 685, 424, 424, 424, 684, 421, 779, 423, 425, 425, 425, 426, 426, 426, 764, 415, 424, 428, 428, 428, 430, 430, 430, 785, 425, 681, 764, 426, 443, 443, 443, 712, 728, 428, 785, 421, 430, 430, 444, 444, 444, 445, 445, 445, 443, 445, 712, 728, 445, 446, 446, 446, 807, 444, 680, 835, 428, 679, 807, 443, 448, 448, 448, 789, 446, 449, 449, 449, 450, 450, 450, 835, 450, 789, 837, 450, 448, 451, 451, 451, 449, 453, 453, 453, 454, 454, 454, 798, 454, 808, 837, 454, 678, 451, 896, 808, 453, 780, 798, 448, 455, 455, 455, 456, 456, 456, 457, 457, 457, 780, 457, 823, 896, 457, 675, 781, 455, 782, 456, 799, 451, 458, 458, 458, 459, 459, 459, 781, 459, 782, 799, 459, 460, 460, 460, 783, 458, 823, 455, 463, 463, 463, 464, 464, 464, 838, 464, 783, 460, 464, 465, 465, 465, 800, 463, 466, 466, 466, 663, 466, 897, 838, 466, 460, 800, 465, 467, 467, 467, 468, 468, 468, 469, 469, 469, 809, 469, 662, 897, 469, 932, 809, 467, 801, 468, 470, 470, 470, 472, 472, 472, 473, 473, 473, 801, 473, 810, 932, 473, 900, 790, 470, 810, 472, 474, 474, 474, 476, 476, 476, 790, 467, 477, 477, 477, 805, 477, 900, 787, 477, 474, 831, 476, 478, 478, 478, 805, 479, 479, 479, 787, 479, 831, 470, 479, 489, 489, 489, 478, 480, 480, 480, 483, 483, 483, 490, 490, 490, 492, 492, 492, 474, 496, 496, 496, 480, 814, 791, 483, 497, 497, 497, 814, 497, 661, 792, 497, 791, 496, 500, 500, 500, 501, 501, 501, 792, 501, 843, 480, 501, 503, 503, 503, 843, 500, 504, 504, 504, 846, 504, 796, 483, 504, 507, 507, 507, 503, 508, 508, 508, 796, 496, 660, 509, 509, 509, 844, 509, 879, 507, 509, 503, 508, 512, 512, 512, 513, 513, 513, 846, 513, 825, 844, 513, 516, 516, 516, 811, 516, 512, 847, 516, 507, 519, 519, 519, 522, 522, 522, 811, 522, 879, 820, 522, 525, 525, 525, 825, 525, 519, 849, 525, 820, 845, 512, 528, 528, 528, 529, 529, 529, 847, 529, 816, 658, 529, 532, 532, 532, 845, 816, 528, 533, 533, 533, 657, 534, 534, 534, 817, 534, 849, 532, 534, 818, 519, 817, 533, 537, 537, 537, 818, 868, 528, 819, 539, 539, 539, 532, 539, 656, 819, 539, 824, 537, 542, 542, 542, 868, 542, 824, 655, 542, 545, 545, 545, 549, 549, 549, 550, 550, 550, 552, 552, 552, 553, 553, 553, 862, 545, 555, 555, 555, 556, 556, 556, 557, 556, 558, 557, 556, 558, 557, 862, 558, 654, 555, 653, 557, 557, 558, 558, 560, 560, 560, 561, 561, 561, 562, 562, 562, 565, 565, 565, 555, 563, 563, 563, 560, 563, 901, 561, 563, 562, 564, 564, 564, 565, 566, 566, 566, 567, 567, 567, 568, 568, 568, 859, 901, 561, 564, 569, 569, 569, 859, 850, 567, 560, 651, 869, 568, 570, 570, 570, 571, 571, 571, 569, 571, 650, 564, 571, 572, 572, 572, 869, 570, 574, 574, 574, 575, 575, 575, 579, 579, 579, 850, 860, 572, 580, 580, 580, 574, 880, 826, 568, 575, 832, 569, 581, 581, 581, 582, 582, 582, 584, 584, 584, 596, 596, 596, 597, 597, 597, 833, 598, 598, 598, 860, 598, 826, 584, 598, 832, 596, 631, 880, 597, 601, 601, 601, 602, 602, 602, 604, 604, 604, 605, 605, 605, 833, 606, 606, 606, 601, 606, 912, 602, 606, 607, 607, 607, 605, 608, 608, 608, 609, 609, 609, 851, 609, 861, 597, 609, 912, 607, 612, 612, 612, 608, 613, 613, 613, 630, 613, 629, 627, 613, 614, 614, 614, 612, 616, 616, 616, 851, 618, 618, 618, 633, 633, 633, 861, 870, 614, 635, 635, 635, 636, 636, 636, 608, 618, 852, 853, 633, 638, 638, 638, 870, 638, 635, 863, 638, 636, 641, 641, 641, 643, 643, 643, 644, 644, 644, 854, 644, 626, 863, 644, 852, 853, 641, 866, 867, 643, 649, 649, 649, 664, 664, 664, 666, 666, 666, 674, 674, 674, 866, 867, 986, 854, 687, 687, 687, 664, 855, 856, 666, 705, 705, 705, 986, 857, 643, 647, 647, 647, 687, 715, 715, 715, 723, 723, 723, 705, 666, 725, 725, 725, 877, 647, 855, 856, 715, 715, 625, 914, 723, 857, 737, 737, 737, 725, 914, 877, 647, 647, 731, 731, 731, 738, 738, 738, 647, 647, 737, 647, 732, 732, 732, 647, 732, 731, 731, 732, 878, 738, 740, 740, 740, 746, 746, 746, 732, 746, 624, 738, 746, 858, 623, 878, 864, 883, 740, 884, 885, 746, 751, 751, 751, 755, 755, 755, 740, 747, 747, 747, 747, 747, 747, 747, 747, 747, 751, 858, 747, 755, 864, 747, 747, 747, 747, 747, 751, 621, 883, 885, 884, 894, 756, 756, 756, 871, 872, 747, 747, 748, 748, 748, 748, 748, 748, 748, 748, 748, 756, 865, 748, 871, 872, 748, 748, 748, 748, 748, 757, 757, 757, 758, 758, 758, 894, 620, 886, 887, 888, 748, 748, 766, 766, 766, 757, 865, 910, 758, 760, 760, 760, 760, 760, 760, 760, 760, 760, 766, 990, 760, 873, 874, 760, 760, 760, 760, 760, 886, 887, 888, 990, 617, 910, 768, 768, 768, 873, 874, 760, 760, 761, 761, 761, 761, 761, 761, 761, 761, 761, 768, 889, 761, 911, 875, 761, 761, 761, 761, 761, 768, 769, 769, 769, 770, 770, 770, 771, 771, 771, 875, 761, 761, 778, 778, 778, 881, 769, 890, 911, 770, 882, 889, 771, 793, 793, 793, 769, 891, 778, 770, 595, 881, 771, 802, 802, 802, 882, 913, 778, 793, 804, 804, 804, 892, 806, 806, 806, 898, 890, 802, 812, 812, 812, 899, 594, 913, 804, 915, 891, 802, 806, 813, 813, 813, 915, 813, 812, 902, 813, 815, 815, 815, 895, 815, 892, 938, 815, 813, 898, 821, 821, 821, 902, 821, 899, 815, 821, 827, 827, 827, 828, 828, 828, 938, 928, 821, 829, 829, 829, 830, 830, 830, 939, 827, 918, 895, 828, 836, 836, 836, 928, 918, 829, 903, 929, 830, 904, 839, 839, 839, 939, 839, 940, 836, 839, 840, 840, 840, 903, 840, 929, 904, 840, 839, 905, 841, 841, 841, 941, 841, 940, 840, 841, 842, 842, 842, 920, 842, 921, 905, 842, 841, 906, 848, 848, 848, 941, 848, 907, 842, 848, 876, 876, 876, 893, 893, 893, 906, 893, 848, 908, 893, 909, 907, 916, 917, 919, 876, 922, 920, 893, 921, 923, 919, 924, 908, 925, 909, 926, 916, 917, 927, 930, 931, 934, 933, 935, 936, 942, 930, 931, 937, 943, 946, 944, 945, 947, 950, 948, 949, 951, 922, 933, 952, 936, 923, 942, 924, 937, 925, 943, 926, 944, 945, 927, 948, 949, 934, 953, 935, 954, 952, 955, 956, 946, 957, 958, 947, 950, 966, 956, 951, 957, 958, 959, 960, 953, 961, 962, 963, 964, 959, 960, 965, 961, 962, 963, 967, 968, 969, 970, 954, 971, 955, 972, 964, 973, 970, 965, 971, 966, 982, 974, 975, 976, 968, 969, 977, 978, 979, 980, 972, 981, 973, 983, 984, 985, 992, 967, 974, 975, 976, 987, 988, 977, 978, 979, 980, 989, 981, 991, 987, 984, 985, 982, 993, 994, 995, 996, 991, 988, 997, 998, 999, 1000, 989, 1001, 983, 992, 1002, 1003, 1005, 1006, 1016, 1004, 1004, 1004, 593, 1017, 1003, 1016, 1002, 1000, 1008, 1001, 1017, 993, 994, 995, 996, 1004, 1009, 997, 998, 999, 1007, 1007, 1007, 1010, 1011, 1008, 1012, 1005, 1006, 1013, 1014, 1015, 1025, 1009, 591, 1021, 1007, 1018, 1018, 1018, 1010, 1011, 1022, 1012, 1025, 590, 1013, 1014, 1015, 1019, 1019, 1019, 1021, 1018, 1023, 1023, 1023, 1026, 1028, 1022, 1027, 1029, 1030, 1031, 1033, 1019, 1026, 1028, 1032, 1034, 1023, 1030, 1027, 1029, 1038, 1031, 1037, 1032, 1035, 1035, 1035, 1033, 1043, 1038, 1044, 589, 1034, 1054, 1037, 1039, 1039, 1039, 1055, 588, 1035, 1040, 1040, 1040, 1041, 1041, 1041, 1042, 1042, 1042, 1054, 1039, 1045, 1045, 1045, 1055, 586, 1040, 585, 1043, 1041, 1044, 583, 1042, 1046, 1046, 1046, 1058, 1045, 1048, 1048, 1048, 1050, 1050, 1050, 1052, 1052, 1052, 1059, 1058, 1046, 1056, 1056, 1056, 559, 1048, 554, 1059, 1050, 551, 538, 1052, 1060, 1060, 1060, 521, 520, 1056, 1061, 1061, 1061, 502, 495, 494, 493, 491, 488, 485, 1060, 482, 475, 471, 462, 461, 1061, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1079, 1079, 1079, 452, 1079, 1080, 1080, 1080, 447, 1080, 1081, 1081, 1081, 442, 1081, 1082, 1082, 1082, 441, 1082, 1083, 1083, 1083, 440, 1083, 1084, 1084, 1084, 438, 1084, 1085, 1085, 1085, 436, 1085, 1086, 1086, 1086, 435, 1086, 1087, 1087, 1087, 434, 1087, 1088, 1088, 1088, 1088, 1088, 433, 1088, 1089, 422, 1089, 1090, 416, 1090, 1091, 410, 1091, 1092, 403, 1092, 1093, 402, 1093, 1094, 390, 1094, 1095, 389, 1095, 1096, 379, 1096, 1097, 378, 1097, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1099, 371, 370, 1099, 1100, 1100, 1100, 1100, 1100, 1100, 1101, 1101, 1101, 1101, 1101, 1101, 1102, 1102, 1102, 1102, 1102, 1102, 1103, 1103, 1103, 1103, 1103, 1103, 1104, 1104, 1104, 1104, 1104, 1104, 1105, 1105, 1105, 1105, 1105, 1105, 1106, 1106, 1106, 1106, 1106, 1106, 1107, 1107, 1107, 1107, 1107, 1107, 1108, 1108, 1108, 1108, 1108, 1108, 1109, 1109, 1109, 1109, 1109, 1109, 1109, 1110, 1110, 1110, 1110, 1110, 1110, 1110, 1111, 1111, 1111, 1111, 1111, 1111, 1111, 369, 368, 367, 366, 365, 362, 361, 360, 358, 354, 351, 350, 349, 346, 345, 342, 341, 338, 337, 336, 335, 332, 331, 328, 327, 326, 323, 319, 318, 317, 314, 313, 312, 311, 310, 309, 308, 306, 305, 304, 303, 302, 298, 296, 295, 294, 293, 292, 291, 288, 287, 286, 285, 282, 281, 278, 277, 276, 275, 274, 271, 270, 269, 268, 265, 264, 263, 260, 259, 258, 255, 254, 253, 251, 250, 247, 246, 244, 242, 239, 238, 237, 236, 235, 229, 228, 226, 223, 222, 221, 220, 216, 212, 211, 210, 206, 201, 197, 188, 187, 186, 182, 174, 173, 169, 164, 163, 159, 152, 148, 144, 142, 141, 137, 126, 121, 120, 119, 113, 112, 110, 107, 95, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063 } ; static xml__state_type xml__last_accepting_state; static char *xml__last_accepting_cpos; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ #define REJECT reject_used_but_not_detected #define xml_more() xml_more_used_but_not_detected #define XML__MORE_ADJ 0 #define XML__RESTORE_XML__MORE_OFFSET char *xml_text; #line 1 "xmltree_read.l" #define INITIAL 0 /* Validating XML processor for octave.dtd. * Generated 2004/02/13 14:47:24. * * This program was generated with the FleXML XML processor generator, * (Id: flexml.pl,v 1.28 2003/02/12 02:55:41 krisrose Exp). * Copyright © 1999 Kristoffer Rose. All rights reserved. * * You can redistribute and/or modify this program provided the following * two conditions hold: * * 1. The program is distributed WITHOUT ANY WARRANTY from the author of * FleXML; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. * * 2. The program distribution conditions do not in any way affect the * distribution conditions of the FleXML system used to generate this * file or any version of FleXML derived from that system. * * Notice that these are explicit rights granted to you for files * generated by the FleXML system. For your rights in connection with * the FleXML system itself please consult the GNU General Public License. */ #line 25 "xmltree_read.l" /* Version strings. */ const char rcs_flexml_skeleton[] = "$" "Id: skel,v 1.16 1999/12/09 04:01:51 krisrose Exp $"; const char rcs_flexml[] = "$" "Id: flexml.pl,v 1.28 2003/02/12 02:55:41 krisrose Exp $"; /* ANSI headers. */ #include #include #include #include #include #include /* Generated definitions. */ #define FLEXML_BUFFERSTACKSIZE 100000 /* XML application entry points. */ static void STag_octave(void); static void ETag_octave(void); static void STag_scalar(void); static void ETag_scalar(void); static void STag_complex(void); static void ETag_complex(void); static void STag_string(void); static void ETag_string(void); static void STag_array(void); static void ETag_array(void); static void STag_matrix(void); static void ETag_matrix(void); static void STag_structure(void); static void ETag_structure(void); static void STag_list(void); static void ETag_list(void); static void STag_cell(void); static void ETag_cell(void); /* XML application data. */ typedef char* AT_list_length; #define AU_list_length NULL typedef char* AT_matrix_rows; #define AU_matrix_rows NULL typedef char* AT_matrix_name; #define AU_matrix_name NULL typedef char* AT_cell_columns; #define AU_cell_columns NULL typedef char* AT_scalar_name; #define AU_scalar_name NULL typedef char* AT_array_name; #define AU_array_name NULL typedef char* AT_complex_name; #define AU_complex_name NULL typedef char* AT_matrix_columns; #define AU_matrix_columns NULL typedef char* AT_cell_name; #define AU_cell_name NULL typedef char* AT_string_length; #define AU_string_length NULL typedef char* AT_list_name; #define AU_list_name NULL typedef enum { AU_scalar_value, A_scalar_value_undefined,A_scalar_value_true,A_scalar_value_false,A_scalar_value_inf,A_scalar_value_neginf,A_scalar_value_na,A_scalar_value_nan } AT_scalar_value; typedef char* AT_structure_name; #define AU_structure_name NULL typedef char* AT_cell_rows; #define AU_cell_rows NULL typedef char* AT_array_rows; #define AU_array_rows NULL typedef char* AT_string_name; #define AU_string_name NULL /* FleXML-provided data. */ static char* pcdata; static AT_list_length A_list_length; static AT_matrix_rows A_matrix_rows; static AT_matrix_name A_matrix_name; static AT_cell_columns A_cell_columns; static AT_scalar_name A_scalar_name; static AT_array_name A_array_name; static AT_complex_name A_complex_name; static AT_matrix_columns A_matrix_columns; static AT_cell_name A_cell_name; static AT_string_length A_string_length; static AT_list_name A_list_name; static AT_scalar_value A_scalar_value; static AT_structure_name A_structure_name; static AT_cell_rows A_cell_rows; static AT_array_rows A_array_rows; static AT_string_name A_string_name; /* XML state. */ #ifdef FLEX_DEBUG # define ENTER(state) debug_enter(state,#state) # define LEAVE debug_leave() # define SET(state) debug_set(state,#state) static void debug_enter(int, char*); static void debug_leave(void); static void debug_set(int, char*); #else # define ENTER(state) (xml__push_state(state)) # define LEAVE (xml__pop_state()) # define SET(state) BEGIN(state) #endif /* Generic actions. */ #define SKIP /*skip*/ #define SUCCEED return 0 #define FAIL return fail static int fail(const char*, ...); /* Text buffer stack handling. */ char bufferstack[FLEXML_BUFFERSTACKSIZE]; char* limit = bufferstack + FLEXML_BUFFERSTACKSIZE; typedef struct BufferLast_s { struct BufferLast_s *old; char* saved; char new[1]; } BufferLast; BufferLast* last = (BufferLast*)0; char* next = bufferstack; #define BUFFERSET(P) (P = next) #define BUFFERPUTC(C) (assert(nextold = last; l->saved = p; next = l->new; last = l; } static char* popbuffer(void) { BufferLast* l = last; assert(last != (BufferLast*)0); last = l->old; next = (char*)l; return l->saved; } #endif /* General internal entities are `unput' back onto the input stream... */ #define ENTITYTEXT(T) \ { char *s = (T), *e = s+strlen(s);\ while (--e >= s) { unput(*e); }} /* Flex standard options. */ #define XML__STACK_USED 1 #define XML__NO_TOP_STATE 1 #define XML__NO_INPUT 1 /* Flex user-requested options. */ #define XML__NO_UNPUT 1 /* XML character classes (currently restricted to ASCII). */ /* "Common syntactic structures." */ /* "Names and Tokens." */ /* Miscellaneous. */ /* Parser states (flex `exclusive start conditions'): * * PROLOG the XML prolog of the document before * DOCTYPE the XML prolog of the document after * EPILOG after the root element * INCOMMENT inside an XML comment * INPI inside an XML PI * VALUE1 inside a '...'-delimited literal * VALUE2 inside a "..."-delimited literal * CDATA inside a section. * ROOT_ expect root element * AL_ inside the attribute list for * IN_ inside a with element contents (ready for end tag) * IMPOSSIBLE dummy to permit disabling rules; must be last */ #define PROLOG 1 #define DOCTYPE 2 #define EPILOG 3 #define INCOMMENT 4 #define INPI 5 #define VALUE1 6 #define VALUE2 7 #define CDATA 8 #define ROOT_octave 9 #define AL_octave 10 #define S_octave 11 #define E_octave 12 #define ROOT_scalar 13 #define AL_scalar 14 #define IN_scalar 15 #define ROOT_complex 16 #define AL_complex 17 #define S_complex 18 #define S_complex_1 19 #define E_complex 20 #define ROOT_string 21 #define AL_string 22 #define IN_string 23 #define ROOT_array 24 #define AL_array 25 #define S_array 26 #define S_array_1 27 #define S_array_2 28 #define S_array_3 29 #define E_array 30 #define ROOT_matrix 31 #define AL_matrix 32 #define S_matrix 33 #define S_matrix_1 34 #define S_matrix_2 35 #define E_matrix 36 #define ROOT_structure 37 #define AL_structure 38 #define IN_structure 39 #define ROOT_list 40 #define AL_list 41 #define IN_list 42 #define ROOT_cell 43 #define AL_cell 44 #define IN_cell 45 #define IMPOSSIBLE 46 #line 245 "xmltree_read.l" /* State names. */ char* statenames[IMPOSSIBLE]; void FleXML_init(void) { statenames[PROLOG] = NULL; statenames[DOCTYPE] = NULL; statenames[EPILOG] = NULL; statenames[INCOMMENT] = NULL; statenames[INPI] = NULL; statenames[VALUE1] = NULL; statenames[VALUE2] = NULL; statenames[CDATA] = NULL; statenames[ROOT_octave] = NULL; statenames[AL_octave] = NULL; statenames[S_octave] = "octave"; statenames[E_octave] = "octave"; statenames[ROOT_scalar] = NULL; statenames[AL_scalar] = NULL; statenames[IN_scalar] = "scalar"; statenames[ROOT_complex] = NULL; statenames[AL_complex] = NULL; statenames[S_complex] = "complex"; statenames[S_complex_1] = "complex"; statenames[E_complex] = "complex"; statenames[ROOT_string] = NULL; statenames[AL_string] = NULL; statenames[IN_string] = "string"; statenames[ROOT_array] = NULL; statenames[AL_array] = NULL; statenames[S_array] = "array"; statenames[S_array_1] = "array"; statenames[S_array_2] = "array"; statenames[S_array_3] = "array"; statenames[E_array] = "array"; statenames[ROOT_matrix] = NULL; statenames[AL_matrix] = NULL; statenames[S_matrix] = "matrix"; statenames[S_matrix_1] = "matrix"; statenames[S_matrix_2] = "matrix"; statenames[E_matrix] = "matrix"; statenames[ROOT_structure] = NULL; statenames[AL_structure] = NULL; statenames[IN_structure] = "structure"; statenames[ROOT_list] = NULL; statenames[AL_list] = NULL; statenames[IN_list] = "list"; statenames[ROOT_cell] = NULL; statenames[AL_cell] = NULL; statenames[IN_cell] = "cell"; } /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef XML__SKIP_XML_WRAP #ifdef __cplusplus extern "C" int xml_wrap XML__PROTO(( void )); #else extern int xml_wrap XML__PROTO(( void )); #endif #endif #ifndef XML__NO_UNPUT static void xml_unput XML__PROTO(( int c, char *buf_ptr )); #endif #ifndef xml_text_ptr static void xml__flex_strncpy XML__PROTO(( char *, xml_const char *, int )); #endif #ifdef XML__NEED_STRLEN static int xml__flex_strlen XML__PROTO(( xml_const char * )); #endif #ifndef XML__NO_INPUT #ifdef __cplusplus static int xml_input XML__PROTO(( void )); #else static int input XML__PROTO(( void )); #endif #endif #if XML__STACK_USED static int xml__start_stack_ptr = 0; static int xml__start_stack_depth = 0; static int *xml__start_stack = 0; #ifndef XML__NO_PUSH_STATE static void xml__push_state XML__PROTO(( int new_state )); #endif #ifndef XML__NO_POP_STATE static void xml__pop_state XML__PROTO(( void )); #endif #ifndef XML__NO_TOP_STATE static int xml__top_state XML__PROTO(( void )); #endif #else #define XML__NO_PUSH_STATE 1 #define XML__NO_POP_STATE 1 #define XML__NO_TOP_STATE 1 #endif #ifdef XML__MALLOC_DECL XML__MALLOC_DECL #else #if __STDC__ #ifndef __cplusplus #include #endif #else /* Just try to get by without declaring the routines. This will fail * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) * or sizeof(void*) != sizeof(int). */ #endif #endif /* Amount of stuff to slurp up with each read. */ #ifndef XML__READ_BUF_SIZE #define XML__READ_BUF_SIZE 8192 #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO (void) fwrite( xml_text, xml_leng, 1, xml_out ) #endif /* Gets input and stuffs it into "buf". number of characters read, or XML__NULL, * is returned in "result". */ #ifndef XML__INPUT #define XML__INPUT(buf,result,max_size) \ if ( xml__current_buffer->xml__is_interactive ) \ { \ int c = '*', n; \ for ( n = 0; n < max_size && \ (c = getc( xml_in )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( xml_in ) ) \ XML__FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else \ { \ errno=0; \ while ( (result = fread(buf, 1, max_size, xml_in))==0 && ferror(xml_in)) \ { \ if( errno != EINTR) \ { \ XML__FATAL_ERROR( "input in flex scanner failed" ); \ break; \ } \ errno=0; \ clearerr(xml_in); \ } \ } #endif /* No semi-colon after return; correct usage is to write "xml_terminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef xml_terminate #define xml_terminate() return XML__NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef XML__START_STACK_INCR #define XML__START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef XML__FATAL_ERROR #define XML__FATAL_ERROR(msg) xml__fatal_error( msg ) #endif /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef XML__DECL #define XML__DECL int xml_lex XML__PROTO(( void )) #endif /* Code executed at the beginning of each rule, after xml_text and xml_leng * have been set up. */ #ifndef XML__USER_ACTION #define XML__USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef XML__BREAK #define XML__BREAK break; #endif #define XML__RULE_SETUP \ XML__USER_ACTION XML__DECL { register xml__state_type xml__current_state; register char *xml__cp, *xml__bp; register int xml__act; #line 298 "xmltree_read.l" /* Bypass Flex's default INITIAL state and begin by parsing the XML prolog. */ SET(PROLOG); FleXML_init(); /* COMMENTS and PIs: handled uniformly for efficiency. */ if ( xml__init ) { xml__init = 0; #ifdef XML__USER_INIT XML__USER_INIT; #endif if ( ! xml__start ) xml__start = 1; /* first start state */ if ( ! xml_in ) xml_in = stdin; if ( ! xml_out ) xml_out = stdout; if ( ! xml__current_buffer ) xml__current_buffer = xml__create_buffer( xml_in, XML__BUF_SIZE ); xml__load_buffer_state(); } while ( 1 ) /* loops until end-of-file is reached */ { xml__cp = xml__c_buf_p; /* Support of xml_text. */ *xml__cp = xml__hold_char; /* xml__bp points to the position in xml__ch_buf of the start of * the current run. */ xml__bp = xml__cp; xml__current_state = xml__start; xml__match: do { register XML__CHAR xml__c = xml__ec[XML__SC_TO_UI(*xml__cp)]; if ( xml__accept[xml__current_state] ) { xml__last_accepting_state = xml__current_state; xml__last_accepting_cpos = xml__cp; } while ( xml__chk[xml__base[xml__current_state] + xml__c] != xml__current_state ) { xml__current_state = (int) xml__def[xml__current_state]; if ( xml__current_state >= 1064 ) xml__c = xml__meta[(unsigned int) xml__c]; } xml__current_state = xml__nxt[xml__base[xml__current_state] + (unsigned int) xml__c]; ++xml__cp; } while ( xml__base[xml__current_state] != 3089 ); xml__find_action: xml__act = xml__accept[xml__current_state]; if ( xml__act == 0 ) { /* have to back up */ xml__cp = xml__last_accepting_cpos; xml__current_state = xml__last_accepting_state; xml__act = xml__accept[xml__current_state]; } XML__DO_BEFORE_ACTION; do_action: /* This label is used only to access EOF actions. */ switch ( xml__act ) { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of XML__DO_BEFORE_ACTION */ *xml__cp = xml__hold_char; xml__cp = xml__last_accepting_cpos; xml__current_state = xml__last_accepting_state; goto xml__find_action; case 1: XML__RULE_SETUP #line 306 "xmltree_read.l" ENTER(INCOMMENT); XML__BREAK case 2: XML__RULE_SETUP #line 307 "xmltree_read.l" ENTER(INPI); XML__BREAK case 3: XML__RULE_SETUP #line 310 "xmltree_read.l" LEAVE; XML__BREAK case 4: #line 312 "xmltree_read.l" case 5: #line 313 "xmltree_read.l" case 6: XML__RULE_SETUP #line 313 "xmltree_read.l" SKIP; XML__BREAK case XML__STATE_EOF(INCOMMENT): #line 314 "xmltree_read.l" FAIL("EOF in comment."); XML__BREAK case 7: XML__RULE_SETUP #line 317 "xmltree_read.l" LEAVE; XML__BREAK case 8: #line 319 "xmltree_read.l" case 9: XML__RULE_SETUP #line 319 "xmltree_read.l" SKIP; XML__BREAK case XML__STATE_EOF(INPI): #line 320 "xmltree_read.l" FAIL("EOF in PI (processing instruction)."); XML__BREAK /* SPACES: skipped uniformly */ case 10: XML__RULE_SETUP #line 325 "xmltree_read.l" SKIP; XML__BREAK /* PROLOG: determine root element and process it. */ case 11: XML__RULE_SETUP #line 330 "xmltree_read.l" SET(DOCTYPE); XML__BREAK case 12: XML__RULE_SETUP #line 331 "xmltree_read.l" FAIL("Bad declaration %s.",xml_text); XML__BREAK case 13: XML__RULE_SETUP #line 335 "xmltree_read.l" SET(ROOT_scalar); XML__BREAK case 14: XML__RULE_SETUP #line 336 "xmltree_read.l" SET(ROOT_octave); XML__BREAK case 15: XML__RULE_SETUP #line 337 "xmltree_read.l" SET(ROOT_complex); XML__BREAK case 16: XML__RULE_SETUP #line 338 "xmltree_read.l" SET(ROOT_string); XML__BREAK case 17: XML__RULE_SETUP #line 339 "xmltree_read.l" SET(ROOT_matrix); XML__BREAK case 18: XML__RULE_SETUP #line 340 "xmltree_read.l" SET(ROOT_array); XML__BREAK case 19: XML__RULE_SETUP #line 341 "xmltree_read.l" SET(ROOT_structure); XML__BREAK case 20: XML__RULE_SETUP #line 342 "xmltree_read.l" SET(ROOT_cell); XML__BREAK case 21: XML__RULE_SETUP #line 343 "xmltree_read.l" SET(ROOT_list); XML__BREAK case 22: XML__RULE_SETUP #line 344 "xmltree_read.l" FAIL("Bad declaration %s.",xml_text); XML__BREAK case 23: XML__RULE_SETUP #line 345 "xmltree_read.l" FAIL("Unexpected character `%c' in prolog.", xml_text[0]); XML__BREAK case XML__STATE_EOF(PROLOG): case XML__STATE_EOF(DOCTYPE): #line 346 "xmltree_read.l" FAIL("EOF in prolog."); XML__BREAK /* RULES DERIVED FROM DTD. */ case 24: XML__RULE_SETUP #line 351 "xmltree_read.l" { ENTER(AL_octave); } XML__BREAK case 25: XML__RULE_SETUP #line 356 "xmltree_read.l" { LEAVE; STag_octave(); pcdata = NULL; ENTER(S_octave); } XML__BREAK case 26: XML__RULE_SETUP #line 359 "xmltree_read.l" FAIL("`octave' element cannot be empty."); XML__BREAK case 27: XML__RULE_SETUP #line 360 "xmltree_read.l" FAIL("Unexpected character `%c' in attribute list of octave element.", xml_text[0]); XML__BREAK case 28: XML__RULE_SETUP #line 361 "xmltree_read.l" FAIL("Bad attribute `%s' in `octave' element start tag.",xml_text); XML__BREAK case XML__STATE_EOF(AL_octave): #line 362 "xmltree_read.l" FAIL("EOF in attribute list of `octave' element."); XML__BREAK case 29: XML__RULE_SETUP #line 366 "xmltree_read.l" { LEAVE; ETag_octave(); switch (XML__START) { case ROOT_octave: SET(EPILOG); break; } } XML__BREAK case 30: XML__RULE_SETUP #line 373 "xmltree_read.l" FAIL("Unexpected end-tag `%s': `
    ' expected.",xml_text); XML__BREAK case 31: XML__RULE_SETUP #line 374 "xmltree_read.l" FAIL("Unexpected character `%c': `
    ' expected.",xml_text[0]); XML__BREAK case XML__STATE_EOF(E_octave): #line 375 "xmltree_read.l" FAIL("Premature EOF: `
    ' expected."); XML__BREAK /* value (undefined | true | false | inf | neginf | na | nan) "undefined" * name CDATA #IMPLIED> */ case 32: XML__RULE_SETUP #line 381 "xmltree_read.l" { A_scalar_value = A_scalar_value_undefined; A_scalar_name = NULL; ENTER(AL_scalar); } XML__BREAK case 33: #line 389 "xmltree_read.l" case 34: XML__RULE_SETUP #line 389 "xmltree_read.l" A_scalar_value = A_scalar_value_undefined; XML__BREAK case 35: #line 391 "xmltree_read.l" case 36: XML__RULE_SETUP #line 391 "xmltree_read.l" A_scalar_value = A_scalar_value_true; XML__BREAK case 37: #line 393 "xmltree_read.l" case 38: XML__RULE_SETUP #line 393 "xmltree_read.l" A_scalar_value = A_scalar_value_false; XML__BREAK case 39: #line 395 "xmltree_read.l" case 40: XML__RULE_SETUP #line 395 "xmltree_read.l" A_scalar_value = A_scalar_value_inf; XML__BREAK case 41: #line 397 "xmltree_read.l" case 42: XML__RULE_SETUP #line 397 "xmltree_read.l" A_scalar_value = A_scalar_value_neginf; XML__BREAK case 43: #line 399 "xmltree_read.l" case 44: XML__RULE_SETUP #line 399 "xmltree_read.l" A_scalar_value = A_scalar_value_na; XML__BREAK case 45: #line 401 "xmltree_read.l" case 46: XML__RULE_SETUP #line 401 "xmltree_read.l" A_scalar_value = A_scalar_value_nan; XML__BREAK case 47: XML__RULE_SETUP #line 403 "xmltree_read.l" ENTER(VALUE1); BUFFERSET(A_scalar_name); XML__BREAK case 48: XML__RULE_SETUP #line 404 "xmltree_read.l" ENTER(VALUE2); BUFFERSET(A_scalar_name); XML__BREAK case 49: XML__RULE_SETUP #line 406 "xmltree_read.l" { LEAVE; STag_scalar(); pcdata = BUFFERSET(pcdata); ENTER(IN_scalar); } XML__BREAK case 50: XML__RULE_SETUP #line 409 "xmltree_read.l" { LEAVE; STag_scalar(); pcdata = ""; ETag_scalar(); switch (XML__START) { case S_complex_1: SET(E_complex); break; case S_octave: SET(E_octave); break; case S_complex: SET(S_complex_1); break; case S_matrix_1: case S_matrix: case S_matrix_2: SET(S_matrix_2); break; case ROOT_scalar: SET(EPILOG); break; } } XML__BREAK case 51: XML__RULE_SETUP #line 419 "xmltree_read.l" FAIL("Unexpected character `%c' in attribute list of scalar element.", xml_text[0]); XML__BREAK case 52: XML__RULE_SETUP #line 420 "xmltree_read.l" FAIL("Bad attribute `%s' in `scalar' element start tag.",xml_text); XML__BREAK case XML__STATE_EOF(AL_scalar): #line 421 "xmltree_read.l" FAIL("EOF in attribute list of `scalar' element."); XML__BREAK case 53: XML__RULE_SETUP #line 425 "xmltree_read.l" { LEAVE; BUFFERDONE; ETag_scalar(); switch (XML__START) { case S_complex_1: SET(E_complex); break; case S_octave: SET(E_octave); break; case S_complex: SET(S_complex_1); break; case S_matrix_1: case S_matrix: case S_matrix_2: SET(S_matrix_2); break; case ROOT_scalar: SET(EPILOG); break; } } XML__BREAK case 54: XML__RULE_SETUP #line 437 "xmltree_read.l" FAIL("Unexpected end-tag `%s': `' expected.",xml_text); XML__BREAK case XML__STATE_EOF(IN_scalar): #line 438 "xmltree_read.l" FAIL("Premature EOF: `' expected."); XML__BREAK case 55: XML__RULE_SETUP #line 441 "xmltree_read.l" { A_complex_name = NULL; ENTER(AL_complex); } XML__BREAK case 56: XML__RULE_SETUP #line 447 "xmltree_read.l" ENTER(VALUE1); BUFFERSET(A_complex_name); XML__BREAK case 57: XML__RULE_SETUP #line 448 "xmltree_read.l" ENTER(VALUE2); BUFFERSET(A_complex_name); XML__BREAK case 58: XML__RULE_SETUP #line 450 "xmltree_read.l" { LEAVE; STag_complex(); pcdata = NULL; ENTER(S_complex); } XML__BREAK case 59: XML__RULE_SETUP #line 453 "xmltree_read.l" FAIL("`complex' element cannot be empty."); XML__BREAK case 60: XML__RULE_SETUP #line 454 "xmltree_read.l" FAIL("Unexpected character `%c' in attribute list of complex element.", xml_text[0]); XML__BREAK case 61: XML__RULE_SETUP #line 455 "xmltree_read.l" FAIL("Bad attribute `%s' in `complex' element start tag.",xml_text); XML__BREAK case XML__STATE_EOF(AL_complex): #line 456 "xmltree_read.l" FAIL("EOF in attribute list of `complex' element."); XML__BREAK case 62: XML__RULE_SETUP #line 460 "xmltree_read.l" { LEAVE; ETag_complex(); switch (XML__START) { case S_octave: SET(E_octave); break; case S_matrix_1: case S_matrix: case S_matrix_2: SET(S_matrix_2); break; case ROOT_complex: SET(EPILOG); break; } } XML__BREAK case 63: XML__RULE_SETUP #line 469 "xmltree_read.l" FAIL("Unexpected end-tag `%s': `' expected.",xml_text); XML__BREAK case 64: XML__RULE_SETUP #line 470 "xmltree_read.l" FAIL("Unexpected character `%c': `' expected.",xml_text[0]); XML__BREAK case XML__STATE_EOF(E_complex): #line 471 "xmltree_read.l" FAIL("Premature EOF: `' expected."); XML__BREAK /* length CDATA #REQUIRED * name CDATA #IMPLIED> */ case 65: XML__RULE_SETUP #line 477 "xmltree_read.l" { A_string_length = NULL; A_string_name = NULL; ENTER(AL_string); } XML__BREAK case 66: XML__RULE_SETUP #line 484 "xmltree_read.l" ENTER(VALUE1); BUFFERSET(A_string_length); XML__BREAK case 67: XML__RULE_SETUP #line 485 "xmltree_read.l" ENTER(VALUE2); BUFFERSET(A_string_length); XML__BREAK case 68: XML__RULE_SETUP #line 487 "xmltree_read.l" ENTER(VALUE1); BUFFERSET(A_string_name); XML__BREAK case 69: XML__RULE_SETUP #line 488 "xmltree_read.l" ENTER(VALUE2); BUFFERSET(A_string_name); XML__BREAK case 70: XML__RULE_SETUP #line 490 "xmltree_read.l" { if (!A_string_length) FAIL("Required attribute `length' not set for `string' element."); LEAVE; STag_string(); pcdata = BUFFERSET(pcdata); ENTER(IN_string); } XML__BREAK case 71: XML__RULE_SETUP #line 494 "xmltree_read.l" { if (!A_string_length) FAIL("Required attribute `length' not set for `string' element."); LEAVE; STag_string(); pcdata = ""; ETag_string(); switch (XML__START) { case S_octave: SET(E_octave); break; case S_array_2: case S_array_3: case S_array_1: SET(S_array_3); break; case ROOT_string: SET(EPILOG); break; case S_array: SET(S_array_1); break; } } XML__BREAK case 72: XML__RULE_SETUP #line 504 "xmltree_read.l" FAIL("Unexpected character `%c' in attribute list of string element.", xml_text[0]); XML__BREAK case 73: XML__RULE_SETUP #line 505 "xmltree_read.l" FAIL("Bad attribute `%s' in `string' element start tag.",xml_text); XML__BREAK case XML__STATE_EOF(AL_string): #line 506 "xmltree_read.l" FAIL("EOF in attribute list of `string' element."); XML__BREAK case 74: XML__RULE_SETUP #line 510 "xmltree_read.l" { LEAVE; BUFFERDONE; ETag_string(); switch (XML__START) { case S_octave: SET(E_octave); break; case S_array_2: case S_array_3: case S_array_1: SET(S_array_3); break; case ROOT_string: SET(EPILOG); break; case S_array: SET(S_array_1); break; } } XML__BREAK case 75: XML__RULE_SETUP #line 521 "xmltree_read.l" FAIL("Unexpected end-tag `%s': `' expected.",xml_text); XML__BREAK case XML__STATE_EOF(IN_string): #line 522 "xmltree_read.l" FAIL("Premature EOF: `' expected."); XML__BREAK /* rows CDATA #REQUIRED * name CDATA #IMPLIED> */ case 76: XML__RULE_SETUP #line 528 "xmltree_read.l" { A_array_rows = NULL; A_array_name = NULL; ENTER(AL_array); } XML__BREAK case 77: XML__RULE_SETUP #line 535 "xmltree_read.l" ENTER(VALUE1); BUFFERSET(A_array_rows); XML__BREAK case 78: XML__RULE_SETUP #line 536 "xmltree_read.l" ENTER(VALUE2); BUFFERSET(A_array_rows); XML__BREAK case 79: XML__RULE_SETUP #line 538 "xmltree_read.l" ENTER(VALUE1); BUFFERSET(A_array_name); XML__BREAK case 80: XML__RULE_SETUP #line 539 "xmltree_read.l" ENTER(VALUE2); BUFFERSET(A_array_name); XML__BREAK case 81: XML__RULE_SETUP #line 541 "xmltree_read.l" { if (!A_array_rows) FAIL("Required attribute `rows' not set for `array' element."); LEAVE; STag_array(); pcdata = NULL; ENTER(S_array); } XML__BREAK case 82: XML__RULE_SETUP #line 545 "xmltree_read.l" FAIL("`array' element cannot be empty."); XML__BREAK case 83: XML__RULE_SETUP #line 546 "xmltree_read.l" FAIL("Unexpected character `%c' in attribute list of array element.", xml_text[0]); XML__BREAK case 84: XML__RULE_SETUP #line 547 "xmltree_read.l" FAIL("Bad attribute `%s' in `array' element start tag.",xml_text); XML__BREAK case XML__STATE_EOF(AL_array): #line 548 "xmltree_read.l" FAIL("EOF in attribute list of `array' element."); XML__BREAK case 85: XML__RULE_SETUP #line 552 "xmltree_read.l" { LEAVE; ETag_array(); switch (XML__START) { case S_octave: SET(E_octave); break; case ROOT_array: SET(EPILOG); break; } } XML__BREAK case 86: XML__RULE_SETUP #line 560 "xmltree_read.l" FAIL("Unexpected end-tag `%s': `' expected.",xml_text); XML__BREAK case 87: XML__RULE_SETUP #line 561 "xmltree_read.l" FAIL("Unexpected character `%c': `' expected.",xml_text[0]); XML__BREAK case XML__STATE_EOF(S_array_3): case XML__STATE_EOF(E_array): #line 562 "xmltree_read.l" FAIL("Premature EOF: `' expected."); XML__BREAK /* rows CDATA #REQUIRED * columns CDATA #REQUIRED * name CDATA #IMPLIED> */ case 88: XML__RULE_SETUP #line 569 "xmltree_read.l" { A_matrix_rows = NULL; A_matrix_columns = NULL; A_matrix_name = NULL; ENTER(AL_matrix); } XML__BREAK case 89: XML__RULE_SETUP #line 577 "xmltree_read.l" ENTER(VALUE1); BUFFERSET(A_matrix_rows); XML__BREAK case 90: XML__RULE_SETUP #line 578 "xmltree_read.l" ENTER(VALUE2); BUFFERSET(A_matrix_rows); XML__BREAK case 91: XML__RULE_SETUP #line 580 "xmltree_read.l" ENTER(VALUE1); BUFFERSET(A_matrix_columns); XML__BREAK case 92: XML__RULE_SETUP #line 581 "xmltree_read.l" ENTER(VALUE2); BUFFERSET(A_matrix_columns); XML__BREAK case 93: XML__RULE_SETUP #line 583 "xmltree_read.l" ENTER(VALUE1); BUFFERSET(A_matrix_name); XML__BREAK case 94: XML__RULE_SETUP #line 584 "xmltree_read.l" ENTER(VALUE2); BUFFERSET(A_matrix_name); XML__BREAK case 95: XML__RULE_SETUP #line 586 "xmltree_read.l" { if (!A_matrix_rows) FAIL("Required attribute `rows' not set for `matrix' element."); if (!A_matrix_columns) FAIL("Required attribute `columns' not set for `matrix' element."); LEAVE; STag_matrix(); pcdata = NULL; ENTER(S_matrix); } XML__BREAK case 96: XML__RULE_SETUP #line 591 "xmltree_read.l" { if (!A_matrix_rows) FAIL("Required attribute `rows' not set for `matrix' element."); if (!A_matrix_columns) FAIL("Required attribute `columns' not set for `matrix' element."); LEAVE; STag_matrix(); pcdata = NULL; ETag_matrix(); switch (XML__START) { case ROOT_matrix: SET(EPILOG); break; } } XML__BREAK case 97: XML__RULE_SETUP #line 599 "xmltree_read.l" FAIL("Unexpected character `%c' in attribute list of matrix element.", xml_text[0]); XML__BREAK case 98: XML__RULE_SETUP #line 600 "xmltree_read.l" FAIL("Bad attribute `%s' in `matrix' element start tag.",xml_text); XML__BREAK case XML__STATE_EOF(AL_matrix): #line 601 "xmltree_read.l" FAIL("EOF in attribute list of `matrix' element."); XML__BREAK case 99: XML__RULE_SETUP #line 605 "xmltree_read.l" { LEAVE; ETag_matrix(); switch (XML__START) { case ROOT_matrix: SET(EPILOG); break; } } XML__BREAK case 100: XML__RULE_SETUP #line 612 "xmltree_read.l" FAIL("Unexpected end-tag `%s': `' expected.",xml_text); XML__BREAK case 101: XML__RULE_SETUP #line 613 "xmltree_read.l" FAIL("Unexpected character `%c': `' expected.",xml_text[0]); XML__BREAK case XML__STATE_EOF(S_matrix): case XML__STATE_EOF(S_matrix_2): case XML__STATE_EOF(E_matrix): #line 614 "xmltree_read.l" FAIL("Premature EOF: `' expected."); XML__BREAK case 102: XML__RULE_SETUP #line 617 "xmltree_read.l" { A_structure_name = NULL; ENTER(AL_structure); } XML__BREAK case 103: XML__RULE_SETUP #line 623 "xmltree_read.l" ENTER(VALUE1); BUFFERSET(A_structure_name); XML__BREAK case 104: XML__RULE_SETUP #line 624 "xmltree_read.l" ENTER(VALUE2); BUFFERSET(A_structure_name); XML__BREAK case 105: XML__RULE_SETUP #line 626 "xmltree_read.l" { LEAVE; STag_structure(); pcdata = BUFFERSET(pcdata); ENTER(IN_structure); } XML__BREAK case 106: XML__RULE_SETUP #line 629 "xmltree_read.l" { LEAVE; STag_structure(); pcdata = ""; ETag_structure(); switch (XML__START) { case S_octave: SET(E_octave); break; case ROOT_structure: SET(EPILOG); break; } } XML__BREAK case 107: XML__RULE_SETUP #line 636 "xmltree_read.l" FAIL("Unexpected character `%c' in attribute list of structure element.", xml_text[0]); XML__BREAK case 108: XML__RULE_SETUP #line 637 "xmltree_read.l" FAIL("Bad attribute `%s' in `structure' element start tag.",xml_text); XML__BREAK case XML__STATE_EOF(AL_structure): #line 638 "xmltree_read.l" FAIL("EOF in attribute list of `structure' element."); XML__BREAK case 109: XML__RULE_SETUP #line 642 "xmltree_read.l" { LEAVE; BUFFERDONE; ETag_structure(); switch (XML__START) { case S_octave: SET(E_octave); break; case ROOT_structure: SET(EPILOG); break; } } XML__BREAK case 110: XML__RULE_SETUP #line 651 "xmltree_read.l" FAIL("Unexpected end-tag `%s': `' expected.",xml_text); XML__BREAK case XML__STATE_EOF(IN_structure): #line 652 "xmltree_read.l" FAIL("Premature EOF: `' expected."); XML__BREAK /* length CDATA #REQUIRED * name CDATA #IMPLIED> */ case 111: XML__RULE_SETUP #line 658 "xmltree_read.l" { A_list_length = NULL; A_list_name = NULL; ENTER(AL_list); } XML__BREAK case 112: XML__RULE_SETUP #line 665 "xmltree_read.l" ENTER(VALUE1); BUFFERSET(A_list_length); XML__BREAK case 113: XML__RULE_SETUP #line 666 "xmltree_read.l" ENTER(VALUE2); BUFFERSET(A_list_length); XML__BREAK case 114: XML__RULE_SETUP #line 668 "xmltree_read.l" ENTER(VALUE1); BUFFERSET(A_list_name); XML__BREAK case 115: XML__RULE_SETUP #line 669 "xmltree_read.l" ENTER(VALUE2); BUFFERSET(A_list_name); XML__BREAK case 116: XML__RULE_SETUP #line 671 "xmltree_read.l" { if (!A_list_length) FAIL("Required attribute `length' not set for `list' element."); LEAVE; STag_list(); pcdata = BUFFERSET(pcdata); ENTER(IN_list); } XML__BREAK case 117: XML__RULE_SETUP #line 675 "xmltree_read.l" { if (!A_list_length) FAIL("Required attribute `length' not set for `list' element."); LEAVE; STag_list(); pcdata = ""; ETag_list(); switch (XML__START) { case S_octave: SET(E_octave); break; case ROOT_list: SET(EPILOG); break; } } XML__BREAK case 118: XML__RULE_SETUP #line 683 "xmltree_read.l" FAIL("Unexpected character `%c' in attribute list of list element.", xml_text[0]); XML__BREAK case 119: XML__RULE_SETUP #line 684 "xmltree_read.l" FAIL("Bad attribute `%s' in `list' element start tag.",xml_text); XML__BREAK case XML__STATE_EOF(AL_list): #line 685 "xmltree_read.l" FAIL("EOF in attribute list of `list' element."); XML__BREAK case 120: XML__RULE_SETUP #line 689 "xmltree_read.l" { LEAVE; BUFFERDONE; ETag_list(); switch (XML__START) { case S_octave: SET(E_octave); break; case ROOT_list: SET(EPILOG); break; } } XML__BREAK case 121: XML__RULE_SETUP #line 698 "xmltree_read.l" FAIL("Unexpected end-tag `%s': `' expected.",xml_text); XML__BREAK case XML__STATE_EOF(IN_list): #line 699 "xmltree_read.l" FAIL("Premature EOF: `' expected."); XML__BREAK /* rows CDATA #REQUIRED * columns CDATA #REQUIRED * name CDATA #IMPLIED> */ case 122: XML__RULE_SETUP #line 706 "xmltree_read.l" { A_cell_rows = NULL; A_cell_columns = NULL; A_cell_name = NULL; ENTER(AL_cell); } XML__BREAK case 123: XML__RULE_SETUP #line 714 "xmltree_read.l" ENTER(VALUE1); BUFFERSET(A_cell_rows); XML__BREAK case 124: XML__RULE_SETUP #line 715 "xmltree_read.l" ENTER(VALUE2); BUFFERSET(A_cell_rows); XML__BREAK case 125: XML__RULE_SETUP #line 717 "xmltree_read.l" ENTER(VALUE1); BUFFERSET(A_cell_columns); XML__BREAK case 126: XML__RULE_SETUP #line 718 "xmltree_read.l" ENTER(VALUE2); BUFFERSET(A_cell_columns); XML__BREAK case 127: XML__RULE_SETUP #line 720 "xmltree_read.l" ENTER(VALUE1); BUFFERSET(A_cell_name); XML__BREAK case 128: XML__RULE_SETUP #line 721 "xmltree_read.l" ENTER(VALUE2); BUFFERSET(A_cell_name); XML__BREAK case 129: XML__RULE_SETUP #line 723 "xmltree_read.l" { if (!A_cell_rows) FAIL("Required attribute `rows' not set for `cell' element."); if (!A_cell_columns) FAIL("Required attribute `columns' not set for `cell' element."); LEAVE; STag_cell(); pcdata = BUFFERSET(pcdata); ENTER(IN_cell); } XML__BREAK case 130: XML__RULE_SETUP #line 728 "xmltree_read.l" { if (!A_cell_rows) FAIL("Required attribute `rows' not set for `cell' element."); if (!A_cell_columns) FAIL("Required attribute `columns' not set for `cell' element."); LEAVE; STag_cell(); pcdata = ""; ETag_cell(); switch (XML__START) { case S_octave: SET(E_octave); break; case ROOT_cell: SET(EPILOG); break; } } XML__BREAK case 131: XML__RULE_SETUP #line 737 "xmltree_read.l" FAIL("Unexpected character `%c' in attribute list of cell element.", xml_text[0]); XML__BREAK case 132: XML__RULE_SETUP #line 738 "xmltree_read.l" FAIL("Bad attribute `%s' in `cell' element start tag.",xml_text); XML__BREAK case XML__STATE_EOF(AL_cell): #line 739 "xmltree_read.l" FAIL("EOF in attribute list of `cell' element."); XML__BREAK case 133: XML__RULE_SETUP #line 743 "xmltree_read.l" { LEAVE; BUFFERDONE; ETag_cell(); switch (XML__START) { case S_octave: SET(E_octave); break; case ROOT_cell: SET(EPILOG); break; } } XML__BREAK case 134: XML__RULE_SETUP #line 752 "xmltree_read.l" FAIL("Unexpected end-tag `%s': `' expected.",xml_text); XML__BREAK case XML__STATE_EOF(IN_cell): #line 753 "xmltree_read.l" FAIL("Premature EOF: `' expected."); XML__BREAK /* EPILOG: after the root element. */ case 135: XML__RULE_SETUP #line 759 "xmltree_read.l" FAIL("Unexpected character `%c' after document.", xml_text[0]); XML__BREAK case XML__STATE_EOF(EPILOG): #line 760 "xmltree_read.l" SUCCEED; XML__BREAK /* CHARACTER DATA. */ /* Non-defined standard entities... */ case 136: XML__RULE_SETUP #line 767 "xmltree_read.l" BUFFERPUTC('&'); XML__BREAK case 137: XML__RULE_SETUP #line 768 "xmltree_read.l" BUFFERPUTC('<'); XML__BREAK case 138: XML__RULE_SETUP #line 769 "xmltree_read.l" BUFFERPUTC('>'); XML__BREAK case 139: XML__RULE_SETUP #line 770 "xmltree_read.l" BUFFERPUTC('\''); XML__BREAK case 140: XML__RULE_SETUP #line 771 "xmltree_read.l" BUFFERPUTC('"'); XML__BREAK /* Character entities. */ case 141: XML__RULE_SETUP #line 774 "xmltree_read.l" BUFFERPUTC((unsigned char)atoi(xml_text+2)); XML__BREAK case 142: XML__RULE_SETUP #line 775 "xmltree_read.l" BUFFERPUTC((unsigned char)strtol(xml_text+3,NULL,16)); XML__BREAK case 143: #line 780 "xmltree_read.l" case 144: #line 781 "xmltree_read.l" case 145: #line 782 "xmltree_read.l" case 146: XML__RULE_SETUP #line 782 "xmltree_read.l" BUFFERPUTC('\n'); XML__BREAK case 147: XML__RULE_SETUP #line 786 "xmltree_read.l" ENTER(CDATA); XML__BREAK case 148: XML__RULE_SETUP #line 787 "xmltree_read.l" FAIL("Unexpected `]]>' in character data."); XML__BREAK case 149: XML__RULE_SETUP #line 791 "xmltree_read.l" BUFFERDONE; LEAVE; XML__BREAK case XML__STATE_EOF(VALUE1): #line 792 "xmltree_read.l" FAIL("EOF in literal (\"'\" expected)."); XML__BREAK case 150: XML__RULE_SETUP #line 796 "xmltree_read.l" BUFFERDONE; LEAVE; XML__BREAK case XML__STATE_EOF(VALUE2): #line 797 "xmltree_read.l" FAIL("EOF in literal (`\"' expected)."); XML__BREAK case 151: XML__RULE_SETUP #line 801 "xmltree_read.l" BUFFERPUTC(xml_text[0]); XML__BREAK case 152: XML__RULE_SETUP #line 802 "xmltree_read.l" FAIL("Spurious `%c' in character data.",xml_text[0]); XML__BREAK case 153: XML__RULE_SETUP #line 806 "xmltree_read.l" LEAVE; XML__BREAK case 154: XML__RULE_SETUP #line 807 "xmltree_read.l" BUFFERPUTC(xml_text[0]); BUFFERPUTC(xml_text[1]); XML__BREAK case 155: XML__RULE_SETUP #line 808 "xmltree_read.l" BUFFERPUTC(xml_text[0]); XML__BREAK case XML__STATE_EOF(CDATA): #line 809 "xmltree_read.l" FAIL("EOF in CDATA section."); XML__BREAK /* Impossible rules to avoid warnings from flex(1). */ case 156: XML__RULE_SETUP #line 815 "xmltree_read.l" FAIL("The Impossible Happened: INITIAL or IMPOSSIBLE state entered?"); XML__BREAK case 157: XML__RULE_SETUP #line 818 "xmltree_read.l" ECHO; XML__BREAK case XML__STATE_EOF(INITIAL): case XML__STATE_EOF(ROOT_octave): case XML__STATE_EOF(S_octave): case XML__STATE_EOF(ROOT_scalar): case XML__STATE_EOF(ROOT_complex): case XML__STATE_EOF(S_complex): case XML__STATE_EOF(S_complex_1): case XML__STATE_EOF(ROOT_string): case XML__STATE_EOF(ROOT_array): case XML__STATE_EOF(S_array): case XML__STATE_EOF(S_array_1): case XML__STATE_EOF(S_array_2): case XML__STATE_EOF(ROOT_matrix): case XML__STATE_EOF(S_matrix_1): case XML__STATE_EOF(ROOT_structure): case XML__STATE_EOF(ROOT_list): case XML__STATE_EOF(ROOT_cell): case XML__STATE_EOF(IMPOSSIBLE): xml_terminate(); case XML__END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int xml__amount_of_matched_text = (int) (xml__cp - xml_text_ptr) - 1; /* Undo the effects of XML__DO_BEFORE_ACTION. */ *xml__cp = xml__hold_char; XML__RESTORE_XML__MORE_OFFSET if ( xml__current_buffer->xml__buffer_status == XML__BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed xml_in at a new source and called * xml_lex(). If so, then we have to assure * consistency between xml__current_buffer and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ xml__n_chars = xml__current_buffer->xml__n_chars; xml__current_buffer->xml__input_file = xml_in; xml__current_buffer->xml__buffer_status = XML__BUFFER_NORMAL; } /* Note that here we test for xml__c_buf_p "<=" to the position * of the first EOB in the buffer, since xml__c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( xml__c_buf_p <= &xml__current_buffer->xml__ch_buf[xml__n_chars] ) { /* This was really a NUL. */ xml__state_type xml__next_state; xml__c_buf_p = xml_text_ptr + xml__amount_of_matched_text; xml__current_state = xml__get_previous_state(); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * xml__get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ xml__next_state = xml__try_NUL_trans( xml__current_state ); xml__bp = xml_text_ptr + XML__MORE_ADJ; if ( xml__next_state ) { /* Consume the NUL. */ xml__cp = ++xml__c_buf_p; xml__current_state = xml__next_state; goto xml__match; } else { xml__cp = xml__c_buf_p; goto xml__find_action; } } else switch ( xml__get_next_buffer() ) { case EOB_ACT_END_OF_FILE: { xml__did_buffer_switch_on_eof = 0; if ( xml_wrap() ) { /* Note: because we've taken care in * xml__get_next_buffer() to have set up * xml_text, we can now set up * xml__c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * XML__NULL, it'll still work - another * XML__NULL will get returned. */ xml__c_buf_p = xml_text_ptr + XML__MORE_ADJ; xml__act = XML__STATE_EOF(XML__START); goto do_action; } else { if ( ! xml__did_buffer_switch_on_eof ) XML__NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: xml__c_buf_p = xml_text_ptr + xml__amount_of_matched_text; xml__current_state = xml__get_previous_state(); xml__cp = xml__c_buf_p; xml__bp = xml_text_ptr + XML__MORE_ADJ; goto xml__match; case EOB_ACT_LAST_MATCH: xml__c_buf_p = &xml__current_buffer->xml__ch_buf[xml__n_chars]; xml__current_state = xml__get_previous_state(); xml__cp = xml__c_buf_p; xml__bp = xml_text_ptr + XML__MORE_ADJ; goto xml__find_action; } break; } default: XML__FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of xml_lex */ /* xml__get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ static int xml__get_next_buffer() { register char *dest = xml__current_buffer->xml__ch_buf; register char *source = xml_text_ptr; register int number_to_move, i; int ret_val; if ( xml__c_buf_p > &xml__current_buffer->xml__ch_buf[xml__n_chars + 1] ) XML__FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); if ( xml__current_buffer->xml__fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ if ( xml__c_buf_p - xml_text_ptr - XML__MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (int) (xml__c_buf_p - xml_text_ptr) - 1; for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); if ( xml__current_buffer->xml__buffer_status == XML__BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ xml__current_buffer->xml__n_chars = xml__n_chars = 0; else { int num_to_read = xml__current_buffer->xml__buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ #ifdef XML__USES_REJECT XML__FATAL_ERROR( "input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); #else /* just a shorter name for the current buffer */ XML__BUFFER_STATE b = xml__current_buffer; int xml__c_buf_p_offset = (int) (xml__c_buf_p - b->xml__ch_buf); if ( b->xml__is_our_buffer ) { int new_size = b->xml__buf_size * 2; if ( new_size <= 0 ) b->xml__buf_size += b->xml__buf_size / 8; else b->xml__buf_size *= 2; b->xml__ch_buf = (char *) /* Include room in for 2 EOB chars. */ xml__flex_realloc( (void *) b->xml__ch_buf, b->xml__buf_size + 2 ); } else /* Can't grow it, we don't own it. */ b->xml__ch_buf = 0; if ( ! b->xml__ch_buf ) XML__FATAL_ERROR( "fatal error - scanner input buffer overflow" ); xml__c_buf_p = &b->xml__ch_buf[xml__c_buf_p_offset]; num_to_read = xml__current_buffer->xml__buf_size - number_to_move - 1; #endif } if ( num_to_read > XML__READ_BUF_SIZE ) num_to_read = XML__READ_BUF_SIZE; /* Read in more data. */ XML__INPUT( (&xml__current_buffer->xml__ch_buf[number_to_move]), xml__n_chars, num_to_read ); xml__current_buffer->xml__n_chars = xml__n_chars; } if ( xml__n_chars == 0 ) { if ( number_to_move == XML__MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; xml_restart( xml_in ); } else { ret_val = EOB_ACT_LAST_MATCH; xml__current_buffer->xml__buffer_status = XML__BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; xml__n_chars += number_to_move; xml__current_buffer->xml__ch_buf[xml__n_chars] = XML__END_OF_BUFFER_CHAR; xml__current_buffer->xml__ch_buf[xml__n_chars + 1] = XML__END_OF_BUFFER_CHAR; xml_text_ptr = &xml__current_buffer->xml__ch_buf[0]; return ret_val; } /* xml__get_previous_state - get the state just before the EOB char was reached */ static xml__state_type xml__get_previous_state() { register xml__state_type xml__current_state; register char *xml__cp; xml__current_state = xml__start; for ( xml__cp = xml_text_ptr + XML__MORE_ADJ; xml__cp < xml__c_buf_p; ++xml__cp ) { register XML__CHAR xml__c = (*xml__cp ? xml__ec[XML__SC_TO_UI(*xml__cp)] : 1); if ( xml__accept[xml__current_state] ) { xml__last_accepting_state = xml__current_state; xml__last_accepting_cpos = xml__cp; } while ( xml__chk[xml__base[xml__current_state] + xml__c] != xml__current_state ) { xml__current_state = (int) xml__def[xml__current_state]; if ( xml__current_state >= 1064 ) xml__c = xml__meta[(unsigned int) xml__c]; } xml__current_state = xml__nxt[xml__base[xml__current_state] + (unsigned int) xml__c]; } return xml__current_state; } /* xml__try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = xml__try_NUL_trans( current_state ); */ #ifdef XML__USE_PROTOS static xml__state_type xml__try_NUL_trans( xml__state_type xml__current_state ) #else static xml__state_type xml__try_NUL_trans( xml__current_state ) xml__state_type xml__current_state; #endif { register int xml__is_jam; register char *xml__cp = xml__c_buf_p; register XML__CHAR xml__c = 1; if ( xml__accept[xml__current_state] ) { xml__last_accepting_state = xml__current_state; xml__last_accepting_cpos = xml__cp; } while ( xml__chk[xml__base[xml__current_state] + xml__c] != xml__current_state ) { xml__current_state = (int) xml__def[xml__current_state]; if ( xml__current_state >= 1064 ) xml__c = xml__meta[(unsigned int) xml__c]; } xml__current_state = xml__nxt[xml__base[xml__current_state] + (unsigned int) xml__c]; xml__is_jam = (xml__current_state == 1063); return xml__is_jam ? 0 : xml__current_state; } #ifndef XML__NO_UNPUT #ifdef XML__USE_PROTOS static void xml_unput( int c, register char *xml__bp ) #else static void xml_unput( c, xml__bp ) int c; register char *xml__bp; #endif { register char *xml__cp = xml__c_buf_p; /* undo effects of setting up xml_text */ *xml__cp = xml__hold_char; if ( xml__cp < xml__current_buffer->xml__ch_buf + 2 ) { /* need to shift things up to make room */ /* +2 for EOB chars. */ register int number_to_move = xml__n_chars + 2; register char *dest = &xml__current_buffer->xml__ch_buf[ xml__current_buffer->xml__buf_size + 2]; register char *source = &xml__current_buffer->xml__ch_buf[number_to_move]; while ( source > xml__current_buffer->xml__ch_buf ) *--dest = *--source; xml__cp += (int) (dest - source); xml__bp += (int) (dest - source); xml__current_buffer->xml__n_chars = xml__n_chars = xml__current_buffer->xml__buf_size; if ( xml__cp < xml__current_buffer->xml__ch_buf + 2 ) XML__FATAL_ERROR( "flex scanner push-back overflow" ); } *--xml__cp = (char) c; xml_text_ptr = xml__bp; xml__hold_char = *xml__cp; xml__c_buf_p = xml__cp; } #endif /* ifndef XML__NO_UNPUT */ #ifdef __cplusplus static int xml_input() #else static int input() #endif { int c; *xml__c_buf_p = xml__hold_char; if ( *xml__c_buf_p == XML__END_OF_BUFFER_CHAR ) { /* xml__c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( xml__c_buf_p < &xml__current_buffer->xml__ch_buf[xml__n_chars] ) /* This was really a NUL. */ *xml__c_buf_p = '\0'; else { /* need more input */ int offset = xml__c_buf_p - xml_text_ptr; ++xml__c_buf_p; switch ( xml__get_next_buffer() ) { case EOB_ACT_LAST_MATCH: /* This happens because xml__g_n_b() * sees that we've accumulated a * token and flags that we need to * try matching the token before * proceeding. But for input(), * there's no matching to consider. * So convert the EOB_ACT_LAST_MATCH * to EOB_ACT_END_OF_FILE. */ /* Reset buffer status. */ xml_restart( xml_in ); /* fall through */ case EOB_ACT_END_OF_FILE: { if ( xml_wrap() ) return EOF; if ( ! xml__did_buffer_switch_on_eof ) XML__NEW_FILE; #ifdef __cplusplus return xml_input(); #else return input(); #endif } case EOB_ACT_CONTINUE_SCAN: xml__c_buf_p = xml_text_ptr + offset; break; } } } c = *(unsigned char *) xml__c_buf_p; /* cast for 8-bit char's */ *xml__c_buf_p = '\0'; /* preserve xml_text */ xml__hold_char = *++xml__c_buf_p; return c; } #ifdef XML__USE_PROTOS void xml_restart( FILE *input_file ) #else void xml_restart( input_file ) FILE *input_file; #endif { if ( ! xml__current_buffer ) xml__current_buffer = xml__create_buffer( xml_in, XML__BUF_SIZE ); xml__init_buffer( xml__current_buffer, input_file ); xml__load_buffer_state(); } #ifdef XML__USE_PROTOS void xml__switch_to_buffer( XML__BUFFER_STATE new_buffer ) #else void xml__switch_to_buffer( new_buffer ) XML__BUFFER_STATE new_buffer; #endif { if ( xml__current_buffer == new_buffer ) return; if ( xml__current_buffer ) { /* Flush out information for old buffer. */ *xml__c_buf_p = xml__hold_char; xml__current_buffer->xml__buf_pos = xml__c_buf_p; xml__current_buffer->xml__n_chars = xml__n_chars; } xml__current_buffer = new_buffer; xml__load_buffer_state(); /* We don't actually know whether we did this switch during * EOF (xml_wrap()) processing, but the only time this flag * is looked at is after xml_wrap() is called, so it's safe * to go ahead and always set it. */ xml__did_buffer_switch_on_eof = 1; } #ifdef XML__USE_PROTOS void xml__load_buffer_state( void ) #else void xml__load_buffer_state() #endif { xml__n_chars = xml__current_buffer->xml__n_chars; xml_text_ptr = xml__c_buf_p = xml__current_buffer->xml__buf_pos; xml_in = xml__current_buffer->xml__input_file; xml__hold_char = *xml__c_buf_p; } #ifdef XML__USE_PROTOS XML__BUFFER_STATE xml__create_buffer( FILE *file, int size ) #else XML__BUFFER_STATE xml__create_buffer( file, size ) FILE *file; int size; #endif { XML__BUFFER_STATE b; b = (XML__BUFFER_STATE) xml__flex_alloc( sizeof( struct xml__buffer_state ) ); if ( ! b ) XML__FATAL_ERROR( "out of dynamic memory in xml__create_buffer()" ); b->xml__buf_size = size; /* xml__ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->xml__ch_buf = (char *) xml__flex_alloc( b->xml__buf_size + 2 ); if ( ! b->xml__ch_buf ) XML__FATAL_ERROR( "out of dynamic memory in xml__create_buffer()" ); b->xml__is_our_buffer = 1; xml__init_buffer( b, file ); return b; } #ifdef XML__USE_PROTOS void xml__delete_buffer( XML__BUFFER_STATE b ) #else void xml__delete_buffer( b ) XML__BUFFER_STATE b; #endif { if ( ! b ) return; if ( b == xml__current_buffer ) xml__current_buffer = (XML__BUFFER_STATE) 0; if ( b->xml__is_our_buffer ) xml__flex_free( (void *) b->xml__ch_buf ); xml__flex_free( (void *) b ); } #ifndef _WIN32 #include #else #ifndef XML__ALWAYS_INTERACTIVE #ifndef XML__NEVER_INTERACTIVE extern int isatty XML__PROTO(( int )); #endif #endif #endif #ifdef XML__USE_PROTOS void xml__init_buffer( XML__BUFFER_STATE b, FILE *file ) #else void xml__init_buffer( b, file ) XML__BUFFER_STATE b; FILE *file; #endif { xml__flush_buffer( b ); b->xml__input_file = file; b->xml__fill_buffer = 1; #if XML__ALWAYS_INTERACTIVE b->xml__is_interactive = 1; #else #if XML__NEVER_INTERACTIVE b->xml__is_interactive = 0; #else b->xml__is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; #endif #endif } #ifdef XML__USE_PROTOS void xml__flush_buffer( XML__BUFFER_STATE b ) #else void xml__flush_buffer( b ) XML__BUFFER_STATE b; #endif { if ( ! b ) return; b->xml__n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->xml__ch_buf[0] = XML__END_OF_BUFFER_CHAR; b->xml__ch_buf[1] = XML__END_OF_BUFFER_CHAR; b->xml__buf_pos = &b->xml__ch_buf[0]; b->xml__at_bol = 1; b->xml__buffer_status = XML__BUFFER_NEW; if ( b == xml__current_buffer ) xml__load_buffer_state(); } #ifndef XML__NO_SCAN_BUFFER #ifdef XML__USE_PROTOS XML__BUFFER_STATE xml__scan_buffer( char *base, xml__size_t size ) #else XML__BUFFER_STATE xml__scan_buffer( base, size ) char *base; xml__size_t size; #endif { XML__BUFFER_STATE b; if ( size < 2 || base[size-2] != XML__END_OF_BUFFER_CHAR || base[size-1] != XML__END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return 0; b = (XML__BUFFER_STATE) xml__flex_alloc( sizeof( struct xml__buffer_state ) ); if ( ! b ) XML__FATAL_ERROR( "out of dynamic memory in xml__scan_buffer()" ); b->xml__buf_size = size - 2; /* "- 2" to take care of EOB's */ b->xml__buf_pos = b->xml__ch_buf = base; b->xml__is_our_buffer = 0; b->xml__input_file = 0; b->xml__n_chars = b->xml__buf_size; b->xml__is_interactive = 0; b->xml__at_bol = 1; b->xml__fill_buffer = 0; b->xml__buffer_status = XML__BUFFER_NEW; xml__switch_to_buffer( b ); return b; } #endif #ifndef XML__NO_SCAN_STRING #ifdef XML__USE_PROTOS XML__BUFFER_STATE xml__scan_string( xml_const char *xml__str ) #else XML__BUFFER_STATE xml__scan_string( xml__str ) xml_const char *xml__str; #endif { int len; for ( len = 0; xml__str[len]; ++len ) ; return xml__scan_bytes( xml__str, len ); } #endif #ifndef XML__NO_SCAN_BYTES #ifdef XML__USE_PROTOS XML__BUFFER_STATE xml__scan_bytes( xml_const char *bytes, int len ) #else XML__BUFFER_STATE xml__scan_bytes( bytes, len ) xml_const char *bytes; int len; #endif { XML__BUFFER_STATE b; char *buf; xml__size_t n; int i; /* Get memory for full buffer, including space for trailing EOB's. */ n = len + 2; buf = (char *) xml__flex_alloc( n ); if ( ! buf ) XML__FATAL_ERROR( "out of dynamic memory in xml__scan_bytes()" ); for ( i = 0; i < len; ++i ) buf[i] = bytes[i]; buf[len] = buf[len+1] = XML__END_OF_BUFFER_CHAR; b = xml__scan_buffer( buf, n ); if ( ! b ) XML__FATAL_ERROR( "bad buffer in xml__scan_bytes()" ); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. */ b->xml__is_our_buffer = 1; return b; } #endif #ifndef XML__NO_PUSH_STATE #ifdef XML__USE_PROTOS static void xml__push_state( int new_state ) #else static void xml__push_state( new_state ) int new_state; #endif { if ( xml__start_stack_ptr >= xml__start_stack_depth ) { xml__size_t new_size; xml__start_stack_depth += XML__START_STACK_INCR; new_size = xml__start_stack_depth * sizeof( int ); if ( ! xml__start_stack ) xml__start_stack = (int *) xml__flex_alloc( new_size ); else xml__start_stack = (int *) xml__flex_realloc( (void *) xml__start_stack, new_size ); if ( ! xml__start_stack ) XML__FATAL_ERROR( "out of memory expanding start-condition stack" ); } xml__start_stack[xml__start_stack_ptr++] = XML__START; BEGIN(new_state); } #endif #ifndef XML__NO_POP_STATE static void xml__pop_state() { if ( --xml__start_stack_ptr < 0 ) XML__FATAL_ERROR( "start-condition stack underflow" ); BEGIN(xml__start_stack[xml__start_stack_ptr]); } #endif #ifndef XML__NO_TOP_STATE static int xml__top_state() { return xml__start_stack[xml__start_stack_ptr - 1]; } #endif #ifndef XML__EXIT_FAILURE #define XML__EXIT_FAILURE 2 #endif #ifdef XML__USE_PROTOS static void xml__fatal_error( xml_const char msg[] ) #else static void xml__fatal_error( msg ) char msg[]; #endif { (void) fprintf( stderr, "%s\n", msg ); exit( XML__EXIT_FAILURE ); } /* Redefine xml_less() so it works in section 3 code. */ #undef xml_less #define xml_less(n) \ do \ { \ /* Undo effects of setting up xml_text. */ \ xml_text[xml_leng] = xml__hold_char; \ xml__c_buf_p = xml_text + n; \ xml__hold_char = *xml__c_buf_p; \ *xml__c_buf_p = '\0'; \ xml_leng = n; \ } \ while ( 0 ) /* Internal utility routines. */ #ifndef xml_text_ptr #ifdef XML__USE_PROTOS static void xml__flex_strncpy( char *s1, xml_const char *s2, int n ) #else static void xml__flex_strncpy( s1, s2, n ) char *s1; xml_const char *s2; int n; #endif { register int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef XML__NEED_STRLEN #ifdef XML__USE_PROTOS static int xml__flex_strlen( xml_const char *s ) #else static int xml__flex_strlen( s ) xml_const char *s; #endif { register int n; for ( n = 0; s[n]; ++n ) ; return n; } #endif #ifdef XML__USE_PROTOS static void *xml__flex_alloc( xml__size_t size ) #else static void *xml__flex_alloc( size ) xml__size_t size; #endif { return (void *) malloc( size ); } #ifdef XML__USE_PROTOS static void *xml__flex_realloc( void *ptr, xml__size_t size ) #else static void *xml__flex_realloc( ptr, size ) void *ptr; xml__size_t size; #endif { /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter * because both ANSI C and C++ allow castless assignment from * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ return (void *) realloc( (char *) ptr, size ); } #ifdef XML__USE_PROTOS static void xml__flex_free( void *ptr ) #else static void xml__flex_free( ptr ) void *ptr; #endif { free( ptr ); } #if XML__MAIN int main() { xml_lex(); return 0; } #endif #line 818 "xmltree_read.l" /* Element context stack lookup. */ int element_context(int i) { return (0 #endif #include "xmltree.h" #define warning perror element **current; element *root; list *lastlist; void STag_octave(void) { #line 43 "xmltree_read.act" root = new_element(); root->def_value = value_data; current = &(root->child); lastlist = new_list(lastlist); lastlist->root = current; } /* STag_octave */ void ETag_octave(void) { #line 52 "xmltree_read.act" current = lastlist->root; lastlist = pop_list(lastlist); current = &((*current)->next); } /* ETag_octave */ void STag_scalar(void) { #line 60 "xmltree_read.act" *current = new_element(); if (A_scalar_name) { (*current)->name = (char *) malloc(strlen(A_scalar_name)+1); strcpy ((*current)->name, A_scalar_name); } (*current)->def_value = value_scalar; switch (A_scalar_value) { case A_scalar_value_true: (*current)->const_value = const_true; break; case A_scalar_value_false: (*current)->const_value = const_false; break; case A_scalar_value_inf: (*current)->const_value = const_inf; break; case A_scalar_value_neginf: (*current)->const_value = const_neginf; break; case A_scalar_value_nan: (*current)->const_value = const_nan; break; case A_scalar_value_na: (*current)->const_value = const_na; break; default: (*current)->const_value = const_undef; } } /* STag_scalar */ void ETag_scalar(void) { #line 80 "xmltree_read.act" if (((*current)->const_value == const_undef) && (pcdata)) (*current)->scalar_value = strtod (pcdata, NULL); (*(lastlist->root))->nb_elements++; current = &((*current)->next); } /* ETag_scalar */ void STag_string(void) { #line 91 "xmltree_read.act" *current = new_element(); if (A_string_name) { (*current)->name = (char *) malloc(strlen(A_string_name)+1); strcpy ((*current)->name, A_string_name); } if (A_string_length) (*current)->length = strtol (A_string_length, NULL, 10); (*current)->def_value = value_string; } /* STag_string */ void ETag_string(void) { #line 105 "xmltree_read.act" if (pcdata) { int len = strlen(pcdata); /* check length parameter */ if ((*current)->length != len) { warning("incorrect length parameter for string\n"); (*current)->length = len; } (*current)->string_value = (char *) malloc ((len+1) * sizeof(char)); strcpy((*current)->string_value, pcdata); } (*(lastlist->root))->nb_elements++; current = &((*current)->next); } /* ETag_string */ void STag_complex(void) { #line 126 "xmltree_read.act" *current = new_element(); if (A_complex_name) { (*current)->name = (char *) malloc(strlen(A_complex_name)+1); strcpy ((*current)->name, A_complex_name); } (*current)->def_value = value_complex; lastlist = new_list(lastlist); lastlist->root = current; current = &((*current)->child); } /* STag_complex */ void ETag_complex(void) { #line 141 "xmltree_read.act" current = lastlist->root; lastlist = pop_list(lastlist); (*(lastlist->root))->nb_elements++; current = &((*current)->next); } /* ETag_complex */ void STag_array(void) { #line 152 "xmltree_read.act" *current = new_element(); if (A_array_name) { (*current)->name = (char *) malloc(strlen(A_array_name)+1); strcpy ((*current)->name, A_array_name); } if (A_array_rows) (*current)->rows = strtol (A_array_rows, NULL, 10); (*current)->def_value = value_array; lastlist = new_list(lastlist); lastlist->root = current; current = &((*current)->child); } /* STag_array */ void ETag_array(void) { #line 170 "xmltree_read.act" /* check rows parameter */ if ((*(lastlist->root))->rows != (*(lastlist->root))->nb_elements) { warning("incorrect length parameter for array\n"); (*(lastlist->root))->rows = (*(lastlist->root))->nb_elements; } current = lastlist->root; lastlist = pop_list(lastlist); (*(lastlist->root))->nb_elements++; current = &((*current)->next); } /* ETag_array */ void STag_matrix(void) { #line 187 "xmltree_read.act" *current = new_element(); if (A_matrix_name) { (*current)->name = (char *) malloc(strlen(A_matrix_name)+1); strcpy ((*current)->name, A_matrix_name); } if (A_matrix_rows) (*current)->rows = strtol (A_matrix_rows, NULL, 10); if (A_matrix_columns) (*current)->columns = strtol (A_matrix_columns, NULL, 10); (*current)->def_value = value_matrix; lastlist = new_list(lastlist); lastlist->root = current; current = &((*current)->child); } /* STag_matrix */ void ETag_matrix(void) { #line 208 "xmltree_read.act" /* check (rows, columns) parameters */ if ((*(lastlist->root))->rows * (*(lastlist->root))->columns != (*(lastlist->root))->nb_elements) { warning("incorrect (rows, columns) parameters for matrix: reshaping matrix into vector\n"); (*(lastlist->root))->rows = 1; (*(lastlist->root))->columns = (*(lastlist->root))->nb_elements; } current = lastlist->root; lastlist = pop_list(lastlist); (*(lastlist->root))->nb_elements++; current = &((*current)->next); } /* ETag_matrix */ void STag_structure(void) { #line 227 "xmltree_read.act" *current = new_element(); if (A_structure_name) { (*current)->name = (char *) malloc(strlen(A_structure_name)+1); strcpy ((*current)->name, A_structure_name); } (*current)->def_value = value_structure; lastlist = new_list(lastlist); lastlist->root = current; current = &((*current)->child); } /* STag_structure */ void ETag_structure(void) { #line 242 "xmltree_read.act" /* no check possible (sic) */ current = lastlist->root; lastlist = pop_list(lastlist); (*(lastlist->root))->nb_elements++; current = &((*current)->next); } /* ETag_structure */ void STag_list(void) { #line 255 "xmltree_read.act" *current = new_element(); if (A_list_name) { (*current)->name = (char *) malloc(strlen(A_list_name)+1); strcpy ((*current)->name, A_list_name); } if (A_list_length) (*current)->length = strtol (A_list_length, NULL, 10); (*current)->def_value = value_list; lastlist = new_list(lastlist); lastlist->root = current; current = &((*current)->child); } /* STag_list */ void ETag_list(void) { #line 273 "xmltree_read.act" /* check length parameter */ if ((*(lastlist->root))->length != (*(lastlist->root))->nb_elements) { warning("incorrect length parameter for list\n"); (*(lastlist->root))->length = (*(lastlist->root))->nb_elements; } current = lastlist->root; lastlist = pop_list(lastlist); (*(lastlist->root))->nb_elements++; current = &((*current)->next); } /* ETag_list */ void STag_cell(void) { #line 290 "xmltree_read.act" *current = new_element(); if (A_cell_name) { (*current)->name = (char *) malloc(strlen(A_cell_name)+1); strcpy ((*current)->name, A_cell_name); } if (A_cell_rows) (*current)->rows = strtol (A_cell_rows, NULL, 10); if (A_cell_columns) (*current)->columns = strtol (A_cell_columns, NULL, 10); (*current)->def_value = value_cell; lastlist = new_list(lastlist); lastlist->root = current; current = &((*current)->child); } /* STag_cell */ void ETag_cell(void) { #line 311 "xmltree_read.act" /* check (rows, columns) parameters */ if ((*(lastlist->root))->rows * (*(lastlist->root))->columns != (*(lastlist->root))->nb_elements) { warning("incorrect (rows, columns) parameters for cell: reshaping cell into list\n"); (*(lastlist->root))->def_value = value_list; (*(lastlist->root))->length = (*(lastlist->root))->nb_elements; } current = lastlist->root; lastlist = pop_list(lastlist); (*(lastlist->root))->nb_elements++; current = &((*current)->next); } /* ETag_cell */ #line 346 "xmltree_read.act" element *read_xmltree (const char *file) { current = NULL; root = NULL; lastlist = NULL; xml_in = fopen(file, "r"); if (!xml_in) perror("can't open file\n"); xml_lex(); fclose(xml_in); return root; } /* XML application entry points. */ io/src/xmltree_read.h0000644000076400010400000000156512217071416016116 0ustar PhilipAdministrators// Copyright (C) 2004 Laurent Mazet // // 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 . #if !defined(__XMLTREE_READ_H__) #define __XMLTREE_READ_H__ #include "xmltree.h" element *read_xmltree (const char *file); #endif /* __XMLTREE_READ_H__ */ io/src/xmltree_read.l0000644000076400010400000010336612217071416016124 0ustar PhilipAdministrators/* Validating XML processor for octave.dtd. * Generated 2004/02/13 14:47:24. * * This program was generated with the FleXML XML processor generator, * (Id: flexml.pl,v 1.28 2003/02/12 02:55:41 krisrose Exp). * Copyright © 1999 Kristoffer Rose. All rights reserved. * * You can redistribute and/or modify this program provided the following * two conditions hold: * * 1. The program is distributed WITHOUT ANY WARRANTY from the author of * FleXML; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. * * 2. The program distribution conditions do not in any way affect the * distribution conditions of the FleXML system used to generate this * file or any version of FleXML derived from that system. * * Notice that these are explicit rights granted to you for files * generated by the FleXML system. For your rights in connection with * the FleXML system itself please consult the GNU General Public License. */ %{ /* Version strings. */ const char rcs_flexml_skeleton[] = "$" "Id: skel,v 1.16 1999/12/09 04:01:51 krisrose Exp $"; const char rcs_flexml[] = "$" "Id: flexml.pl,v 1.28 2003/02/12 02:55:41 krisrose Exp $"; /* ANSI headers. */ #include #include #include #include #include #include /* Generated definitions. */ #define FLEXML_BUFFERSTACKSIZE 100000 /* XML application entry points. */ static void STag_octave(void); static void ETag_octave(void); static void STag_scalar(void); static void ETag_scalar(void); static void STag_complex(void); static void ETag_complex(void); static void STag_string(void); static void ETag_string(void); static void STag_array(void); static void ETag_array(void); static void STag_matrix(void); static void ETag_matrix(void); static void STag_structure(void); static void ETag_structure(void); static void STag_list(void); static void ETag_list(void); static void STag_cell(void); static void ETag_cell(void); /* XML application data. */ typedef char* AT_list_length; #define AU_list_length NULL typedef char* AT_matrix_rows; #define AU_matrix_rows NULL typedef char* AT_matrix_name; #define AU_matrix_name NULL typedef char* AT_cell_columns; #define AU_cell_columns NULL typedef char* AT_scalar_name; #define AU_scalar_name NULL typedef char* AT_array_name; #define AU_array_name NULL typedef char* AT_complex_name; #define AU_complex_name NULL typedef char* AT_matrix_columns; #define AU_matrix_columns NULL typedef char* AT_cell_name; #define AU_cell_name NULL typedef char* AT_string_length; #define AU_string_length NULL typedef char* AT_list_name; #define AU_list_name NULL typedef enum { AU_scalar_value, A_scalar_value_undefined,A_scalar_value_true,A_scalar_value_false,A_scalar_value_inf,A_scalar_value_neginf,A_scalar_value_na,A_scalar_value_nan } AT_scalar_value; typedef char* AT_structure_name; #define AU_structure_name NULL typedef char* AT_cell_rows; #define AU_cell_rows NULL typedef char* AT_array_rows; #define AU_array_rows NULL typedef char* AT_string_name; #define AU_string_name NULL /* FleXML-provided data. */ static char* pcdata; static AT_list_length A_list_length; static AT_matrix_rows A_matrix_rows; static AT_matrix_name A_matrix_name; static AT_cell_columns A_cell_columns; static AT_scalar_name A_scalar_name; static AT_array_name A_array_name; static AT_complex_name A_complex_name; static AT_matrix_columns A_matrix_columns; static AT_cell_name A_cell_name; static AT_string_length A_string_length; static AT_list_name A_list_name; static AT_scalar_value A_scalar_value; static AT_structure_name A_structure_name; static AT_cell_rows A_cell_rows; static AT_array_rows A_array_rows; static AT_string_name A_string_name; /* XML state. */ #ifdef FLEX_DEBUG # define ENTER(state) debug_enter(state,#state) # define LEAVE debug_leave() # define SET(state) debug_set(state,#state) static void debug_enter(int, char*); static void debug_leave(void); static void debug_set(int, char*); #else # define ENTER(state) (yy_push_state(state)) # define LEAVE (yy_pop_state()) # define SET(state) BEGIN(state) #endif /* Generic actions. */ #define SKIP /*skip*/ #define SUCCEED return 0 #define FAIL return fail static int fail(const char*, ...); /* Text buffer stack handling. */ char bufferstack[FLEXML_BUFFERSTACKSIZE]; char* limit = bufferstack + FLEXML_BUFFERSTACKSIZE; typedef struct BufferLast_s { struct BufferLast_s *old; char* saved; char new[1]; } BufferLast; BufferLast* last = (BufferLast*)0; char* next = bufferstack; #define BUFFERSET(P) (P = next) #define BUFFERPUTC(C) (assert(nextold = last; l->saved = p; next = l->new; last = l; } static char* popbuffer(void) { BufferLast* l = last; assert(last != (BufferLast*)0); last = l->old; next = (char*)l; return l->saved; } #endif /* General internal entities are `unput' back onto the input stream... */ #define ENTITYTEXT(T) \ { char *s = (T), *e = s+strlen(s);\ while (--e >= s) { unput(*e); }} %} /* Flex standard options. */ %option stack %option noyy_top_state %option noinput %option noreject %option noyymore %option noyywrap /* Flex user-requested options. */ %option nounput /* XML character classes (currently restricted to ASCII). */ /* "Common syntactic structures." */ S [ \t\n\r\f]+ s [ \t\n\r\f]* /* "Names and Tokens." */ NameChar [A-Za-z0-9.:_-] Name [A-Za-z_:]{NameChar}* Names {Name}({S}{Name})* Nmtoken ({NameChar})+ Nmtokens {Nmtoken}({S}{Nmtoken})* /* Miscellaneous. */ VersionNum [a-zA-Z0-9_.:-]+ Eq {s}"="{s} Literal \'[^'']*\'|\"[^""]*\" /* Parser states (flex `exclusive start conditions'): * * PROLOG the XML prolog of the document before * DOCTYPE the XML prolog of the document after * EPILOG after the root element * INCOMMENT inside an XML comment * INPI inside an XML PI * VALUE1 inside a '...'-delimited literal * VALUE2 inside a "..."-delimited literal * CDATA inside a section. * ROOT_ expect root element * AL_ inside the attribute list for * IN_ inside a with element contents (ready for end tag) * IMPOSSIBLE dummy to permit disabling rules; must be last */ %x PROLOG DOCTYPE EPILOG INCOMMENT INPI VALUE1 VALUE2 CDATA %x ROOT_octave AL_octave S_octave E_octave %x ROOT_scalar AL_scalar IN_scalar %x ROOT_complex AL_complex S_complex S_complex_1 E_complex %x ROOT_string AL_string IN_string %x ROOT_array AL_array S_array S_array_1 S_array_2 S_array_3 E_array %x ROOT_matrix AL_matrix S_matrix S_matrix_1 S_matrix_2 E_matrix %x ROOT_structure AL_structure IN_structure %x ROOT_list AL_list IN_list %x ROOT_cell AL_cell IN_cell %x IMPOSSIBLE %{ /* State names. */ char* statenames[IMPOSSIBLE]; void FleXML_init(void) { statenames[PROLOG] = NULL; statenames[DOCTYPE] = NULL; statenames[EPILOG] = NULL; statenames[INCOMMENT] = NULL; statenames[INPI] = NULL; statenames[VALUE1] = NULL; statenames[VALUE2] = NULL; statenames[CDATA] = NULL; statenames[ROOT_octave] = NULL; statenames[AL_octave] = NULL; statenames[S_octave] = "octave"; statenames[E_octave] = "octave"; statenames[ROOT_scalar] = NULL; statenames[AL_scalar] = NULL; statenames[IN_scalar] = "scalar"; statenames[ROOT_complex] = NULL; statenames[AL_complex] = NULL; statenames[S_complex] = "complex"; statenames[S_complex_1] = "complex"; statenames[E_complex] = "complex"; statenames[ROOT_string] = NULL; statenames[AL_string] = NULL; statenames[IN_string] = "string"; statenames[ROOT_array] = NULL; statenames[AL_array] = NULL; statenames[S_array] = "array"; statenames[S_array_1] = "array"; statenames[S_array_2] = "array"; statenames[S_array_3] = "array"; statenames[E_array] = "array"; statenames[ROOT_matrix] = NULL; statenames[AL_matrix] = NULL; statenames[S_matrix] = "matrix"; statenames[S_matrix_1] = "matrix"; statenames[S_matrix_2] = "matrix"; statenames[E_matrix] = "matrix"; statenames[ROOT_structure] = NULL; statenames[AL_structure] = NULL; statenames[IN_structure] = "structure"; statenames[ROOT_list] = NULL; statenames[AL_list] = NULL; statenames[IN_list] = "list"; statenames[ROOT_cell] = NULL; statenames[AL_cell] = NULL; statenames[IN_cell] = "cell"; } %} %% /* Bypass Flex's default INITIAL state and begin by parsing the XML prolog. */ SET(PROLOG); FleXML_init(); /* COMMENTS and PIs: handled uniformly for efficiency. */ { "" LEAVE; "--" | . | \n SKIP; <> FAIL("EOF in comment."); } { "?>" LEAVE; . | \n SKIP; <> FAIL("EOF in PI (processing instruction)."); } /* SPACES: skipped uniformly */ {S} SKIP; /* PROLOG: determine root element and process it. */ { "" SET(DOCTYPE); "]*">" FAIL("Bad declaration %s.",yytext); } { "" SET(ROOT_scalar); "" SET(ROOT_octave); "" SET(ROOT_complex); "" SET(ROOT_string); "" SET(ROOT_matrix); "" SET(ROOT_array); "" SET(ROOT_structure); "" SET(ROOT_cell); "" SET(ROOT_list); "-][^>]*">" FAIL("Bad declaration %s.",yytext); . FAIL("Unexpected character `%c' in prolog.", yytext[0]); <> FAIL("EOF in prolog."); } /* RULES DERIVED FROM DTD. */ "{ ">" { LEAVE; STag_octave(); pcdata = NULL; ENTER(S_octave); } "/>" FAIL("`octave' element cannot be empty."); . FAIL("Unexpected character `%c' in attribute list of octave element.", yytext[0]); {Name} FAIL("Bad attribute `%s' in `octave' element start tag.",yytext); <> FAIL("EOF in attribute list of `octave' element."); } { "" { LEAVE; ETag_octave(); switch (YY_START) { case ROOT_octave: SET(EPILOG); break; } } "" FAIL("Unexpected end-tag `%s': `
    ' expected.",yytext); . FAIL("Unexpected character `%c': `
    ' expected.",yytext[0]); <> FAIL("Premature EOF: `
    ' expected."); } /* value (undefined | true | false | inf | neginf | na | nan) "undefined" * name CDATA #IMPLIED> */ "{ "value"{Eq}"'undefined'" | "value"{Eq}"\"undefined\"" A_scalar_value = A_scalar_value_undefined; "value"{Eq}"'true'" | "value"{Eq}"\"true\"" A_scalar_value = A_scalar_value_true; "value"{Eq}"'false'" | "value"{Eq}"\"false\"" A_scalar_value = A_scalar_value_false; "value"{Eq}"'inf'" | "value"{Eq}"\"inf\"" A_scalar_value = A_scalar_value_inf; "value"{Eq}"'neginf'" | "value"{Eq}"\"neginf\"" A_scalar_value = A_scalar_value_neginf; "value"{Eq}"'na'" | "value"{Eq}"\"na\"" A_scalar_value = A_scalar_value_na; "value"{Eq}"'nan'" | "value"{Eq}"\"nan\"" A_scalar_value = A_scalar_value_nan; "name"{Eq}\' ENTER(VALUE1); BUFFERSET(A_scalar_name); "name"{Eq}\" ENTER(VALUE2); BUFFERSET(A_scalar_name); ">" { LEAVE; STag_scalar(); pcdata = BUFFERSET(pcdata); ENTER(IN_scalar); } "/>" { LEAVE; STag_scalar(); pcdata = ""; ETag_scalar(); switch (YY_START) { case S_complex_1: SET(E_complex); break; case S_octave: SET(E_octave); break; case S_complex: SET(S_complex_1); break; case S_matrix_1: case S_matrix: case S_matrix_2: SET(S_matrix_2); break; case ROOT_scalar: SET(EPILOG); break; } } . FAIL("Unexpected character `%c' in attribute list of scalar element.", yytext[0]); {Name} FAIL("Bad attribute `%s' in `scalar' element start tag.",yytext); <> FAIL("EOF in attribute list of `scalar' element."); } { "" { LEAVE; BUFFERDONE; ETag_scalar(); switch (YY_START) { case S_complex_1: SET(E_complex); break; case S_octave: SET(E_octave); break; case S_complex: SET(S_complex_1); break; case S_matrix_1: case S_matrix: case S_matrix_2: SET(S_matrix_2); break; case ROOT_scalar: SET(EPILOG); break; } } "" FAIL("Unexpected end-tag `%s': `' expected.",yytext); <> FAIL("Premature EOF: `' expected."); } "{ "name"{Eq}\' ENTER(VALUE1); BUFFERSET(A_complex_name); "name"{Eq}\" ENTER(VALUE2); BUFFERSET(A_complex_name); ">" { LEAVE; STag_complex(); pcdata = NULL; ENTER(S_complex); } "/>" FAIL("`complex' element cannot be empty."); . FAIL("Unexpected character `%c' in attribute list of complex element.", yytext[0]); {Name} FAIL("Bad attribute `%s' in `complex' element start tag.",yytext); <> FAIL("EOF in attribute list of `complex' element."); } { "" { LEAVE; ETag_complex(); switch (YY_START) { case S_octave: SET(E_octave); break; case S_matrix_1: case S_matrix: case S_matrix_2: SET(S_matrix_2); break; case ROOT_complex: SET(EPILOG); break; } } "" FAIL("Unexpected end-tag `%s': `' expected.",yytext); . FAIL("Unexpected character `%c': `' expected.",yytext[0]); <> FAIL("Premature EOF: `' expected."); } /* length CDATA #REQUIRED * name CDATA #IMPLIED> */ "{ "length"{Eq}\' ENTER(VALUE1); BUFFERSET(A_string_length); "length"{Eq}\" ENTER(VALUE2); BUFFERSET(A_string_length); "name"{Eq}\' ENTER(VALUE1); BUFFERSET(A_string_name); "name"{Eq}\" ENTER(VALUE2); BUFFERSET(A_string_name); ">" { if (!A_string_length) FAIL("Required attribute `length' not set for `string' element."); LEAVE; STag_string(); pcdata = BUFFERSET(pcdata); ENTER(IN_string); } "/>" { if (!A_string_length) FAIL("Required attribute `length' not set for `string' element."); LEAVE; STag_string(); pcdata = ""; ETag_string(); switch (YY_START) { case S_octave: SET(E_octave); break; case S_array_2: case S_array_3: case S_array_1: SET(S_array_3); break; case ROOT_string: SET(EPILOG); break; case S_array: SET(S_array_1); break; } } . FAIL("Unexpected character `%c' in attribute list of string element.", yytext[0]); {Name} FAIL("Bad attribute `%s' in `string' element start tag.",yytext); <> FAIL("EOF in attribute list of `string' element."); } { "" { LEAVE; BUFFERDONE; ETag_string(); switch (YY_START) { case S_octave: SET(E_octave); break; case S_array_2: case S_array_3: case S_array_1: SET(S_array_3); break; case ROOT_string: SET(EPILOG); break; case S_array: SET(S_array_1); break; } } "" FAIL("Unexpected end-tag `%s': `' expected.",yytext); <> FAIL("Premature EOF: `' expected."); } /* rows CDATA #REQUIRED * name CDATA #IMPLIED> */ "{ "rows"{Eq}\' ENTER(VALUE1); BUFFERSET(A_array_rows); "rows"{Eq}\" ENTER(VALUE2); BUFFERSET(A_array_rows); "name"{Eq}\' ENTER(VALUE1); BUFFERSET(A_array_name); "name"{Eq}\" ENTER(VALUE2); BUFFERSET(A_array_name); ">" { if (!A_array_rows) FAIL("Required attribute `rows' not set for `array' element."); LEAVE; STag_array(); pcdata = NULL; ENTER(S_array); } "/>" FAIL("`array' element cannot be empty."); . FAIL("Unexpected character `%c' in attribute list of array element.", yytext[0]); {Name} FAIL("Bad attribute `%s' in `array' element start tag.",yytext); <> FAIL("EOF in attribute list of `array' element."); } { "" { LEAVE; ETag_array(); switch (YY_START) { case S_octave: SET(E_octave); break; case ROOT_array: SET(EPILOG); break; } } "" FAIL("Unexpected end-tag `%s': `' expected.",yytext); . FAIL("Unexpected character `%c': `' expected.",yytext[0]); <> FAIL("Premature EOF: `' expected."); } /* rows CDATA #REQUIRED * columns CDATA #REQUIRED * name CDATA #IMPLIED> */ "{ "rows"{Eq}\' ENTER(VALUE1); BUFFERSET(A_matrix_rows); "rows"{Eq}\" ENTER(VALUE2); BUFFERSET(A_matrix_rows); "columns"{Eq}\' ENTER(VALUE1); BUFFERSET(A_matrix_columns); "columns"{Eq}\" ENTER(VALUE2); BUFFERSET(A_matrix_columns); "name"{Eq}\' ENTER(VALUE1); BUFFERSET(A_matrix_name); "name"{Eq}\" ENTER(VALUE2); BUFFERSET(A_matrix_name); ">" { if (!A_matrix_rows) FAIL("Required attribute `rows' not set for `matrix' element."); if (!A_matrix_columns) FAIL("Required attribute `columns' not set for `matrix' element."); LEAVE; STag_matrix(); pcdata = NULL; ENTER(S_matrix); } "/>" { if (!A_matrix_rows) FAIL("Required attribute `rows' not set for `matrix' element."); if (!A_matrix_columns) FAIL("Required attribute `columns' not set for `matrix' element."); LEAVE; STag_matrix(); pcdata = NULL; ETag_matrix(); switch (YY_START) { case ROOT_matrix: SET(EPILOG); break; } } . FAIL("Unexpected character `%c' in attribute list of matrix element.", yytext[0]); {Name} FAIL("Bad attribute `%s' in `matrix' element start tag.",yytext); <> FAIL("EOF in attribute list of `matrix' element."); } { "" { LEAVE; ETag_matrix(); switch (YY_START) { case ROOT_matrix: SET(EPILOG); break; } } "" FAIL("Unexpected end-tag `%s': `' expected.",yytext); . FAIL("Unexpected character `%c': `' expected.",yytext[0]); <> FAIL("Premature EOF: `' expected."); } "{ "name"{Eq}\' ENTER(VALUE1); BUFFERSET(A_structure_name); "name"{Eq}\" ENTER(VALUE2); BUFFERSET(A_structure_name); ">" { LEAVE; STag_structure(); pcdata = BUFFERSET(pcdata); ENTER(IN_structure); } "/>" { LEAVE; STag_structure(); pcdata = ""; ETag_structure(); switch (YY_START) { case S_octave: SET(E_octave); break; case ROOT_structure: SET(EPILOG); break; } } . FAIL("Unexpected character `%c' in attribute list of structure element.", yytext[0]); {Name} FAIL("Bad attribute `%s' in `structure' element start tag.",yytext); <> FAIL("EOF in attribute list of `structure' element."); } { "" { LEAVE; BUFFERDONE; ETag_structure(); switch (YY_START) { case S_octave: SET(E_octave); break; case ROOT_structure: SET(EPILOG); break; } } "" FAIL("Unexpected end-tag `%s': `' expected.",yytext); <> FAIL("Premature EOF: `' expected."); } /* length CDATA #REQUIRED * name CDATA #IMPLIED> */ "{ "length"{Eq}\' ENTER(VALUE1); BUFFERSET(A_list_length); "length"{Eq}\" ENTER(VALUE2); BUFFERSET(A_list_length); "name"{Eq}\' ENTER(VALUE1); BUFFERSET(A_list_name); "name"{Eq}\" ENTER(VALUE2); BUFFERSET(A_list_name); ">" { if (!A_list_length) FAIL("Required attribute `length' not set for `list' element."); LEAVE; STag_list(); pcdata = BUFFERSET(pcdata); ENTER(IN_list); } "/>" { if (!A_list_length) FAIL("Required attribute `length' not set for `list' element."); LEAVE; STag_list(); pcdata = ""; ETag_list(); switch (YY_START) { case S_octave: SET(E_octave); break; case ROOT_list: SET(EPILOG); break; } } . FAIL("Unexpected character `%c' in attribute list of list element.", yytext[0]); {Name} FAIL("Bad attribute `%s' in `list' element start tag.",yytext); <> FAIL("EOF in attribute list of `list' element."); } { "" { LEAVE; BUFFERDONE; ETag_list(); switch (YY_START) { case S_octave: SET(E_octave); break; case ROOT_list: SET(EPILOG); break; } } "" FAIL("Unexpected end-tag `%s': `' expected.",yytext); <> FAIL("Premature EOF: `' expected."); } /* rows CDATA #REQUIRED * columns CDATA #REQUIRED * name CDATA #IMPLIED> */ "{ "rows"{Eq}\' ENTER(VALUE1); BUFFERSET(A_cell_rows); "rows"{Eq}\" ENTER(VALUE2); BUFFERSET(A_cell_rows); "columns"{Eq}\' ENTER(VALUE1); BUFFERSET(A_cell_columns); "columns"{Eq}\" ENTER(VALUE2); BUFFERSET(A_cell_columns); "name"{Eq}\' ENTER(VALUE1); BUFFERSET(A_cell_name); "name"{Eq}\" ENTER(VALUE2); BUFFERSET(A_cell_name); ">" { if (!A_cell_rows) FAIL("Required attribute `rows' not set for `cell' element."); if (!A_cell_columns) FAIL("Required attribute `columns' not set for `cell' element."); LEAVE; STag_cell(); pcdata = BUFFERSET(pcdata); ENTER(IN_cell); } "/>" { if (!A_cell_rows) FAIL("Required attribute `rows' not set for `cell' element."); if (!A_cell_columns) FAIL("Required attribute `columns' not set for `cell' element."); LEAVE; STag_cell(); pcdata = ""; ETag_cell(); switch (YY_START) { case S_octave: SET(E_octave); break; case ROOT_cell: SET(EPILOG); break; } } . FAIL("Unexpected character `%c' in attribute list of cell element.", yytext[0]); {Name} FAIL("Bad attribute `%s' in `cell' element start tag.",yytext); <> FAIL("EOF in attribute list of `cell' element."); } { "" { LEAVE; BUFFERDONE; ETag_cell(); switch (YY_START) { case S_octave: SET(E_octave); break; case ROOT_cell: SET(EPILOG); break; } } "" FAIL("Unexpected end-tag `%s': `' expected.",yytext); <> FAIL("Premature EOF: `' expected."); } /* EPILOG: after the root element. */ { . FAIL("Unexpected character `%c' after document.", yytext[0]); <> SUCCEED; } /* CHARACTER DATA. */ { /* Non-defined standard entities... */ "&" BUFFERPUTC('&'); "<" BUFFERPUTC('<'); ">" BUFFERPUTC('>'); "'" BUFFERPUTC('\''); """ BUFFERPUTC('"'); /* Character entities. */ "&#"[[:digit:]]+";" BUFFERPUTC((unsigned char)atoi(yytext+2)); "&#x"[[:xdigit:]]+";" BUFFERPUTC((unsigned char)strtol(yytext+3,NULL,16)); } { "\n" | "\r" | "\r\n" | "\n\r" BUFFERPUTC('\n'); } { "" FAIL("Unexpected `]]>' in character data."); } { \' BUFFERDONE; LEAVE; <> FAIL("EOF in literal (\"'\" expected)."); } { \" BUFFERDONE; LEAVE; <> FAIL("EOF in literal (`\"' expected)."); } { [^<&] BUFFERPUTC(yytext[0]); [<&] FAIL("Spurious `%c' in character data.",yytext[0]); } { "]]>" LEAVE; "]]" BUFFERPUTC(yytext[0]); BUFFERPUTC(yytext[1]); . BUFFERPUTC(yytext[0]); <> FAIL("EOF in CDATA section."); } /* Impossible rules to avoid warnings from flex(1). */ { .|[\n] FAIL("The Impossible Happened: INITIAL or IMPOSSIBLE state entered?"); } %% /* Element context stack lookup. */ int element_context(int i) { return (0 #endif #include "xmltree.h" #define warning perror element **current; element *root; list *lastlist; void STag_octave(void) { #line 43 "xmltree_read.act" root = new_element(); root->def_value = value_data; current = &(root->child); lastlist = new_list(lastlist); lastlist->root = current; } /* STag_octave */ void ETag_octave(void) { #line 52 "xmltree_read.act" current = lastlist->root; lastlist = pop_list(lastlist); current = &((*current)->next); } /* ETag_octave */ void STag_scalar(void) { #line 60 "xmltree_read.act" *current = new_element(); if (A_scalar_name) { (*current)->name = (char *) malloc(strlen(A_scalar_name)+1); strcpy ((*current)->name, A_scalar_name); } (*current)->def_value = value_scalar; switch (A_scalar_value) { case A_scalar_value_true: (*current)->const_value = const_true; break; case A_scalar_value_false: (*current)->const_value = const_false; break; case A_scalar_value_inf: (*current)->const_value = const_inf; break; case A_scalar_value_neginf: (*current)->const_value = const_neginf; break; case A_scalar_value_nan: (*current)->const_value = const_nan; break; case A_scalar_value_na: (*current)->const_value = const_na; break; default: (*current)->const_value = const_undef; } } /* STag_scalar */ void ETag_scalar(void) { #line 80 "xmltree_read.act" if (((*current)->const_value == const_undef) && (pcdata)) (*current)->scalar_value = strtod (pcdata, NULL); (*(lastlist->root))->nb_elements++; current = &((*current)->next); } /* ETag_scalar */ void STag_string(void) { #line 91 "xmltree_read.act" *current = new_element(); if (A_string_name) { (*current)->name = (char *) malloc(strlen(A_string_name)+1); strcpy ((*current)->name, A_string_name); } if (A_string_length) (*current)->length = strtol (A_string_length, NULL, 10); (*current)->def_value = value_string; } /* STag_string */ void ETag_string(void) { #line 105 "xmltree_read.act" if (pcdata) { int len = strlen(pcdata); /* check length parameter */ if ((*current)->length != len) { warning("incorrect length parameter for string\n"); (*current)->length = len; } (*current)->string_value = (char *) malloc ((len+1) * sizeof(char)); strcpy((*current)->string_value, pcdata); } (*(lastlist->root))->nb_elements++; current = &((*current)->next); } /* ETag_string */ void STag_complex(void) { #line 126 "xmltree_read.act" *current = new_element(); if (A_complex_name) { (*current)->name = (char *) malloc(strlen(A_complex_name)+1); strcpy ((*current)->name, A_complex_name); } (*current)->def_value = value_complex; lastlist = new_list(lastlist); lastlist->root = current; current = &((*current)->child); } /* STag_complex */ void ETag_complex(void) { #line 141 "xmltree_read.act" current = lastlist->root; lastlist = pop_list(lastlist); (*(lastlist->root))->nb_elements++; current = &((*current)->next); } /* ETag_complex */ void STag_array(void) { #line 152 "xmltree_read.act" *current = new_element(); if (A_array_name) { (*current)->name = (char *) malloc(strlen(A_array_name)+1); strcpy ((*current)->name, A_array_name); } if (A_array_rows) (*current)->rows = strtol (A_array_rows, NULL, 10); (*current)->def_value = value_array; lastlist = new_list(lastlist); lastlist->root = current; current = &((*current)->child); } /* STag_array */ void ETag_array(void) { #line 170 "xmltree_read.act" /* check rows parameter */ if ((*(lastlist->root))->rows != (*(lastlist->root))->nb_elements) { warning("incorrect length parameter for array\n"); (*(lastlist->root))->rows = (*(lastlist->root))->nb_elements; } current = lastlist->root; lastlist = pop_list(lastlist); (*(lastlist->root))->nb_elements++; current = &((*current)->next); } /* ETag_array */ void STag_matrix(void) { #line 187 "xmltree_read.act" *current = new_element(); if (A_matrix_name) { (*current)->name = (char *) malloc(strlen(A_matrix_name)+1); strcpy ((*current)->name, A_matrix_name); } if (A_matrix_rows) (*current)->rows = strtol (A_matrix_rows, NULL, 10); if (A_matrix_columns) (*current)->columns = strtol (A_matrix_columns, NULL, 10); (*current)->def_value = value_matrix; lastlist = new_list(lastlist); lastlist->root = current; current = &((*current)->child); } /* STag_matrix */ void ETag_matrix(void) { #line 208 "xmltree_read.act" /* check (rows, columns) parameters */ if ((*(lastlist->root))->rows * (*(lastlist->root))->columns != (*(lastlist->root))->nb_elements) { warning("incorrect (rows, columns) parameters for matrix: reshaping matrix into vector\n"); (*(lastlist->root))->rows = 1; (*(lastlist->root))->columns = (*(lastlist->root))->nb_elements; } current = lastlist->root; lastlist = pop_list(lastlist); (*(lastlist->root))->nb_elements++; current = &((*current)->next); } /* ETag_matrix */ void STag_structure(void) { #line 227 "xmltree_read.act" *current = new_element(); if (A_structure_name) { (*current)->name = (char *) malloc(strlen(A_structure_name)+1); strcpy ((*current)->name, A_structure_name); } (*current)->def_value = value_structure; lastlist = new_list(lastlist); lastlist->root = current; current = &((*current)->child); } /* STag_structure */ void ETag_structure(void) { #line 242 "xmltree_read.act" /* no check possible (sic) */ current = lastlist->root; lastlist = pop_list(lastlist); (*(lastlist->root))->nb_elements++; current = &((*current)->next); } /* ETag_structure */ void STag_list(void) { #line 255 "xmltree_read.act" *current = new_element(); if (A_list_name) { (*current)->name = (char *) malloc(strlen(A_list_name)+1); strcpy ((*current)->name, A_list_name); } if (A_list_length) (*current)->length = strtol (A_list_length, NULL, 10); (*current)->def_value = value_list; lastlist = new_list(lastlist); lastlist->root = current; current = &((*current)->child); } /* STag_list */ void ETag_list(void) { #line 273 "xmltree_read.act" /* check length parameter */ if ((*(lastlist->root))->length != (*(lastlist->root))->nb_elements) { warning("incorrect length parameter for list\n"); (*(lastlist->root))->length = (*(lastlist->root))->nb_elements; } current = lastlist->root; lastlist = pop_list(lastlist); (*(lastlist->root))->nb_elements++; current = &((*current)->next); } /* ETag_list */ void STag_cell(void) { #line 290 "xmltree_read.act" *current = new_element(); if (A_cell_name) { (*current)->name = (char *) malloc(strlen(A_cell_name)+1); strcpy ((*current)->name, A_cell_name); } if (A_cell_rows) (*current)->rows = strtol (A_cell_rows, NULL, 10); if (A_cell_columns) (*current)->columns = strtol (A_cell_columns, NULL, 10); (*current)->def_value = value_cell; lastlist = new_list(lastlist); lastlist->root = current; current = &((*current)->child); } /* STag_cell */ void ETag_cell(void) { #line 311 "xmltree_read.act" /* check (rows, columns) parameters */ if ((*(lastlist->root))->rows * (*(lastlist->root))->columns != (*(lastlist->root))->nb_elements) { warning("incorrect (rows, columns) parameters for cell: reshaping cell into list\n"); (*(lastlist->root))->def_value = value_list; (*(lastlist->root))->length = (*(lastlist->root))->nb_elements; } current = lastlist->root; lastlist = pop_list(lastlist); (*(lastlist->root))->nb_elements++; current = &((*current)->next); } /* ETag_cell */ #line 346 "xmltree_read.act" element *read_xmltree (const char *file) { current = NULL; root = NULL; lastlist = NULL; xml_in = fopen(file, "r"); if (!xml_in) perror("can't open file\n"); xml_lex(); fclose(xml_in); return root; } /* XML application entry points. */