--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://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 <http://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
+<http://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
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
--- /dev/null
+
+Introduction
+------------
+
+This is an alternative to jextract for the OpenJDK panama project
+which in turn is a project to implement Java to Native interfaces at
+runtime.
+
+It uses a gcc plugin for type extraction and a "simple" perl script to
+transform this into Java source files with the appropriate annotations
+for panama to do it's thing.
+
+Compile
+-------
+
+Edit the makefile to point to your gcc directory and make.
+
+$ cd src
+$ vi Makefile
+$ make
+
+generate is a perl script.
+
+See test-api/* for a simple example. JAVA_HOME must point to
+a compatible panama-enabled jdk.
+
+Use dump.so
+-----------
+
+dump.so is a gcc plugin which captures structures, unions, enums,
+exported functions, and a few typedefs into a perl source file
+containing a single hash.
+
+Put all the include files required for your api in api.h.
+
+$ gcc -fplugin=src/export.so -fplugin-arg-export-output=api.pm api.h -o /dev/null
+
+api.pm is a text file of perl source-code which contains a descriptor
+of all supported types found.
+
+Use generate
+------------
+
+Quick and dirty:
+
+$ generate -d dir -t name.space -c APILib -lapi ./api.pm
+
+Generate all structures in api.pm (the ./ is required) and place all
+functions into dir/name/space/APILib.java which will link with
+libapi.so.
+
+The generator is quite flexible, sub-sets of functions can be placed
+in alternative *Lib.java files, types can be filtered. If a function
+or type is specified explicitly, then only those types it requires are
+included in the generated output.
+
+See the top of the file for details, it's probably up to date.
+
+Status
+------
+
+This is currently just a 'quick and dirty' weekend hack. The tools
+spew a lot of debug. dump.cc is basic c-compatible-c++, because I
+don't know c++.
+
+dump.so works by hooking into the gcc pre-compiled headers function,
+it might work with a c source file as well. It's only been used with
+gcc 9.
+
+The dumper will hard-fail if it sees defintions it doesn't understand,
+and currently it's only been tested with a small nubmer of libraries.
+
+enumerations are currently translated to integres. The generator
+doesn't currently export any to Java.
+
+varags is not implemented.
+
+All function pointers are translated to a unique set of functional
+interfaces whose names are based on the function signature. So they
+should remain stable.
+
+Anonymous type names are based on the structure member they belong to,
+but they may not be unique.
+
+It will only ever support c.
+
+Only tested against the panama 'openjdk-14-panama+1-15_linux'.
+
+License
+-------
+
+GNU General Public License, version 3 or later, but see individual
+file headers for specifics.
+
+Links
+-----
+
+ * https://www.zedzone/software/panamaz.html - project page.
+ * https://openjdk.java.net/projects/panama - openjdk panama page.
--- /dev/null
+
+CXXFLAGS=-fPIC -Wall -Wno-switch -g
+CPPFLAGS=-I. -I/usr/lib64/gcc/x86_64-slackware-linux/9.2.0/plugin/include
+
+all: export.so
+
+export.o: export.cc list.h tree-codes.h
+export.so: export.o
+ $(CC) $(INCLUDE) -shared -fPIC -o $@ $^
+
+clean:
+ rm -f export.o export.so
+
+.PHONY: clean
--- /dev/null
+/*
+ * export c types and prototypes to perl file.
+ *
+ * Copyright (c) 2019 Yonatan Goldschmidt
+ * Copyright (c) 2020 Michael Zucchi
+ *
+ * The MIT License (MIT)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/*
+ skeleton taken from structsizes.cc plugin by Richard W.M. Jones
+ https://rwmj.wordpress.com/2016/02/24/playing-with-gcc-plugins/
+ some other bits from
+ https://blog.adacore.com/bindings-gcc-plugins
+ */
+
+/*
+
+function declarations, i think
+
+ chain param type name size
+TYPE_DECL TYPE_ARG_TYPES TYPE_VALUE(item):TREE_LIST <empty> TYPE_SIZE(item_type)
+ /POINTER
+ /FUNCTION_TYPE
+FUNCTION_DECL DECL_ARGUENTS TREE_TYPE(item):PARM_DECL DECL_NAME(item) DECL_SIZE(item)
+ TYPE_SIZE(item_type)
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gcc-plugin.h>
+#include <tree.h>
+#include <print-tree.h>
+
+#include "tree-codes.h"
+#include "list.h"
+
+#define D(x) do { x; } while(0)
+
+//Enums have a type, otherwise they're just integers
+//#define TYPED_ENUMS
+
+// remove some of the debug
+//#define NDEBUG
+
+int plugin_is_GPL_compatible; // must be defined for the plugin to run
+
+static FILE *output_file;
+
+static void debug_tree_helper(tree t, const char *msg) {
+#ifndef NDEBUG
+ fflush(stdout);
+ fprintf(stderr, "dumping tree: '%s'\n", msg);
+ debug_tree(t);
+ fprintf(stderr, "\n\n");
+ fflush(stdout);
+#endif
+}
+
+static struct hash dumped;
+static struct list todump;
+static struct list context_stack;
+
+/*
+ Join all names in the stack, in reverse order.
+ */
+static char *stack_path(struct list *stack, const char *sep) {
+ size_t total = 1;
+
+ for (struct node *n = stack->tail; n; n=n->link)
+ total += strlen(n->name)+strlen(sep);
+
+ char *data = (char *)xmalloc(total);
+ char *p = data;
+
+ // FIXME: some other context name
+ for (struct node *n = stack->tail; n; n=n->link) {
+ p = stpcpy(p, n->name);
+ if (n->link)
+ p = stpcpy(p, sep);
+ }
+
+ return data;
+}
+
+// returns 0 if type has no size (i.e VOID_TYPE)
+static bool is_struct_or_union(const_tree type) {
+ return RECORD_TYPE == TREE_CODE(type) || UNION_TYPE == TREE_CODE(type);
+}
+
+static void print_spaces(int n) {
+ for (int i = 0; i < n; ++i)
+ fputc('\t', output_file);
+}
+
+static int is_ref_type(tree type) {
+ switch (TREE_CODE(type)) {
+ case VECTOR_TYPE:
+ case ARRAY_TYPE:
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static tree target_type(tree type) {
+ while (is_ref_type(type))
+ type = TREE_TYPE(type);
+ return type;
+}
+
+static size_t value_size(tree n) {
+ return n ? tree_to_uhwi(n) : 0;
+}
+
+static const char *value_name(tree type) {
+ tree test = TYPE_IDENTIFIER(type);
+ const char *value = test ? IDENTIFIER_POINTER(test) : NULL;
+
+ // __va_list_tag is the final type beneath __builtin_va_list.
+ // it behaves different from other types - it has a TYPE_MAIN_VARIANT, but the main TYPE_NAME seems to give
+ // an unexpected tree, and therefore ORIG_TYPE_NAME returns a garbage value.
+ // I think this patch is good enough.
+ if (value && 0 == strcmp("__va_list_tag", value))
+ return "__va_list_tag";
+
+ test = TYPE_MAIN_VARIANT(type);
+ test = test ? TYPE_NAME(test) : test;
+ test = test && TREE_CODE(test) == TYPE_DECL ? DECL_NAME(test) : test;
+
+ return test ? IDENTIFIER_POINTER(test) : value;
+}
+
+/*
+ Find a non-ref type in the type chain, i.e. skip pointers/arrays.
+ */
+static tree simple_type(tree t) {
+ while (is_ref_type(t))
+ t = TREE_TYPE(t);
+ return t;
+}
+
+/*
+ Create a 'panama' signature for a single type.
+ */
+static void export_desc(tree field, tree field_type, struct buffer *b) {
+ const size_t data_size = value_size(TYPE_SIZE(field_type));
+
+ switch (TREE_CODE(field_type)) {
+ case VOID_TYPE:
+ buffer_add(b, "v");
+ break;
+ case VECTOR_TYPE:
+ case ARRAY_TYPE: {
+ const size_t elem_size = tree_to_uhwi(TYPE_SIZE_UNIT(TREE_TYPE(field_type)));
+ size_t num_elem;
+
+ if (elem_size == 0 || NULL == TYPE_SIZE_UNIT(field_type)) {
+ // it is a flexible array or empty types
+ num_elem = 0;
+ } else {
+ // it might be 0 / elem_size, in which case we also end up with num_elem = 0.
+ num_elem = tree_to_uhwi(TYPE_SIZE_UNIT(field_type)) / elem_size;
+ }
+
+ buffer_room(b, 16);
+ b->pos += sprintf(b->data + b->pos, "[%zu", num_elem);
+ export_desc(field, TREE_TYPE(field_type), b);
+ buffer_add(b, "]");
+ break;
+ }
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ buffer_room(b, 16);
+ b->pos += sprintf(b->data + b->pos, "u%zu:", data_size);
+ export_desc(field, TREE_TYPE(field_type), b);
+ break;
+ case FUNCTION_TYPE: {
+ // TODO: handle void f() type -> null TYPE_ARG_TYPES()
+ tree return_type = TREE_TYPE(field_type);
+
+ buffer_add(b, "(");
+ for (tree param = TYPE_ARG_TYPES(field_type); param != NULL; param = TREE_CHAIN(param)) {
+ tree param_type = TREE_VALUE(param);
+
+ if (TREE_CODE(param_type) == VOID_TYPE)
+ break;
+
+ export_desc(param, param_type, b);
+ }
+ buffer_add(b, ")");
+ export_desc(field, return_type, b);
+ break;
+ }
+ case ENUMERAL_TYPE:
+#if defined(TYPED_ENUMS)
+ buffer_add(b, "${");
+ buffer_add(b, TYPE_IDENTIFIER(field_type) ? value_name(field_type) : "enum");
+ buffer_add(b, "}");
+#else
+ buffer_room(b, 16);
+ b->pos += sprintf(b->data + b->pos, "%c%zu",
+ TYPE_UNSIGNED(field_type) ? 'u' : 'i',
+ data_size);
+#endif
+ break;
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ if (TYPE_IDENTIFIER(field_type)) {
+ list_add(&todump, node_alloc(field_type, NULL));
+
+ buffer_add(b, "${");
+ buffer_add(b, value_name(field_type));
+ buffer_add(b, "}");
+ } else {
+ char *name = stack_path(&context_stack, "_");
+
+ list_add(&todump, node_alloc(field_type, name));
+
+ buffer_add(b, "${");
+ buffer_add(b, name);
+ buffer_add(b, "}");
+
+ free(name);
+ }
+ break;
+ case REAL_TYPE:
+ buffer_room(b, 16);
+ b->pos += sprintf(b->data + b->pos, "f%zu", data_size);
+ break;
+ case INTEGER_TYPE:
+ buffer_room(b, 16);
+ b->pos += sprintf(b->data + b->pos, "%c%zu",
+ TYPE_UNSIGNED(field_type) ? 'u' : 'i',
+ data_size);
+ break;
+ default:
+ debug_tree_helper(field_type, "unknown type!");
+ gcc_unreachable();
+ break;
+ }
+}
+
+/*
+ Print a single parameter or field.
+ */
+static void export_param(tree field, tree field_type, size_t field_size) {
+ switch (TREE_CODE(field_type)) {
+ case VECTOR_TYPE:
+ case ARRAY_TYPE:
+ case POINTER_TYPE:
+ case REFERENCE_TYPE: {
+ struct buffer b;
+
+ buffer_init(&b, 256);
+ export_desc(field, field_type, &b);
+ fprintf(output_file, " deref => '%s',", b.data);
+ free(b.data);
+
+ field_type = simple_type(field_type);
+ field_size = value_size(TYPE_SIZE(field_type));
+
+ export_param(field, field_type, field_size);
+ break;
+ }
+ case VOID_TYPE:
+ fprintf(output_file, " type => 'void',");
+ break;
+ case ENUMERAL_TYPE: {
+#if defined(TYPED_ENUMS)
+ const char *names = TYPE_IDENTIFIER(field_type) ? value_name(field_type) : "enum";
+ fprintf(output_file, " type => 'enum:%s',", names);
+#else
+ fprintf(output_file, " type => '%c%zu',", TYPE_UNSIGNED(field_type) ? 'u' : 'i', field_size);
+#endif
+ break;
+ }
+ case FUNCTION_TYPE: {
+ // If the function is a typedef we could use the name
+ // but it's a pain to find up the tree, so don't bother.
+ // Use the signature instead. This is what jextract appears to use.
+ struct buffer b;
+
+ //char *name = stack_path(&context_stack);
+ //fprintf(output_file, " type => 'call:%s', ", name);
+ //free(name);
+
+ buffer_init(&b, 256);
+
+ export_desc(field, field_type, &b);
+ list_add(&todump, node_alloc(field_type, b.data));
+ fprintf(output_file, " type => 'call:%s', ", b.data);
+
+ free(b.data);
+
+ break;
+ }
+ case REAL_TYPE:
+ fprintf(output_file, " ctype => '%s',", value_name(field_type));
+ fprintf(output_file, " type => 'f%zu',", field_size);
+ break;
+ case INTEGER_TYPE:
+ if (TREE_CODE(field) == FIELD_DECL && DECL_BIT_FIELD(field)) {
+ fprintf(output_file, " ctype => 'bitfield',");
+ fprintf(output_file, " type => '%c%zu',", TYPE_UNSIGNED(field_type) ? 'u' : 'i', value_size(DECL_SIZE(field)));
+ } else {
+ fprintf(output_file, " ctype => '%s',", value_name(field_type));
+ fprintf(output_file, " type => '%c%zu',", TYPE_UNSIGNED(field_type) ? 'u' : 'i', field_size);
+ }
+ break;
+ case RECORD_TYPE:
+ case UNION_TYPE: {
+ const char *us = TREE_CODE(field_type) == RECORD_TYPE ? "struct" : "union";
+
+ if (TYPE_IDENTIFIER(field_type)) {
+ fprintf(output_file, " type => '%s:%s',", us, value_name(field_type));
+ } else {
+ char *name = stack_path(&context_stack, "_");
+
+ list_add(&todump, node_alloc(field_type, name));
+ fprintf(output_file, " type => '%s:%s',", us, name);
+ free(name);
+ }
+ break;
+ }
+ default:
+ printf("unknown param type: %s\n", ZTREE_CODE(field_type));
+ gcc_unreachable();
+ }
+}
+
+/*
+ Export a chain of parameters
+*/
+static void export_params(tree first_param, size_t indent_level) {
+ int id = 0;
+ char nameb[16];
+ const char *names = nameb;
+
+ for (tree param = first_param; param; param = TREE_CHAIN(param)) {
+ tree param_type = TREE_VALUE(param);
+ const size_t data_size = value_size(TYPE_SIZE(param_type));
+
+ // non-varags functions end in VOID_TYPE
+ if (!TREE_CHAIN(param) && TREE_CODE(param_type) == VOID_TYPE)
+ break;
+
+ fprintf(output_file, "\t\t{");
+
+ // size: do we need it?
+ fprintf(output_file, " size => %zu,", data_size);
+
+ // name: none available, use position
+ sprintf(nameb, "arg_%d", id);
+
+ fprintf(output_file, " name => '%s',", names);
+ stack_push(&context_stack, node_alloc(param, names));
+
+ // value: details
+ export_param(param, param_type, data_size);
+
+ free(stack_pull(&context_stack));
+
+ fprintf(output_file, "},\n");
+ id++;
+ }
+}
+
+/*
+ Export a chain of fields.
+*/
+static void export_fields(tree first_field, size_t base_offset, int indent) {
+ for (tree field = first_field; field; field = TREE_CHAIN(field)) {
+ gcc_assert(TREE_CODE(field) == FIELD_DECL);
+
+ tree field_type = TREE_TYPE(field);
+ const size_t field_size = value_size(DECL_SIZE(field));
+ size_t offset = base_offset + tree_to_uhwi(DECL_FIELD_OFFSET(field)) * 8 + tree_to_uhwi(DECL_FIELD_BIT_OFFSET(field));
+
+ // name: if none, then inline
+ if (!DECL_NAME(field)) {
+ if (is_struct_or_union(field_type))
+ export_fields(TYPE_FIELDS(field_type), offset, indent);
+ } else {
+ const char *names = IDENTIFIER_POINTER(DECL_NAME(field));
+
+ printf(" name=%s\n", names);
+ print_spaces(indent+1);
+ fprintf(output_file, "{ name => '%s', size => %zu, offset => %zu,", names, field_size, offset);
+ stack_push(&context_stack, node_alloc(field, names));
+
+ // value: details
+ export_param(field, field_type, field_size);
+
+ free(stack_pull(&context_stack));
+
+ fprintf(output_file, "},\n");
+ }
+ }
+}
+
+/*
+ Main entry point for exporting any type.
+*/
+static void export_type(tree type, const char *names) {
+ tree name;
+ tree deftype;
+ tree target;
+
+ D(printf("export: %s %s\n", names, ZTREE_CODE(type)));
+
+ switch (TREE_CODE(type)) {
+ case TYPE_DECL: {
+ if (!names) {
+ name = DECL_NAME(type);
+ if (!name)
+ return;
+ names = IDENTIFIER_POINTER(name);
+ }
+ if (hash_lookup(&dumped, names))
+ return;
+ hash_put(&dumped, node_alloc(type, names));
+
+ deftype = TREE_TYPE(type);
+ target = target_type(deftype);
+ switch (TREE_CODE(target)) {
+ case FUNCTION_TYPE: {
+ // I don't know if i even want this
+
+ fprintf(output_file, "'call:%s' => { name => '%s',", names, names);
+
+ // the deftype is always a pointer for a function_type
+
+ struct buffer b;
+
+ buffer_init(&b, 256);
+ export_desc(type, deftype, &b);
+ fprintf(output_file, " deref => '%s',", b.data);
+ free(b.data);
+
+ // TODO: cleanup
+ {
+ tree result_type = TREE_TYPE(target);
+ const size_t data_size = value_size(TYPE_SIZE(result_type));
+
+ fprintf(output_file, "\n\tresult => {");
+ export_param(target, result_type, data_size);
+ fprintf(output_file, " },");
+ }
+
+ fprintf(output_file, "\n\targuments => [\n");
+ export_params(TYPE_ARG_TYPES(target), 0);
+ fprintf(output_file, "]},\n");
+ break;
+ }
+ case RECORD_TYPE:
+ printf(" typedef record: %s\n", names);
+ break;
+ case UNION_TYPE:
+ printf(" typedef union: %s\n", names);
+ break;
+ case ENUMERAL_TYPE: {
+ // TODO: typedef of anonymous enumerations may be repeated
+ // TODO: this could be detected in the frontend - e.g. don't include any
+ // TODO: anon enum values if any are already there
+ // TODO: or maybe duplicates could be detected here
+ size_t size = tree_to_uhwi(TYPE_SIZE(target));
+
+ if (size > 64) {
+ fprintf(stderr, "Warning: enum '%s' requires too many bits (%zu)\n", names, size);
+ return;
+ }
+
+ fprintf(output_file, "'enum:%s' => { name => '%s', type => 'enum', size => %zu, value_type => '%c%zu', values => [\n",
+ names, names, size, TYPE_UNSIGNED(target) ? 'u' : 'i', size);
+
+ for (tree v = TYPE_VALUES(target); v != NULL; v = TREE_CHAIN (v)) {
+ fprintf(output_file, "\t{ label => '%s', value => '%ld' },\n",
+ IDENTIFIER_POINTER(TREE_PURPOSE(v)),
+ tree_to_shwi(TREE_VALUE(v)));
+ }
+ fprintf(output_file, "]},\n");
+ break;
+ }
+ case VOID_TYPE:
+ case INTEGER_TYPE:
+ case REAL_TYPE:
+ break;
+ default:
+ printf("unknown type def: %s\n", ZTREE_CODE(target));
+ gcc_unreachable();
+ }
+
+ break;
+ }
+ case FUNCTION_DECL: {
+ if (!names) {
+ name = DECL_NAME(type);
+ if (!name)
+ return;
+ names = IDENTIFIER_POINTER(name);
+ }
+ if (hash_lookup(&dumped, names))
+ return;
+ hash_put(&dumped, node_alloc(type, names));
+ printf("export type func decl %s\n", names);
+
+ fprintf(output_file, "'func:%s' => { name => '%s', type => 'func',", names, names);
+
+ // FUNCTION_DECL -> FUNCTION_TYPE -> RESULT_TYPE, get FUNCTION_TYPE
+ type = TREE_TYPE(type);
+
+ // TODO: cleanup
+ debug_tree_helper(type, "function 1");
+ {
+ tree result_type = TREE_TYPE(type);
+ const size_t data_size = value_size(TYPE_SIZE(result_type));
+
+ fprintf(output_file, "\n\tresult => {");
+ export_param(type, result_type, data_size);
+ fprintf(output_file, " },");
+ }
+
+ fprintf(output_file, "\n\targuments => [\n");
+ //export_decl_params(DECL_ARGUMENTS(type), 0);
+ export_params(TYPE_ARG_TYPES(type), 0);
+ fprintf(output_file, "]},\n");
+ break;
+ }
+ case FUNCTION_TYPE: {
+ if (!names) {
+ name = TYPE_IDENTIFIER(type);
+ if (!name)
+ return;
+ names = IDENTIFIER_POINTER(name);
+ }
+ if (hash_lookup(&dumped, names))
+ return;
+ hash_put(&dumped, node_alloc(type, names));
+ printf("export type func %s\n", names);
+
+ fprintf(output_file, "'call:%s' => { name => '%s', type => 'call',", names, names);
+
+ debug_tree_helper(type, "function type");
+
+ // TODO: cleanup
+ // FUNCTION_TYPE -> RESULT_TYPE
+ {
+ tree result = TREE_TYPE(type);
+ //tree result_type = TREE_TYPE(result);
+ //printf(" result type type %s\n", ZTREE_CODE(result_type));
+ const size_t data_size = value_size(TYPE_SIZE(result));
+
+ printf(" result size %zu\n", data_size);
+ fprintf(output_file, "\n\tresult => {");
+ export_param(type, result, data_size);
+ fprintf(output_file, " },");
+ }
+
+ stack_push(&context_stack, node_alloc(type, names));
+ fprintf(output_file, "\n\targuments => [\n");
+ export_params(TYPE_ARG_TYPES(type), 0);
+ free(stack_pull(&context_stack));
+ fprintf(output_file, "]},\n");
+ break;
+ }
+ case RECORD_TYPE: // struct
+ case UNION_TYPE: {
+ const char *su = TREE_CODE(type) == RECORD_TYPE ? "struct" : "union";
+
+ // ignore empty types
+ if (!TYPE_FIELDS(type))
+ return;
+
+ if (!names) {
+ name = TYPE_IDENTIFIER(type);
+ if (!name)
+ return;
+ names = IDENTIFIER_POINTER(name);
+ }
+ if (hash_lookup(&dumped, names))
+ return;
+ hash_put(&dumped, node_alloc(type, names));
+
+ fprintf(output_file, "'%s:%s' => { name => '%s', type => '%s', size => %zu, fields => [\n",
+ su, names, names, su, tree_to_uhwi(TYPE_SIZE(type)));
+
+ stack_push(&context_stack, node_alloc(type, names));
+ export_fields(TYPE_FIELDS(type), 0, 0);
+ free(stack_pull(&context_stack));
+
+ fprintf(output_file, "]},\n");
+ break;
+ }
+ case ENUMERAL_TYPE: {
+ // FIXME: see ENUMERAL_TYPE above regarding duplicate anon enums
+
+ // ignore empty enums
+ if (!TYPE_VALUES(type))
+ return;
+
+ // We can only assume a non-named enum type isn't repeatedly sent here
+ if (!names) {
+ name = TYPE_IDENTIFIER(type);
+ if (name)
+ names = IDENTIFIER_POINTER(name);
+ }
+ if (names) {
+ if (hash_lookup(&dumped, names))
+ return;
+ hash_put(&dumped, node_alloc(type, names));
+ }
+
+ size_t size = tree_to_uhwi(TYPE_SIZE(type));
+
+ if (size > 64) {
+ fprintf(stderr, "Warning: enum '%s' requires too many bits (%zu)\n", names, size);
+ return;
+ }
+
+ // FIXME: choose a better anon name
+ char nameb[64];
+ static int namei;
+
+ if (!names) {
+ sprintf(nameb, "enum$%d", namei++);
+ names = nameb;
+ }
+ fprintf(output_file, "'enum:%s' => { name => '%s', type => 'enum', size => %zu, value_type => '%c%zu', values => [\n",
+ names, names, size, TYPE_UNSIGNED(type) ? 'u' : 'i', size);
+
+ for (tree v = TYPE_VALUES(type); v != NULL; v = TREE_CHAIN (v)) {
+ fprintf(output_file, "\t{ label => '%s', value => '%ld' },\n",
+ IDENTIFIER_POINTER(TREE_PURPOSE(v)),
+ tree_to_shwi(TREE_VALUE(v)));
+ }
+ fprintf(output_file, "]},\n");
+ break;
+ }
+ case FIELD_DECL:
+ case PARM_DECL:
+ break;
+ case VAR_DECL:
+ // global external variables, might want these
+ // well, if there's a way to resolve them
+ break;
+ default:
+ printf("unknown export: %s\n", ZTREE_CODE(type));
+ gcc_unreachable();
+ }
+}
+
+static void plugin_finish_type(void *event_data, void *user_data) {
+ tree type = (tree)event_data;
+
+ export_type(type, NULL);
+}
+
+static void plugin_finish_decl(void *event_data, void *user_data) {
+ tree type = (tree)event_data;
+
+ export_type(type, NULL);
+}
+
+static void plugin_finish(void *event_data, void *user_data) {
+ for (struct node *n = todump.head; n; n=n->next) {
+ if (COMPLETE_TYPE_P(n->type)) {
+ if (n->name[0]) {
+ export_type(n->type, n->name);
+ } else {
+ export_type(n->type, value_name(n->type));
+ }
+ }
+ }
+
+ fprintf(output_file, "# dumped structs:\n");
+ for (struct node *n = dumped.list.head; n; n=n->next)
+ fprintf(output_file, "# %s\n", n->name);
+
+ fprintf(output_file, ");\n");
+ //fclose(output_file);
+}
+
+int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) {
+ const char *output = NULL;
+
+ for (int i = 0; i < plugin_info->argc; ++i) {
+ if (0 == strcmp(plugin_info->argv[i].key, "output")) {
+ output = plugin_info->argv[i].value;
+ }
+ }
+
+ if (NULL == output) {
+ fprintf(stderr, "export plugin: missing parameter: -fplugin-arg-export-output=<output>\n");
+ exit(EXIT_FAILURE);
+ }
+
+ output_file = fopen(output, "w");
+ if (NULL == output_file) {
+ perror(output);
+ exit(EXIT_FAILURE);
+ }
+
+ fprintf(output_file, "%%data = (\n");
+
+ register_callback(plugin_info->base_name, PLUGIN_FINISH_DECL, plugin_finish_decl, NULL);
+ register_callback(plugin_info->base_name, PLUGIN_FINISH_TYPE, plugin_finish_type, NULL);
+ register_callback(plugin_info->base_name, PLUGIN_FINISH, plugin_finish, NULL);
+
+ return 0;
+}
--- /dev/null
+#!/usr/bin/perl
+
+# usage
+# generate [-d dir] [-t package] [--enclosing-type type ] [-s struct-root-pattern]* [--struct-file file]* [-c class [-llib]* [-f func-pattern]* [--func-file file]* ]*
+# -d dir
+# root output directory
+# -t package
+# output package
+# --enclosing-type type
+# If supplied, all structures and classes are written to an enclosing class
+# -s struct-root-pattern
+# provide one or more patterns for matching structure roots.
+# all dependencies are automatically included.
+# if no pattern is provided, all match.
+# --struct-file file
+# provide a filename with exact structure names in it. These are
+# used as roots(?)
+# -c class
+# specify class name to generate
+# -llib
+# specify link library used by class
+# -f func-pattern
+# function name pattern to include for the last class
+# --func-file file
+# point to a filename with exact function names in it, one per line ('#' is a comment).
+
+# TODO: scan all functions and include any types they use as struct roots
+# TODO: some way to specify external types
+
+@matchStruct = ();
+$meta = "";
+# @classes = ( { name => 'class', match => [ func-pattern, ... ], match_file => [ file, ... ] } )
+@classes = ();
+%lastclass = ();
+$output = ".";
+# map call signatures to a class name
+%callMap = ();
+$package = "";
+
+while (@ARGV) {
+ my $cmd = shift(@ARGV);
+
+ if ($cmd eq "-f") {
+ my $v = shift(@ARGV);
+ push @{$lastclass{match}}, qr/$v/;
+ } elsif ($cmd eq "--func-file") {
+ my $file = shift(@ARGV);
+ push @{$lastclass{match_file}}, $file;
+ push @{$lastclass{match}}, readMatchFile($file);
+ } elsif ($cmd eq "-s") {
+ my $v = shift(@ARGV);
+ push @matchStruct, qr/$v/;
+ } elsif ($cmd eq "--struct-file") {
+ my $file = shift(@ARGV);
+ push @matchStruct, readMatchFile($file);
+ } elsif ($cmd eq "-t") {
+ $package = shift(@ARGV);
+ } elsif ($cmd eq "-c") {
+ %lastclass = (
+ name => shift(@ARGV),
+ match => [],
+ match_file => [],
+ libs => []);
+ push @classes, \%lastclass;
+ } elsif ($cmd =~ m/^-l(.*)/) {
+ push @{$lastclass{libs}}, $1;
+ } elsif ($cmd eq "-d") {
+ $output = shift(@ARGV);
+ } elsif ($cmd eq "--enclosing-type") {
+ $enclosingType = shift(@ARGV);
+ } else {
+ $meta = $cmd;
+ }
+}
+
+use Data::Dumper;
+print Dumper(@classes);
+#exit 0;
+
+require $meta;
+
+# box types for primitives
+%map_box = (
+ "long" => "Long",
+ "int" => "Integer",
+ "short" => "Short",
+ "char" => "Character",
+ "float" => "Float",
+ "double" => "Double",
+ "byte" => "Byte",
+ "void" => "Void"
+ );
+
+sub readMatchFile {
+ my $path = shift @_;
+ my @lines = ();
+
+ open(my $f,"<$path");
+ while (<$f>) {
+ chop;
+ next if m/^#/;
+
+ #push @lines, qr/\^$_\$/;
+ push @lines, $_;
+ }
+ close($f);
+
+ my $all = join ('|', @lines);
+
+ return qr/^($all)$/;
+}
+
+sub camelCase {
+ my $name = shift @_;
+
+ $name =~ s/_(.)/uc($1)/eg;
+
+ return $name;
+}
+
+sub StudlyCaps {
+ my $name = shift @_;
+
+ $name =~ s/^(.)/uc($1)/e;
+ $name =~ s/_(.)/uc($1)/eg;
+
+ return $name;
+}
+
+
+sub structSignature {
+ my %struct = %{shift(@_)};
+ my $union = shift(@_);
+ my $sig = "";
+ my @fields = @{$struct{fields}};
+ my $offset = 0;
+
+ my $inbf = 0;
+ my $bfoffset = 0;
+ my $bfstart = 0;
+ my $bfsig = "";
+
+ for $fi (@fields) {
+ my %field = %{$fi};
+ my $off = $field{offset};
+
+ # bitfields, this only handles 1x u64 bitfield section
+ # They need to: align to u32/u64
+ # Group fields into one full u32/u64
+ # TODO: check alignment @ start?
+ # TODO: clean up and complete
+ # TODO: bitfields in unions are probably broken
+ if ($field{ctype} eq 'bitfield') {
+ if ($inbf) {
+ if ($off - $offset) {
+ $bfsig .= "x";
+ $bfsig .= ($off - $offset);
+ }
+ $bfsig .= $field{type};
+ $bfsig .= "($field{name})";
+ $offset = $off + $field{size};
+ } else {
+ $inbf = 1;
+ $bfsig = $field{type};
+ $bfsig .= "($field{name})";
+ $offset = $off + $field{size};
+ $bfstart = $field{offset};
+ }
+
+ if ($union) {
+ $inbf = 0;
+
+ if (($offset - $bfstart) == 32) {
+ $bfsig = "u32=[$bfsig]";
+ } elsif (($offset - $bfstart) < 32) {
+ $bfsig .= "x";
+ $bfsig .= 32 - ($offset - $bfstart);
+ $offset = $bfstart + 32;
+ $bfsig = "u32=[$bfsig]";
+ } elsif (($offset - $bfstart) == 64) {
+ $bfsig = "u64=[$bfsig]";
+ } elsif (($offset - $bfstart) < 64) {
+ $bfsig .= "x";
+ $bfsig .= 64 - ($offset - $bfstart);
+ $offset = $bfstart + 64;
+ $bfsig = "u64=[$bfsig]";
+ }
+
+ $sig .= $bfsig;
+ $sig .= "|" if ($union && $fi != @fields[$#fields]);
+ }
+ next;
+ } elsif ($inbf) {
+ if (($offset - $bfstart) == 32) {
+ $bfsig = "u32=[$bfsig]";
+ } elsif (($offset - $bfstart) < 32) {
+ $bfsig .= "x";
+ $bfsig .= 32 - ($offset - $bfstart);
+ $offset = $bfstart + 32;
+ $bfsig = "u32=[$bfsig]";
+ } elsif (($offset - $bfstart) == 64) {
+ $bfsig = "u64=[$bfsig]";
+ } elsif (($offset - $bfstart) < 64) {
+ $bfsig .= "x";
+ $bfsig .= 64 - ($offset - $bfstart);
+ $offset = $bfstart + 64;
+ $bfsig = "u64=[$bfsig]";
+ }
+ $sig .= $bfsig;
+ $inbf = 0;
+ }
+
+ # skip to next offset if necessary
+ if ($off > $offset) {
+ $sig .= "x";
+ $sig .= ($off - $offset);
+ }
+ $offset = $off + $field{size};
+
+ # normal field processing
+ if ($field{deref}) {
+ my $deref = $field{deref};
+
+ # HACK: function -> Void
+ # if ($field{debug} eq 'function') {
+ # $sig .= "u64($field{name}):v";
+ # } els
+ if ($deref =~ m/^(u\d\d)(:.*)/) {
+ $sig .= "$1($field{name})$2";
+ } else {
+ $sig .= "$deref($field{name})";
+ }
+ } else {
+ if ($field{type} =~ m/(struct|union):(.*)/) {
+ $sig .= "\${$2}";
+ } elsif ($field{type} =~ m/([iuf])(\d+)/) {
+ $sig .= $1;
+ $sig .= $2;
+ } elsif ($field{type} eq 'void') {
+ $sig .= "v";
+ } elsif ($field{type} eq 'enum') {
+ # FIXME: set type in compiler
+ $sig .= "u32";
+ }
+
+ $sig .= "($field{name})";
+ }
+
+ $sig .= "|" if ($union && $fi != @fields[$#fields]);
+ }
+
+ # finish any trailing bitfield
+ # TODO: cleanup
+ if ($inbf) {
+ if (($offset - $bfstart) == 32) {
+ $bfsig = "u32=[$bfsig]";
+ } elsif (($offset - $bfstart) < 32) {
+ $bfsig .= "x";
+ $bfsig .= 32 - ($offset - $bfstart);
+ $offset = $bfstart + 32;
+ $bfsig = "u32=[$bfsig]";
+ } elsif (($offset - $bfstart) == 64) {
+ $bfsig = "u64=[$bfsig]";
+ } elsif (($offset - $bfstart) < 64) {
+ $bfsig .= "x";
+ $bfsig .= 64 - ($offset - $bfstart);
+ $offset = $bfstart + 64;
+ $bfsig = "u64=[$bfsig]";
+ }
+ #$bfsig .= "]";
+ $sig .= $bfsig;
+ }
+
+ return "[".$sig."]";
+}
+
+sub funcSignature {
+ my %func = %{shift(@_)};
+ my $sig = "";
+ my @params = @{$func{arguments}};
+
+ for $pi (@params) {
+ my %param = %{$pi};
+
+ if ($param{deref}) {
+ # HACK: function to void
+ if ($param{debug} eq "function") {
+ $sig .= "u64:v";
+ } else {
+ $sig .= $param{deref};
+ }
+ } else {
+ if ($param{type} =~ m/struct:(.*)/) {
+ $sig .= "\${$1}";
+ } elsif ($param{type} =~ m/([iuf])(\d*)/) {
+ $sig .= $1;
+ $sig .= $2;
+ } elsif ($param{type} eq "void") {
+ $sig .= "v";
+ }
+ }
+ }
+
+ my %result = %{$func{result}};
+ my $ret = "";
+
+ if ($result{deref}) {
+ $ret .= $result{deref};
+ } else {
+ if ($result{type} =~ m/^struct:(.*)/) {
+ $ret .= "\${$1}";
+ } elsif ($result{type} =~ m/^([iuf])(\d+)/) {
+ $ret .= $1;
+ $ret .= $2;
+ } elsif ($result{type} eq "void") {
+ $ret .= "v";
+ }
+ }
+
+ return "($sig)$ret";
+}
+
+sub deref {
+ my $type = shift @_;
+ my $ref = shift @_;
+
+ while ($ref) {
+ if ($ref =~ m/\[\d*(.*)\]/) {
+ my $sub = deref($type, $1);
+
+ return "Array<$sub>";
+ } elsif ($ref =~ m/^u64:(.*)/) {
+ $type = "Pointer<$type>";
+ $ref = $1;
+ } else {
+ last;
+ }
+ }
+ return $type;
+}
+
+sub typeToJava {
+ my %param = %{shift(@_)};
+ my $type = $param{type};
+ my $ref = $param{deref};
+
+ if ($type =~ m/^struct:(.*)/) {
+ $type = StudlyCaps($1);
+ } elsif ($type =~ m/call:/) {
+ # this re-writes ref to remove one pointer-to as the Callback absorbs it.
+ $type = "Callback<".$callMap{$type}.">";
+ $type || die ("No mapping for type ".Dumper(\%param));
+ $ref =~ s/^u(32|64)://;
+ } elsif ($type =~ m/^enum:(.*)/) {
+ # TODO: other enum options
+ $type = "int";
+ } elsif ($type eq "void") {
+ $type = "void";
+ } elsif ($type =~ m/^([iu])(\d*)/) {
+ my $sign = $1;
+ my $size = $2;
+
+ if ($size <= 8) {
+ $type = "byte";
+ } elsif ($size <= 16) {
+ if ($sign eq "i") {
+ $type = "short";
+ } else {
+ $type = "char";
+ }
+ } elsif ($size <= 32) {
+ $type = "int";
+ } else {
+ $type = "long";
+ }
+ } elsif ($type =~ m/^[f](\d*)$/) {
+ my $size = $1;
+
+ if ($size == 32) {
+ $type = "float";
+ } elsif ($size == 64) {
+ $type = "double";
+ }
+ }
+
+ if ($ref) {
+ $type = $map_box{$type} if ($map_box{$type});
+ $type = deref($type, $ref);
+ }
+
+ return $type;
+}
+
+sub testMatch {
+ my $name = shift @_;
+
+ if (@_) {
+ for $pat (@_) {
+ if ($name =~ /$pat/) {
+ return 1;
+ }
+ }
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+# find all matching structures and then all that they require
+sub findStructs {
+ my %all = %{shift @_};
+ my @match = @_;
+ my @stack = grep {
+ my %e = %{$all{$_}};
+ $e{type} =~ m/(struct|union)/ && testMatch($e{name}, @match);
+ } keys %all;
+ my %visit = ();
+
+ while (@stack) {
+ my $test = shift @stack;
+
+ if (!$visit{$test}) {
+ my %struct = %{$all{$test}};
+
+ $visit{$test} = 1;
+
+ if (%struct) {
+ print "class: $struct{name}\n";
+ # find all types this one uses
+ for $f (@{$struct{fields}}) {
+ my %field = %{$f};
+
+ if ($field{type} =~ m/^(struct|union):(.*)/) {
+ if (!$set{$field{type}}) {
+ $set{$field{type}} = $all{$field{type}};
+ push @stack, $field{type};
+ }
+ }
+ }
+ } else {
+ # this is an anon type, typically used for handles
+ $test =~ m/^(struct|union):(.*)/;
+ print " anon: $2\n";
+ my %rec = (
+ type => 'struct',
+ name => $2,
+ size => 0
+ );
+ $data{$test} = \%rec;
+ }
+ }
+ }
+ return keys %visit;
+}
+
+sub findFuncs {
+ my %all = %{shift @_};
+ my @match = @_;
+ my @stack = grep {
+ my %e = %{$all{$_}};
+ $e{type} eq "func" && testMatch($e{name}, @match);
+ } keys %all;
+
+ return @stack;
+}
+
+# ######################################################################
+
+# setup section
+
+# find all classes used by functions, add them to the struct roots
+my %roots = ();
+for $c (@classes) {
+ my %class = %{$c};
+ my @libs = @{$class{libs}};
+ my @match = @{$class{match}};
+
+ for $k (findFuncs(\%data, @match)) {
+ my %func = %{$data{$k}};
+ my @params = @{$func{arguments}};
+
+ for $pi (@params) {
+ my %param = %{$pi};
+
+ if ($param{type} =~ m/^(struct|union):(.*)/) {
+ $roots{$2} = 1;
+ }
+ }
+
+ my %result = %{$func{result}};
+
+ if ($result{type} =~ m/^(struct|union):(.*)/) {
+ $roots{$2} = 1;
+ }
+ }
+}
+
+# FIXME: only include ones used elsewhere
+# add roots for any types used by calls
+for $k (grep { $_ =~ m/^call:/n } keys %data) {
+ my %func = %{$data{$k}};
+ my @params = @{$func{arguments}};
+
+ for $pi (@params) {
+ my %param = %{$pi};
+
+ if ($param{type} =~ m/^(struct|union):(.*)/) {
+ $roots{$2} = 1;
+ }
+ }
+
+ my %result = %{$func{result}};
+
+ if ($result{type} =~ m/^(struct|union):(.*)/) {
+ $roots{$2} = 1;
+ }
+}
+
+$all = join ('|', keys %roots);
+if ($all) {
+ push @matchStruct, qr/^($all)$/;
+}
+print "structures:\n";
+print Dumper(@matchStruct);
+
+# make a map for all callbacks (call: type) to generated names
+for $c (grep { $_ =~ m/^call:/n } keys %data) {
+ my $name = $c;
+
+ print "$c\n";
+ # enum maybe to int?
+
+ $name =~ s/^call:/Call/;
+ $name =~ s/\$\{[^\}]*\}/L/g;
+ $name =~ s/[ui](64|32):/p/g;
+ $name =~ s/[ui]64/J/g;
+ $name =~ s/[ui]32/I/g;
+ $name =~ s/[ui]8/B/g;
+ $name =~ s/f32/F/g;
+ $name =~ s/f64/D/g;
+ $name =~ s/[\[\]\(\)]/_/g;
+
+ $callMap{$c} = "$name";
+}
+
+print "call mappings\n";
+print Dumper(\%callMap);
+
+# ######################################################################
+# Start output
+my $dst;
+
+use File::Basename;
+use File::Path qw(make_path);
+
+if ($package ne "") {
+ $packagePrefix = $package.".";
+}
+
+if ($enclosingType) {
+ my $classname = $packagePrefix.$enclosingType;
+
+ $classname =~ s@\.@/@g;
+
+ my $path = $output."/".$classname.".java";
+ my $dir = dirname($path);
+ my $class = basename($path, ".java");
+
+ print "path $path\n";
+ print "dirname $dir\n";
+
+ make_path($dir);
+ open ($dst, ">$path");
+
+ if ($package ne "") {
+ print $dst "package $package;\n";
+ }
+
+ print $dst <<END;
+import java.foreign.Libraries;
+import java.foreign.annotations.*;
+import java.foreign.memory.*;
+import java.lang.invoke.MethodHandles;
+END
+ print $dst "public class $class {\n";
+}
+
+# Dump structures
+for $k (findStructs(\%data, @matchStruct)) {
+ my %struct = %{$data{$k}};
+ my @fields = @{$struct{fields}};
+ my $signature = structSignature(\%struct, ($struct{type} eq "union"));
+ my $name = StudlyCaps($struct{name});
+
+ if (!$enclosingType) {
+ my $classname = $packagePrefix.$name;
+
+ open ($dst, ">$path");
+ $classname =~ s@\.@/@g;
+
+ my $path = $output."/".$classname.".java";
+ my $dir = dirname($path);
+ my $class = basename($path, ".java");
+ make_path($dir);
+ open ($dst, ">$path");
+
+ if ($package ne "") {
+ print $dst "package $package;\n";
+ }
+ print $dst <<END;
+import java.foreign.annotations.*;
+import java.foreign.memory.*;
+END
+ }
+
+ # any in-line structures need to be added to the resolutionContext
+ # TODO: only include actual inline, not pointers
+ my %resolve = ();
+ for $fi (@fields) {
+ my %field = %{$fi};
+
+ if ($field{type} =~ m/^(struct|union):(.*)/) {
+ $resolve{StudlyCaps($2).".class"} = 1;
+ }
+ }
+ my $resolve = join (",", keys %resolve);
+
+ print $dst "\@NativeStruct(value=\"$signature($struct{name})\", resolutionContext={$resolve})\n";
+ print $dst "public interface $name extends Struct<$name> {\n";
+
+ for $fi (@fields) {
+ my %field = %{$fi};
+ my $type = typeToJava(\%field);
+ my $cc = StudlyCaps($field{name});
+
+ print $dst "\t\@NativeGetter(value=\"$field{name}\")\n";
+ print $dst "\tpublic $type get$cc();\n";
+
+ print $dst "\t\@NativeSetter(value=\"$field{name}\")\n";
+ print $dst "\tpublic void set$cc($type value);\n";
+ }
+
+ print $dst "}\n";
+
+ if (!$enclosingType) {
+ close($dst);
+ }
+}
+
+# Dump classes for library linkage
+for $c (@classes) {
+ my %class = %{$c};
+ my @libs = @{$class{libs}};
+ my @match = @{$class{match}};
+
+ if (!$enclosingType) {
+ my $classname = $packagePrefix.$class{name};
+
+ open ($dst, ">$path");
+ $classname =~ s@\.@/@g;
+
+ my $path = $output."/".$classname.".java";
+ my $dir = dirname($path);
+ my $class = basename($path, ".java");
+ make_path($dir);
+ open ($dst, ">$path");
+
+ if ($package ne "") {
+ print $dst "package $package;\n";
+ }
+ print $dst <<END;
+import java.foreign.Libraries;
+import java.foreign.annotations.*;
+import java.foreign.memory.*;
+import java.lang.invoke.MethodHandles;
+END
+ }
+
+ print $dst "\@NativeHeader(libraries={";
+ print $dst join(",", map { "\"$_\"" } @libs);
+ print $dst "})\n";
+ print $dst "public interface $class{name} {\n";
+
+ for $k (sort(findFuncs(\%data, @match))) {
+ my %func = %{$data{$k}};
+ my @params = @{$func{arguments}};
+ my $signature = funcSignature(\%func);
+ my $name = ($func{name});
+ my $result = typeToJava(\%{$func{result}});
+
+ print $dst "\n\t\@NativeFunction(value=\"$signature\")\n";
+ print $dst "\tpublic $result $name(";
+
+ for $pi (@params) {
+ my %param = %{$pi};
+ my $type = typeToJava($pi);
+
+ print $dst "$type $param{name}";
+ print $dst ", " if ($pi != $params[$#params]);
+ }
+
+ print $dst ");\n";
+ }
+
+ print $dst "\n";
+ print $dst "\tpublic static final $class{name} bind = Libraries.bind(MethodHandles.lookup(), $class{name}.class);\n";
+
+ print $dst "}\n";
+
+ if (!$enclosingType) {
+ close($dst);
+ }
+}
+
+# Dump callbacks
+# TODO: only those used by classes and functions that were exported
+for $c (keys %callMap) {
+ my %call = %{$data{$c}};
+ my $name = $callMap{$c};
+ my @params = @{$call{arguments}};
+ my $result = typeToJava(\%{$call{result}});
+
+ if (!$enclosingType) {
+ my $classname = $packagePrefix.$name;
+
+ open ($dst, ">$path");
+ $classname =~ s@\.@/@g;
+
+ my $path = $output."/".$classname.".java";
+ my $dir = dirname($path);
+ my $class = basename($path, ".java");
+ make_path($dir);
+ open ($dst, ">$path");
+
+ if ($package ne "") {
+ print $dst "package $package;\n";
+ }
+ print $dst <<END;
+import java.foreign.Libraries;
+import java.foreign.annotations.*;
+import java.foreign.memory.*;
+END
+ }
+
+ # FIXME: use something other than name to store this
+ print $dst "\@FunctionalInterface\n";
+ print $dst "\@NativeCallback(value=\"$call{name}\")\n";
+ print $dst "public interface $name {\n";
+ print $dst "\tpublic $result fn(";
+
+ for $pi (@params) {
+ my %param = %{$pi};
+ my $type = typeToJava($pi);
+
+ print $dst "$type $param{name}";
+ print $dst ", " if ($pi != $params[$#params]);
+ }
+
+ print $dst ");\n";
+ print $dst "}\n";
+
+ if (!$enclosingType) {
+ close($dst);
+ }
+}
+
+# Finish off
+if ($enclosingType) {
+ print $dst "}\n";
+ close($dst);
+}
--- /dev/null
+
+/*
+ Copyright (C) 2010,2019,2020 Michael Zucchi
+
+ 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
+ <http://www.gnu.org/licenses/>.
+*/
+
+/* **********************************************************************
+ * a simple ordered hash/list/stack
+ */
+struct node {
+ // list/stack next
+ struct node *next;
+ // hash chain link/stack prev
+ struct node *link;
+
+ // payload
+ tree type;
+ char name[];
+};
+
+struct list {
+ struct node *head;
+ struct node *tail;
+};
+
+struct hash {
+ struct node *table[64];
+ struct list list;
+};
+
+static struct node *node_alloc(tree type, const char *name) {
+ struct node *n = (struct node *)xmalloc(sizeof(struct node) + (name ? strlen(name) + 1 : 1));
+
+ n->next = NULL;
+ n->link = NULL;
+ n->type = type;
+ if (name)
+ strcpy(n->name, name);
+ else
+ n->name[0] = 0;
+
+ return n;
+}
+
+static void stack_push(struct list *stack, struct node *node) {
+ if (stack->head) {
+ stack->head->link = node;
+ node->next = stack->head;
+ stack->head = node;
+ } else {
+ stack->head = node;
+ stack->tail = node;
+ }
+}
+
+static struct node *stack_pull(struct list *stack) {
+ struct node *n = stack->head;
+
+ if (n) {
+ stack->head = n->next;
+ if (stack->head)
+ stack->head->link = NULL;
+ else
+ stack->tail = NULL;
+ }
+
+ return n;
+}
+
+static unsigned int ez_hash_string(const char *s) {
+ unsigned int hash = 5381;
+
+ while (*s)
+ //hash = (*s++) + (hash << 5) + hash;
+ hash = hash * 33 + (*s++);
+
+ return hash;
+}
+
+static void list_add(struct list *list, struct node *node) {
+ if (list->head) {
+ list->tail->next = node;
+ list->tail = node;
+ } else {
+ list->head = node;
+ list->tail = node;
+ }
+}
+
+static void hash_put(struct hash *hash, struct node *node) {
+ int code = ez_hash_string(node->name) & 63;
+
+ list_add(&hash->list, node);
+
+ node->link = hash->table[code];
+ hash->table[code] = node;
+}
+
+struct node *hash_lookup(struct hash *hash, const char *name) {
+ int code = ez_hash_string(name) & 63;
+
+ for (struct node *n = hash->table[code]; n; n=n->link) {
+ if (strcmp(n->name, name) == 0)
+ return n;
+ }
+
+ return NULL;
+}
+
+/* simple growable c buffer */
+struct buffer {
+ size_t size;
+ size_t pos;
+ char *data;
+};
+
+static void buffer_init(struct buffer *b, size_t size) {
+ b->size = size;
+ b->pos = 0;
+ b->data = (char *)xmalloc(size);
+}
+
+static void buffer_room(struct buffer *b, size_t len) {
+ if (b->pos + len >= b->size) {
+ do {
+ b->size *= 2;
+ } while (b->pos + len >= b->size);
+
+ b->data = (char *)xrealloc(b->data, b->size);
+ }
+}
+
+static void buffer_add(struct buffer *b, const char *v) {
+ size_t len = strlen(v);
+
+ buffer_room(b, len);
+ strcpy(b->data + b->pos, v);
+ b->pos += len;
+}
--- /dev/null
+/*
+Taken from gcc plugin/tree.defs
+
+GCC 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, or (at your option) any later
+version.
+
+GCC 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 GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+const char *tree_codes[] = {
+ "ERROR_MARK",
+"IDENTIFIER_NODE",
+"TREE_LIST",
+"TREE_VEC",
+"BLOCK",
+"OFFSET_TYPE",
+"ENUMERAL_TYPE",
+"BOOLEAN_TYPE",
+"INTEGER_TYPE",
+"REAL_TYPE",
+"POINTER_TYPE",
+"REFERENCE_TYPE",
+"NULLPTR_TYPE",
+"FIXED_POINT_TYPE",
+"COMPLEX_TYPE",
+"VECTOR_TYPE",
+"ARRAY_TYPE",
+"RECORD_TYPE",
+"UNION_TYPE",
+"QUAL_UNION_TYPE",
+"VOID_TYPE",
+"FUNCTION_TYPE",
+"METHOD_TYPE",
+"LANG_TYPE",
+"VOID_CST",
+"INTEGER_CST",
+"POLY_INT_CST",
+"REAL_CST",
+"FIXED_CST",
+"COMPLEX_CST",
+"VECTOR_CST",
+"STRING_CST",
+"FUNCTION_DECL",
+"LABEL_DECL",
+"FIELD_DECL",
+"VAR_DECL",
+"CONST_DECL",
+"PARM_DECL",
+"TYPE_DECL",
+"RESULT_DECL",
+"DEBUG_EXPR_DECL",
+"DEBUG_BEGIN_STMT",
+"NAMESPACE_DECL",
+"IMPORTED_DECL",
+"NAMELIST_DECL",
+"TRANSLATION_UNIT_DECL",
+"COMPONENT_REF",
+"BIT_FIELD_REF",
+"ARRAY_REF",
+"ARRAY_RANGE_REF",
+"REALPART_EXPR",
+"IMAGPART_EXPR",
+"VIEW_CONVERT_EXPR",
+"INDIRECT_REF",
+"OBJ_TYPE_REF",
+"CONSTRUCTOR",
+"COMPOUND_EXPR",
+"MODIFY_EXPR",
+"INIT_EXPR",
+"TARGET_EXPR",
+"COND_EXPR",
+"VEC_DUPLICATE_EXPR",
+"VEC_SERIES_EXPR",
+"VEC_COND_EXPR",
+"VEC_PERM_EXPR",
+"BIND_EXPR",
+"CALL_EXPR",
+"WITH_CLEANUP_EXPR",
+"CLEANUP_POINT_EXPR",
+"PLACEHOLDER_EXPR",
+"PLUS_EXPR",
+"MINUS_EXPR",
+"MULT_EXPR",
+"POINTER_PLUS_EXPR",
+"POINTER_DIFF_EXPR",
+"MULT_HIGHPART_EXPR",
+"TRUNC_DIV_EXPR",
+"CEIL_DIV_EXPR",
+"FLOOR_DIV_EXPR",
+"ROUND_DIV_EXPR",
+"TRUNC_MOD_EXPR",
+"CEIL_MOD_EXPR",
+"FLOOR_MOD_EXPR",
+"ROUND_MOD_EXPR",
+"RDIV_EXPR",
+"EXACT_DIV_EXPR",
+"FIX_TRUNC_EXPR",
+"FLOAT_EXPR",
+"NEGATE_EXPR",
+"MIN_EXPR",
+"MAX_EXPR",
+"ABS_EXPR",
+"ABSU_EXPR",
+"LSHIFT_EXPR",
+"RSHIFT_EXPR",
+"LROTATE_EXPR",
+"RROTATE_EXPR",
+"BIT_IOR_EXPR",
+"BIT_XOR_EXPR",
+"BIT_AND_EXPR",
+"BIT_NOT_EXPR",
+"TRUTH_ANDIF_EXPR",
+"TRUTH_ORIF_EXPR",
+"TRUTH_AND_EXPR",
+"TRUTH_OR_EXPR",
+"TRUTH_XOR_EXPR",
+"TRUTH_NOT_EXPR",
+"LT_EXPR",
+"LE_EXPR",
+"GT_EXPR",
+"GE_EXPR",
+"EQ_EXPR",
+"NE_EXPR",
+"UNORDERED_EXPR",
+"ORDERED_EXPR",
+"UNLT_EXPR",
+"UNLE_EXPR",
+"UNGT_EXPR",
+"UNGE_EXPR",
+"UNEQ_EXPR",
+"LTGT_EXPR",
+"RANGE_EXPR",
+"PAREN_EXPR",
+"CONVERT_EXPR",
+"ADDR_SPACE_CONVERT_EXPR",
+"FIXED_CONVERT_EXPR",
+"NOP_EXPR",
+"NON_LVALUE_EXPR",
+"COMPOUND_LITERAL_EXPR",
+"SAVE_EXPR",
+"ADDR_EXPR",
+"FDESC_EXPR",
+"BIT_INSERT_EXPR",
+"COMPLEX_EXPR",
+"CONJ_EXPR",
+"PREDECREMENT_EXPR",
+"PREINCREMENT_EXPR",
+"POSTDECREMENT_EXPR",
+"POSTINCREMENT_EXPR",
+"VA_ARG_EXPR",
+"TRY_CATCH_EXPR",
+"TRY_FINALLY_EXPR",
+"DECL_EXPR",
+"LABEL_EXPR",
+"GOTO_EXPR",
+"RETURN_EXPR",
+"EXIT_EXPR",
+"LOOP_EXPR",
+"SWITCH_EXPR",
+"CASE_LABEL_EXPR",
+"ASM_EXPR",
+"SSA_NAME",
+"CATCH_EXPR",
+"EH_FILTER_EXPR",
+"SCEV_KNOWN",
+"SCEV_NOT_KNOWN",
+"POLYNOMIAL_CHREC",
+"STATEMENT_LIST",
+"ASSERT_EXPR",
+"TREE_BINFO",
+"WITH_SIZE_EXPR",
+"REALIGN_LOAD_EXPR",
+"TARGET_MEM_REF",
+"MEM_REF",
+"OACC_PARALLEL",
+"OACC_KERNELS",
+"OACC_DATA",
+"OACC_HOST_DATA",
+"OMP_PARALLEL",
+"OMP_TASK",
+"OMP_FOR",
+"OMP_SIMD",
+"OMP_DISTRIBUTE",
+"OMP_TASKLOOP",
+"OACC_LOOP",
+"OMP_TEAMS",
+"OMP_TARGET_DATA",
+"OMP_TARGET",
+"OMP_SECTIONS",
+"OMP_ORDERED",
+"OMP_CRITICAL",
+"OMP_SINGLE",
+"OMP_TASKGROUP",
+"OMP_SECTION",
+"OMP_MASTER",
+"OACC_CACHE",
+"OACC_DECLARE",
+"OACC_ENTER_DATA",
+"OACC_EXIT_DATA",
+"OACC_UPDATE",
+"OMP_TARGET_UPDATE",
+"OMP_TARGET_ENTER_DATA",
+"OMP_TARGET_EXIT_DATA",
+"OMP_ATOMIC",
+"OMP_ATOMIC_READ",
+"OMP_ATOMIC_CAPTURE_OLD",
+"OMP_ATOMIC_CAPTURE_NEW",
+"OMP_CLAUSE",
+"TRANSACTION_EXPR",
+"DOT_PROD_EXPR",
+"WIDEN_SUM_EXPR",
+"SAD_EXPR",
+"WIDEN_MULT_EXPR",
+"WIDEN_MULT_PLUS_EXPR",
+"WIDEN_MULT_MINUS_EXPR",
+"WIDEN_LSHIFT_EXPR",
+"VEC_WIDEN_MULT_HI_EXPR",
+"VEC_WIDEN_MULT_LO_EXPR",
+"VEC_WIDEN_MULT_EVEN_EXPR",
+"VEC_WIDEN_MULT_ODD_EXPR",
+"VEC_UNPACK_HI_EXPR",
+"VEC_UNPACK_LO_EXPR",
+"VEC_UNPACK_FLOAT_HI_EXPR",
+"VEC_UNPACK_FLOAT_LO_EXPR",
+"VEC_UNPACK_FIX_TRUNC_HI_EXPR",
+"VEC_UNPACK_FIX_TRUNC_LO_EXPR",
+"VEC_PACK_TRUNC_EXPR",
+"VEC_PACK_SAT_EXPR",
+"VEC_PACK_FIX_TRUNC_EXPR",
+"VEC_PACK_FLOAT_EXPR",
+"VEC_WIDEN_LSHIFT_HI_EXPR",
+"VEC_WIDEN_LSHIFT_LO_EXPR",
+"PREDICT_EXPR",
+"OPTIMIZATION_NODE",
+"TARGET_OPTION_NODE",
+"ANNOTATE_EXPR",
+"LAST_AND_UNUSED_TREE_CODE",
+"C_MAYBE_CONST_EXPR",
+"EXCESS_PRECISION_EXPR",
+"USERDEF_LITERAL",
+"SIZEOF_EXPR",
+"UNCONSTRAINED_ARRAY_TYPE",
+"UNCONSTRAINED_ARRAY_REF",
+"NULL_EXPR",
+"PLUS_NOMOD_EXPR",
+"MINUS_NOMOD_EXPR",
+"POWER_EXPR",
+"ATTR_ADDR_EXPR",
+"STMT_STMT",
+"LOOP_STMT",
+"EXIT_STMT",
+"OFFSET_REF",
+"PTRMEM_CST",
+"NEW_EXPR",
+"VEC_NEW_EXPR",
+"DELETE_EXPR",
+"VEC_DELETE_EXPR",
+"SCOPE_REF",
+"MEMBER_REF",
+"TYPE_EXPR",
+"AGGR_INIT_EXPR",
+"VEC_INIT_EXPR",
+"THROW_EXPR",
+"EMPTY_CLASS_EXPR",
+"BASELINK",
+"TEMPLATE_DECL",
+"TEMPLATE_PARM_INDEX",
+"TEMPLATE_TEMPLATE_PARM",
+"TEMPLATE_TYPE_PARM",
+"TYPENAME_TYPE",
+"TYPEOF_TYPE",
+"BOUND_TEMPLATE_TEMPLATE_PARM",
+"UNBOUND_CLASS_TEMPLATE",
+"USING_DECL",
+"USING_STMT",
+"DEFAULT_ARG",
+"DEFERRED_NOEXCEPT",
+"TEMPLATE_ID_EXPR",
+"OVERLOAD",
+"PSEUDO_DTOR_EXPR",
+"MODOP_EXPR",
+"CAST_EXPR",
+"REINTERPRET_CAST_EXPR",
+"CONST_CAST_EXPR",
+"STATIC_CAST_EXPR",
+"DYNAMIC_CAST_EXPR",
+"IMPLICIT_CONV_EXPR",
+"DOTSTAR_EXPR",
+"TYPEID_EXPR",
+"NOEXCEPT_EXPR",
+"NON_DEPENDENT_EXPR",
+"CTOR_INITIALIZER",
+"TRY_BLOCK",
+"EH_SPEC_BLOCK",
+"HANDLER",
+"MUST_NOT_THROW_EXPR",
+"CLEANUP_STMT",
+"IF_STMT",
+"FOR_STMT",
+"RANGE_FOR_STMT",
+"WHILE_STMT",
+"DO_STMT",
+"BREAK_STMT",
+"CONTINUE_STMT",
+"SWITCH_STMT",
+"EXPR_STMT",
+"TAG_DEFN",
+"OFFSETOF_EXPR",
+"ADDRESSOF_EXPR",
+"ARROW_EXPR",
+"ALIGNOF_EXPR",
+"AT_ENCODE_EXPR",
+"STMT_EXPR",
+"UNARY_PLUS_EXPR",
+"STATIC_ASSERT",
+"TYPE_ARGUMENT_PACK",
+"NONTYPE_ARGUMENT_PACK",
+"TYPE_PACK_EXPANSION",
+"EXPR_PACK_EXPANSION",
+"ARGUMENT_PACK_SELECT",
+"UNARY_LEFT_FOLD_EXPR",
+"UNARY_RIGHT_FOLD_EXPR",
+"BINARY_LEFT_FOLD_EXPR",
+"BINARY_RIGHT_FOLD_EXPR",
+"TRAIT_EXPR",
+"LAMBDA_EXPR",
+"DECLTYPE_TYPE",
+"UNDERLYING_TYPE",
+"BASES",
+"TEMPLATE_INFO",
+"OMP_DEPOBJ",
+"CONSTRAINT_INFO",
+"WILDCARD_DECL",
+"REQUIRES_EXPR",
+"SIMPLE_REQ",
+"TYPE_REQ",
+"COMPOUND_REQ",
+"NESTED_REQ",
+"PRED_CONSTR",
+"CHECK_CONSTR",
+"EXPR_CONSTR",
+"TYPE_CONSTR",
+"ICONV_CONSTR",
+"DEDUCT_CONSTR",
+"EXCEPT_CONSTR",
+"PARM_CONSTR",
+"CONJ_CONSTR",
+"DISJ_CONSTR",
+"UNSIGNED_RSHIFT_EXPR",
+"FLOAT_MOD_EXPR",
+"FUNCFRAME_INFO",
+"CLASS_INTERFACE_TYPE",
+"CLASS_IMPLEMENTATION_TYPE",
+"CATEGORY_INTERFACE_TYPE",
+"CATEGORY_IMPLEMENTATION_TYPE",
+"PROTOCOL_INTERFACE_TYPE",
+"KEYWORD_DECL",
+"INSTANCE_METHOD_DECL",
+"CLASS_METHOD_DECL",
+"PROPERTY_DECL",
+"MESSAGE_SEND_EXPR",
+"CLASS_REFERENCE_EXPR",
+"PROPERTY_REF",
+ };
+
+#define ZTREE_CODE(x) tree_codes[TREE_CODE(x)]
--- /dev/null
+
+CFLAGS=-g -fPIC
+
+JAVA_HOME ?= /home/notzed/src/openjdk-panama-14
+JAVAC=$(JAVA_HOME)/bin/javac
+JAVA=$(JAVA_HOME)/bin/java
+
+all: bin/libapi.so bin/api.classes bin/classes/api/test/TestAPI.class
+
+bin/classes/api/test/TestAPI.class: api/test/TestAPI.java bin/api.classes
+ $(JAVAC) -cp bin/classes -d bin/classes $<
+
+bin/api.classes: bin/api.pm
+ ../src/generate -d bin/java -t api -c APILib -lapi ./bin/api.pm
+ $(JAVAC) -d bin/classes bin/java/api/*.java
+ touch $@
+
+bin/api.pm: api.h
+ gcc -fplugin=../src/export.so -fplugin-arg-export-output=$@ ./$< -o /dev/null
+
+bin/api.o: api.c api.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+bin/libapi.so: bin/api.o
+ $(CC) -o $@ -shared $^
+
+check: all
+ $(JAVA) -Djava.library.path=bin -cp bin/classes api.test.TestAPI
+
+clean:
+ rm -rf bin
+
+.PHONY: check clean
+
+$(if $(filter clean,$(MAKECMDGOALS)),,$(shell mkdir -p bin))
--- /dev/null
+
+#include <stdio.h>
+#include "api.h"
+
+void print_data(struct data *data) {
+ while (data) {
+ printf("%p: a=%d b=%d c=%d d=%d", data, data->a, data->b, data->c, data->d);
+ if (data->test_a)
+ printf(" data->test_a()=%d", data->test_a());
+ printf("\n");
+ data = data->next;
+ }
+}
--- /dev/null
+
+struct data {
+ struct data *next;
+
+ int a;
+ int b;
+ int c:3;
+ unsigned d:5;
+ int (*test_a)(void);
+};
+
+void print_data(struct data *data);
--- /dev/null
+
+package api.test;
+
+import java.foreign.*;
+import java.foreign.memory.*;
+import java.foreign.annotations.*;
+import java.util.function.IntFunction;
+
+import api.*;
+
+public class TestAPI {
+ public static void main(String[] args) {
+ APILib lib = APILib.bind;
+ LayoutType<Data> dataLayout = LayoutType.ofStruct(Data.class);
+
+ try (Scope s = Libraries.libraryScope(lib).fork()) {
+ Pointer<Data> a = s.allocate(dataLayout);
+ Pointer<Data> b = s.allocate(dataLayout);
+ Callback<Call__I> cb = s.allocateCallback(Call__I.class,
+ () -> {
+ return 56;
+ });
+
+ Data ad = a.get();
+ Data bd = b.get();
+
+ ad.setNext(b);
+ ad.setA(1);
+ ad.setB(2);
+ ad.setC((byte)3);
+ ad.setD((byte)4);
+
+ bd.setA(5);
+ bd.setB(6);
+ bd.setC((byte)255);
+ bd.setD((byte)255);
+
+ bd.setTestA(cb);
+
+ System.out.println("from a\n");
+ lib.print_data(a);
+ System.out.println("\bfrom b\n");
+ lib.print_data(b);
+ }
+ }
+}