diff options
Diffstat (limited to 'support')
-rw-r--r-- | support/ltx2mathml/COPYING | 674 | ||||
-rw-r--r-- | support/ltx2mathml/README | 42 | ||||
-rw-r--r-- | support/ltx2mathml/src/ltx2mathml.h | 22 | ||||
-rw-r--r-- | support/ltx2mathml/src/ltx2mathmlclasses.cpp | 185 | ||||
-rw-r--r-- | support/ltx2mathml/src/ltx2mathmlclasses.h | 40 | ||||
-rw-r--r-- | support/ltx2mathml/src/ltx2mathmlexceptions.h | 51 | ||||
-rw-r--r-- | support/ltx2mathml/src/ltx2mathmlparser.cpp | 2367 | ||||
-rw-r--r-- | support/ltx2mathml/src/ltx2mathmltables.cpp | 672 | ||||
-rw-r--r-- | support/ltx2mathml/src/ltx2mathmltables.h | 125 | ||||
-rw-r--r-- | support/ltx2mathml/src/test.cpp | 41 |
10 files changed, 4219 insertions, 0 deletions
diff --git a/support/ltx2mathml/COPYING b/support/ltx2mathml/COPYING new file mode 100644 index 0000000000..e72bfddabc --- /dev/null +++ b/support/ltx2mathml/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> + 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. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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 <https://www.gnu.org/licenses/>. + +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: + + <program> Copyright (C) <year> <name of author> + 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 +<https://www.gnu.org/licenses/>. + + 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 +<https://www.gnu.org/licenses/why-not-lgpl.html>.
\ No newline at end of file diff --git a/support/ltx2mathml/README b/support/ltx2mathml/README new file mode 100644 index 0000000000..735d5bf8b5 --- /dev/null +++ b/support/ltx2mathml/README @@ -0,0 +1,42 @@ +LTX2MathML v. 1.0 + +About +===== + +LTX2MathML converts a subset of LaTeX math to MathML. + +I wrote this over a decade ago (my coding style has changed since then :). As the original sources did not compile correctly with Visual Studio 2019, I had to make some modifications to them. Only compilation errors were addressed. The rest of the source codes have largely remained unchanged since I last wrote them. + + +Usage +===== + +1. Include the file 'ltx2mathml.h' and the 3 CPP files (ltx2mathmlclasses.cpp, ltx2mathmlparser.cpp, and ltx2mathmltables.cpp) in your project. + +2. Call the function 'convertFormula'. + +3. If that function succeeds, call 'getMathMLOutput' (overloaded) to retrieve the results. Otherwise, call 'getLastError' to retrieve the error message. + + +See the header 'ltx2mathml.h' for a description of these functions. See the file 'test.cpp' for the usage. + + +LaTeX Commands/Symbols Supported +======================== + +The most common LaTeX commands and symbols are supported. See the file 'ltx2mathmltables.cpp' for the complete list. + + +Copying +======= + +This program is released under the GNU General Public License +version 3 or newer. See the COPYING file included with this distribution or <http://www.gnu.org/licenses/>. + + Copyright (C) 2020 Peter Frane Jr. + + +Contact +======= + +Please send any inquries to pfranejr@hotmail.com diff --git a/support/ltx2mathml/src/ltx2mathml.h b/support/ltx2mathml/src/ltx2mathml.h new file mode 100644 index 0000000000..4bbd227245 --- /dev/null +++ b/support/ltx2mathml/src/ltx2mathml.h @@ -0,0 +1,22 @@ +#pragma once + +#include <string> + +using namespace std; + +// 'input': the latex formula to convert +// 'len' : the length of 'input'; use a value <0 to indicate that 'input' is null terminated +// 'errorIndex': on error, this gives the location in 'input' where the error was found + +bool convertFormula( const char *input, int len, int *errorIndex ); + +// raw copy, i.e., without the '<math>' tag +const char *getMathMLOutput(); + +// 'buf': the buffer where the output will be written to +// 'display: flag indicating whether the output is either an inline or a display equation +bool getMathMLOutput(string &buf, bool display); + +// function for obtaining the error message + +const char *getLastError(); diff --git a/support/ltx2mathml/src/ltx2mathmlclasses.cpp b/support/ltx2mathml/src/ltx2mathmlclasses.cpp new file mode 100644 index 0000000000..81dbc603dd --- /dev/null +++ b/support/ltx2mathml/src/ltx2mathmlclasses.cpp @@ -0,0 +1,185 @@ + +#include "ltx2mathmlclasses.h" +#include <stdio.h> + +Buffer::Buffer() +{ + m_buf = NULL; + m_index = 0; + m_size = 0; +} + +Buffer::~Buffer() +{ + destroy(); +} + +void Buffer::destroy() +{ + if( m_buf != NULL ) + free( m_buf ); + + m_buf = NULL; + m_index = 0; +} + +void Buffer::setlength( size_t len ) +{ + char *tmp = (char *) realloc( m_buf, len + 1 ); + + if( tmp != NULL ) + { + m_buf = tmp; + + m_size = len; + if( m_index > len ) // truncated + { + m_index = len; + } + else + { + ZeroMemory( &m_buf[ m_index ], ( len - m_index ) ); + } + } + else + throw ex_out_of_memory; +} + +size_t Buffer::length() +{ + return m_index; +} + +void Buffer::format( const char *fmt, ... ) +{ + va_list list; + size_t len; + char s[256]; + + va_start( list, fmt ); + //len = vsprintf_s( s, sizeof( s ) - 1, fmt, list ); + len = vsprintf( s, fmt, list ); + va_end( list ); + _write( m_index, s, len ); +} + + +void Buffer::_write( size_t index, const char *s, size_t len ) +{ + if( !s || ( len <= 0 ) ) + { + return; + } + + if( ( m_size - m_index ) <= len ) + { + setlength( m_size + len + 1); + + } + + memcpy( &m_buf[ index ], s, len ); + + + m_index += len; +} + + +void Buffer::write( const char *s, size_t len ) +{ + _write( m_index, s, len ); +} + +void Buffer::write( const char *s ) +{ + _write( m_index, s, strlen( s ) ); +} + +char *Buffer::data( size_t *len ) +{ + if( len != NULL ) + { + *len = m_index; + } + + return m_buf; +} + + +void Buffer::append( Buffer &buf, bool transfer ) +{ + if( transfer && m_index == 0 ) + { + BufferStruct temp; + + buf.releaseBuffer( temp ); + + m_buf = temp.m_buf; + m_index = temp.m_index; + m_size = temp.m_size; + } + else + { + _write( m_index, buf.m_buf, buf.m_index ); + } +} + +void Buffer::releaseBuffer( BufferStruct &buf ) +{ + buf.m_buf = m_buf; + buf.m_index = m_index; + buf.m_size = m_size; + + m_size = 0; + m_index = 0; + m_buf = NULL; +} + +void Buffer::reset() +{ + ZeroMemory( m_buf, m_index ); + m_index = 0; +} + +char *Buffer::release() +{ + char *temp; + + temp = m_buf; + m_size = 0; + m_index = 0; + m_buf = NULL; + + return temp; +} + +void Buffer::insertAt( size_t index, const char *s ) +{ + size_t len, count; + char *src, *dest; + + len = strlen( s ); + + if( len == 0 ) + return; + + if( index >= m_index ) + { + _write( index, s, len ); + return; + } + + if( ( m_size - m_index ) <= len ) + { + setlength( m_size + len + 1); + } + src = m_buf + index; + dest = src + len; + + count = m_index - index; + + //memmove_s( dest, m_size, src, count ); + + memmove( dest, src, count ); + memcpy( m_buf + index, s, len ); + m_index += len; +} diff --git a/support/ltx2mathml/src/ltx2mathmlclasses.h b/support/ltx2mathml/src/ltx2mathmlclasses.h new file mode 100644 index 0000000000..4e3eed5dfe --- /dev/null +++ b/support/ltx2mathml/src/ltx2mathmlclasses.h @@ -0,0 +1,40 @@ +#pragma once + +#include <memory.h> +#include <stdarg.h> +#include <malloc.h> +#include <string.h> +#include "ltx2mathmlexceptions.h" + +#ifndef ZeroMemory +#define ZeroMemory(p,n) memset( (p), 0, (n) ) +#endif + + + +struct BufferStruct { + char *m_buf; + size_t m_index, m_size; +}; + +struct Buffer { + char *m_buf; + size_t m_index, m_size; + Buffer(); + ~Buffer(); + void setlength( size_t len ); + void write( const char *s, size_t len ); + void write( const char *s ); + size_t length(); + void append( Buffer &buf, bool transfer = false ); + char *data( size_t *len = NULL ); + void insertAt( size_t index, const char *s ); + void format( const char *fmt, ... ); + void releaseBuffer( BufferStruct &buf ); + void reset(); + char *release(); + void destroy(); +private: + void _write( size_t index, const char *s, size_t len ); +}; + diff --git a/support/ltx2mathml/src/ltx2mathmlexceptions.h b/support/ltx2mathml/src/ltx2mathmlexceptions.h new file mode 100644 index 0000000000..5131c5dec3 --- /dev/null +++ b/support/ltx2mathml/src/ltx2mathmlexceptions.h @@ -0,0 +1,51 @@ +#ifndef __exception +#define __exception + + +enum ex_exception { + ex_syntax_error, + ex_out_of_memory, //"Out of memory"}, + ex_missing_lbrace, //"Missing '{'"}, + ex_prefix_superscript, //"Illegal prefix superscript: use the '\\lsup' command"}, + ex_prefix_subscript, //"Illegal prefix superscript: use the '\\lsub' command"}, + ex_misplaced_column_separator, //"Misplaced column separator"}, + ex_more_rbrace_than_lbrace, //"Syntax error: more '}' than '{'"}, + ex_control_name_too_long, //"Control name too long: maximum is 32"}, + ex_misplaced_row_separator, //"Misplaced row separator"}, + ex_illegal_subscript, //"Illegal subscript"}, + ex_illegal_superscript, //"Illegal superscript"}, + ex_undefined_control_sequence, //"Undefined control sequence"}, + ex_misplaced_inline_formula, //"Misplaced inline formula"}, + ex_missing_parameter, //"Missing parameter"}, + ex_more_lbrace_than_rbrace, //"Syntax error: more '{' than '}'"}, + ex_double_superscript, //"Double superscript"}, + ex_double_subscript, //"Double subscript"}, + ex_use_subscript_before_superscript, //"Use subscript first as the element is <msubsup>"}, + ex_internal_error, //"Internal error"}, + ex_missing_end_tag, //"Missing end tag"}, + ex_undefined_environment_type, //"Undefined environment type"}, + ex_unknown_alignment_character, //"Unknown alignment character"}, + ex_missing_begin, //"Missing \\begin"}, + ex_missing_end, //"Missing \\end"}, + ex_mismatched_environment_type, //"Mismatched environment type"} + ex_too_many_columns, + ex_unknown_attribute, + ex_misplaced_limits, + ex_misplaced_nolimits, + ex_no_command_allowed, + ex_missing_fence_parameter, + ex_not_math_mode, + ex_missing_right_sq_bracket, + ex_missing_dollar_symbol, + ex_missing_left_fence, + ex_missing_right_fence, + ex_ambiguous_script, + ex_misplaced_eqno, + ex_duplicate_eqno, + ex_missing_column_alignment, + ex_missing_subsup_base, + ex_unknown_character, + ex_unhandled_mathtype +}; + +#endif
\ No newline at end of file diff --git a/support/ltx2mathml/src/ltx2mathmlparser.cpp b/support/ltx2mathml/src/ltx2mathmlparser.cpp new file mode 100644 index 0000000000..a9a2ded9ee --- /dev/null +++ b/support/ltx2mathml/src/ltx2mathmlparser.cpp @@ -0,0 +1,2367 @@ + +#include "ltx2mathmlclasses.h" +#include "ltx2mathmltables.h" +#include "ltx2mathmlexceptions.h" +#include <ctype.h> +#include <string> + +using namespace std; +// GLOBALS + + +enum sub_expression { se_none, se_use_default, se_braced, se_optional_param, se_inline_math, se_fence, + se_matrix };//, se_eqalign, se_array, se_eqnarray }; + +enum element_type { et_unknown, et_tag_off, et_tag_on, et_tag_open, et_tag_on_open }; + + +enum skip_input { sp_skip_all, sp_skip_once, sp_no_skip }; + +enum { MAX_CONTROL_NAME = 32, EXTRA_BUF = 8 }; + + +#define char_null '\0' +#define char_backslash '\\' +#define char_prime '\'' + + +struct ArrayStruct { + short maxColumn, columnCount; + //sub_expression subType; + command_id id; +}; + +struct ErrorMessage { + const char *msg; + int index; + int code; + string msg2; +}; + +struct InputStream { + token_type token; + char buffer[MAX_CONTROL_NAME+EXTRA_BUF+1]; + char *start; + char nextChar; +}; + + +static SymbolTable limits[] = { + { "<munder>", "</munder>" }, + { "<mover>", "</mover>" }, + { "<munderover>", "</munderover>" } +}; + +static SymbolTable nolimits[] = { + { "<msub>", "</msub>" }, + { "<msup>", "</msup>" }, + { "<msubsup>", "</msubsup>" } +}; + +static SymbolTable limitsMovable[] = { + { "<msub movablelimits='true'>", "</msub>" }, + { "<msup movablelimits='true'>", "</msup>" }, + { "<msubsup movablelimits='true'>", "</msubsup>" } +}; + +static char *pStart = NULL; +static char *pCur = NULL; +static char *pEnd = NULL; +static bool isNumberedFormula = false; +static Buffer globalBuf, eqNumber; +static ErrorMessage errMsg; + + +void onDigit( Buffer &prevBuf ); +void onAlpha( Buffer &prevBuf ); +void onSymbol( Buffer &prevBuf, InputStream &input, bool checkSubSup = true ); +void onSubscript( Buffer &prevBuf ); +void onSuperscript( Buffer &prevBuf ); +void onControlName( Buffer &prevBuf, InputStream &input, bool &quit ); +void onEntity( Buffer &prevBuf, EntityStruct *entity, bool checkLimits = true, bool checkSubSup = true ); +void onFunction( Buffer &prevBuf, FunctionStruct *function, bool checkLimits = true ); +bool onCommand( Buffer &prevBuf, ControlStruct &control, sub_expression subType, void *paramExtra ); +void getCommandParam( Buffer &prevBuf, sub_expression subType ); +bool followedBy( char **p, const char *pattern, skip_input skip ); +bool parseExpression(const char *input, int len, int *errorIndex ); +void runLoop( Buffer &prevBuf, sub_expression subType, void *paramExtra = NULL ); +EnvironmentStruct *getEnvironmentType(); +void onBeginEnvironment( Buffer &prevBuf ); +bool onEndEnvironment( sub_expression subType, void *paramExtra ); +void precondition( char **p ); +void skipSpaces( char **p ); +void skipChar( char **p ); +bool getInput( InputStream &input, skip_input white_space ); +bool scriptNext( char *p ); +int getLastTagIndex(const char *p, size_t length, element_type element ); +token_type getControlTypeEx( InputStream &input, ControlStruct &control ); +void onColumn( Buffer &prevBuf, const char *pos, ArrayStruct &ar ); +void onRow( Buffer &prevBuf, ArrayStruct &ar ); +bool needsMrow(const char *p ); +void onMathFont( Buffer &prevBuf, const char *tagOn, const char *tagOff ); +void onTextFont( Buffer &prevBuf, const char *tagOn, const char *tagOff, command_id id, bool allowInline = true ); +bool onFence( Buffer &prevBuf, command_id id, sub_expression subType, const char *tagOn, const char *tagOff ); +void onEndExpression( sub_expression subType, token_type token, CommandStruct *command ); +void getPrime( char **p, char *buf ); +void onPrime( Buffer &prevBuf ); + +bool convertFormula(const char *input, int len, int *errorIndex ) +{ + + if( len < 0 ) + { + len = (int) strlen( input ); + } + + if( len == 0 ) + { + return false; + } + + return parseExpression( input, len, errorIndex ); +} + +bool parseExpression( const char *input, int len, int *errorIndex ) +{ + + bool result; + + pStart = (char *)input; + pCur = pStart; + pEnd = pStart + len; + + ZeroMemory( &errMsg, sizeof( errMsg ) ); + + globalBuf.destroy(); + eqNumber.destroy(); + isNumberedFormula = false; + + result = true; + try + { + precondition( &pCur ); + runLoop( globalBuf, se_use_default ); + if( needsMrow( globalBuf.data() ) ) + { + globalBuf.insertAt( 0, "<mrow>" ); + globalBuf.write( "</mrow>" ); + } + if( isNumberedFormula ) + { + globalBuf.insertAt( 0, eqNumber.data() ); + globalBuf.write( "</mtd></mlabeledtr></mtable>" ); + } + } + catch( const ErrorMessage &err ) + { + result = false; + *errorIndex = err.index; + } + + return result; +} + + +const char *getMathMLOutput() +{ + if( globalBuf.length() != 0 ) + { + return globalBuf.data(); + } + + return NULL; +} + +bool getMathMLOutput(string& buf, bool display) +{ + if (globalBuf.length() != 0) + { + const char *data = globalBuf.data(); + + buf = display ? "<math display=\"block\" xmlns=\"http://www.w3.org/1998/Math/MathML\">" : "<math xmlns=\"http://www.w3.org/1998/Math/MathML\">"; + + buf.append(data); + + buf.append("</math>"); + + return true; + } + return false; +} + +static void getControlName(const char* start, string& name) +{ + char* p = (char*)(start+1); + + name.push_back('\\'); + + if (!isalpha(*p)) + { + name.push_back(*p); + return; + } + while (*p && isalnum(*p)) + { + name.push_back(*p); + ++p; + } +} + +ErrorMessage &error(const char *index, ex_exception code ) +{ + errMsg.code = (int) code; + errMsg.index = (int) (index - pStart); + + if (ex_undefined_control_sequence == code) + { + string name; + + errMsg.msg2 = getErrorMsg(code); + errMsg.msg2.append(": "); + + getControlName(index, name); + + errMsg.msg2.append(name); + + errMsg.msg = errMsg.msg2.c_str(); + } + else + { + errMsg.msg = getErrorMsg(code); + } + return errMsg; +} + +ErrorMessage& error(const char* index, ex_exception code, const string &msg) +{ + errMsg.code = (int)code; + errMsg.index = (int)(index - pStart); + errMsg.msg = getErrorMsg(code); + + return errMsg; +} + + +const char *getLastError() +{ + return errMsg.msg; +} + +/* + + PRECONDITION traps as many errors as possible + +*/ + + +static void precondition( char **p ) +{ + int braces; + char *s, *lastLeftBrace; + + skipSpaces( p ); + + // these chars can't start an equation + + //lastPos = *p; + + s = *p; + + switch( *s ) + { + case '}': + throw error( s, ex_missing_lbrace ); + case '^': + throw error( s, ex_prefix_superscript ); + case '_': + throw error( s, ex_prefix_subscript ); + case '&': + throw error( s, ex_misplaced_column_separator ); + } + + braces = 0; + lastLeftBrace = NULL; + + while( *s ) + { + if( *s == '{' ) + { + lastLeftBrace = s; + ++braces; + skipChar( &s ); + if( *s == '}' ) + { + skipChar( &s ); + --braces; + } + switch( *s ) + { + case '^': + throw error( s, ex_prefix_superscript ); + case '_': + throw error( s, ex_prefix_subscript ); + } + } + else if( *s == '}' ) + { + --braces; + if( braces < 0 ) + { + throw error( s, ex_more_rbrace_than_lbrace ); + } + ++s; + } + else if( *s == char_backslash ) + { + ++s; + if( isdigit( *s ) ) + { + throw error( s-1, ex_undefined_control_sequence ); + } + else if( isalpha( *s ) ) + { + char *start; + + start = s; + + // compute the length of the control name + do + { + ++s; + } + while( isalpha( *s ) ); + + if( ( s - start ) > MAX_CONTROL_NAME ) + { + throw error( start - 1, ex_control_name_too_long ); + } + } + else + { + // only the following chars can be escaped + + switch( *s ) + { + case '}': + case '{': + case '&': + case '^': + case '_': + case '-': + case '$': + case '#': + case '!': + case ';': + case '>': + case ':': // check + case ',': + case '|': + case ' ': + ++s; + break; + case char_backslash: + skipChar( &s ); + if( scriptNext( s ) ) + { + if( *s == '_' ) + { + throw error( s, ex_prefix_subscript ); + } + else + { + throw error( s, ex_prefix_superscript ); + } + } + break; + default: + throw error( s-1, ex_undefined_control_sequence ); + } + } + } + else if( *s == '&' ) + { + skipChar( &s ); + if( scriptNext( s ) ) + { + if( *s == '_' ) + { + throw error( s, ex_prefix_subscript ); + } + else + { + throw error( s, ex_prefix_superscript ); + } + } + } + else if( *s == '$' ) + { + if( braces == 0 ) + { + throw error( s, ex_misplaced_inline_formula ); + } + + skipChar( &s ); + if( scriptNext( s ) ) + { + if( *s == '_' ) + { + throw error( s, ex_prefix_subscript ); + } + else + { + throw error( s, ex_prefix_superscript ); + } + } + } + else if( scriptNext( s ) ) + { + char *pos; + + pos = s; + skipChar( &s ); + switch( *s ) + { + case char_null: + case '}': + case '$': + case '&': + throw error( pos, ex_missing_parameter ); + case char_backslash: + if( s[1] == char_backslash ) // row separator + { + throw error( pos, ex_missing_parameter ); + } + } + } + else + { + ++s; + } + + } + + if( braces != 0 ) + { + throw error( lastLeftBrace, ex_more_lbrace_than_rbrace ); + } + // check backwards + + do { + --s; + } + while( (s > *p ) && isspace( *s ) ); + + pEnd = s+1; +} + +static void skipSpaces( char **p ) +{ + char *s; + + if( p == NULL ) + { + return; + } + + s = *p; + + while( (*s) && isspace( *s ) ) + { + ++s; + } + + *p = s; +} + +static void skipChar( char **p ) +{ + char *s; + + if( p == NULL ) + { + return; + } + + s = *p; + + ++s; // skip one char, then spaces + + while( (*s) && isspace( *s ) ) + { + ++s; + } + + *p = s; +} + + +static bool followedBy( char **p, const char *pattern, skip_input skip ) +{ + char *s; + + if( p == NULL ) + { + return false; + } + + s = *p; + + do { + if( *s == *pattern ) + { + ++s; + ++pattern; + } + else + { + return false; + } + } while( *s && *pattern ); + + if( ( *pattern == char_null ) && !isalpha( *s ) ) + { + if( skip != sp_no_skip ) + { + if( isspace( *s ) ) + { + skipSpaces( &s ); + } + *p = s; + } + return true; + } + + return false; +} + + +static bool scriptNext( char *p ) +{ + return ( *p == '_' ) || ( *p == '^' ); +} + +static int getLastTagIndex( char *p, size_t length, element_type element ) +{ + int inside; // inside a tag + element_type current; + size_t i; + + if( ( p == NULL ) || (length == 0) ) + { + return -1; + } + + i = length-1; + inside = 0; + current = et_unknown; + + while( i >= 0 ) + { + if( p[i] == '>' ) + { + if( p[i-1] == '/' ) + { + current = et_tag_open; + --i; // to skip twice + } + } + else if( p[i] == '<' ) + { + if( p[i+1] == '/' ) + { + current = et_tag_off; + if( element == current ) + { + return (int) i; + } + inside++; + } + else + { + --inside; + if( inside == 0 ) + { + return (int) i; + } + } + } + if( i == 0 ) + { + break; + } + --i; + } + + return -1; +} + +static bool getInput( InputStream &input, skip_input white_space ) +{ + + ZeroMemory( &input, sizeof( input ) ); + + if( white_space == sp_skip_all ) + { + if( isspace( *pCur ) ) + { + skipSpaces( &pCur ); + } + } + + if( *pCur == char_null ) + { + input.token = token_eof; + return false; + } + + + while( *pCur ) + { + input.start = pCur; + if( isalpha( *pCur ) ) + { + input.token = token_alpha; + break; + } + else if( isdigit( *pCur ) ) + { + input.token = token_digit; + break; + } + else if( *pCur == '&' ) + { + input.token = token_column_sep; + skipChar( &pCur ); + break; + } + else if( *pCur == '{' ) + { + input.token = token_left_brace; + skipChar( &pCur ); + break; + } + else if( *pCur == '}' ) + { + input.token = token_right_brace; + skipChar( &pCur ); + break; + } + else if( *pCur == '^' ) + { + input.token = token_superscript; + skipChar( &pCur ); + break; + } + else if( *pCur == '_' ) + { + input.token = token_subscript; + skipChar( &pCur ); + break; + } + else if( isspace( *pCur ) ) + { + if( *pCur == ' ' ) + { + if( white_space == sp_skip_all ) + { + skipSpaces( &pCur ); + } + else if ( white_space == sp_skip_once ) + { + + input.token = token_white_space; + ++pCur; + break; + } + else + { + //input.token = token_white_space; + skipSpaces( &pCur ); + } + } + else // other spaces \n\r + { + skipSpaces( &pCur ); + } + } + else if( *pCur == char_backslash ) + { + ++pCur; + if( isalpha( *pCur ) ) + { + input.token = token_control_name; + for( int i = 0; i < MAX_CONTROL_NAME; ++i ) + { + input.buffer[i] = *pCur; + ++pCur; + if( !isalpha( *pCur ) ) + { + break; + } + } + // use this to determine whether control name + // is followed IMMEDIATELY by digits + // cf. \abc123 vs.\abc 123 + input.nextChar = *pCur; + if( isspace( *pCur ) ) + { + skipSpaces( &pCur ); + } + } + else + { + if( *pCur == char_backslash ) + { + input.token = token_row_sep; + } + else + { + input.token = token_control_symbol; + } + input.buffer[0] = char_backslash; + input.buffer[1] = *pCur; + skipChar( &pCur ); + input.nextChar = *pCur; + } + break; + } + else if( *pCur == ']' ) + { + input.token = token_right_sq_bracket; + input.buffer[0] = *pCur; + skipChar( &pCur ); + input.nextChar = *pCur; + break; + } + else if( *pCur == '$' ) + { + input.token = token_inline_math; + input.buffer[0] = *pCur; + //skipChar( &pCur ); don't skip + input.nextChar = *pCur; + break; + } + else if( *pCur == char_prime ) + { + input.token = token_prime; + input.buffer[0] = *pCur; + input.nextChar = pCur[1]; + // don't skip + break; + } + else // symbols + { + input.token = token_symbol; + input.buffer[0] = *pCur; + skipChar( &pCur ); + input.nextChar = *pCur; + break; + } + } + + return true; +} + +static void onPrime( Buffer &prevBuf ) +{ + SymbolStruct *sym; + char buf[5]; + + getPrime( &pCur, buf ); + + sym = getSymbol( buf ); + + prevBuf.write( sym->element ); +} + +static void getPrime( char **p, char *buf ) +{ + int i = 0; + do { + *buf = **p; + ++buf; + ++(*p); + ++i; + if( i == 3 ) + { + break; + } + } while( **p == char_prime ); + + *buf = char_null; + + if( isspace( *pCur ) ) + { + skipSpaces( &pCur ); + } +} + +static token_type getControlTypeEx( InputStream &input, ControlStruct &control ) +{ + Buffer buf; + + control.start = input.start; + input.token = getControlType( input.buffer, control ); + + if( input.token != token_unknown ) + { + return input.token; + } + + if( isdigit( input.nextChar ) ) + { + buf.write( input.buffer ); + buf.write( pCur, 1 ); // write the next digit + ++pCur; + } + else + { + return input.token; + } + + while( ( input.token = getControlType( buf.data(), control ) ) == token_unknown ) + { + if( isdigit( *pCur ) ) + { + buf.write( pCur, 1 ); + ++pCur; + } + else + { + break; + } + } + + return input.token; +} + +static void runLoop( Buffer &prevBuf, sub_expression subType, void *paramExtra ) +{ + InputStream input; + ControlStruct control; + Buffer str; + bool quitLoop; + + ZeroMemory( &control, sizeof( control ) ); + + quitLoop = false; + + while( getInput( input, sp_skip_all ) ) + { + switch( input.token ) + { + case token_alpha: + onAlpha( str ); + break; + + case token_digit: + onDigit( str ); + break; + + case token_prime: + onPrime( str ); + break; + case token_symbol: + case token_control_symbol: + onSymbol( str, input ); + break; + /* + case token_white_space: + onWhiteSpace( str ); + break; + */ + case token_inline_math: + + if( subType != se_inline_math ) + { + throw error( pCur, ex_misplaced_inline_formula ); + } + quitLoop = true; + break; + case token_left_brace: + runLoop( str, se_braced ); + break; + case token_right_brace: + quitLoop = true; + break; + case token_right_sq_bracket: + if( subType == se_optional_param ) + { + quitLoop = true; + } + else + { + onSymbol( str, input ); + } + break; + case token_superscript: + onSuperscript( str ); + break; + + case token_subscript: + onSubscript( str ); + break; + + case token_column_sep: + if( subType < se_matrix ) + { + throw error( input.start, ex_misplaced_column_separator ); + } + else + { + onColumn( str, input.start, *((ArrayStruct *)paramExtra) ); + } + break; + case token_row_sep: + if( subType < se_matrix ) + { + throw error( input.start, ex_misplaced_row_separator ); + } + else + { + onRow( str, *((ArrayStruct *)paramExtra) ); + } + break; + case token_control_name: + //onControlName( str, input, quit ); + + input.token = getControlTypeEx( input, control ); + + switch( input.token ) + { + case token_control_entity: + onEntity( str, control.entity ); + break; + case token_control_command: + quitLoop = onCommand( str, control, subType, paramExtra ); + break; + case token_control_function: + onFunction( str, control.function ); + break; + //case token_unknown: + default: + throw error( input.start, ex_undefined_control_sequence ); + } + + break; + } + + if( quitLoop ) + { + break; + } + } + + onEndExpression( subType, input.token, control.command ); + + prevBuf.append( str, true ); +} + +//se_optional_param, se_inline_math, se_fence, +// se_matrix +static void onEndExpression( sub_expression subType, token_type token, CommandStruct *command ) +{ + switch( subType ) + { + case se_optional_param: + if( token != token_right_sq_bracket ) + { + throw error( pCur, ex_missing_right_sq_bracket ); + } + break; + case se_inline_math: + if( token != token_inline_math ) + { + throw error( pCur, ex_missing_dollar_symbol ); + } + break; + case se_matrix: + if( token != token_control_command ) + { + throw error( pCur, ex_missing_end ); + } + else if( command->id != ci_end ) + { + throw error( pCur, ex_missing_end ); + } + break; + case se_fence: + if( token != token_control_command ) + { + throw error( pCur, ex_missing_right_fence ); + } + else if( command->id != ci_right ) + { + throw error( pCur, ex_missing_right_fence ); + } + } + +} + + +static void onAlpha( Buffer &prevBuf ) +{ + char tag[] = "<mi>?</mi>"; + char *p; + Buffer str; + + + str.setlength( 50 ); + + p = strchr( tag, '?' ); + + do { + *p = *pCur; + str.write( tag, sizeof( tag ) - 1 ); + ++pCur; + } + while( isalpha( *pCur ) ); + + prevBuf.append( str, true ); + +} + +static void onDigit( Buffer &prevBuf ) +{ + char tagOn[] = "<mn>"; + char tagOff[] = "</mn>"; + + Buffer str; + char *start; + + + str.setlength( 50 ); + + + str.write(tagOn, sizeof( tagOn ) - 1 ); + + + start = pCur; + + do { + ++pCur; + } + while( isdigit( *pCur ) ); + + str.write( start, (pCur - start) ); + + str.write(tagOff, sizeof( tagOff ) - 1 ); + + prevBuf.append( str, true ); + +} + +static void onSymbol( Buffer &prevBuf, InputStream &input, bool checkSubSup ) +{ + SymbolStruct *symbol; + + symbol = getSymbol( input.buffer ); + + if( symbol == NULL ) + { + throw error( pCur, ex_unknown_character ); + } + + + switch( symbol->mathType ) + { + case mt_fence: + case mt_left_fence: + case mt_right_fence: + if( checkSubSup && scriptNext( pCur ) ) + { + throw error( pCur, ex_ambiguous_script ); + } + break; + } + + prevBuf.write( symbol->element ); +} + +static bool needsMrow( const char *p ) +{ + element_type et; + short inside, count; + + if( p == NULL ) + { + return false; + } + + inside = count = 0; + et = et_unknown; + + while( *p ) + { + if( *p == '<' ) + { + if( p[1] == '/' ) + { + et = et_tag_off; + ++p; + } + else + { + et = et_tag_on; + } + } + else if( *p == '>' ) + { + if( *(p-1) == '/' ) // tag open + { + if( inside == 0 ) + { + ++count; + } + } + else if( et == et_tag_off ) + { + --inside; + } + else + { + if( inside == 0 ) + { + ++count; + } + ++inside; + } + if( count > 1 ) + { + return true; + } + } + ++p; + } + + return false; +} + +static void getCommandParam( Buffer &prevBuf, sub_expression subType ) +{ + InputStream input; + Buffer str; + ControlStruct control; + + getInput( input, sp_skip_all ); + + switch( input.token ) + { + case token_alpha: + prevBuf.format( "<mi>%c</mi>", *pCur ); + skipChar( &pCur ); + break; + + case token_digit: + prevBuf.format( "<mn>%c</mn>", *pCur ); + skipChar( &pCur ); + break; + case token_prime: + prevBuf.write( "<mo>′</mo>" ); + skipChar( &pCur ); + break; + case token_symbol: + case token_control_symbol: + onSymbol( prevBuf, input, false ); // ignore subscript/superscript + break; + + case token_left_brace: + if( subType == se_use_default ) + { + runLoop( str, se_braced ); + } + else + { + runLoop( str, subType ); + } + if( needsMrow( str.data() ) ) + { + str.insertAt( 0, "<mrow>" ); + str.write( "</mrow>" ); + } + prevBuf.append( str, true ); + break; + + case token_right_brace: + case token_superscript: + case token_subscript: + case token_column_sep: + case token_row_sep: + case token_eof: + throw error( pCur, ex_missing_parameter ); + + case token_control_name: + //onControlName( str, input, quit ); + + input.token = getControlTypeEx( input, control ); + + switch( input.token ) + { + case token_control_entity: + // don't check limits and subscript + onEntity( prevBuf, control.entity, false, false ); + break; + case token_control_command: + if( control.command->id == ci_frac ) + { + onCommand( str, control, se_use_default, NULL ); + prevBuf.append( str, true ); + } + else + { + throw error( input.start, ex_no_command_allowed ); + } + break; + case token_control_function: + onFunction( prevBuf, control.function, false ); + break; + //case token_unknown: + default: + throw error( input.start, ex_undefined_control_sequence ); + } + break; + default: + break; + } +} + +static void getSuperscript( Buffer &prevBuf, bool subsup ) +{ + if( *pCur == char_prime ) + { + throw error( pCur, ex_missing_lbrace ); + } + + getCommandParam( prevBuf, se_use_default ); + + if( ( *pCur == '^' ) || ( *pCur == char_prime ) ) + { + throw error( pCur, ex_double_superscript ); + } + else if( *pCur == '_' ) + { + if( subsup ) + { + throw error( pCur, ex_double_subscript ); + } + else + { + throw error( pCur, ex_use_subscript_before_superscript ); + } + } +} + +static void onSuperscript( Buffer &prevBuf ) +{ + Buffer str; + int index; + SymbolTable *sup; + + sup = &nolimits[1]; + + + index = getLastTagIndex( prevBuf.data(), prevBuf.length(), et_tag_on_open ); + + if( index < 0 ) + { + throw error( pCur, ex_missing_subsup_base ); + } + + str.setlength( 50 ); + + prevBuf.insertAt( index, sup->tagOn ); + + getSuperscript( str, false ); + + str.write( sup->tagOff ); + + prevBuf.append( str, true ); +} + +static void getSubscript( Buffer &prevBuf, command_id &which ) +{ + + if( *pCur == char_prime ) + { + throw error( pCur, ex_missing_lbrace ); + } + + getCommandParam( prevBuf, se_use_default ); + + if( *pCur == '^' ) + { + skipChar( &pCur ); + getSuperscript( prevBuf, true ); + + which = ci_msubsup; + } + else if( *pCur == char_prime ) + { + onPrime( prevBuf ); + which = ci_msubsup; + } + else + { + which = ci_msub; + } +} + +static void onSubscript( Buffer &prevBuf ) +{ + Buffer str; + int index; + command_id which; + SymbolTable *sub; + + index = getLastTagIndex( prevBuf.data(), prevBuf.length(), et_tag_on_open ); + + if( index < 0 ) + { + throw error( pCur, ex_missing_subsup_base ); + } + + str.setlength( 50 ); + + getSubscript( str, which ); + + if( which == ci_msub ) + { + sub = &nolimits[0]; + } + else + { + sub = &nolimits[2]; + } + + prevBuf.insertAt( index, sub->tagOn ); + str.write( sub->tagOff ); + + prevBuf.append( str, true ); +} + + + +enum limits_type { lt_default, lt_subsup, lt_underover }; + +static void onLimits( Buffer &prevBuf, math_type mathType ) +{ + limits_type useLimits; + + useLimits = lt_default; + + do { + if( followedBy( &pCur, "\\limits", sp_skip_all ) ) + { + useLimits = lt_underover; + } + else if( followedBy( &pCur, "\\nolimits", sp_skip_all ) ) + { + useLimits = lt_subsup; + } + else + { + break; + } + } while( 1 ); + + if( *pCur == char_null ) + { + return; + } + else if( scriptNext( pCur ) || *pCur == char_prime ) + { + Buffer str; + command_id which; + //char *nextChar; + int index; + SymbolTable *lim; + + index = getLastTagIndex( prevBuf.data(), prevBuf.length(), et_tag_on_open ); + + if( index < 0 ) + { + index = 0; + } + + + if( *pCur == '_' ) + { + skipChar( &pCur ); + getSubscript( str, which ); + } + else if( *pCur == '^' ) + { + skipChar( &pCur ); + getSuperscript( str, false ); + which = ci_msup; + } + else // prime///// + { + onPrime( str ); + which = ci_msup; + + if( *pCur == '^' || *pCur == char_prime ) + { + throw error( pCur, ex_double_superscript ); + } + else if( *pCur == '_' ) + { + throw error( pCur, ex_use_subscript_before_superscript ); + } + } + + if( useLimits == lt_underover ) + { + lim = limits; + } + else if( useLimits == lt_subsup ) + { + lim = nolimits; + } + else + { + if( mathType == mt_limits ) + { + lim = nolimits; + } + else + { + lim = limitsMovable; + } + } + + switch( which ) + { + case ci_msub: + prevBuf.insertAt( index, lim[0].tagOn ); + str.write( lim[0].tagOff ); + break; + case ci_msup: + prevBuf.insertAt( index, lim[1].tagOn ); + str.write( lim[1].tagOff ); + break; + case ci_msubsup: + prevBuf.insertAt( index, lim[2].tagOn ); + str.write( lim[2].tagOff ); + break; + } + prevBuf.append( str, true ); + } +} + +static void onEntity( Buffer &prevBuf, EntityStruct *entity, bool checkLimits, bool checkSubSup ) +{ + + switch( entity->mathType ) + { + case mt_ident: + prevBuf.format( "<mi>&#x%x;</mi>", entity->code ); + break; + case mt_digit: + prevBuf.format( "<mn>&#x%x;</mn>", entity->code ); + break; + case mt_ord: + case mt_punct: + prevBuf.format( "<mo>&#x%x;</mo>", entity->code ); + break; + case mt_limits: + case mt_mov_limits: + + prevBuf.format( "<mo>&#x%x;</mo>", entity->code ); + + if( checkLimits ) + { + onLimits( prevBuf, entity->mathType ); + } + break; + case mt_left_fence: + case mt_right_fence: + case mt_fence: + if( checkSubSup && scriptNext( pCur ) ) + { + throw error( pCur, ex_ambiguous_script ); + } + prevBuf.format( "<mo mathsize='1'>&#x%x;</mo>", entity->code ); + break; + case mt_text: + prevBuf.format( "<mtext>&#x%x;</mtext>", entity->code ); + break; + case mt_rel: + case mt_bin: + case mt_unary: + case mt_bin_unary: + prevBuf.format( "<mo>&#x%x;</mo>", entity->code ); + break; + default: + throw error( pCur, ex_unhandled_mathtype ); + } +} + +static void onFunction( Buffer &prevBuf, FunctionStruct *function, bool checkLimits ) +{ + prevBuf.format( "<mi>%s</mi>", function->output ); + + if( ( function->mathType == mt_func_limits ) && checkLimits ) + { + onLimits( prevBuf, function->mathType ); + } +} +/* +enum param_type { pt_unknown, pt_none, pt_one, pt_two, pt_three, pt_table, pt_others, + pt_especial }; +*/ + +static void onSqrt( Buffer &prevBuf, const char *tagOn, const char *tagOff ) +{ + + if( *pCur == char_prime ) + { + throw error( pCur, ex_missing_lbrace ); + } + else if( *pCur == '[' ) + { + Buffer str, radix; + + skipChar( &pCur ); + runLoop( radix, se_optional_param ); + if( radix.length() != 0 ) + { + str.write( "<mroot>" ); + getCommandParam( str, se_use_default ); + if( needsMrow( radix.data() ) ) + { + radix.insertAt( 0, "<mrow>" ); + radix.write( "</mrow>" ); + } + str.append( radix, true ); + str.write( "</mroot>" ); + } + else + { + prevBuf.write( tagOn ); + getCommandParam( str, se_use_default ); + str.write( tagOff ); + } + + prevBuf.append( str, true ); + } + else + { + prevBuf.write( tagOn ); + getCommandParam( prevBuf, se_use_default ); + prevBuf.write( tagOff ); + } +} + +static void getAttribute( Buffer &prevBuf, char lastChar ) +{ + char *start, *end; + + start = pCur; + + while( *pCur && ( *pCur != lastChar ) ) + { + ++pCur; + } + + if( *pCur != lastChar ) + { + throw error( pCur, ex_missing_end_tag ); + } + + end = pCur - 1; + + + while( isspace( *end ) ) + { + --end; + } + + if( *end == char_backslash ) + { + end += 2; + } + else + { + end++; + } + + prevBuf.write( start, (end - start ) ); + + skipChar( &pCur ); + +} + +static void onMiMnMo( Buffer &prevBuf, const char *tagOn, const char *tagOff ) +{ + Buffer str; + const char* attrib; + char *start; + + if( *pCur == '[' ) + { + start = pCur+1; + skipChar( &pCur ); + getAttribute( str, ']' ); + + attrib = getMathVariant( str.data() ); + + if( attrib == NULL ) + { + throw error( start, ex_unknown_attribute ); + } + + str.destroy(); + str.write( tagOn, strlen(tagOn) - 1 ); // don't include '>' + str.format( " mathvariant='%s'>", attrib ); + } + else + { + str.write( tagOn ); + } + onMathFont( prevBuf, str.data(), tagOff ); + //prevBuf.write( tagOff ); +} + + +static EnvironmentStruct *getEnvironmentType() +{ + Buffer str; + char *curPos; + EnvironmentStruct *environment; + + if( *pCur != '{' ) + { + throw error( pCur, ex_missing_lbrace ); + } + + skipChar( &pCur); + + curPos = pCur; + + getAttribute( str, '}' ); + + environment = getEnvironmentType( str.data() ); + + if( environment != NULL ) + { + return environment; + } + else + { + throw error( curPos, ex_undefined_environment_type ); + } +} + +static void getColumnAlignment( Buffer &align, short &maxColumn, const char *tagOn ) +{ + char *curPos, *p, *attrib; + Buffer str; + + if( *pCur != '{' ) + { + throw error( pCur, ex_missing_lbrace ); + } + + skipChar( &pCur ); + + curPos = pCur; + + getAttribute( str, '}' ); + + if( str.length() == 0 ) + { + throw error( pCur, ex_missing_column_alignment ); + } + + p = str.data(); + + maxColumn = 0; + + attrib = (char *)strchr( tagOn, '>' ); + + align.write( tagOn, size_t( attrib - tagOn ) ); + + align.write( " columnalign='" ); + + while( *p ) + { + switch( *p ) + { + case 'l': + align.write( "left" ); + break; + case 'c': + align.write( "center" ); + break; + case 'r': + align.write( "right" ); + break; + default: + if( isspace( *p ) ) + { + ++p; + continue; + } + throw error( curPos, ex_unknown_alignment_character ); + } + + ++maxColumn; + ++p; + if( *p ) + { + align.write( " " ); + } + } + align.format( "'%s", attrib ); +} + +static void onBeginEnvironment( Buffer &prevBuf ) +{ + ArrayStruct ar; + Buffer str, align; + EnvironmentStruct *environment; + + environment = getEnvironmentType(); + + ar.id = environment->id; + ar.columnCount = 1; + ar.maxColumn = 5000; // arbitrary + + + + switch( environment->id ) + { + case ci_array: + getColumnAlignment( align, ar.maxColumn, environment->tagOn ); + prevBuf.append( align, true ); + runLoop( str, se_matrix, &ar ); + break; + case ci_eqnarray: + ar.maxColumn = 3; + // fall through + default: + prevBuf.write( environment->tagOn ); + runLoop( str, se_matrix, &ar ); + break; + } + str.write( environment->tagOff ); + prevBuf.append( str, true ); +} + +static bool onEndEnvironment( sub_expression subType, void *paramExtra ) +{ + command_id id; + char *temp; + EnvironmentStruct *environment; + + temp = pCur; + if( subType == se_matrix ) + { + id = ((ArrayStruct *)paramExtra)->id; + } + else + { + throw error( temp, ex_missing_begin ); + } + + environment = getEnvironmentType(); + + if( environment->id != id ) + { + throw error( temp, ex_mismatched_environment_type ); + } + return true; +} + +static void onColumn( Buffer &prevBuf, const char *pos, ArrayStruct &ar ) +{ + ++ar.columnCount; + + if( ar.columnCount > ar.maxColumn ) + { + throw error( pos, ex_too_many_columns ); + } + + prevBuf.write( "</mtd><mtd>" ); +} + +static void onRow( Buffer &prevBuf, ArrayStruct &ar ) +{ + if( (*pCur == char_backslash ) && (pCur[1] == 'e' ) ) // \end? + { + if( followedBy( &pCur, "\\end", sp_no_skip ) ) + { + return; // do nothing + } + } + + prevBuf.write( "</mtd></mtr><mtr><mtd>" ); + ar.columnCount = 1; // reset columns +} + + +static void onHfill( Buffer &prevBuf, sub_expression subType, void *paramExtra ) +{ + if( scriptNext( pCur ) ) + { + if( *pCur == '^' ) + { + throw error( pCur, ex_prefix_superscript ); + } + else + { + throw error( pCur, ex_prefix_subscript ); + } + } + if( subType < se_matrix ) // not in a table + { + return; + } +} + +static void onArrows( Buffer &prevBuf, const char *tagOn, const char *tagOff ) +{ + Buffer str; + + //tagOn is the base + if( *pCur == '[' ) + { + Buffer underscript; + + skipChar( &pCur ); + runLoop( underscript, se_optional_param ); + if( underscript.length() != 0 ) + { + if( needsMrow( underscript.data() ) ) + { + underscript.insertAt( 0, "<mrow>" ); + underscript.write( "</mrow>" ); + } + str.format( "<munderover>%s", tagOn ); + + str.append( underscript, true ); + + getCommandParam( str, se_use_default ); + + str.write( "</munderover>" ); + prevBuf.append( str, true ); + return; + } + } + + // fall through + //prevBuf.write( tagOn ); + str.format( "<mover>%s", tagOn ); + getCommandParam( str, se_use_default ); + str.write( tagOff ); + prevBuf.append( str, true ); +} + +static void onCfrac( Buffer &prevBuf, const char *tagOn, const char *tagOff ) +{ + Buffer str; + const char *extra = "<mstyle displaystyle='true' scriptlevel='0'>"; + + str.format( "%s%s", tagOn, extra ); + getCommandParam( str, se_use_default ); + str.format( "</mstyle>%s", extra ); + getCommandParam( str, se_use_default ); + str.write( tagOff ); + prevBuf.append( str, true ); +} + + +static bool onCommand( Buffer &prevBuf, ControlStruct &control, sub_expression subType, void *paramExtra ) +{ + Buffer str, str2; + CommandStruct *command; + + command = control.command; + + switch( command->param ) + { + case pt_plain: + switch( command->id ) + { + case ci_mn: + case ci_mo: + onMiMnMo( prevBuf, command->tagOn, command->tagOff ); + break; + case ci_mathop: + onMathFont( str, command->tagOn, command->tagOff ); + //str.write( command->tagOff ); + onLimits(str, mt_limits ); + prevBuf.append( str, true ); + break; + /* + case ci_mathrm: + case ci_mathit: + case ci_mathbf: + case ci_mathbi: + + case ci_mathord, + case ci_func: + */ + case ci_mathfont: + case ci_mathord: + case ci_mathbin: + case ci_mathrel: + //str.write( command->tagOn ); + onMathFont( str, command->tagOn, command->tagOff ); + //str.write( command->tagOff ); + prevBuf.append( str, true ); + } + break; + case pt_especial: + switch( command->id ) + { + //case ci_mi: + + case ci_sqrt: + onSqrt( prevBuf, command->tagOn, command->tagOff ); + break; + case ci_begin: + onBeginEnvironment( prevBuf ); + break; + case ci_end: + return onEndEnvironment( subType, paramExtra ); + case ci_stackrel: + str.write( command->tagOn ); + getCommandParam( str2, se_use_default ); + getCommandParam( str, se_use_default ); + str.append( str2, true ); + str.write( command->tagOff ); + prevBuf.append( str, true ); + break; + case ci_hfill: + onHfill( prevBuf, subType, paramExtra ); + break; + case ci_strut: + prevBuf.write( command->tagOn ); + break; + case ci_limits: + case ci_nolimits: + throw error( control.start, ex_misplaced_limits ); + case ci_mathstring: + onTextFont( prevBuf, command->tagOn, command->tagOff, command->id, false ); + break; + case ci_text: + onTextFont( prevBuf, command->tagOn, command->tagOff, command->id ); + break; + case ci_eqno: + case ci_leqno: + if( subType != se_use_default ) + { + throw error( pCur, ex_misplaced_eqno ); + } + else if ( isNumberedFormula ) + { + throw error( pCur, ex_duplicate_eqno ); + } + isNumberedFormula = true; + onTextFont( eqNumber, command->tagOn, command->tagOff, ci_eqno, false ); + break; + case ci_left: + case ci_right: + return onFence( prevBuf, command->id, subType, command->tagOn, command->tagOff ); + case ci_ext_arrows: + onArrows( prevBuf, command->tagOn, command->tagOff ); + break; + case ci_cfrac: + onCfrac( prevBuf, command->tagOn, command->tagOff ); + break; + case ci_underoverbrace: + str.write( command->tagOn ); + getCommandParam( str, se_use_default ); + str.write( command->tagOff ); + onLimits( str, mt_mov_limits ); + prevBuf.append( str, true ); + break; + case ci_lsub: + str.write( command->tagOn ); + getCommandParam( str, se_use_default ); + str.write( "<mprescripts/>" ); + getCommandParam( str, se_use_default ); + str.write( "<none/>" ); + str.write( command->tagOff ); + prevBuf.append( str, true ); + break; + case ci_lsup: + str.write( command->tagOn ); + getCommandParam( str, se_use_default ); + str.write( "<mprescripts/><none/>" ); + getCommandParam( str, se_use_default ); + str.write( command->tagOff ); + prevBuf.append( str, true ); + break; + case ci_lsubsup: + str.write( command->tagOn ); + getCommandParam( str, se_use_default ); + str.write( "<mprescripts/>" ); + getCommandParam( str, se_use_default ); + getCommandParam( str, se_use_default ); + str.write( command->tagOff ); + prevBuf.append( str, true ); + break; + default: + break; + } + break; + + case pt_one: + prevBuf.write( command->tagOn ); + getCommandParam( prevBuf, se_use_default ); + prevBuf.write( command->tagOff ); + break; + + case pt_two: + prevBuf.write( command->tagOn ); + getCommandParam( prevBuf, se_use_default ); + getCommandParam( prevBuf, se_use_default ); + prevBuf.write( command->tagOff ); + break; + + case pt_three: + break; + + case pt_table: + break; + + case pt_none: + break; + + case pt_others: + default: + break; + } + + return false; +} + +static void onMathFont( Buffer &prevBuf, const char *tagOn, const char *tagOff ) +{ + InputStream input; + ControlStruct control; + SymbolStruct *symbol; + Buffer str; + int brace; + bool quitLoop; + + brace = 0; + + if( *pCur == '{' ) + { + quitLoop = false; // loop + } + else + { + quitLoop = true; // read only one char + } + + + while( getInput( input, sp_skip_all ) ) + { + switch( input.token ) + { + case token_alpha: + case token_digit: + str.write( pCur, 1 ); + ++pCur; + break; + case token_prime: + { + SymbolStruct *sym; + char buf[5]; + + getPrime( &pCur, buf ); + + sym = getSymbol( buf ); + str.write( sym->literal ); + } + break; + case token_symbol: + case token_control_symbol: + case token_right_sq_bracket: + symbol = getSymbol( input.buffer ); + str.write( symbol->literal ); + break; + + case token_white_space: + str.write( " " ); + if( isspace( *pCur ) ) + { + skipSpaces( &pCur ); + } + break; + case token_left_brace: + ++brace; + break; + case token_right_brace: + --brace; + if( brace < 0 ) + { + throw error( input.start, ex_missing_parameter ); + } + quitLoop = true; + break; + case token_inline_math: + throw error( input.start, ex_misplaced_inline_formula ); + + case token_superscript: + case token_subscript: + throw error( input.start, ex_no_command_allowed ); + case token_column_sep: + throw error( input.start, ex_misplaced_column_separator ); + case token_row_sep: + throw error( input.start, ex_misplaced_row_separator ); + + case token_control_name: + + switch( getControlTypeEx( input, control ) ) + { + case token_control_entity: + str.format( "&#x%x;", control.entity->code ); + break; + case token_control_function: + str.write( control.function->output ); + break; + case token_control_command: + throw error( input.start, ex_no_command_allowed ); + break; + //case token_unknown: + default: + throw error( input.start, ex_undefined_control_sequence ); + } + break; + default: + break; + } + if( quitLoop ) + { + break; + } + } + + prevBuf.write( tagOn ); + str.write( tagOff ); + prevBuf.append( str, true ); +} + + +static void onTextFont( Buffer &prevBuf, const char *tagOn, const char *tagOff, command_id id, bool allowInline ) +{ + InputStream input; + ControlStruct control; + SymbolStruct *symbol; + Buffer str, temp; + int brace; + bool quitLoop; + + brace = 0; + + if( ( id != ci_eqno ) && ( id != ci_leqno ) ) + { + if( *pCur != '{' ) + { + throw error( pCur, ex_missing_lbrace ); + } + } + + quitLoop = false; + + while( getInput( input, sp_skip_once ) ) + { + switch( input.token ) + { + case token_alpha: + case token_digit: + str.write( pCur, 1 ); + ++pCur; + break; + + case token_symbol: + case token_control_symbol: + case token_right_sq_bracket: + symbol = getSymbol( input.buffer ); + str.write( symbol->literal ); + break; + case token_prime: + if( pCur[1] == char_prime ) + { + str.write( "”" ); + pCur += 2; + } + else + { + str.write( "’" ); + ++pCur; + } + break; + case token_inline_math: + if( !allowInline ) + { + throw error( input.start, ex_misplaced_inline_formula ); + } + if( str.length() > 0 ) + { + temp.write( tagOn ); + str.write( tagOff ); + temp.append( str, true ); + str.reset(); + } + + skipChar( &pCur ); + runLoop( str, se_inline_math, NULL ); + // skip end $ + ++pCur; + + if( needsMrow( str.data() ) ) + { + str.insertAt( 0, "<mrow>" ); + str.write( "</mrow>" ); + } + temp.append( str, true ); + str.reset(); + break; + + case token_white_space: + str.write( " " ); + if( isspace( *pCur ) ) + { + skipSpaces( &pCur ); + } + break; + case token_left_brace: + ++brace; + break; + case token_right_brace: + --brace; + if( brace < 0 ) + { + throw error( input.start, ex_missing_parameter ); + } + quitLoop = true; + break; + case token_superscript: + case token_subscript: + throw error( input.start, ex_no_command_allowed ); + case token_column_sep: + throw error( input.start, ex_misplaced_column_separator ); + case token_row_sep: + throw error( input.start, ex_misplaced_row_separator ); + + case token_control_name: + + switch( getControlTypeEx( input, control ) ) + { + case token_control_entity: + str.format( "&#x%x;", control.entity->code ); + break; + case token_control_function: + throw error( input.start, ex_not_math_mode ); + case token_control_command: + throw error( input.start, ex_no_command_allowed ); + //case token_unknown: + default: + throw error( input.start, ex_undefined_control_sequence ); + } + break; + default: + break; + } + if( quitLoop ) + { + break; + } + } + + + if( str.length() ) + { + temp.write( tagOn ); + str.write( tagOff ); + } + temp.append( str, true ); + + if( needsMrow( temp.data() ) ) + { + temp.insertAt( 0, "<mrow>" ); + temp.write( "</mrow>" ); + } + prevBuf.append( temp, true ); +} + +static void getFence( Buffer &prevBuf, const char *tagOn, command_id id ) +{ + InputStream input; + FenceStruct fence; + size_t len; + + + len = strlen( tagOn ); + + getInput( input, sp_skip_all ); + + switch( input.token ) + { + case token_control_symbol: + case token_symbol: + case token_control_name: + if( !getFenceType( input.buffer, fence ) ) + { + throw error( input.start, ex_missing_fence_parameter ); + } + + if ( id == ci_left ) + { + if( *input.start == '(' ) + { + prevBuf.write( tagOn, len ); + } + else + { + prevBuf.write( tagOn, len - 1 ); // don't write > + prevBuf.format( " left='%s'", fence.output ); + } + } + else + { + if( *input.start == ')' ) + { + prevBuf.write( "><mrow>" ); + } + else + { + prevBuf.format( " right='%s'><mrow>", fence.output ); + } + } + break; + default: + throw error( input.start, ex_missing_fence_parameter ); + } +} + +static bool onFence( Buffer &prevBuf, command_id id, sub_expression subType, const char *tagOn, const char *tagOff ) +{ + Buffer str, fence; + + if( id == ci_right ) + { + if( subType == se_fence ) + { + return true; + } + throw error( pCur, ex_missing_left_fence ); + } + + getFence( fence, tagOn, ci_left ); + runLoop( str, se_fence, NULL ); + getFence( fence, tagOn, ci_right ); + + str.write( tagOff ); + prevBuf.append( fence, true ); + prevBuf.append( str, true ); + return false; +} + diff --git a/support/ltx2mathml/src/ltx2mathmltables.cpp b/support/ltx2mathml/src/ltx2mathmltables.cpp new file mode 100644 index 0000000000..b41016ad08 --- /dev/null +++ b/support/ltx2mathml/src/ltx2mathmltables.cpp @@ -0,0 +1,672 @@ +#include "ltx2mathmltables.h" +#include <stdio.h> + +static CommandStruct commandTable[] = { +{"Overleftarrow", ci_accent,pt_one, "<mover accent='true'>", "<mo stretchy='true'>⇐</mo></mover>" }, +{"Overleftrightarrow", ci_accent,pt_one, "<mover accent='true'>", "<mo stretchy='true'>⇔</mo></mover>" }, +{"Overrightarrow", ci_accent,pt_one, "<mover accent='true'>", "<mo stretchy='true'>⇒</mo></mover>" }, +{"actuarial", ci_menclose, pt_one,"<menclose notation='actuarial'>", "</menclose>" }, +{"acute", ci_accent,pt_one, "<mover accent='true'>", "<mo>´</mo></mover>" }, +{"bar", ci_accent,pt_one, "<mover accent='true'>", "<mo stretchy='false'>¯</mo></mover>" }, +{"begin", ci_begin,pt_especial,"", "" }, +{"binom", ci_binom,pt_two, "<mfenced><mrow><mfrac linethickness='0'>","</mfrac></mrow></mfenced>" }, +{"breve", ci_accent,pt_one, "<mover accent='true'>", "<mo>˘</mo></mover>" }, +{"cfrac", ci_cfrac,pt_especial, "<mfrac>", "</mstyle></mfrac>" }, +{"check", ci_accent,pt_one, "<mover accent='true'>", "<mo>ˇ</mo></mover>" }, +{"ddddot", ci_accent,pt_one, "<mover accent='true'>", "<mo>¨¨</mo></mover>" }, +{"dddot", ci_accent, pt_one, "<mover accent='true'>", "<mo>⃛</mo></mover>" }, +{"ddot", ci_accent, pt_one, "<mover accent='true'>", "<mo>¨</mo></mover>" }, +{"dfrac", ci_mfrac, pt_two, "<mstyle displaystyle='true' scriptlevel='0'><mfrac>", "</mfrac></mstyle>" }, +{"dot", ci_accent, pt_one, "<mover accent='true'>", "<mo>˙</mo></mover>" }, +{"end", ci_end, pt_especial, "","" }, +{"eqno", ci_eqno, pt_especial, "<mtable><mlabeledtr><mtd><mtext>", "</mtext></mtd><mtd>" }, +{"frac", ci_frac, pt_two, "<mfrac>", "</mfrac>" }, +{"func", ci_func, pt_plain, "<mi>", "</mi>" }, +{"grave", ci_accent, pt_one, "<mover accent='true'>", "<mo>̀</mo></mover>" }, +{"hat", ci_accent, pt_one, "<mover accent='true'>", "<mo>ˆ</mo></mover>" }, +{"hfill", ci_hfill, pt_especial, "","" }, +{"hphantom", ci_phantom, pt_one, "<mphantom><mpadded height='0%' depth='0'>", "</mpadded></mphantom>" }, +{"hungarumlaut", ci_accent, pt_one, "<mover accent='true'>", "<mo>˝</mo></mover>" }, +{"left", ci_left, pt_especial, "<mfenced>", "</mrow></mfenced>" }, +{"leqno", ci_eqno, pt_especial, "<mtable side='left'><mlabeledtr><mtd><mtext>", "</mtext></mtd><mtd>" }, +{"limits", ci_limits, pt_especial, "","" }, +{"longdiv", ci_menclose, pt_one, "<menclose notation='longdiv'>", "</menclose>" }, +{"lsub", ci_lsub, pt_especial, "<mmultiscripts>", "</mmultiscripts>" }, +{"lsubsup", ci_lsubsup, pt_especial, "<mmultiscripts>", "</mmultiscripts>" }, +{"lsup", ci_lsup, pt_especial, "<mmultiscripts>", "</mmultiscripts>" }, +{"mathbb", ci_mathfont, pt_plain, "<mi mathvariant='double-struck'>", "</mi>" }, +{"mathbf", ci_mathfont, pt_plain, "<mi mathvariant='bold'>", "</mi>" }, +{"mathbfrak", ci_mathfont, pt_plain, "<mi mathvariant='bold-fraktur'>", "</mi>" }, +{"mathbi", ci_mathfont, pt_plain, "<mi mathvariant='bold-italic'>", "</mi>" }, +{"mathbin", ci_mathbin, pt_plain, "<mo lspace='.222222em' rspace='.222222em'>", "</mo>" }, +{"mathbsc", ci_mathfont, pt_plain, "<mi mathvariant='bold-script'>", "</mi>" }, +{"mathbss", ci_mathfont, pt_plain, "<mi mathvariant='bold-sans-serif'>", "</mi>" }, +{"mathfrak", ci_mathfont, pt_plain, "<mi mathvariant='fraktur'>", "</mi>" }, +{"mathit", ci_mathfont, pt_plain, "<mi mathvariant='italic'>", "</mi>" }, +{"mathop", ci_mathop, pt_plain, "<mo>", "</mo>" }, +{"mathord", ci_mathord, pt_plain, "<mo lspace='0' rspace='0'>", "</mo>" }, +{"mathord", ci_mathord, pt_plain, "<mo lspace='0' rspace='0'>", "</mo>"}, +{"mathrel", ci_mathrel, pt_plain, "<mo lspace='.27777em' rspace='.27777em'>", "</mo>" }, +{"mathring", ci_accent, pt_one, "<mover accent='true'>", "<mo>˚</mo></mover>" }, +{"mathrm", ci_mathfont, pt_plain, "<mi mathvariant='normal'>", "</mi>" }, +{"mathsc", ci_mathfont, pt_plain, "<mi mathvariant='script'>", "</mi>" }, +{"mathss", ci_mathfont, pt_plain, "<mi mathvariant='sans-serif'>", "</mi>" }, +{"mathssbi", ci_mathfont, pt_plain, "<mi mathvariant='sans-serif-bold-italic'>", "</mi>" }, +{"mathssi", ci_mathfont, pt_plain, "<mi mathvariant='sans-serif-italic'>", "</mi>" }, +{"mathstrut", ci_strut, pt_especial, "<mphantom><mpadded width='0%' lspace='0'><mo>(</mo></mpadded></mphantom>","" }, +{"mathtt", ci_mathfont, pt_plain, "<mi mathvariant='monospace'>", "</mi>" }, +{"mn", ci_mn, pt_plain, "<mn>", "</mn>" }, +{"mo", ci_mo, pt_plain, "<mo>", "</mo>" }, +{"ms", ci_mathstring, pt_especial, "<ms>", "</ms>" }, +{"nolimits", ci_limits, pt_especial, "","" }, +{"overbrace", ci_underoverbrace, pt_especial, "<mover accent='false'>", "<mo stretchy='true'>︷</mo></mover>" }, +{"overbrack", ci_accent, pt_one, "<mover accent='false'>", "<mo stretchy='true'>⎴</mo></mover>" }, +{"overleftarrow", ci_accent, pt_one, "<mover accent='true'>", "<mo stretchy='true'>←</mo></mover>" }, +{"overleftrightarrow", ci_accent, pt_one, "<mover accent='true'>", "<mo stretchy='true'>↔</mo></mover>" }, +{"overline", ci_accent, pt_one, "<mover accent='false'>", "<mo stretchy='true'>¯</mo></mover>" }, +{"overparen", ci_accent, pt_one, "<mover accent='false'>", "<mo stretchy='true'>⌢</mo></mover>" }, +{"overrightarrow", ci_accent, pt_one, "<mover accent='true'>", "<mo stretchy='true'>→</mo></mover>" }, +{"phantom", ci_phantom, pt_one, "<mphantom>", "</mphantom>" }, +{"qdot", ci_accent, pt_one, "<mover accent='true'>", "<mo>¨¨</mo></mover>" }, +{"right", ci_right, pt_especial, "","" }, +{"sqrt", ci_sqrt, pt_especial, "<msqrt>", "</msqrt>" }, +{"stack", ci_stack, pt_two, "<mfrac linethickness='0'>", "</mfrac>" }, +{"stackrel", ci_stackrel, pt_especial, "<mover>", "</mover>" }, +{"strut", ci_strut, pt_especial, "<mspace width='0pt' height='8.5pt' depth='3.5pt'/>","" }, +{"tbinom", ci_binom, pt_two, "<mstyle scriptlevel='1'><mfenced><mrow><mfrac linethickness='0'>", "</mfrac></mrow></mfenced></mstyle>" }, +{"tdot", ci_accent, pt_one, "<mover accent='true'>", "<mo>⃛</mo></mover>" }, +{"text", ci_text, pt_especial, "<mtext>", "</mtext>" }, +{"textbf", ci_text, pt_especial, "<mtext mathvariant='bold'>", "</mtext>" }, +{"textbi", ci_text, pt_especial, "<mtext mathvariant='bold-italic'>", "</mtext>" }, +{"textbsf", ci_text, pt_especial, "<mtext mathvariant='bold-sans-serif'>", "</mtext>" }, +{"textit", ci_text, pt_especial, "<mtext mathvariant='italic'>", "</mtext>" }, +{"textsf", ci_text, pt_especial, "<mtext mathvariant='sans-serif'>", "</mtext>" }, +{"textsfbi", ci_text, pt_especial, "<mtext mathvariant='sans-serif-bold-italic'>", "</mtext>" }, +{"textsfit", ci_text, pt_especial, "<mtext mathvariant='sans-serif-italic'>", "</mtext>" }, +{"texttt", ci_text, pt_especial, "<mtext mathvariant='monospace'>", "</mtext>" }, +{"tfrac", ci_mfrac, pt_two, "<mstyle displaystyle='false' scriptlevel='0'><mfrac>", "</mfrac></mstyle>" }, +{"tilde", ci_accent, pt_one, "<mover accent='true'>", "<mo stretchy='false'>˜</mo></mover>" }, +{"underbrace", ci_underoverbrace, pt_especial, "<munder accentunder='false'>", "<mo stretchy='true'>︸</mo></munder>" }, +{"underbrack", ci_accent, pt_one, "<munder accentunder='false'>", "<mo stretchy='true'>⎵</mo></munder>" }, +{"underleftarrow", ci_accent, pt_one, "<munder accentunder='true'>", "<mo stretchy='true'>←</mo></munder>" }, +{"underleftrightarrow", ci_accent, pt_one, "<munder accentunder='true'>", "<mo stretchy='true'>↔</mo></munder>" }, +{"underline", ci_accent, pt_one, "<munder accentunder='false'>", "<mo stretchy='true'>̲</mo></munder>" }, +{"underparen", ci_accent, pt_one, "<munder accentunder='false'>", "<mo stretchy='true'></mo></munder>" }, +{"underrightarrow", ci_accent, pt_one, "<munder accentunder='true'>", "<mo stretchy='true'>→</mo></munder>" }, +{"undertilde", ci_accent, pt_one, "<munder accentunder='false'>", "<mo stretchy='true'>˜</mo></munder>" }, +{"vec", ci_accent, pt_one, "<mover accent='true'>", "<mo stretchy='false'>→</mo></mover>" }, +{"vphantom", ci_phantom, pt_one, "<mphantom><mpadded width='0%' lspace='0'>", "</mpadded></mphantom>" }, +{"widehat", ci_accent, pt_one, "<mover accent='true'>", "<mo stretchy='true'>̂</mo></mover>" }, +{"widetilde", ci_accent, pt_one, "<mover accent='true'>", "<mo stretchy='true'>˜</mo></mover>" }, +{"widevec", ci_accent, pt_one, "<mover accent='true'>", "<mo stretchy='true'>→</mo></mover>" }, +{"xleftarrow", ci_ext_arrows, pt_especial, "<mo stretchy='true'>←</mo>", "</mover>" }, +{"xleftrightarrow", ci_ext_arrows, pt_especial, "<mo stretchy='true'>↔</mo>", "</mover>"}, +{"xrightarrow", ci_ext_arrows, pt_especial, "<mo stretchy='true'>→</mo>", "</mover>" } +}; + +struct EnvironmentStruct environmentTable[] = { + { "array", ci_array, "<mtable><mtr><mtd>", "</mtd></mtr></mtable>" }, + { "bmatrix", ci_bmatrix, "<mfenced open='[' close=']' separators=''><mtable><mtr><mtd>", "</mtd></mtr></mtable></mfenced>" }, + { "cases", ci_cases, "<mfenced open='{' close='' separators=''><mtable><mtr><mtd>", "</mtd></mtr></mtable></mfenced>" }, + { "eqnarray", ci_eqnarray, "<mtable columnalign='right center left' columnspacing='.222222em'><mtr><mtd>", "</mtd></mtr></mtable>" }, + { "matrix", ci_matrix, "<mtable><mtr><mtd>", "</mtd></mtr></mtable>" }, + { "pmatrix", ci_pmatrix, "<mfenced separators=''><mtable><mtr><mtd>", "</mtd></mtr></mtable></mfenced>" }, + { "vmatrix", ci_vmatrix, "<mfenced open='|' close='|' separators=''><mtable><mtr><mtd>", "</mtd></mtr></mtable></mfenced>" }, + { "Bmatrix", ci_Bmatrix, "<mfenced open='{' close='}' separators=''><mtable><mtr><mtd>", "</mtd></mtr></mtable></mfenced>" }, + { "Vmatrix", ci_Vmatrix, "<mfenced open='‖' close='‖' separators=''><mtable><mtr><mtd>", "</mtd></mtr></mtable></mfenced>" } + +}; + +static FunctionStruct functionTable[] = { + { "Pr", "Pr", mt_func_limits}, + { "arccos", "arccos", mt_func}, + { "arcsin", "arcsin", mt_func}, + { "arctan", "arctan", mt_func}, + { "arg", "arg", mt_func}, + { "cos", "cos", mt_func}, + { "cosh", "cosh", mt_func}, + { "cot", "cot", mt_func}, + { "coth", "coth", mt_func}, + { "csc", "csc", mt_func}, + { "deg", "deg", mt_func}, + { "det", "det", mt_func_limits}, + { "dim", "dim", mt_func}, + { "exp", "exp", mt_func}, + { "gcd", "gcd", mt_func_limits}, + { "hom", "hom", mt_func}, + { "inf", "inf", mt_func_limits}, + { "ker", "ker", mt_func}, + { "lg", "lg", mt_func}, + { "lim", "lim", mt_func_limits}, + { "liminf", "lim sup", mt_func_limits}, + { "limsup", "lim sup", mt_func_limits}, + { "ln", "ln", mt_func}, + { "log", "log", mt_func}, + { "max", "max", mt_func_limits}, + { "min", "min", mt_func_limits}, + { "sec", "sec", mt_func}, + { "sin", "sin", mt_func}, + { "sinh", "sinh", mt_func}, + { "sup", "sup", mt_func_limits}, + { "tan", "tan", mt_func}, + { "tanh", "tanh", mt_func} +}; + + +static EntityStruct entityTable[] = { + +{ "Delta", 0x394, mt_ident }, +{ "Gamma", 0x393, mt_ident }, +{ "Lambda", 0x39B, mt_ident }, +{ "Omega", 0x3A9, mt_ident }, +{ "Phi", 0x3A6, mt_ident }, +{ "Psi", 0x3A8, mt_ident }, +{ "Sigma", 0x3A3, mt_ident }, +{ "Xi", 0x39E, mt_ident }, +{ "alpha", 0x3B1, mt_ident }, +{ "ast", 0x2A, mt_bin }, +{ "beta", 0x3B2, mt_ident }, +{ "bigcap", 0x22C2, mt_mov_limits }, + +{ "bigcup", 0x22C3, mt_mov_limits }, + +{ "bigodot", 0x2299, mt_mov_limits }, + +{ "bigoplus", 0x2295, mt_mov_limits }, + +{ "bigotimes", 0x2297, mt_mov_limits }, + +{ "bigsqcup", 0x2A06, mt_mov_limits }, + +{ "biguplus", 0x2A04, mt_mov_limits }, + +{ "bigvee", 0x22C1, mt_mov_limits }, + +{ "bigwedge", 0x22C0, mt_mov_limits }, + +{ "cdot", 0xB7, mt_bin }, +{ "cdots", 0x22EF, mt_ord }, +{ "centerdot", 0xB7, mt_bin }, +{ "chi", 0x3C7, mt_ident }, +{ "coprod", 0x2210, mt_mov_limits }, + +{ "ddots", 0x22F1, mt_ord }, +{ "delta", 0x3B4, mt_ident }, +{ "div", 0xF7, mt_bin }, +{ "epsilon", 0x3B5, mt_ident }, +{ "gamma", 0x3B3, mt_ident }, +{ "ge", 0x2265, mt_rel }, +{ "iiiint", 0x2A0C, mt_limits }, + +{ "iiint", 0x222D, mt_limits }, + +{ "iint", 0x222C, mt_limits }, + +{ "infinity", 0x221E, mt_rel }, +{ "int", 0x222B, mt_limits }, + +{ "kappa", 0x3BA, mt_ident }, +{ "lambda", 0x3BB, mt_ident }, +{ "ldots", 0x2026, mt_ord }, +{ "le", 0x2264, mt_rel }, +{ "leftarrow", 0x2190, mt_rel }, + + + +{ "mu", 0x3BC, mt_ident }, + +{ "nabla", 0x2207, mt_ident }, +{ "nu", 0x3BD, mt_ident }, +{ "oint", 0x222E, mt_limits }, + + +{ "omega", 0x3C9, mt_ident }, +{ "partial", 0x2202, mt_ord }, +{ "phi", 0x3C6, mt_ident }, +{ "pi", 0x3C0, mt_ident }, +{ "pm", 0xB1, mt_rel }, + +{ "prod", 0x220f, mt_mov_limits }, +{ "psi", 0x3C8, mt_ident }, + +{ "rho", 0x3C1, mt_ident }, +{ "rightarrow", 0x2192, mt_rel }, +{ "sigma", 0x3C3, mt_ident }, +{ "sim", 0x223C, mt_rel }, +{ "sum", 0x2211, mt_mov_limits }, + +{ "tau", 0x3C4, mt_ident }, +{ "theta", 0x3B8, mt_ident }, +{ "times", 0xD7, mt_bin }, +{ "to", 0x2192, mt_rel }, +{ "upsilon", 0x3C5, mt_ident }, +{ "varepsilon", 0x3B5, mt_ident }, +{ "vdots", 0x22EE, mt_ord }, +{ "xi", 0x3BE, mt_ident }, +{ "zeta", 0x3B6, mt_ident } + + +}; + +static ErrorTable errorTable[] = { + { ex_out_of_memory, "Out of memory" }, + { ex_missing_lbrace, "Missing '{'" }, + { ex_prefix_superscript, "Illegal prefix superscript: use the '\\lsup' command" }, + { ex_prefix_subscript, "Illegal prefix subscript: use the '\\lsub' command" }, + { ex_misplaced_column_separator, "Misplaced column separator" }, + { ex_more_rbrace_than_lbrace, "Syntax error: more '}' than '{'" }, + { ex_control_name_too_long, "Control name too long: maximum is 32" }, + { ex_misplaced_row_separator, "Misplaced row separator" }, + { ex_illegal_subscript, "Illegal subscript" }, + { ex_illegal_superscript, "Illegal superscript" }, + { ex_undefined_control_sequence, "Undefined control sequence" }, + { ex_misplaced_inline_formula, "Misplaced inline formula" }, + { ex_missing_parameter, "Missing parameter" }, + { ex_more_lbrace_than_rbrace, "Syntax error: more '{' than '}'" }, + { ex_double_superscript, "Double superscript" }, + { ex_double_subscript, "Double subscript" }, + { ex_use_subscript_before_superscript, "Use subscript first as the element is <msubsup>" }, + { ex_internal_error, "Internal error" }, + { ex_missing_end_tag, "Missing end tag" }, + { ex_undefined_environment_type, "Undefined environment type" }, + { ex_unknown_alignment_character, "Unknown alignment character" }, + { ex_missing_begin, "Missing \\begin" }, + { ex_missing_end, "Missing \\end" }, + { ex_mismatched_environment_type, "Mismatched environment type"}, + { ex_too_many_columns, "Too many columns" }, + { ex_unknown_attribute, "Unknown attribute" }, + { ex_no_command_allowed, "Command not allowed here" }, + { ex_misplaced_limits, "Limit controls must follow a math operator" }, + { ex_missing_fence_parameter, "Missing fence parameter" }, + { ex_not_math_mode, "Not in math mode" }, + { ex_missing_right_sq_bracket, "Missing ']'" }, + { ex_missing_dollar_symbol, "Missing '$'" }, + { ex_missing_left_fence, "Missing \\left" }, + { ex_missing_right_fence, "Missing \\right" }, + { ex_ambiguous_script, "Ambiguous script; use \\left and \\right" }, + { ex_misplaced_eqno, "Equation number not allowed here" }, + { ex_duplicate_eqno, "Duplicate equation number" }, + { ex_missing_column_alignment, "Missing column alignment" }, + { ex_missing_subsup_base, "Missing subscript/superscript base" }, + { ex_unknown_character, "Internal error: Unknown character" }, + { ex_unhandled_mathtype, "Internal error: unhandled math type" } + //{ ex_misplaced_nolimits, "Nolimits control must follow a math operator" } +}; + +SymbolTable mathvariant[]= { + {"bb", "double-struck"}, + {"bf", "bold"}, + {"bfrak", "bold-fraktur"}, + {"bi", "bold-italic"}, + {"bsc", "bold-script"}, + {"bss", "bold-sans-serif"}, + {"frak", "fraktur"}, + {"it", "italic"}, + {"rm", "normal"}, + {"sc", "script"}, + {"ss", "sans-serif"}, + {"ssbi", "sans-serif-bold-italic"}, + {"ssi", "sans-serif-italic"}, + {"tt", "monospace"} +}; + +static EntityStruct fenceTable[] = { + + { "[", '[', mt_left_fence }, + { "]", ']', mt_right_fence }, + { "\\{", '{', mt_left_fence }, + { "\\}", '}', mt_right_fence }, + { "/", '/', mt_ord }, + { "(", '(', mt_left_fence }, + { ")", ')', mt_right_fence }, + { "|", 0x007C, mt_ord }, + { "\\|", 0x2016, mt_ord }, + { "<", 0x2329, mt_left_fence }, + { ">", 0x232A, mt_right_fence }, + { ".", 0, mt_ord }, //see function below + { "lgroup", '(', mt_left_fence }, + { "rgroup", ')', mt_right_fence }, + { "langle", 0x2329, mt_left_fence }, + { "rangle", 0x232A, mt_right_fence }, + { "lAngle", 0x300A, mt_left_fence }, + { "rAngle", 0x300B, mt_right_fence }, + { "lfloor", 0x230A, mt_left_fence },//'&lfloor}, //0x230A}, + { "rfloor", 0x230B, mt_right_fence },//'&rfloor}, //0x230B}, + { "lceil", 0x2308, mt_left_fence },//'&lceil}, // 0x2308}, + { "rceil", 0x2309, mt_right_fence },//'&rceil}, // 0x2309}, + { "lbrack", '[', mt_left_fence }, + { "rbrack", ']', mt_right_fence }, + { "lBrack", 0x301A, mt_left_fence }, + { "rBrack", 0x301B, mt_right_fence }, + { "lbrace", '{', mt_left_fence }, + { "rbrace", '}', mt_right_fence }, + { "backslash", '\\', mt_ord }, + { "vert", 0x007C, mt_ord }, + { "Vert", 0x2016, mt_ord }, + { "uparrow", 0x2191, mt_ord }, + { "Uparrow", 0x21D1, mt_ord }, + { "downarrow", 0x2193, mt_ord }, + { "Downarrow", 0x21D3, mt_ord }, + { "updownarrow", 0x2195, mt_ord }, + { "Updownarrow", 0x21D5, mt_ord }, + { "lmoustache", 0x23B0, mt_left_fence }, //0x23B0}, + { "rmoustache", 0x23B1, mt_right_fence }, //0x23B1}, + { "lmoust", 0x23B0, mt_left_fence }, + { "rmoust", 0x23B1, mt_right_fence } +}; + +// thickspace .27777 +// medspace .222222em +// thinspace .16667em +static SymbolStruct symbols[]= { + {"\\ ", " ", "<mspace width='.25em'/>", mt_ord }, + {"\\,", " ", "<mspace width='.16667em'/>", mt_ord }, + {"\\:", " ", "<mspace width='.222222em'/>", mt_ord }, + {"\\>", " ", "<mspace width='.222222em'/>", mt_ord }, + {"\\;", " ", "<mspace width='.27777em'/>", mt_ord }, + {"\\!", " ", "<mspace width='-.16667em'/>", mt_ord }, + {"\\~", " ", "<mo> </mo>", mt_ord }, + {"\\|", "‖", "<mo mathsize='1'>‖</mo>", mt_fence }, + {"\\{", "{", "<mo mathsize='1'>{</mo>", mt_left_fence }, + {"\\}", "}", "<mo mathsize='1'>}</mo>", mt_right_fence }, + //{"|", "|", "<mo mathsize='1'>|</mo>", mt_ord }, + {"|", "|", "<mo mathsize='1'>|</mo>", mt_ord }, + {"[", "[", "<mo mathsize='1'>[</mo>", mt_left_fence }, + {"]", "]", "<mo mathsize='1'>]</mo>", mt_right_fence }, + {"(", "(", "<mo mathsize='1'>(</mo>", mt_left_fence }, + {")", ")", "<mo mathsize='1'>)</mo>", mt_right_fence }, + {"<", "<", "<mo mathsize='1'><</mo>", mt_left_fence }, + {">", ">", "<mo mathsize='1'>></mo>", mt_right_fence }, + {"-", "-", "<mo>−</mo>", mt_bin_unary }, + {"`", "̀", "<mo>̀</mo>", mt_ord }, + {"@", "@", "<mo>@</mo>", mt_ord }, + {"*", "*", "<mo>*</mo>", mt_ord }, + {"'", "′", "<mo>′</mo>", mt_ord }, + {"''", "″", "<mo>″</mo>", mt_ord }, + {"'''", "‴", "<mo>‴</mo>", mt_ord }, + {"\"", "”", "<mo>”</mo>", mt_ord }, + {"/", "/", "<mtext>/</mtext>", mt_ord }, + {"\\/", "​", "<mo>​</mo>", mt_ord }, + {"\\%", "%", "<mo>%</mo>", mt_ord }, + {"\\#", "#", "<mo>#</mo>", mt_ord }, + {"\\$", "$", "<mtext>$</mtext>", mt_ord }, + {"\\^", "ˆ", "<mo>ˆ</mo>", mt_ord }, + {"\\&", "&", "<mo>&</mo>", mt_ord }, + {"\\_", "_", "<mo>_</mo>", mt_ord }, + {"\\-", "​", "<mo>​</mo>", mt_ord }, + {"!", "!", "<mo>!</mo>", mt_ord }, + {"+", "+", "<mo>+</mo>", mt_bin_unary }, + {"=", "=", "<mo>=</mo>", mt_bin }, + {":", ":", "<mo>:</mo>", mt_bin }, + {";", ";", "<mo>;</mo>", mt_ord }, + {",", ",", "<mo>,</mo>", mt_punct }, + {".", ".", "<mo>.</mo>", mt_ord }, + {"?", "?", "<mo>?</mo>", mt_ord } +}; + +#define TABLE_SIZE(x) ( sizeof( (x) )/sizeof( (x)[0] )) + + +inline int fastCompare( const char *s1, const char *s2 ) +{ + return ( ( *s1 == *s2 ) ? strcmp( s1, s2 ) : *s1 - *s2 ); +} + + +CommandStruct *isCommand( const char *name ) +{ + const int size = TABLE_SIZE( commandTable ); + + int result, low, mid, high; + + low = 0; + high = size - 1; + + while( low <= high ) + { + mid = ( low + high )/2; + + result = fastCompare( name, commandTable[mid].name ); + + if( result < 0 ) + { + high = mid - 1; + } + else if( result > 0 ) + { + low = mid + 1; + } + else + { + return &commandTable[mid]; + } + } + + return NULL; +} + + +EntityStruct *isEntity( const char *name ) +{ + const int size = TABLE_SIZE( entityTable ); + + int result, low, mid, high; + + low = 0; + high = size - 1; + + while( low <= high ) + { + mid = ( low + high )/2; + + result = fastCompare( name, entityTable[mid].name ); + + if( result < 0 ) + { + high = mid - 1; + } + else if( result > 0 ) + { + low = mid + 1; + } + else + { + return &entityTable[mid]; + } + } + + return NULL; + +} + + +FunctionStruct *isFunction( const char *name ) +{ + const int size = TABLE_SIZE( functionTable ); + + int result, low, mid, high; + + low = 0; + high = size - 1; + + while( low <= high ) + { + mid = ( low + high )/2; + + result = fastCompare( name, functionTable[mid].name ); + + if( result < 0 ) + { + high = mid - 1; + } + else if( result > 0 ) + { + low = mid + 1; + } + else + { + return &functionTable[mid]; + } + } + + return NULL; +} + +token_type getControlType( const char *name, ControlStruct &control ) +{ + + if( ( control.command = isCommand( name ) ) != NULL ) + { + control.token = token_control_command; + } + else if( ( control.entity = isEntity( name ) ) != NULL ) + { + control.token = token_control_entity; + } + else if( ( control.function = isFunction( name ) ) != NULL ) + { + control.token = token_control_function; + } + else + { + control.token = token_unknown; + } + + return control.token; +} + +/* + +enum math_type { mt_unknown, mt_ident, mt_digit, mt_ord, mt_bin, mt_unary, mt_rel, mt_fence, + mt_mov_limits, mt_limits, mt_func, mt_func_limits, mt_text }; +*/ + +const char *getErrorMsg( ex_exception code ) +{ + const int size = TABLE_SIZE( errorTable ); + + for( int i = 0; i < size; ++i ) + { + if( code == errorTable[i].code ) + { + return errorTable[i].msg; + } + } + + return NULL; +} + +const char *getMathVariant( const char *attrib ) +{ + const int size = TABLE_SIZE( mathvariant ); + + int result, low, mid, high; + + low = 0; + high = size - 1; + + while( low <= high ) + { + mid = ( low + high )/2; + + result = fastCompare( attrib, mathvariant[mid].key ); + + if( result < 0 ) + { + high = mid - 1; + } + else if( result > 0 ) + { + low = mid + 1; + } + else + { + return mathvariant[mid].value; + } + } + + return NULL; +} + + +bool getFenceType( const char *name, FenceStruct &fence ) +{ + const int size = TABLE_SIZE( fenceTable ); + + for( int i = 0; i < size; ++i ) + { + if( strcmp( name, fenceTable[i].name ) == 0 ) + { + fence.entity = &fenceTable[i]; + + + if( fence.entity->code < 256 ) // ascii + { + fence.output[0] = (char)fence.entity->code; + fence.output[1] = '\0'; + } + else + { + //sprintf_s( fence.output, sizeof( fence.output ) - 1, "&#x%x;", fence.entity->code ); + sprintf( fence.output, "&#x%x;", fence.entity->code ); + } + return true; + } + } + + fence.entity = NULL; + return false; +} + + + +EnvironmentStruct *getEnvironmentType( const char *name ) +{ + const int size = TABLE_SIZE( environmentTable ); + + int result, low, mid, high; + + low = 0; + high = size - 1; + + while( low <= high ) + { + mid = ( low + high )/2; + + result = fastCompare( name, environmentTable[mid].name ); + + if( result < 0 ) + { + high = mid - 1; + } + else if( result > 0 ) + { + low = mid + 1; + } + else + { + return &environmentTable[mid]; + } + } + + + return NULL; +} + + +SymbolStruct *getSymbol( const char *name ) +{ + const int size = TABLE_SIZE( symbols ); + + for( int i = 0; i < size; ++i ) + { + if( strcmp( name, symbols[i].name ) == 0 ) + { + return &symbols[i]; + } + } + + return NULL; +} + + diff --git a/support/ltx2mathml/src/ltx2mathmltables.h b/support/ltx2mathml/src/ltx2mathmltables.h new file mode 100644 index 0000000000..ebc9baef24 --- /dev/null +++ b/support/ltx2mathml/src/ltx2mathmltables.h @@ -0,0 +1,125 @@ +#pragma once + +#include <string.h> +#include "ltx2mathmlexceptions.h" + +enum command_id { + ci_unknown, ci_msub, ci_msup, ci_msubsup, ci_munder, ci_mover, ci_munderover, + + ci_mi, ci_mn, ci_mo, ci_text, ci_cfrac, ci_mfrac, ci_frac, ci_mathfont, ci_sqrt, ci_begin, ci_end, + ci_array, ci_eqnarray, ci_cases, ci_matrix, ci_bmatrix, ci_Bmatrix, ci_pmatrix, ci_vmatrix, + ci_Vmatrix, ci_mathop, ci_accent, ci_ext_arrows, + ci_func, ci_binom, ci_stack, ci_stackrel, ci_hfill, ci_limits, ci_nolimits, + ci_menclose, ci_strut, ci_phantom, ci_left, ci_right, ci_underoverbrace, + ci_mathstring, ci_lsub, ci_lsup, ci_lsubsup, ci_eqno, ci_leqno, ci_mathord, ci_mathbin, ci_mathrel +}; + +enum math_type { mt_unknown, mt_ident, mt_digit, mt_ord, + mt_bin, mt_unary, mt_bin_unary, mt_rel, + mt_left_fence, mt_right_fence, mt_fence, + mt_mov_limits, mt_limits, mt_func, mt_func_limits, + mt_text, mt_punct }; + +enum param_type { pt_unknown, pt_none, pt_plain, pt_one, pt_two, pt_three, pt_table, pt_others, + pt_especial }; + +enum token_type { + token_eof = -1, + token_unknown = 0, + token_alpha, + token_digit, + token_symbol, + token_white_space, + token_left_brace, + token_right_brace, + token_right_sq_bracket, + token_superscript, + token_subscript, + token_column_sep, + token_row_sep, + token_control_symbol, + token_control_name, + token_control_command, + token_control_entity, + token_control_function, + token_inline_math, + token_prime +}; + +struct SymbolTable { + union { + char const *tagOn; + char const*key; + char const*name; + //exception code; + }; + union { + char const*tagOff; + char const*value; + math_type mathType; + //char *errorMsg; + }; +}; + +struct ErrorTable { + ex_exception code; + char const *msg; +}; + +struct EntityStruct { + char const *name; + unsigned int code; + math_type mathType; +}; + +struct FunctionStruct { + char const *name; + char const *output; + math_type mathType; +}; + +struct FenceStruct { + EntityStruct *entity; + char output[20]; +}; + +struct CommandStruct { + char const *name; + command_id id; + param_type param; + char const *tagOn; + char const *tagOff; +}; + +struct EnvironmentStruct { + char const *name; + command_id id; + char const *tagOn; + char const*tagOff; +}; + +struct SymbolStruct { + char const* name; + char const* literal; + char const* element; + math_type mathType; +}; + +struct ControlStruct { + CommandStruct *command; + token_type token; + char *start; + union { + EntityStruct *entity; + FunctionStruct *function; + }; +}; + + +token_type getControlType(const char *name, ControlStruct &control ); +const char *getErrorMsg( ex_exception code ); +const char *getMathVariant(const char *attrib ); +bool getFenceType(const char *name, FenceStruct &fence ); +EnvironmentStruct *getEnvironmentType(const char *name ); +SymbolStruct *getSymbol(const char *name ); + diff --git a/support/ltx2mathml/src/test.cpp b/support/ltx2mathml/src/test.cpp new file mode 100644 index 0000000000..99b68a5d58 --- /dev/null +++ b/support/ltx2mathml/src/test.cpp @@ -0,0 +1,41 @@ +// testtex.cpp : This file contains the 'main' function. Program execution begins and ends there. +// + +#include <iostream> +#include "ltx2mathml.h" + + +int main() +{ + int index; + char input[256]; + + while (true) + { + printf("> "); + + if( !fgets(input, 255, stdin) || ('\n' == input[0])) + break; + else + { + if (convertFormula(input, -1, &index))// -1 indicates 'input' is null terminated + { + string result; + + if (getMathMLOutput(result, true)) + { + std::cout << result << std::endl; + } + else + { + std::cout << "Input produced no output\n"; + } + } + else + { + std::cout << "[Index: " << index << "] " << getLastError() << std::endl; + } + } + } + return 0; +} |